Respostas:
Por padrão, os destinos do Makefile são "destinos de arquivos" - são usados para criar arquivos de outros arquivos. Make assume que seu destino é um arquivo, e isso facilita a escrita de Makefiles:
foo: bar
create_one_from_the_other foo bar
No entanto, às vezes você deseja que o Makefile execute comandos que não representam arquivos físicos no sistema de arquivos. Bons exemplos para isso são os alvos comuns "limpo" e "todos". Provavelmente, esse não é o caso, mas você pode ter um arquivo com o nome clean
no diretório principal. Nesse caso, o Make ficará confuso porque, por padrão, o clean
destino estaria associado a esse arquivo e o Make só o executará quando o arquivo não parecer atualizado com relação às dependências.
Esses alvos especiais são chamados de falsos e você pode dizer explicitamente que eles não estão associados aos arquivos, por exemplo:
.PHONY: clean
clean:
rm -rf *.o
Agora make clean
será executado conforme o esperado, mesmo se você tiver um arquivo chamado clean
.
Em termos de Make, um destino falso é simplesmente um destino sempre desatualizado; portanto, sempre que você solicitar make <phony_target>
, ele será executado independentemente do estado do sistema de arquivos. Alguns comuns make
alvos que estão muitas vezes falsa são: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Vamos supor que você tenha um install
alvo, o que é muito comum em makefiles. Se você não usar .PHONY
, e um arquivo nomeado install
existir no mesmo diretório que o Makefile, make install
não fará nada . Isso ocorre porque Make interpreta a regra como "execute tal e qual receita para criar o arquivo chamado install
". Como o arquivo já está lá e suas dependências não foram alteradas, nada será feito.
No entanto, se você criar o install
alvo PHONY, ele informará à ferramenta make que o alvo é fictício, e esse make não deve esperar que ele crie o arquivo real. Portanto, ele não verifica se o install
arquivo existe, o que significa: a) seu comportamento não será alterado se o arquivo existir eb) extra stat()
não será chamado.
Geralmente todos os alvos em seu Makefile que não produzem um arquivo de saída com o mesmo nome que o nome do alvo devem ser PHONY. Isso normalmente inclui all
, install
, clean
, distclean
, e assim por diante.
.sh
ou .bash
dos "programas" executados como se tivessem uma função principal e reserve adicionar uma extensão para as bibliotecas que você inclui ( source mylib.sh
). Na verdade, eu comecei a esta pergunta SO porque eu tinha um script no mesmo diretório como o meu Makefile chamadoinstall
.PHONY
o tempo todo ...
.PHONY
versão.
NOTA : A ferramenta make lê o makefile e verifica os carimbos de data / hora da modificação dos arquivos ao lado do símbolo ':' em uma regra.
Em um diretório 'test', os seguintes arquivos estão presentes:
prerit@vvdn105:~/test$ ls
hello hello.c makefile
No makefile, uma regra é definida da seguinte maneira:
hello:hello.c
cc hello.c -o hello
Agora, suponha que o arquivo 'hello' seja um arquivo de texto que contenha alguns dados, que foram criados após o arquivo 'hello.c'. Portanto, o carimbo de data / hora de modificação (ou criação) de 'hello' será mais novo que o de 'hello.c'. Portanto, quando chamaremos 'make hello' na linha de comando, ela será impressa como:
make: `hello' is up to date.
Agora acesse o arquivo 'hello.c' e coloque alguns espaços em branco, o que não afeta a sintaxe ou a lógica do código, e salve e saia. Agora, o carimbo de data / hora da modificação do hello.c é mais recente que o do 'hello'. Agora, se você chamar 'make hello', ele executará os comandos como:
cc hello.c -o hello
E o arquivo 'olá' (arquivo de texto) será substituído por um novo arquivo binário 'olá' (resultado do comando de compilação acima).
Se usarmos .PHONY no makefile da seguinte maneira:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
e depois invoque 'make hello', ele ignorará qualquer arquivo presente no pwd 'test' e executará o comando sempre.
Agora, suponha que o destino 'hello' não tenha dependências declaradas:
hello:
cc hello.c -o hello
e o arquivo 'hello' já estiver presente no pwd 'test', então 'make hello' sempre será exibido como:
make: `hello' is up to date.
make
como finalmente faz com que o todo faça sentido, é tudo sobre os arquivos! Obrigado por esta resposta.
.PHONY: install
A melhor explicação é o próprio manual do GNU make: 4.6 Seção de alvos falsos .
.PHONY
é um dos nomes de destino internos especiais do make . Você pode estar interessado em outros alvos, por isso vale a pena examinar essas referências.
Quando chegar a hora de considerar um destino .PHONY, o make executará sua receita incondicionalmente, independentemente de existir um arquivo com esse nome ou qual seja a hora da última modificação.
Você também pode estar interessado nos destinos padrão da marca , como all
e clean
.
Há também um tratamento complicado e importante de ".PHONY" - quando um alvo físico depende de um alvo falso que depende de outro alvo físico:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
Você simplesmente esperaria que, se atualizasse o TARGET2, o TARGET1 fosse considerado obsoleto contra o TARGET1, portanto, o TARGET1 deve ser reconstruído. E realmente funciona dessa maneira .
A parte complicada é quando o TARGET2 não está obsoleto contra o TARGET1 - nesse caso, você deve esperar que o TARGET1 não deva ser reconstruído.
Surpreendentemente, isso não funciona porque: o alvo falso foi executado de qualquer maneira (como os destinos falsos normalmente fazem) , o que significa que o alvo falso foi considerado atualizado . E por causa disso, o TARGET1 é considerado obsoleto contra o alvo falso .
Considerar:
all: fileall
fileall: file2 filefwd
echo file2 file1 >fileall
file2: file2.src
echo file2.src >file2
file1: file1.src
echo file1.src >file1
echo file1.src >>file1
.PHONY: filefwd
.PHONY: filefwd2
filefwd: filefwd2
filefwd2: file1
@echo "Produced target file1"
prepare:
echo "Some text 1" >> file1.src
echo "Some text 2" >> file2.src
Você pode brincar com isso:
Você pode ver que o arquivo filiall depende indiretamente do arquivo1 através de um destino falso - mas ele sempre é reconstruído devido a essa dependência. Se você alterar a dependência fileall
de filefwd
para file
, agora fileall
não será reconstruído todas as vezes, mas apenas quando algum dos destinos dependentes estiver obsoleto como um arquivo.
O alvo especial .PHONY:
permite declarar alvos falsos, para que make
não os verifique como nomes de arquivo reais: funcionará o tempo todo, mesmo que esses arquivos ainda existam.
Você pode colocar vários .PHONY:
em seu Makefile
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
Existe outra maneira de declarar alvos falsos: basta colocar '::'
all :: prog1 prog2
...
clean ::
...
distclean ::
...
O '::' tem um significado especial: os alvos são falsos e podem aparecer várias vezes:
clean ::
rm file1
...
clean ::
rm file2
Os blocos de comando serão chamados um após o outro.
Costumo usá-los para dizer ao alvo padrão para não disparar.
superclean: clean andsomethingelse
blah: superclean
clean:
@echo clean
%:
@echo catcher $@
.PHONY: superclean
Sem FALSO, make superclean
iria disparar clean
, andsomethingelse
e catcher superclean
; mas com PHONY, make superclean
não vai disparar o catcher superclean
.
Não precisamos nos preocupar em dizer que o clean
alvo é PHONY, porque não é completamente falso. Embora nunca produza o arquivo limpo, ele possui comandos para acionar, portanto, o make pensará que é um alvo final.
No entanto, o superclean
alvo é realmente falsa, então make vai tentar empilhar-lo com qualquer outra coisa que fornece deps para o superclean
alvo - o que inclui outras superclean
metas e o%
alvo.
Note que não dizemos nada sobre andsomethingelse
ou blah
, então eles claramente vão para o coletor.
A saída é mais ou menos assim:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah