TL; DR nie próbuj tego robić
$ make run arg
zamiast tego utwórz skrypt:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
i zrób to:
$ ./buildandrunprog.sh arg
odpowiedz na zadane pytanie:
możesz użyć zmiennej w recepturze
run: prog
./prog $(var)
następnie przekaż przypisanie zmiennej jako argument do wykonania
$ make run var=arg
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
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
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:
$ ./buildandrunprog.sh foo "bar baz"
porównać do:
$ ./prog foo "bar baz"
w przeciwieństwie do
$ make run var="foo bar\ baz"
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:
$ make run foo --wat var=arg
Marka będzie interpretować run
i foo
jako cele (cele) aktualizować zgodnie z ich przepisami. --wat
jako opcja dla make. i var=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
$ make run var=arg
i zmienna w recepturze
run: prog
./prog $(var)
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
argument arg
. ale zamiast pisać:
$ ./prog arg
piszesz:
$ make run var=arg
staje się to jeszcze bardziej niezręczne przy próbie przekazania wielu argumentów lub argumentów zawierających spacje:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
porównać do:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
dla przypomnienia prog
wygląda to tak:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
zauważ także, że nie powinieneś umieszczać $(var)
cudzysłowów w pliku makefile:
run: prog
./prog "$(var)"
ponieważ wtedy prog
zawsze otrzyma tylko jeden argument:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
wszystko dlatego polecam przeciwko tej trasie.
dla kompletności oto kilka innych metod „przekazywania argumentów do uruchomienia”.
metoda 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
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:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
super krótkie wyjaśnienie: jeśli celem jest run
usunięcie pierwszego celu i utworzenie nic nie rób dla pozostałych celów eval
.
oba pozwolą ci napisać coś takiego
$ make run arg1 arg2
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.
$ make run --foo --bar
obejście
$ make run -- --foo --bar
argumenty ze znakiem równości będą interpretowane przez make, a nie przekazywane
$ make run foo=bar
bez obejścia
kłótnie ze spacjami są niezręczne
$ make run foo "bar\ baz"
bez obejścia
jeśli argument stanie się run
(równy celowi), zostanie również usunięty
$ make run foo bar run
uruchomi 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.
$ make run foo bar clean
uruchomi się, ./prog foo bar clean
ale także przepis na cel clean
(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.
$ make celan
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ć
$ make run arg
zamiast tego utwórz skrypt:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
i zrób to:
$ ./buildandrunprog.sh arg