¿Cuál es el propósito de .PHONY en un archivo MAKE?

1739

¿Qué .PHONYsignifica en un Makefile? He pasado por esto , pero es demasiado complicado.

¿Alguien me lo puede explicar en términos simples?

Lazer
fuente

Respuestas:

1947

De forma predeterminada, los destinos de Makefile son "destinos de archivo": se utilizan para crear archivos a partir de otros archivos. Make asume que su objetivo es un archivo, y esto hace que escribir Makefiles sea relativamente fácil:

foo: bar
  create_one_from_the_other foo bar

Sin embargo, a veces desea que su Makefile ejecute comandos que no representan archivos físicos en el sistema de archivos. Buenos ejemplos de esto son los objetivos comunes "limpio" y "todos". Lo más probable es que este no sea el caso, pero es posible que tenga un archivo nombrado cleanen su directorio principal. En tal caso, Make se confundirá porque, de forma predeterminada, el cleandestino se asociaría con este archivo y Make solo lo ejecutará cuando el archivo no parezca estar actualizado con respecto a sus dependencias.

Estos objetivos especiales se llaman falsos y puede decirle explícitamente a Make que no están asociados con archivos, por ejemplo:

.PHONY: clean
clean:
  rm -rf *.o

Ahora make cleanse ejecutará como se espera, incluso si tiene un archivo llamado clean.

En términos de Make, un objetivo falso es simplemente un objetivo que siempre está desactualizado, por lo que siempre que lo solicite make <phony_target>, se ejecutará, independientemente del estado del sistema de archivos. Algunos comunes makeobjetivos que a menudo son falsas son: all, install, clean, distclean, TAGS, info, check.

Eli Bendersky
fuente
49
@eSKay: '¿por qué se llama' falso '?' - Porque no es un objetivo real. Es decir, el nombre del objetivo no es un archivo producido por los comandos de ese objetivo.
Bernard
97
@Lazer: No sé si eres un hablante nativo de inglés. No soy. la palabra falsa no significa cómo suena. en.wiktionary.org/wiki/phony dice: Fraudulento; falso; Tener una apariencia engañosa.
Bahbar el
57
Esta respuesta no es exactamente completa, aunque puede abordarse en el tutorial vinculado. .PHONY obliga a construir una etiqueta / archivo en un Makefile si es parte del tipo topológico de lo que sea su objetivo. Es decir, si tiene una etiqueta 'cleanup:' que está configurada como falsa, y su etiqueta de instalación se define con cleanup como requisito previo, es decir, 'install: cleanup', la limpieza siempre se ejecutará cuando el Makefile intente construir 'Instalar en pc'. Esto es útil para los pasos que siempre desea tomar, independientemente de si tienen éxito: ignorará las marcas de tiempo y solo lo forzará.
sintetizadorpatel
99
Tenga en cuenta que no necesita usar .PHONY siempre que no tenga un archivo con el mismo nombre que la tarea. La tarea siempre se ejecutará de todos modos, y el Makefile será más legible.
Bernard
15
"un objetivo falso es simplemente un objetivo que siempre está desactualizado" - ¡gran explicación!
Danijel
730

Supongamos que tiene un installobjetivo, que es muy común en los archivos MAKE. Si no lo usa .PHONY, y un archivo llamadoinstall existe en el mismo directorio que el Makefile, entonces make installno hará nada . Esto se debe a que Make interpreta que la regla significa "ejecutar tal y tal receta para crear el archivo llamadoinstall ". Como el archivo ya está allí y sus dependencias no cambiaron, no se hará nada.

Sin embargo, si haces el install crea el PHONY de destino, le dirá a la herramienta de creación que el destino es ficticio, y que make no debe esperar que cree el archivo real. Por lo tanto, no verificará si el installarchivo existe, lo que significa: a) su comportamiento no se alterará si el archivo existe yb) extrastat() no se llamará .

En general, todos los objetivos en su Makefile que no producen un archivo de salida con el mismo nombre que el nombre del objetivo deben ser PHONY. Esto normalmente incluye all, install, clean, distclean, y así sucesivamente.

George Y.
fuente
66
@PineappleUndertheSea La respuesta aceptada se ha mejorado significativamente desde su nivel inicial de inutilidad, y ahora es tan buena como esta. Tuve que revisar su historial de revisiones para entender su comentario.
Mark Amery
2
Esto parece un poco inútil ya que nunca tendré archivos llamados 'instalar' o similares en mi base de código. La mayoría de los archivos tendrán una extensión de archivo, y los archivos sin extensión de archivo generalmente están en mayúsculas, como 'README'. Por otra parte, si tiene un script bash llamado 'install' en lugar de 'install.sh', lo pasará mal.
nucleartide
66
@JasonTu Esto no es necesariamente cierto. Las convenciones de scripts de Bash le piden que omita la extensión .sho .bashpara los "programas" que se ejecutan como si tuvieran una función principal y que se reserve agregar una extensión para las bibliotecas que incluya ( source mylib.sh). De hecho, llegué a esta pregunta SO porque tenía un script en el mismo directorio que llamaba mi Makefileinstall
Kyle
10
@Kyle Sí, no estoy seguro de lo que significaba mi pasado. En estos días uso .PHONYtodo el tiempo ...
nucleartide
2
@JasonTu La solución aquí es simple: construir una máquina del tiempo y "reemplazar" su yo pasado. Recomiendo llevar una pala contigo para que nadie se dé cuenta de que eres la .PHONYversión.
Mateen Ulhaq
120

