¿Cómo se obtiene la lista de objetivos en un archivo MAKE?

Resuelto Brian Burns asked hace 13 años • 29 respuestas

He usado un poco rake (un programa de creación de Ruby) y tiene una opción para obtener una lista de todos los objetivos disponibles, por ejemplo

> rake --tasks
rake db:charset      # retrieve the charset for your data...
rake db:collation    # retrieve the collation for your da...
rake db:create       # Creates the databases defined in y...
rake db:drop         # Drops the database for your curren...
...

pero parece que no hay ninguna opción para hacer esto en GNU make.

Aparentemente, el código casi está disponible, en 2007 : http://www.mail-archive.com/[email protected]/msg06434.html .

De todos modos, hice un pequeño truco para extraer los objetivos de un archivo MAKE, que puedes incluir en un archivo MAKE.

list:
    @grep '^[^#[:space:]].*:' Makefile

Le dará una lista de los objetivos definidos. Es sólo un comienzo: no filtra las dependencias, por ejemplo.

> make list
list:
copy:
run:
plot:
turnin:
Brian Burns avatar Nov 19 '10 03:11 Brian Burns
Aceptado

En Bash (al menos), esto se puede hacer automáticamente completando con tabulación:

make spacetabtab


Si está utilizando una distribución básica (tal vez un contenedor), es posible que necesite instalar un paquete.

$ apt-get install bash-completion ## Debian/Ubuntu/etc.
$ . /etc/bash_completion ## or just launch bash again
Brent Bradburn avatar May 15 '2014 00:05 Brent Bradburn

Prefacio :

  • Según esta respuesta , una makeversión posterior a la 4.4.1 admitirá de forma nativa --print-targets, lo que hace que la solución siguiente sea innecesaria.

  • Esta respuesta se basa en la solución siguiente y agrega soporte para imprimir descripciones junto con los nombres de los objetivos, suponiendo que haya incrustado @#comentarios con prefijo en sus objetivos.


Nota: Esta respuesta se actualizó para seguir funcionando a partir de GNU make v4.3 ; avísenos si encuentra algo que se rompe.

Este es un intento de mejorar el gran enfoque de Brent Bradburn de la siguiente manera:

  • utiliza un comando más sólido para extraer los nombres de los objetivos, lo que con suerte evita falsos positivos (y también elimina los innecesarios sh -c)
  • no siempre apunta al archivo MAKE en el directorio actual ; respeta los archivos MAKE especificados explícitamente con-f <file>
  • Excluye objetivos ocultos: por convención, estos son objetivos cuyo nombre no comienza ni con una letra ni con un dígito.
  • se conforma con un único objetivo falso
  • antepone el comando con @para evitar que se repita antes de la ejecución

Curiosamente, GNU makeno tiene ninguna función para enumerar sólo los nombres de los objetivos definidos en un archivo MAKE. Si bien la -popción produce una salida que incluye todos los objetivos, los oculta en mucha otra información y también ejecuta el objetivo predeterminado (que podría suprimirse con -f/dev/null).

Coloque la siguiente regla en un archivo MAKE para que GNU makeimplemente un objetivo llamado listque simplemente enumere todos los nombres de objetivos en orden alfabético, es decir, invocar comomake list :

