¿Cómo se obtiene la lista de objetivos en un archivo MAKE?
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:
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
Prefacio :
Según esta respuesta , una
make
versió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 make
no tiene ninguna función para enumerar sólo los nombres de los objetivos definidos en un archivo MAKE. Si bien la -p
opció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 make
implemente un objetivo llamado list
que 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.a
z
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=C
se asegura de quemake
el 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
make
nuevamente para imprimir y analizar la base de datos derivada del archivo MAKE:-p
imprime la base de datos-Rr
suprime la inclusión de reglas y variables integradas-q
só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 queMAKEFILE_LIST
también contiene la lista deinclude
Makefiles,firstword
se 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/null
suprime el mensaje de error resultante. Nota: No obstante, esto depende de-p
la 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 usarmake -p -f/dev/null
, como se recomienda en laman
página.
- Se invoca
-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
make
las versiones 3.x y 4.3, la estructuración de párrafos enmake
la 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
:
- Ignora bloques selectivamente:
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 ellist
objetivo en sí
Luego, ejecutar make list
imprime todos los objetivos, cada uno en su propia línea ; en su lugar , puede canalizar para xargs
crear una lista separada por espacios.
¡Actualizar!
A partir del 8 de enero de 2024 , Make tiene una --print-targets
opció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 Makefile
fue 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 -l
bandera para enumerar los objetivos:
./make -C /path/to/your/project -l
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