Como posso verificar se um programa pode ser chamado de um Makefile?
(Ou seja, o programa deve existir no caminho ou pode ser chamado de outra forma.)
Pode ser usado para verificar qual compilador está instalado, por exemplo.
Por exemplo, algo como esta questão , mas sem assumir que o shell subjacente é compatível com POSIX.
automake
script que verifica vários pré-requisitos e escreve um adequadoMakefile
.Respostas:
Às vezes, você precisa de um Makefile para ser executado em diferentes sistemas operacionais de destino e deseja que a compilação falhe mais cedo se um executável necessário não estiver disponível, em
PATH
vez de ser executado por um possivelmente longo tempo antes de falhar.A excelente solução fornecida por engineerchuan requer fazer um alvo . No entanto, se você tiver muitos executáveis para testar e seu Makefile tiver muitos destinos independentes, cada um dos quais requer os testes, então cada destino requer o destino de teste como uma dependência. Isso gera uma grande quantidade de digitação extra, bem como tempo de processamento, quando você cria mais de um destino por vez.
A solução fornecida por 0xf pode testar um executável sem criar um alvo. Isso economiza muito tempo de digitação e execução quando há vários destinos que podem ser construídos separadamente ou juntos.
Meu aprimoramento para a última solução é usar o
which
executável (where
no Windows), ao invés de contar com a existência de uma--version
opção em cada executável, diretamente naifeq
diretiva GNU Make , ao invés de definir uma nova variável, e usar o GNU Makeerror
para interromper a construção se um executável necessário não estiver disponível${PATH}
. Por exemplo, para testar olzop
executável:Se você tiver vários executáveis para verificar, convém usar uma
foreach
função com owhich
executável:Observe o uso do
:=
operador de atribuição que é necessário para forçar a avaliação imediata da expressão RHS. Se o seu Makefile mudar oPATH
, então, em vez da última linha acima, você precisará:Isso deve fornecer uma saída semelhante a:
fonte
where my_exe 2>NUL
vez dewhich
.Bash
, não há necessidade de fazer uma chamada externa parawhich
. Emcommand -v
vez disso, use o integrado . Mais informações .Eu misturei as soluções de @kenorb e @ 0xF e consegui isso:
Funciona perfeitamente porque "command -v" não imprime nada se o executável não estiver disponível, então a variável DOT nunca é definida e você pode apenas checá-la sempre que quiser em seu código. Neste exemplo, estou gerando um erro, mas você poderia fazer algo mais útil, se quisesse.
Se a variável estiver disponível, "command -v" realiza a operação barata de imprimir o caminho do comando, definindo a variável DOT.
fonte
$(shell command -v dot)
falha commake: command: Command not found
. Para corrigir isso, a saída stderr redirecionamento para / dev / null:$(shell command -v dot 2> /dev/null)
. Explicaçãocommand
é um bash embutido, para mais portabilidade, considere usarwhich
?command
utilitário é exigido por posix (incluindo a-v
opção) Por outro ladowhich
não tem bahaviour padronizado (que eu saiba) e às vezes é totalmente inutilizávelcommand -v
requer um ambiente de shell semelhante ao POSIX. Isso não funcionará no Windows sem cygwin ou emulação semelhante.command
muitas vezes não funciona não é por causa de sua ausência , mas por causa de uma otimização peculiar que o GNU Make faz: se um comando for "simples o suficiente", ele contornará o shell; infelizmente isso significa que os embutidos às vezes não funcionarão a menos que você altere um pouco o comando.é isso que você fez?
crédito ao meu colega de trabalho.
fonte
Use a
shell
função para chamar seu programa de forma que imprima algo na saída padrão. Por exemplo, passe--version
.GNU Make ignora o status de saída do comando passado para
shell
. Para evitar a mensagem potencial "comando não encontrado", redirecione o erro padrão para/dev/null
.Depois, você pode verificar o resultado utilizando
ifdef
,ifndef
,$(if)
etc.Como um bônus, a saída (como a versão do programa) pode ser útil em outras partes do seu Makefile.
fonte
*** missing separator. Stop.
Se eu adicionar abas em todas as linhas depois deall:
obter o erromake: ifdef: Command not found
ifdef
será avaliado como verdadeiro mesmo seyour_program
não existir gnu.org/software/make/manual/make.html#Conditional-Syntaxifdef
,else
,endif
linhas. Apenas certifique-se de que as@echo
linhas comecem com tabulações.ifdef
verifica o valor da variável não vazia. Se sua variável não estiver vazia, o que ela avalia?ifdef
ouifndef
(como na resposta aceita) só funciona se a variável sendo avaliada for imediatamente definida (:=
) em vez de preguiçosamente definida (=
). No entanto, uma desvantagem de usar variáveis definidas imediatamente é que elas são avaliadas no momento da declaração, enquanto as variáveis definidas preguiçosamente são avaliadas quando são chamadas. Isso significa que você estaria executando comandos para variáveis:=
mesmo quando o Make estivesse executando apenas regras que nunca usam essas variáveis! Você pode evitar isso usando um=
comifneq ($(MY_PROG),)
Limpei algumas das soluções existentes aqui ...
O
$(info ...)
que você pode excluir se você quer que isso seja mais silencioso.Isso vai falhar rapidamente . Nenhum alvo necessário.
fonte
Minha solução envolve um pequeno script auxiliar 1 que coloca um arquivo de sinalização se todos os comandos necessários existirem. Isso tem a vantagem de que a verificação dos comandos necessários é feita apenas uma vez e não a cada
make
invocação.check_cmds.sh
Makefile
1 Mais sobre a
command -v
técnica pode ser encontrado aqui .fonte
if
declaração.Para mim, todas as respostas acima são baseadas no Linux e não funcionam com o Windows. Eu sou novo para fazer, então minha abordagem pode não ser ideal. Mas um exemplo completo que funciona para mim tanto no Linux quanto no Windows é este:
opcionalmente, quando preciso detectar mais ferramentas que posso usar:
fonte
Você pode usar comandos bash construídos como
type foo
oucommand -v foo
, conforme abaixo:Onde
foo
está seu programa / comando. Redirecione para> /dev/null
se desejar silencioso.fonte
Suponha que você tenha alvos e construtores diferentes, cada um requer outro conjunto de ferramentas. Defina uma lista dessas ferramentas e considere-as como alvo para forçar a verificação de sua disponibilidade
Por exemplo:
fonte
Estou definindo pessoalmente um
require
alvo que corre antes de todos os outros. Este destino simplesmente executa os comandos de versão de todos os requisitos, um por vez, e imprime as mensagens de erro apropriadas se o comando for inválido.A saída do script abaixo é
fonte
Resolvido ao compilar um pequeno programa especial em outro destino makefile, cujo único propósito é verificar qualquer coisa de tempo de execução que eu estava procurando.
Então, chamei este programa em outro destino makefile.
Foi algo assim, se bem me lembro:
fonte
A verificação de soluções para
STDERR
saída de--version
não funciona para programas que imprimem suas versões em emSTDOUT
vez deSTDERR
. Em vez de verificar sua saída paraSTDERR
ouSTDOUT
, verifique o código de retorno do programa. Se o programa não existir, seu código de saída sempre será diferente de zero.fonte