Como imprimir uma variável no makefile

246

No meu makefile, tenho uma variável 'NDK_PROJECT_PATH', minha pergunta é como posso imprimi-lo quando ele compila?

Eu li Criar arquivo eco exibindo a string "$ PATH" e tentei:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

Ambos me dão

"build-local.mk:102: *** missing separator.  Stop."

Alguém sabe por que não está funcionando para mim?

Michael
fonte

Respostas:

222

Você pode imprimir variáveis ​​à medida que o makefile é lido (assumindo que o GNU make tenha marcado essa pergunta adequadamente) usando este método (com uma variável chamada "var"):

$(info $$var is [${var}])

Você pode adicionar essa construção a qualquer receita para ver o que a marca passará para o shell:

.PHONY: all
all: ; $(info $$var is [${var}])echo Hello world

Agora, o que acontece aqui é que torna as lojas armazenam toda a receita ( $(info $$var is [${var}])echo Hello world) como uma única variável expandida recursivamente. Quando make decide executar a receita (por exemplo, quando você manda construir all), ela expande a variável e passa cada linha resultante separadamente para o shell.

Então, com detalhes dolorosos:

  • Expande $(info $$var is [${var}])echo Hello world
  • Para fazer isso, ele primeiro se expande $(info $$var is [${var}])
    • $$ torna-se literal $
    • ${var}torna-se :-)(digamos)
    • O efeito colateral é o que $var is [:-)]aparece na saída padrão
    • A expansão do $(info...)pensamento está vazia
  • Make fica com echo Hello world
    • Faça impressões echo Hello worldno stdout primeiro para que você saiba o que ele solicitará ao shell
  • O shell é impresso Hello worldno stdout.
bobbogo
fonte
2
deveria ser (ponto) .PHONY em vez de PHONY?
hammadian
172

De acordo com o manual GNU Make e também apontado por 'bobbogo' na resposta abaixo, você pode usar informações / aviso / erro para exibir texto.

$(error   text…)
$(warning text…)
$(info    text…)

Para imprimir variáveis,

$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

'error' interromperia a execução do make , depois de mostrar a string de erro

tsenapatia
fonte
Uau, não sabia disso. Muito melhor que o eco, que duplica o comando nos logs.
deepelement
148

de um "Mr. Make post" https://www.cmcrossroads.com/article/printing-value-makefile-variable

Adicione a seguinte regra ao seu Makefile:

print-%  : ; @echo $* = $($*)

Então, se você deseja descobrir o valor de uma variável makefile, apenas:

make print-VARIABLE

e retornará:

VARIABLE = the_value_of_the_variable
Anthony Earl Wong
fonte
Você explicou melhor do que o autor. Afirmativo!
f0nzie 03/06
44

Se você simplesmente deseja alguma saída, deseja usar $(info)por si só. Você pode fazer isso em qualquer lugar do Makefile e ele será exibido quando a linha for avaliada:

$(info VAR="$(VAR)")

Produzirá VAR="<value of VAR>"sempre que criar processos nessa linha. Esse comportamento depende muito da posição; portanto, você deve garantir que a $(info)expansão ocorra APÓS tudo o que possa ser modificado $(VAR)já aconteceu!

Uma opção mais genérica é criar uma regra especial para imprimir o valor de uma variável. De um modo geral, as regras são executadas depois que as variáveis ​​são atribuídas, e isso mostra o valor que está realmente sendo usado. (Porém, é possível que uma regra altere uma variável .) A boa formatação ajudará a esclarecer como uma variável está definida e a $(flavor)função informará que tipo de variável é algo. Então, nesta regra:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*expande para a raiz que o % padrão corresponde à regra.
  • $($*)expande para o valor da variável cujo nome é dado por por $*.
  • A [e ]claramente delinear a expansão variável. Você também pode usar "e "ou similar.
  • $(flavor $*)informa qual é o tipo de variável. NOTA: $(flavor) recebe um nome de variável e não sua expansão. Então, se você diz make print-LDFLAGS, recebe $(flavor LDFLAGS), e é isso que você deseja.
  • $(info text) fornece saída. Faça impressões textem stdout como efeito colateral da expansão. A expansão do $(info)pensamento está vazia. Você pode pensar assim @echo, mas o mais importante é que não usa o shell, portanto, não precisa se preocupar com as regras de citação do shell.
  • @trueexiste apenas para fornecer um comando para a regra. Sem isso, make também produzirá print-blah is up to date. Eu sinto que @truedeixa mais claro que é para ser um não-op.

Executando, você obtém

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]
Jim Nasby
fonte
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos a um autor, deixe um comentário abaixo da postagem - você sempre pode comentar em suas próprias postagens e, quando tiver reputação suficiente , poderá comentar em qualquer post . - Da avaliação
Dragon Energy
Obrigado pela revisão. Entendo que posso comentar quando tiver reputação suficiente, mas o que devo fazer enquanto isso? Acredito que minha resposta fornece um valor adicional, então não devo adicioná-lo?
Jim Nasby
1
Eu sugiro que reescreva esta para ser uma resposta independente, competindo com a que você está comentando, em vez de tê-la formulada como um comentário fora do lugar para essa resposta.
Charles Duffy
@ JimNasby Sim, o que Charles sugeriu. Na verdade, pode ajudar, para começar, simplesmente remover o tipo de parte "desculpe, não o suficiente para comentar", como se fosse uma bandeira vermelha. Se você transformá-lo em uma resposta completa (pode editar tudo o que você quiser), deve ser bastante agradável. Felicidades.
Dragon Energy
Excelente - esta é uma resposta muito melhor agora. :)
Charles Duffy
6

