Używam Makefiles.
Mam cel o nazwie, run
który uruchamia cel kompilacji. Uproszczony wygląda następująco:
prog: ....
...
run: prog
./prog
Czy jest jakiś sposób na przekazanie argumentów? Po to aby
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
Dzięki!
Odpowiedzi:
Nie znam sposobu na zrobienie dokładnie tego, co chcesz, ale obejście może być następujące:
Następnie:
źródło
$(foo)' or
$ {foo} 'jest poprawnym odniesieniem do zmienna „foo”. ” i podaje przykłady, w których użyto tylko $ (). Ach tak.To pytanie ma prawie trzy lata, ale w każdym razie ...
Jeśli używasz GNU make, jest to łatwe. Jedynym problemem jest to, że
make
zinterpretuje argumenty nie będące opcjami w wierszu poleceń jako cele. Rozwiązaniem jest przekształcenie ich w cele bezczynności, abymake
nie narzekać:Uruchomienie tego daje:
źródło
prog foo bar --baz
make
, aby nie interpretować--baz
jako opcja wiersza poleceń:make -- prog foo bar --baz
.--
Oznacza „wszystko po to jest argument, nie jest rozwiązaniem”.RUN_ARGS
korzystania z tego?else
gałąźifeq
i ustawićRUN_ARGS
tam?$(eval $(RUN_ARGS):dummy;@:)
, bez zdefiniowanego fałszywego celu.dla standardowego make możesz przekazać argumenty, definiując takie makra
następnie użyj ich w ten sposób
Referencje dla make Microsoft's NMake
źródło
Możesz przekazać zmienną do pliku Makefile, jak poniżej:
Stosowanie:
lub:
Alternatywnie skorzystaj z rozwiązania dostarczonego przez Beta :
Stosowanie:
źródło
TL; DR nie próbuj tego robić
zamiast tego utwórz skrypt:
i zrób to:
odpowiedz na zadane pytanie:
możesz użyć zmiennej w recepturze
następnie przekaż przypisanie zmiennej jako argument do wykonania
to się wykona
./prog arg
.ale strzeżcie się pułapek. omówię pułapki tej metody i innych metod w dalszej części.
odpowiedz na zakładaną intencję pytania:
założenie: chcesz uruchomić
prog
z kilkoma argumentami, ale w razie potrzeby przebuduj go przed uruchomieniem.odpowiedź: utwórz skrypt, który w razie potrzeby odbuduje, a następnie uruchomi prog z args
ten skrypt wyraźnie wyjaśnia intencję. używa make do robienia tego, co jest dobre: budowania. używa skryptu powłoki do robienia tego, co jest dobre dla: przetwarzania wsadowego.
a ponadto możesz robić wszystko, czego potrzebujesz, z pełną elastycznością i ekspresyjnością skryptu powłoki, bez wszystkich zastrzeżeń makefile.
również składnia wywołująca jest teraz praktycznie identyczna:
porównać do:
w przeciwieństwie do
tło:
make nie jest przeznaczony do przekazywania argumentów do celu. wszystkie argumenty w wierszu poleceń są interpretowane jako cel (aka target), jako opcja lub jako przypisanie zmiennej.
więc jeśli uruchomisz to:
Marka będzie interpretować
run
ifoo
jako cele (cele) aktualizować zgodnie z ich przepisami.--wat
jako opcja dla make. ivar=arg
jako zmienne przypisanie.Więcej informacji: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
terminologia patrz: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
na temat metody przypisywania zmiennych i dlaczego odradzam
i zmienna w recepturze
jest to najbardziej „poprawny” i najprostszy sposób przekazywania argumentów do przepisu. ale chociaż można go używać do uruchamiania programu z argumentami, to z pewnością nie jest przeznaczony do użycia w ten sposób. patrz https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
moim zdaniem ma to jedną wielką wadę: to, co chcesz zrobić, to uruchomić
prog
argumentarg
. ale zamiast pisać:piszesz:
staje się to jeszcze bardziej niezręczne przy próbie przekazania wielu argumentów lub argumentów zawierających spacje:
porównać do:
dla przypomnienia
prog
wygląda to tak:zauważ także, że nie powinieneś umieszczać
$(var)
cudzysłowów w pliku makefile:ponieważ wtedy
prog
zawsze otrzyma tylko jeden argument:wszystko dlatego polecam przeciwko tej trasie.
dla kompletności oto kilka innych metod „przekazywania argumentów do uruchomienia”.
metoda 1:
super krótkie wyjaśnienie: odfiltruj aktualny cel z listy celów. create catch all target (
%
), który nie robi nic, aby po cichu zignorować pozostałe cele.metoda 2:
super krótkie wyjaśnienie: jeśli celem jest
run
usunięcie pierwszego celu i utworzenie nic nie rób dla pozostałych celóweval
.oba pozwolą ci napisać coś takiego
dla głębszego wyjaśnienia zapoznaj się z instrukcją make: https://www.gnu.org/software/make/manual/html_node/index.html
problemy metody 1:
argumenty rozpoczynające się od myślnika będą interpretowane przez make, a nie przekazywane jako cel.
obejście
argumenty ze znakiem równości będą interpretowane przez make, a nie przekazywane
bez obejścia
kłótnie ze spacjami są niezręczne
bez obejścia
jeśli argument stanie się
run
(równy celowi), zostanie również usuniętyuruchomi się
./prog foo bar
zamiast./prog foo bar run
obejście możliwe dzięki metodzie 2
jeśli argument jest uzasadnionym celem, zostanie również uruchomiony.
uruchomi się,
./prog foo bar clean
ale także przepis na celclean
(zakładając, że istnieje).obejście możliwe dzięki metodzie 2
gdy błędnie wpiszesz prawidłowy cel, zostanie on po cichu zignorowany z powodu złapania wszystkich celów.
po prostu po cichu zignoruje
celan
.obejście polega na tym, aby wszystko było pełne. więc widzisz, co się dzieje. ale to powoduje dużo hałasu dla legalnej wydajności.
problemy metody 2:
jeśli argument ma taką samą nazwę jak istniejący cel, wtedy make wypisze ostrzeżenie, że jest zastępowane.
brak obejścia, o którym wiem
argumenty ze znakiem równości będą nadal interpretowane przez make, a nie przekazywane
bez obejścia
spory ze spacjami są wciąż niezręczne
bez obejścia
argumenty z przerwami w przestrzeni
eval
próbujące stworzyć nic nie rób celów.obejście: utwórz globalny cel catch all, nie robiąc nic tak jak powyżej. z powyższym problemem, że ponownie po cichu zignoruje błędnie wpisane uzasadnione cele.
używa
eval
do modyfikowania pliku makefile w czasie wykonywania. o ile gorzej możesz pójść pod względem czytelności i debugowania oraz zasady najmniejszego zdziwienia .obejście: nie rób tego !! 1 zamiast tego napisz skrypt powłoki, który uruchamia make, a następnie uruchamia
prog
.testowałem tylko przy użyciu gnu make. inne marki mogą mieć różne zachowania.
TL; DR nie próbuj tego robić
zamiast tego utwórz skrypt:
i zrób to:
źródło
Oto inne rozwiązanie, które może pomóc w niektórych z tych przypadków użycia:
Innymi słowy, wybierz jakiś prefiks (
test-
w tym przypadku), a następnie przekaż nazwę docelową bezpośrednio do programu / programu uruchamiającego. Wydaje mi się, że jest to szczególnie przydatne, jeśli zaangażowany jest jakiś skrypt uruchamiający, który może rozpakować docelową nazwę na coś przydatnego dla programu bazowego.źródło
$*
aby przekazać tylko część celu, która pasowała do%
.Nie. Patrząc na składnię ze strony podręcznika dla GNU make
możesz określić wiele celów, a więc „nie” (przynajmniej nie w dokładnie taki sposób, jaki określiłeś).
źródło
Możesz jawnie wyodrębnić każdy n-ty argument z wiersza poleceń. Aby to zrobić, możesz użyć zmiennej MAKECMDGOALS, która zawiera listę argumentów wiersza poleceń podanych dla „make”, co interpretuje jako listę celów. Jeśli chcesz wyodrębnić n-ty argument, możesz użyć tej zmiennej w połączeniu z funkcją „słowo”, na przykład, jeśli chcesz drugi argument, możesz zapisać go w zmiennej w następujący sposób:
źródło
make: *** No rule to make target 'arg'. Stop.
anon ,
run: ./prog
wygląda nieco dziwnie, jak prawa część powinna być celem, takrun: prog
wygląda lepiej.Sugerowałbym po prostu:
i chciałbym dodać, że argumenty można przekazać:
make arg1="asdf" run
arg1="asdf" make run
źródło
Oto mój przykład. Zauważ, że piszę pod Windows 7, używając mingw32-make.exe, który jest dostarczany z Dev-Cpp. (Mam c: \ Windows \ System32 \ make.bat, więc polecenie wciąż nazywa się „make”.)
Zastosowanie do regularnego czyszczenia:
Zastosowanie do czyszczenia i tworzenia kopii zapasowej w mydir /:
źródło
Nie jestem z tego dumny, ale nie chciałem przekazywać zmiennych środowiskowych, więc odwróciłem sposób uruchamiania komendy w puszce:
to wypisze polecenie, które chcesz uruchomić, więc po prostu oceń je w podpowłoce:
źródło
Znalazłem sposób na uzyskanie argumentów znakiem równości (=)! Odpowiedź jest szczególnie dodatkiem do odpowiedzi @lesmana (ponieważ jest to najbardziej kompletna i wyjaśniona tutaj), ale byłoby zbyt duże, aby napisać ją jako komentarz. Ponownie powtarzam jego wiadomość: TL; DR nie próbuj tego robić!
Potrzebowałem sposobu na potraktowanie mojego argumentu
--xyz-enabled=false
(ponieważ domyślnie jest to prawda), o którym wszyscy wiemy, że nie jest to cel docelowy i dlatego nie jest częścią$(MAKECMDGOALS)
.Przeglądając wszystkie zmienne make przez echo,
$(.VARIABLES)
otrzymałem te interesujące wyniki:To pozwala nam iść na dwa sposoby: albo zacząć wszystko od
--
(jeśli dotyczy to twojego przypadku), albo przyjrzeć się GNU, tworząc specyficzną (prawdopodobnie nie przeznaczoną dla nas) zmienną-*-command-variables-*-
. ** Zobacz stopkę dla dodatkowych opcji ** W moim przypadku ta zmienna posiadała:Za pomocą tej zmiennej możemy połączyć ją z już istniejącym rozwiązaniem,
$(MAKECMDGOALS)
a tym samym definiując:i używając go (jawnie mieszając kolejność argumentów):
zwrócony:
Jak widać, tracimy całkowitą kolejność argumentów. Część z „przypisaniem” -arg wydaje się być odwrócona, kolejność „docelowych” -arg jest zachowana. Umieściłem „przypisanie” na początku, mam nadzieję, że twój program nie dba o to, gdzie znajduje się argument.
Aktualizacja: dzięki nim zmienne również wyglądają obiecująco:
źródło
Inną sztuczką, której używam, jest
-n
flaga, która każemake
wykonać próbę na sucho. Na przykład,źródło