Por que parar com “Makefile: 6: *** vários padrões de destino. Pare."?

1

Objetivo Eu escrevo meus slides em um arquivo de marcação e compilo para revelar depois, fazendo o upload para o meu servidor e fazendo outras coisas. Eu queria organizar as etapas depois que o markdown for gravado em um makefile:

PROJNAME = 'pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]''

presentation: slides.pandoc
    pandoc --self-contained --data-dir=$(HOME)/.pandoc --template=slides/revealjs_niels_tmpl.html -V revealjs-url:$(HOME)/.pandoc/revealjs -V theme:solarized slides.pandoc -f markdown -t revealjs -o $(PROJNAME).html

onlinepresent: $(PROJNAME).html
    cp $(PROJNAME).html $(HOME)/Share/index.html

Explicação PROJNAME procura o nome da pasta do projeto e o converte em minúsculas. Na pasta de exemplo em que estou usando e que gera a mensagem mostrada no título, isso resulta em ws-anno-ii . A regra presentation compila os slides como html usando pandoc . A macro PROJNAME é usada para definir o nome do arquivo de saída. onlinepresent onde make está parando deve copiar um arquivo que contém o nome do projeto ( ws-anno-ii.html ) se esse arquivo existir em um sistema de arquivos externo montado ( Share ). Se não existir, é claro que a regra presentation deve ser aplicada primeiro. Mas quando eu coloco o comando make nada acontece, e eu recebo a mensagem

O processo make é interrompido com Makefile:6: *** multiple target patterns. Stop. , referindo-se à linha onlinepresent: $(PROJNAME).html

Alguém pode me explicar por que isso está acontecendo?

    
por Cutú Chiqueño 09.10.2015 / 11:51

2 respostas

1

O valor da variável PROJNAME é

'pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]''

O caractere backquote não é especial no make. Se você usar a variável em um comando shell, o shell verá os backquotes e os analisará como uma substituição de comando. Mas se você usar a variável em um lugar onde ela é interpretada por make, as backquotes não fazem nada de especial. A linha onlinepresent: $(PROJNAME).html torna-se, após a expansão da variável,

onlinepresent: 'pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]''.html

que faz análises como onlinepresent , dois pontos, 'pwd , \ , grep , -oP , '(\w|-)+' , | , tail , -n , 2 , | , head , -n , 1 , | , tr , '[ , dois pontos, upper , dois pontos, ]' , '[ , dois pontos, lower , dois pontos ]''.html . Existem várias palavras à esquerda do cólon mais à direita, portanto, "vários padrões de destino".

Se você quiser usar a saída de um comando shell em um lugar onde o make irá lê-lo, você precisará invocar o % funçãoshell . Este é um recurso do GNU make, não funcionará em outras implementações do make.

PROJNAME = $(shell pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'')

Isso define a variável PROJNAME como o próximo ao último componente do diretório de trabalho transformado em minúsculas.

Observe que o uso do diretório atual é frágil: significa que seu makefile não funcionará se chamado de um diretório diferente como o destino. Seria mais robusto calcular PROJNAME do caminho para o destino. Se não fosse pela parte em minúscula, você poderia fazê-lo inteiramente (se complicado) com funções de criação (suponho que a intenção do seu código de divisão é realmente extrair componentes do nome do caminho):

$(notdir $(patsubst %/,%,$(dir $(patsubst %/,%,$(dir $(abspath $@))))))

mas o GNU make não possui um recurso de conversão de caso. Se você for invocar um shell de qualquer maneira, você pode simplificar.

PROJNAME = $(shell set -x; echo '$(abspath $@)' | awk -F/ '{$$0=tolower($$0); print $$(NF-2)}')
onlinepresent: $(PROJNAME).html
        cp $< $$HOME/Share/index.html

Observe o uso de $$ no makefile, que se torna $ nos comandos do shell. Isso funciona porque a variável PROJNAME é calculada em cada uso, não no momento da definição (as definições de variável no make são expandidas em cada uso se usarem = e quando a atribuição for lida se usar := ) .

    
por 10.10.2015 / 02:44
0

Quando você executa make onlinepresent , make vai para o destino onlinepresent e vê que ele exige $(PROJNAME).html , que é meio errado ... do ponto de vista de make, porque não há alvo fornecendo diretamente $(PROJNAME).html .

Estou assumindo também que sua atribuição de PROJNAME tem apenas um possível resultado.

Tente com

presentation: slides.pandoc
#your pandoc rule
onlinepresent: presentation
#your mv command

Isso diz make que, para tornar o destino onlinepresent , o destino presentation é obrigatório. Em seguida, a apresentação de destino informa que slides.pandoc é necessário, portanto, a regra será executada se slides.pandoc for novo ou tiver sido modificado.

OR

Você também pode tentar renomear o destino presentation para $(PROJNAME).html para que pareça

$(PROJNAME).html: slides.pandoc
#your pandoc rule
onlinepresent: $(PROJNAME).html
#your mv command
    
por 09.10.2015 / 12:26

Tags