Eu uso Makefiles.
Eu tenho um destino chamado run
que executa o destino da compilação. Simplificado, parece com o seguinte:
prog: ....
...
run: prog
./prog
Existe alguma maneira de passar argumentos? De modo a
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
Obrigado!
Respostas:
Não sei como fazer exatamente o que você deseja, mas uma solução alternativa pode ser:
Então:
fonte
$(foo)' or
$ {foo} 'é uma referência válida para a variável `foo '." e continua dando exemplos onde apenas $ () é usado. Ah bem.Esta pergunta tem quase três anos, mas mesmo assim ...
Se você estiver usando o GNU make, isso é fácil. O único problema é que
make
interpretará argumentos não opcionais na linha de comando como destinos. A solução é transformá-los em alvos do tipo "não faça nada", paramake
não reclamar:A execução disso fornece:
fonte
prog foo bar --baz
make
não interpretar--baz
como uma opção de linha de comando:make -- prog foo bar --baz
. O--
meio "tudo depois disso é um argumento, não uma opção".RUN_ARGS
usar isso?else
ramo aoifeq
e definirRUN_ARGS
lá?$(eval $(RUN_ARGS):dummy;@:)
, com nenhum alvo fictício definido.para make padrão, você pode passar argumentos definindo macros como esta
então use-os assim
Referências para make NMake da Microsoft
fonte
Você pode passar a variável para o Makefile como abaixo:
Uso:
ou:
Como alternativa, use a solução fornecida pela Beta :
Uso:
fonte
TL; DR não tente fazer isso
em vez disso, crie um script:
e faça o seguinte:
responda à pergunta declarada:
você pode usar uma variável na receita
depois passe uma atribuição de variável como argumento para fazer
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
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:
comparado a:
contrasta com
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 interpretará
run
efoo
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
e a variável na receita
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 argumentoarg
. mas em vez de escrever:tu estás a escrever:
isso fica ainda mais estranho ao tentar passar vários argumentos ou argumentos que contêm espaços:
comparado a:
para o registro é assim que a minha
prog
aparência:Observe também que você não deve colocar
$(var)
aspas no makefile:porque
prog
sempre terá apenas um argumento:é 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:
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:
explicação super curta: se o alvo for
run
, remova o primeiro objetivo e crie não faça nada para os demais objetivos usandoeval
.ambos permitem que você escreva algo parecido com isto
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.
Gambiarra
argumentos com um sinal de igual serão interpretados por make e não passados
nenhuma solução alternativa
argumentos com espaços é estranho
nenhuma solução alternativa
se um argumento for
run
(igual ao alvo), ele também será removidoserá 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.
será executado,
./prog foo bar clean
mas também a receita para o destinoclean
(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.
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
em vez disso, crie um script:
e faça o seguinte:
fonte
Aqui está outra solução que pode ajudar com alguns desses casos de uso:
Em outras palavras, escolha um prefixo (
test-
nesse caso) e depois passe o nome do destino diretamente para o programa / corredor. Eu acho que isso é útil principalmente se houver algum script de corredor envolvido que possa desembrulhar o nome do destino em algo útil para o programa subjacente.fonte
$*
para passar apenas a parte do destino que correspondeu ao%
.Não. Examinar a sintaxe da página de manual do GNU make
você pode especificar vários destinos, daí 'não' (pelo menos não da maneira exata que você especificou).
fonte
Você pode extrair explicitamente cada n-ésimo argumento na linha de comando. Para fazer isso, você pode usar a variável MAKECMDGOALS, que contém a lista de argumentos de linha de comando fornecidos para 'make', que interpreta como uma lista de destinos. Se você deseja extrair o n-ésimo argumento, pode usar essa variável combinada com a função "word"; por exemplo, se desejar o segundo argumento, pode armazená-lo em uma variável da seguinte maneira:
fonte
make: *** No rule to make target 'arg'. Stop.
anon ,
run: ./prog
parece um pouco estranho, pois a parte certa deve ser um alvo, entãorun: prog
fica melhor.Eu sugeriria simplesmente:
e gostaria de acrescentar que argumentos podem ser passados:
make arg1="asdf" run
arg1="asdf" make run
fonte
Aqui está o meu exemplo. Observe que estou escrevendo no Windows 7, usando o mingw32-make.exe que acompanha o Dev-Cpp. (Eu tenho c: \ Windows \ System32 \ make.bat, então o comando ainda é chamado de "make".)
Uso para limpeza regular:
Uso para limpar e criar um backup no mydir /:
fonte
Não tenho muito orgulho disso, mas como não queria passar variáveis de ambiente, inverti a maneira de executar um comando fixo:
isso imprimirá o comando que você deseja executar, então apenas avalie-o em uma subshell:
fonte
Eu encontrei uma maneira de obter os argumentos com um sinal de igual (=)! A resposta é especialmente uma adição à resposta do @lesmana (como a mais completa e explicada aqui), mas seria muito grande para ser escrita como um comentário. Mais uma vez, repito sua mensagem: TL; DR não tente fazer isso!
Eu precisava de uma maneira de tratar meu argumento
--xyz-enabled=false
(já que o padrão é verdadeiro), que todos sabemos até agora que este não é um objetivo de criação e, portanto, não faz parte do$(MAKECMDGOALS)
.Ao olhar para todas as variáveis de make , ecoando o
$(.VARIABLES)
eu tenho essas saídas interessantes:Isso nos permite seguir dois caminhos: começar tudo com uma
--
(se isso se aplica ao seu caso) ou olhar para o GNU fazer variável específica (provavelmente não pretendida para nós usarmos)-*-command-variables-*-
. ** Veja o rodapé para opções adicionais ** No meu caso, essa variável contém:Com esta variável, podemos combiná-la com a solução já existente
$(MAKECMDGOALS)
e, assim, definindo:e usá-lo com (misturando explicitamente a ordem dos argumentos):
devolvida:
Como você pode ver, perdemos a ordem total dos argumentos. A parte com as "atribuições" -args parece ter sido revertida, a ordem dos "destino" -args é mantida. Eu coloquei a "atribuição" -args no começo, espero que seu programa não se importe onde o argumento é colocado.
Atualização: a seguir, as variáveis também parecem promissoras:
fonte
Outro truque que uso é a
-n
bandeira, que dizmake
para fazer uma corrida a seco. Por exemplo,fonte