@echo $ (NDK_PROJECT_PATH) é a boa maneira de fazer isso. Eu não acho que o erro vem daí. Geralmente, esse erro aparece quando você digitou incorretamente a intenção: Acho que você tem espaços em que deveria ter uma guia.


fonte
2
Tentei '@echo $ (NDK_PROJECT_PATH)', ainda recebo o erro "build-local.mk:102: *** separador ausente. Pare.". Eu só tenho 1 espaço após 'eco', não há espaço ou tabulação antes de '@echo'.
9603 Michael
Tem certeza de que o erro vem desta linha? Esta linha está em uma regra? Ela deve provavelmente ser recuado ...
6

Todas as versões de makeexigem que as linhas de comando sejam recuadas com uma TAB (não espaço) como o primeiro caractere na linha. Se você nos mostrou a regra inteira, em vez de apenas as duas linhas em questão, poderíamos dar uma resposta mais clara, mas deve ser algo como:

myTarget: myDependencies
        @echo hi

onde o primeiro caractere na segunda linha deve ser TAB.

Cientista maluco
fonte
4

Corra make -n; mostra o valor da variável

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

Comando:

export NDK_PROJECT_PATH=/opt/ndk/project
make -n 

Resultado:

echo /opt/ndk/project
ivandcl
fonte
Isso é muito útil embora e eu uso --just-printé a mesma em vez de Execução
Fredrick Gauss
3

Isso makefileirá gerar a mensagem de erro 'separador ausente':

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

Há uma guia antes do @echo "All done"(embora a done:regra e a ação sejam amplamente supérfluas), mas não antes do @echo PATH=$(PATH).

O problema é que a linha de partida alldeve ter dois pontos :ou igual =para indicar que é uma linha de destino ou uma linha de macro e não possui nenhuma, portanto o separador está ausente.

A ação que ecoa o valor de uma variável deve estar associada a um destino, possivelmente um destino fictício ou PHONEY. E essa linha de destino deve ter dois pontos nela. Se você adicionar um :depois allno exemplomakefile e substituir os espaços em branco à esquerda na próxima linha por uma guia, ele funcionará de maneira saudável.

Você provavelmente tem um problema análogo próximo à linha 102 no original makefile. Se você mostrasse cinco linhas sem comentários e sem comentários antes das operações de eco que estão falhando, provavelmente seria possível concluir o diagnóstico. No entanto, como a pergunta foi feita em maio de 2013, é improvável que o problema makefileainda esteja disponível agora (agosto de 2014), portanto, essa resposta não pode ser validada formalmente. Só pode ser usado para ilustrar uma maneira plausível pela qual o problema ocorreu.

Jonathan Leffler
fonte
3

Não há necessidade de modificar o Makefile.

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE
Talespin_Kit
fonte
2

O problema é que o eco funciona apenas em um bloco de execução. ou seja, qualquer coisa após "xx:"

Portanto, qualquer coisa acima do primeiro bloco de execução é apenas inicialização, portanto, nenhum comando de execução pode ser usado.

Então crie um blocl de execução

Andy
fonte
1

Isso pode ser feito de uma maneira genérica e pode ser muito útil ao depurar um makefile complexo. Seguindo a mesma técnica descrita em outra resposta , você pode inserir o seguinte em qualquer makefile:

# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)

  # take the rest of the arguments as variable names
  VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))

  # turn them into do-nothing targets
  $(eval $(VAR_NAMES):;@:))

  # then print them
  .PHONY: print
  print:
          @$(foreach var,$(VAR_NAMES),\
            echo '$(var) = $($(var))';)
endif

Então você pode simplesmente fazer "make print" para despejar o valor de qualquer variável:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall
Idelic
fonte
0

Se você não quiser modificar o Makefile, poderá usar --evalpara adicionar um novo destino e executar o novo destino, por exemplo

make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

Você pode inserir o caractere TAB necessário na linha de comando usando CTRL-V, TAB

exemplo Makefile de cima:

all: do-something

TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1
Wade
fonte
Estou tentando executar o script, mas eu estou recebendo erromake: *** missing separator. Stop.
Rinaldi Segecin
Ah, desculpe, consertado. Dois pontos ausentes no final do destino "testes de impressão".
Wade
Novas linhas e tabs Na verdade, você não precisa, um ponto e vírgula será suficiente:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo
0

se você usar o android make (mka) @echo $(NDK_PROJECT_PATH)não funcionará e fornecer erro, *** missing separator. Stop." use esta resposta se você estiver tentando imprimir variáveis ​​no android make

NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))

isso funcionou para mim

mjalil
fonte
0

Eu geralmente echo com um erro se eu quiser ver o valor da variável. (Somente se você quiser ver o valor. Ele interromperá a execução.)

@echo $ (erro NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

Abdul Jaleel
fonte