Em um Makefile, uma deploy
receita precisa que uma variável de ambiente ENV
seja definida para se executar adequadamente, enquanto outras não se importam, por exemplo:
ENV =
.PHONY: deploy hello
deploy:
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
Como posso garantir que essa variável seja definida, por exemplo: existe uma maneira de declarar essa variável de makefile como um pré-requisito da receita de implantação, como:
deploy: make-sure-ENV-variable-is-set
?
Obrigado.
make
configurá-lo ou dar um aviso ou gerar um erro fatal?make ENV=dev
mas se ele esquecerENV=dev
, adeploy
receita falhará ...Respostas:
Isso causará um erro fatal se não
ENV
for definido e algo precisar (no GNUMake, de qualquer maneira).(Observe que ifndef e endif não são recuados - eles controlam o que "vê" , entrando em vigor antes da execução do Makefile. "$ (Error" é recuado com uma guia para que seja executado apenas no contexto da regra.)
fonte
ENV is undefined
ao executar uma tarefa que não tem o check-env como pré-requisito.check-env
regra; O Make não o expandirá, a menos que / até executar a regra. Se não começar com um TAB (como no exemplo de @ rane), o Make interpreta como não estando em uma regra e o avalia antes de executar qualquer regra, independentemente do destino.Você pode criar um destino de guarda implícito, que verifica se a variável no tronco está definida, assim:
Em seguida, você adiciona um
guard-ENVVAR
destino em qualquer lugar que desejar afirmar que uma variável está definida, assim:Se você ligar
make change-hostname
, sem adicionarHOSTNAME=somehostname
a chamada, você receberá um erro e a compilação falhará.fonte
if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
DVariante em linha
Nos meus makefiles, eu normalmente uso uma expressão como:
As razões:
Não se esqueça do comentário que é importante para a depuração:
... força você a procurar o Makefile enquanto ...
... explica diretamente o que há de errado
Variante global (por completo, mas não solicitada)
Além do Makefile, você também pode escrever:
Advertências:
clean
destino falhará se ENV não estiver definido. Caso contrário, veja a resposta de Hudon, que é mais complexafonte
@
. -> gnu.org/software/make/manual/make.html#Echoing@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)
Um possível problema com as respostas dadas até agora é que a ordem de dependência no make não está definida. Por exemplo, executando:
Quando
target
possui algumas dependências, não garante que elas sejam executadas em qualquer ordem.A solução para isso (para garantir que o ENV será verificado antes da escolha das receitas) é verificar o ENV durante o primeiro passe do make, fora de qualquer receita:
Você pode ler sobre as diferentes funções / variáveis usadas aqui e
$()
é apenas uma maneira de declarar explicitamente que estamos comparando "nada".fonte
Descobri que a melhor resposta não pode ser usada como requisito, exceto para outros destinos PHONY. Se usado como uma dependência para um destino que é um arquivo real, o uso
check-env
forçará a reconstrução desse destino.Outras respostas são globais (por exemplo, a variável é necessária para todos os destinos no Makefile) ou usam o shell, por exemplo, se ENV estava ausente, o make terminaria independentemente do destino.
Uma solução que encontrei para ambos os problemas é
A saída parece
value
tem algumas advertências assustadoras, mas para esse uso simples, acredito que seja a melhor escolha.fonte
Como eu vejo, o próprio comando precisa da variável ENV para que você possa verificá-lo no próprio comando:
fonte
deploy
não é necessariamente a única receita que precisa dessa variável. Com esta solução, tenho que testar o estado deENV
cada um deles ... enquanto gostaria de lidar com isso como um (pré-requisito) único.Eu sei que isso é antigo, mas achei que iria concorrer com minhas próprias experiências para futuros visitantes, já que é um IMHO um pouco melhor.
Normalmente,
make
usarásh
como seu shell padrão ( definido através daSHELL
variável especial ). Emsh
e seus derivados, é trivial para sair com uma mensagem de erro ao recuperar uma variável de ambiente se não for definida ou nulo fazendo:${VAR?Variable VAR was not set or null}
.Estendendo isso, podemos escrever um destino de reutilização que pode ser usado para falhar em outros destinos se uma variável de ambiente não foi configurada:
Coisas de nota:
$$
) é necessário para adiar a expansão para o shell em vez de dentromake
test
é apenas para impedir que o shell tente executar o conteúdo deVAR
(ele não serve para nenhum outro propósito significativo).check-env-vars
pode ser estendido trivialmente para verificar se há mais variáveis de ambiente, cada uma das quais adiciona apenas uma linha (por exemplo@test $${NEWENV?Please set environment variable NEWENV}
)fonte
ENV
contiver espaços, isso parece falhar (pelo menos para mim)Você pode usar em
ifdef
vez de um destino diferente.fonte
deploy
ainda não é a única receita que precisa verificar aENV
variável de estado..PHONY: deploy
edeploy:
antes do bloco ifdef e remova a duplicação. (btw eu editar tenho a resposta para refletir o método correto)