TL; DR não tente fazer isso
$ make run arg
em vez disso, crie um script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
e faça o seguinte:
$ ./buildandrunprog.sh arg
responda à pergunta declarada:
você pode usar uma variável na receita
run: prog
./prog $(var)
depois passe uma atribuição de variável como argumento para fazer
$ make run var=arg
isso será executado ./prog arg
.
mas cuidado com as armadilhas. vou elaborar sobre as armadilhas deste método e outros métodos mais adiante.
responda à intenção assumida por trás da pergunta:
a suposição: você deseja executar prog
com alguns argumentos, mas reconstrua-o antes de executar, se necessário.
a resposta: crie um script que reconstrua, se necessário, e execute prog com args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
esse script deixa a intenção muito clara. usa make para fazer o que é bom para: construir. Ele usa um script de shell para fazer o que é bom: processamento em lote.
Além disso, você pode fazer o que precisar com toda a flexibilidade e expressividade de um script de shell sem todas as ressalvas de um makefile.
também a sintaxe de chamada agora é praticamente idêntica:
$ ./buildandrunprog.sh foo "bar baz"
comparado a:
$ ./prog foo "bar baz"
contrasta com
$ make run var="foo bar\ baz"
fundo:
make não foi projetado para passar argumentos para um destino. todos os argumentos na linha de comando são interpretados como um objetivo (também conhecido como destino), como uma opção ou como uma atribuição de variável.
então, se você executar isso:
$ make run foo --wat var=arg
make interpretará run
e foo
como objetivos (metas) a serem atualizados de acordo com suas receitas. --wat
como uma opção para make. evar=arg
como uma atribuição de variável.
para mais detalhes veja: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
para obter a terminologia, consulte: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
sobre o método de atribuição de variáveis e por que eu recomendo isso
$ make run var=arg
e a variável na receita
run: prog
./prog $(var)
essa é a maneira mais "correta" e direta de passar argumentos para uma receita. mas, embora possa ser usado para executar um programa com argumentos, certamente não foi projetado para ser usado dessa maneira. consulte https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
na minha opinião, isso tem uma grande desvantagem: o que você quer fazer é executar prog
com argumento arg
. mas em vez de escrever:
$ ./prog arg
tu estás a escrever:
$ make run var=arg
isso fica ainda mais estranho ao tentar passar vários argumentos ou argumentos que contêm espaços:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
comparado a:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
para o registro é assim que a minha prog
aparência:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
Observe também que você não deve colocar $(var)
aspas no makefile:
run: prog
./prog "$(var)"
porque prog
sempre terá apenas um argumento:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
é por isso que eu recomendo contra essa rota.
para completar, aqui estão alguns outros métodos para "passar argumentos para executar".
Método 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
explicação super curta: filtre a meta atual da lista de metas. create catch all target ( %
) que não faz nada para ignorar silenciosamente os outros objetivos.
método 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
explicação super curta: se o alvo for run
, remova o primeiro objetivo e crie não faça nada para os demais objetivos usando eval
.
ambos permitem que você escreva algo parecido com isto
$ make run arg1 arg2
para uma explicação mais aprofundada, estude o manual do make: https://www.gnu.org/software/make/manual/html_node/index.html
problemas do método 1:
argumentos que começam com um traço serão interpretados por make e não passados como um objetivo.
$ make run --foo --bar
Gambiarra
$ make run -- --foo --bar
argumentos com um sinal de igual serão interpretados por make e não passados
$ make run foo=bar
nenhuma solução alternativa
argumentos com espaços é estranho
$ make run foo "bar\ baz"
nenhuma solução alternativa
se um argumento for run
(igual ao alvo), ele também será removido
$ make run foo bar run
será executado em ./prog foo bar
vez de./prog foo bar run
solução possível com o método 2
se um argumento é um alvo legítimo, ele também será executado.
$ make run foo bar clean
será executado, ./prog foo bar clean
mas também a receita para o destino clean
(supondo que ele exista).
solução possível com o método 2
quando você digitar incorretamente um destino legítimo, ele será ignorado silenciosamente por causa da captura de todos os alvos.
$ make celan
apenas ignorará silenciosamente celan
.
solução alternativa é tornar tudo detalhado. para você ver o que acontece. mas isso cria muito ruído para a saída legítima.
problemas do método 2:
se um argumento tiver o mesmo nome que um destino existente, o make imprimirá um aviso de que está sendo substituído.
nenhuma solução alternativa que eu conheço
argumentos com um sinal de igual ainda serão interpretados por make e não serão passados
nenhuma solução alternativa
argumentos com espaços ainda é estranho
nenhuma solução alternativa
argumentos com quebras de espaço eval
tentando criar alvos não fazem nada.
solução alternativa: crie a captura global de todos os destinos, sem fazer nada como acima. com o problema acima, ele novamente ignorará silenciosamente alvos legítimos incorretos.
Ele usa eval
para modificar o makefile em tempo de execução. quanto pior você pode ir em termos de legibilidade e depuração e do Princípio de menor espanto .
solução alternativa: não faça isso !! 1 em vez disso, escreva um script de shell que execute make e, em seguida, execute prog
.
Eu só testei usando o gnu make. outras marcas podem ter um comportamento diferente.
TL; DR não tente fazer isso
$ make run arg
em vez disso, crie um script:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
e faça o seguinte:
$ ./buildandrunprog.sh arg