.PHONY: list
list:
    @LC_ALL=C $(MAKE) -pRrq -f $(firstword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'

Importante : al pegar esto, asegúrese de que la última línea tenga una sangría de exactamente 1 carácter de tabulación real. (los espacios no funcionan) .

Tenga en cuenta que ordenar la lista resultante de objetivos es la mejor opción, ya que no ordenar no produce un orden útil ya que no se conserva el orden en el que aparecen los objetivos en el archivo MAKE .
Además, los subobjetivos de una regla que comprende múltiples objetivos siempre se generan por separado y, por lo tanto, debido a la clasificación, normalmente no aparecerán uno al lado del otro; por ejemplo, una regla que comienza con noa z: tendrá objetivos y se enumerará una al lado de la otra en el resultado, si hay objetivos adicionales.az

Explicación de la regla :

  • .PHONY: list

    • declara la lista de objetivos como un objetivo falso, es decir, uno que no hace referencia a un archivo , por lo que se debería invocar su receta incondicionalmente
  • LC_ALL=Cse asegura de que makeel resultado esté en inglés , ya que el análisis del resultado depende de eso. Quitándose el sombrero a Bastian Bittorf

  • $(MAKE) -pRrq -f $(firstword $(MAKEFILE_LIST)) : 2>/dev/null

    • Se invoca makenuevamente para imprimir y analizar la base de datos derivada del archivo MAKE:
      • -pimprime la base de datos

      • -Rrsuprime la inclusión de reglas y variables integradas

      • -qsólo prueba el estado actualizado de un objetivo (sin rehacer nada), pero eso por sí solo no impide la ejecución de comandos de recetas en todos los casos; por eso:

      • -f $(firstword $(MAKEFILE_LIST))garantiza que se apunte al mismo archivo MAKE que en la invocación original, independientemente de si se apuntó implícita o explícitamente con -f ....
        (Dado que MAKEFILE_LISTtambién contiene la lista de includeMakefiles, firstwordse utiliza para extraer solo el archivo de destino original; la implicación es que el nombre/ruta del archivo de destino no debe contener espacios , pero es poco probable que ese sea el caso en la práctica).

      • :es un objetivo deliberadamente no válido cuyo objetivo es garantizar que no se ejecute ningún comando ; 2>/dev/nullsuprime el mensaje de error resultante. Nota: No obstante, esto depende de -pla impresión de la base de datos, como es el caso a partir de GNU make 3.82. Lamentablemente, GNU make no ofrece una opción directa para simplemente imprimir la base de datos, sin ejecutar también la tarea predeterminada (o dada); Si no necesita apuntar a un Makefile específico, puede usar make -p -f/dev/null, como se recomienda en la manpágina.

  • -v RS=

    • Este es un modismo awk que divide la entrada en bloques de líneas contiguas no vacías.
  • /(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/

    • Coincide con el rango de líneas en la salida que contiene todos los objetivos, en todos los párrafos; al limitar el análisis a este rango, no hay necesidad de lidiar con falsos positivos de otras secciones de salida.
    • Nota: Entre makelas versiones 3.x y 4.3, la estructuración de párrafos en makela salida de 's cambió, por lo que (^|\n)/ (\n|$$)garantiza que las líneas que identifican el inicio y el final del rango de líneas de interés entre párrafos se detecten independientemente de si ocurren en el inicio o dentro / al final de un párrafo.
  • if ($$1 !~ "^[#.]")

    • Ignora bloques selectivamente:
      • #... ignora los no objetivos, cuyos bloques comienzan con# Not a target:
      • .... ignora objetivos especiales
    • Todos los demás bloques deben comenzar con una línea que contenga solo el nombre de un objetivo definido explícitamente seguido de:
  • grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'elimina objetivos no deseados de la salida:

    • '^[^[:alnum:]]'... excluye los objetivos ocultos , que, por convención, son objetivos que no comienzan ni con una letra ni con un dígito.
    • '^$@$$'... excluye el listobjetivo en sí

Luego, ejecutar make listimprime todos los objetivos, cada uno en su propia línea ; en su lugar , puede canalizar para xargscrear una lista separada por espacios.

mklement0 avatar Oct 13 '2014 12:10 mklement0

¡Actualizar!

A partir del 8 de enero de 2024 , Make tiene una --print-targetsopción que debería hacer esto correctamente sin expresiones regulares hacky. La versión actual es Make 4.4.1, por lo que la próxima versión tendrá esta característica.


Si Makefilefue creado por CMake, es posible que pueda ejecutar make help.

$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... install
etc

Si no, escribí un parche para agregar soporte adecuado para esta característica obviamente útil en Make. Esto es mucho mejor que todas las otras respuestas aquí, que implican trucos horribles para recuperar los Makefiles. Obviamente, eso no funciona si incluye otros Makefiles, usa nombres de destino calculados, etc.

El parche no se ha fusionado, por lo que debe compilarlo desde la fuente. No es tan malo, pero necesitas algunas herramientas de compilación antiguas y crujientes relacionadas con autoconf:

git clone https://github.com/Timmmm/make
cd make
./bootstrap
./configure
make -j4

En Linux puedes usar este binario que ya construí .

Luego puedes usar la -lbandera para enumerar los objetivos:

./make -C /path/to/your/project -l
Timmmm avatar Jan 05 '2017 16:01 Timmmm

Combiné estas dos respuestas: https://stackoverflow.com/a/9524878/86967 y https://stackoverflow.com/a/7390874/86967 y escapé un poco para que esto pudiera usarse desde dentro de un archivo MAKE.

.PHONY: no_targets__ list
no_targets__:
list:
    sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | sort"

.

$ make -s list
build
clean
default
distclean
doc
fresh
install
list
makefile ## this is kind of extraneous, but whatever...
run
Brent Bradburn avatar Feb 25 '2013 01:02 Brent Bradburn