NOTA : La herramienta make lee el archivo make y comprueba las marcas de tiempo de modificación de los archivos a ambos lados del símbolo ':' en una regla.

Ejemplo

En un directorio 'prueba' están presentes los siguientes archivos:

prerit@vvdn105:~/test$ ls
hello  hello.c  makefile

En makefile, una regla se define de la siguiente manera:

hello:hello.c
    cc hello.c -o hello

Ahora suponga que el archivo 'hola' es un archivo de texto que contiene algunos datos, que se creó después del archivo 'hola.c'. Por lo tanto, la marca de tiempo de modificación (o creación) de 'hello' será más nueva que la de 'hello.c'. Entonces, cuando invoquemos 'make hello' desde la línea de comandos, se imprimirá como:

make: `hello' is up to date.

Ahora acceda al archivo 'hello.c' y coloque algunos espacios en blanco, lo que no afecta la sintaxis o la lógica del código, luego guarde y salga. Ahora la marca de tiempo de modificación de hello.c es más nueva que la de 'hola'. Ahora si invocas 'make hello', ejecutará los comandos como:

cc hello.c -o hello

Y el archivo 'hola' (archivo de texto) se sobrescribirá con un nuevo archivo binario 'hola' (resultado del comando de compilación anterior).

Si usamos .PHONY en makefile de la siguiente manera:

.PHONY:hello

hello:hello.c
    cc hello.c -o hello

y luego invoque 'make hello', ignorará cualquier archivo presente en la 'prueba' de pwd y ejecutará el comando cada vez.

Ahora suponga que ese objetivo 'hola' no tiene dependencias declaradas:

hello:
    cc hello.c -o hello

y el archivo 'hello' ya está presente en la 'prueba' de pwd, luego 'make hello' siempre se mostrará como:

make: `hello' is up to date.
prerit jain
fuente
3
Esto no solo hace que los comandos que ejecuto tengan sentido, sino que finalmente hace makeque todo tenga sentido, ¡todo se trata de los archivos! Gracias por esta respuesta
Kzqai
80
.PHONY: install
  • significa que la palabra "instalar" no representa un nombre de archivo en este Makefile;
  • significa que el Makefile no tiene nada que ver con un archivo llamado "instalar" en el mismo directorio.
Su mejor apuesta
fuente
45

Es un objetivo de compilación que no es un nombre de archivo.

JohnMcG
fuente
33

La mejor explicación es el manual de creación de GNU en sí mismo: 4.6 Sección de objetivos falsos .

.PHONYes uno de los nombres de destino incorporados especiales de la marca . Hay otros objetivos en los que puede estar interesado, por lo que vale la pena hojear estas referencias.

Cuando es hora de considerar un objetivo .PHONY, make ejecutará su receta incondicionalmente, independientemente de si existe un archivo con ese nombre o cuál es su hora de última modificación.

También puede estar interesado en los objetivos estándar de make , como ally clean.

James Wald
fuente
11

También hay un importante truco de ".PHONY": cuando un objetivo físico depende de un objetivo falso que depende de otro objetivo físico:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Simplemente esperaría que si actualizara TARGET2, entonces TARGET1 debería considerarse obsoleto frente a TARGET1, por lo que TARGET1 debería reconstruirse. Y realmente funciona de esta manera .

La parte difícil es cuando TARGET2 no está rancio contra TARGET1, en cuyo caso debe esperar que TARGET1 no se reconstruya.

Esto sorprendentemente no funciona porque: el objetivo falso se ejecutó de todos modos (como normalmente lo hacen los objetivos falsos) , lo que significa que el objetivo falso se consideró actualizado . Y debido a eso, TARGET1 se considera rancio contra el objetivo 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

Puedes jugar con esto:

  • primero 'make prepare' para preparar los "archivos fuente"
  • juega con eso tocando archivos particulares para verlos actualizados

Puede ver que fileall depende del archivo1 indirectamente a través de un objetivo falso, pero siempre se reconstruye debido a esta dependencia. Si cambia la dependencia fileallde filefwda file, ahora fileallno se reconstruye cada vez, sino solo cuando cualquiera de los objetivos dependientes está obsoleto como un archivo.

Ethouris
fuente
5

El objetivo especial .PHONY:permite declarar objetivos falsos, por lo que makeno los verificará como nombres de archivo reales: funcionará todo el tiempo incluso si dichos archivos aún existen.

Puedes poner varios .PHONY:en tu Makefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

Hay otra forma de declarar objetivos falsos: simplemente ponga '::'

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

El '::' tiene un significado especial: los objetivos son falsos y pueden aparecer varias veces:

clean ::
    rm file1

...


clean ::
    rm file2

Los bloques de comando se llamarán uno tras otro.

Edouard Thiel
fuente
3

A menudo los uso para decirle al objetivo predeterminado que no dispare.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Sin falsos, make supercleandispararía clean, andsomethingelsey catcher superclean; pero con PHONY, make supercleanno disparará catcher superclean.

No tenemos que preocuparnos por decir que el cleanobjetivo es FALSIA, porque no es completamente falso. Aunque nunca produce el archivo limpio, tiene comandos para disparar, así que crea que será un objetivo final.

Sin embargo, el supercleanobjetivo es realmente falso, por lo que make intentará apilarlo con cualquier otra cosa que proporcione detalles para el supercleanobjetivo; esto incluye otros supercleanobjetivos y el% objetivo.

Tenga en cuenta que no decimos nada sobre andsomethingelseo blah, por lo que claramente van al receptor.

El resultado se parece a esto:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
jettero
fuente