makefile executa outro alvo

122

Eu tenho um makefile estruturado mais ou menos assim:

all : 
    compile executable

clean :
    rm -f *.o $(EXEC)

Percebi que estava executando consistentemente "make clean" seguido de "clear" no meu terminal antes de executar "make all". Gosto de ter um terminal limpo antes de tentar vasculhar os erros de compilação de C ++ desagradáveis. Então, tentei adicionar um terceiro alvo:

fresh :
    rm -f *.o $(EXEC)
    clear
    make all

Isso funciona, mas executa uma segunda instância do make (acredito). Existe uma maneira certa de obter a mesma funcionalidade sem executar uma segunda instância do make?

sas4740
fonte

Respostas:

171

Na verdade, você está certo: ele executa outra instância do make. Uma possível solução seria:

.PHONY : clearscr fresh clean all

all :
    compile executable

clean :
    rm -f *.o $(EXEC)

fresh : clean clearscr all

clearscr:
    clear

Ao chamar, make freshvocê obtém primeiro o cleanalvo, depois o clearscreenque é executado cleare, finalmente, o allque faz o trabalho.

EDITAR 4 de agosto

O que acontece no caso de compilações paralelas com a -jopção de make ? Existe uma maneira de corrigir a ordem. Do manual do make, seção 4.2:

Ocasionalmente, no entanto, você tem uma situação em que deseja impor uma ordem específica nas regras a serem chamadas, sem forçar a atualização do destino se uma dessas regras for executada. Nesse caso, você deseja definir os pré-requisitos somente do pedido. Os pré-requisitos somente do pedido podem ser especificados colocando um símbolo de barra vertical (|) na lista de pré-requisitos: quaisquer pré-requisitos à esquerda do símbolo de barra vertical são normais; quaisquer pré-requisitos à direita são apenas pedidos: alvos: pré-requisitos normais | pré-requisitos apenas de pedido

A seção de pré-requisitos normais pode, obviamente, estar vazia. Além disso, você ainda pode declarar várias linhas de pré-requisitos para o mesmo destino: eles são anexados apropriadamente. Observe que se você declarar o mesmo arquivo como um pré-requisito normal e somente de pedido, o pré-requisito normal terá precedência (uma vez que eles são um superconjunto estrito do comportamento de um pré-requisito somente de pedido).

Portanto, o makefile se torna

.PHONY : clearscr fresh clean all

all :
    compile executable

clean :
    rm -f *.o $(EXEC)

fresh : | clean clearscr all

clearscr:
    clear

EDITAR 5 de dezembro

Não é grande coisa executar mais de uma instância de makefile, pois cada comando dentro da tarefa será um sub-shell de qualquer maneira. Mas você pode ter métodos reutilizáveis ​​usando a função de chamada .

log_success = (echo "\x1B[32m>> $1\x1B[39m")
log_error = (>&2 echo "\x1B[31m>> $1\x1B[39m" && exit 1)

install:
  @[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
  command1  # this line will be a subshell
  command2  # this line will be another subshell
  @command3  # Use `@` to hide the command line
  $(call log_error, "It works, yey!")

uninstall:
  @[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
  ....
  $(call log_error, "Nuked!")
Dacav
fonte
6
@ sas4740: basicamente tudo o que se segue .PHONY : é tratado como alguma palavra-chave que sempre é executada, enquanto os alvos não falsos são destinados a ser arquivos.
Dacav
são "pré-requisitos somente do pedido" condicionais? para o alvo t2, quero primeiro fazer t0, do que apenas se t0 suceder executar t1, e somente se ambos os sucessos executarem alguma tarefa em t3
fantastory
1
@fantastory, não, acho que são independentes. t2vai depender de t0, t1e t3. Se precisar, coloque t3conforme exigido por t2, t1conforme exigido por t3e t0conforme exigido por t1. Isso significa 3 regras diferentes. Você deve verificar isso, no entanto. Não tenho 100% de certeza.
Dacav
3
Os "pré-requisitos somente para pedidos" são independentes
fantastory
2
Não vejo onde está a garantia de que 'limpo' funciona antes de 'todos'? O fato de que você os corrigiu | não faz com que sejam executados em ordem. Dependência somente de pedido significa que o destino não é necessariamente atualizado após tal operação. Não tem nada a ver com a ordenação dos elementos dependentes ... ou?
CygnusX1
6

Se você removeu a make alllinha de seu alvo "fresco":

fresh :
    rm -f *.o $(EXEC)
    clear

Você pode simplesmente executar o comando make fresh all, que será executado como make fresh; make all.

Alguns podem considerar isso como uma segunda instância de make, mas certamente não é uma sub-instância de make (um make dentro de um make), que é o que sua tentativa parecia resultar.

codenaugh
fonte