Enumerar objetivos / metas en GNU make que contienen variables en su definición


Tengo un makefile bastante grande que crea un número de objetivos sobre la marcha computando nombres de variables. (eg foo fo (VAR): PRERE (PREREQS)). ¿Hay alguna manera de que gnu make pueda ser convencido de escupir una lista de objetivos después de haber expandido estas variables?

Me gustaría ser capaz de obtener los objetivos para un makefile aribitrary. Estoy tratando de escribir una función de finalización para mi shell.

16 answers

¿Puedes analizar la salida de make -pn (es decir, make --print-data-base --dry-run)? Imprime todas las variables, reglas, reglas implícitas y qué comandos se ejecutarán en detalle laborioso.

 77
Author: Jack Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-03 02:02:12
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'     

Tomado de la terminación make arg, que funciona como un encanto.

 111
Author: todd hodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-02 18:55:54

No estoy seguro si esto es solo una cosa de gnu make, pero esto funciona bien:

make help

 13
Author: Zdenik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-11 21:23:28

Varios respondedores han sugerido usar make -pn, que imprimirá la base de datos de reglas pero no ejecutará nada more más o menos. El problema con este enfoque es que -n todavía invoca todas las marcas recursivas, y todavía hace mucho más trabajo del necesario, porque imprime cada comando que habría invocado en una compilación regular. Una solución más eficiente sería crear un makefile trivial, dummy.mk, con estos contenidos:

__all_targets__: ; #no-op

Ahora invoca make como make -p -f Makefile -f dummy.mk __all_targets__. En cualquier construcción sustancial, la diferencia en la cantidad de producción generada por make es significativa. Por ejemplo:

$ gmake -pn | wc
 138985 2632330 69612711
$ gmake -f Makefile -f /tmp/dummy.mk -pn __all_targets__ | wc
  21673   93437  878985

El tiempo de ejecución también fue dramáticamente mejor 2 2.063 s para la primera versión, 0.059 s para la segunda.

 10
Author: Eric Melski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 16:14:51

Echa un vistazo a la finalización de bash para make en GitHub.

 9
Author: js.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-01 08:25:11

Edit: FYI el repositorio git de finalización de bash de debian en otra respuesta ahora incorpora una versión mejorada de este script adaptada a los casos de uso de finalización de bash.

#!/bin/bash

SCRIPT='
  /^# Make data base/,/^# Files/d             # skip until files section
  /^# Not a target/,+1          d             # following target isnt
  /^\.PHONY:/                   d             # special target
  /^\.SUFFIXES:/                d             # special target
  /^\.DEFAULT:/                 d             # special target
  /^\.PRECIOUS:/                d             # special target
  /^\.INTERMEDIATE:/            d             # special target
  /^\.SECONDARY:/               d             # special target
  /^\.SECONDEXPANSION/          d             # special target
  /^\.DELETE_ON_ERROR:/         d             # special target
  /^\.IGNORE:/                  d             # special target
  /^\.LOW_RESOLUTION_TIME:/     d             # special target
  /^\.SILENT:/                  d             # special target
  /^\.EXPORT_ALL_VARIABLES:/    d             # special target
  /^\.NOTPARALLEL:/             d             # special target
  /^\.ONESHELL:/                d             # special target
  /^\.POSIX:/                   d             # special target
  /^\.NOEXPORT:/                d             # special target
  /^\.MAKE:/                    d             # special target

# The stuff above here describes lines that are not
#  explicit targets or not targets other than special ones
# The stuff below here decides whether an explicit target
#  should be output.

  /^[^#\t:=%]+:([^=]|$)/ {                    # found target block
    h                                         # hold target
    d                                         # delete line
  }
  /^# File is an intermediate prerequisite/ { # nope
    s/^.*$//;x                                # unhold target
    d                                         # delete line
  }
  /^([^#]|$)/ {                               # end of target block
    s/^.*$//;x                                # unhold target
    s/:.*$//p                                 # write current target
    d                                         # hide any bugs
  }
'

make -npq .DEFAULT 2>/dev/null | sed -n -r "$SCRIPT" \
  | sort | uniq

Este es un script mucho más completo que el script de finalización de debian bash porque proporciona resultados para las reglas generadas que es lo que pide la pregunta y la respuesta más votada (script de finalización de debian bash en el servidor debian git) no va lo suficientemente lejos.

Este no es el script original que He vinculado a pero es mucho más simple y es un toque más rápido.

 7
Author: codeshot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-18 21:37:45

Este es el código para alias basado en la solución Todd Hodes

alias mtargets='make -qp | awk -F":" "/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split(\$1,A,/ /);for(i in A)print A[i]}"'
 4
Author: Nguyễn Minh Vũ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-20 06:40:23

Esto dará una buena salida:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort
 3
Author: Andor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-08 13:22:19

Hay una solución muy buena con algo de sed y magia egrep aquí: https://gist.github.com/pvdb/777954

 3
Author: Atilla Filiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-06 08:42:19

Supongo que llego un poco tarde a esta fiesta, pero si estás buscando un comando específico, podrías probar

make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'

Esto funciona en su mayoría, aunque todavía podría incluir algunas cosas no objetivo como una directiva vpath. Si no depende de las reglas integradas de make, puede usar make -qpR como el primer comando de la canalización.

 2
Author: DGrady,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-06 17:31:04

Solución de rubí:

`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}
 1
Author: gdub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-09 08:39:55

Estoy trabajando en solaris 10 y turbo C shell. La solución dada no funciona para mi proyecto makefile. incluso después de alterar la línea de comandos anterior a la sintaxis tcsh. Sin embargo, descubrí que puede obtener una solución fácil usando

remake --tasks | grep -v "clean some static output or just grep tabs on start of line" | awk ´{print $1}´

Versión remake:

remake --version

Es

GNU Make 3.82+dbg0.8
Built for sparc-sun-sparc2-9

Y algunos otros datos de versión sin importancia

 1
Author: Aviv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-20 05:14:41

Fui a buscar la misma pregunta y se me ocurrió este giro:

make -pn | sed -rn '/^[^# \t\.%].*:/p'

Esto elimina todas las líneas de comentario, reglas de patrón (líneas que comienzan con pestañas), todos los intrínsecos (ejemplo .c.o y %.o: %.c patrones).

 0
Author: Jamie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-03 21:41:12

Encontró esta solución en otro hilo:

sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\""

También puedes añadirlo a tu Makefile:

list:
    sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\\""

Y ejecutar make list.

 0
Author: thisismydesign,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-03 16:26:45

Claro, pero ¿cuándo quieres que los escupa?

Para informar el nombre del destino cuando se ejecuta la regla, ponga una línea en la regla:

foo$(VAR): $(PREREQS)
    @echo now making the foo target: $@
    do_other_stuff...

Para escupirlos a todos a la vez, podrías hacer un objetivo falso separado:

.PHONY: show_vars
show_vars:
    @echo foo$(VAR)
    @echo bar$(PARAM) blah$(FLAG)
    # and so on

Y esto se puede hacer un requisito previo de su destino predeterminado:

all: show_vars
    ...

EDITAR:
Quieres una forma de mostrar todos los posibles objetivos de un makefile arbitrario, que supongo que significa no intrusivamente. Bien...

Para hacerlo exactamente, y ser capaz de hacer frente a sofisticados makefiles, por ejemplo, que involucran reglas construidas por eval declaraciones, tendría que escribir algo cercano a un emulador Make. Práctico.

Para ver los objetivos de las reglas simples, podría escribir un makefile que actuaría como un escáner de makefile, operando en un makefile arbitrario:

  1. Obtiene todos los nombres de destino del makefile usando sed.
  2. 'incluir' el makefile para usarlo para expandir variable.
  3. Use ' show_%:; echo**` para imprimir todos los destinos

Este sería un trabajo impresionante. ¿Estás seguro de que el objetivo vale la pena el esfuerzo?

 -1
Author: Beta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-22 19:08:48
grep ^[a-z].*\:$ Makefile | sed s,:,,g
 -4
Author: Willian Braga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-20 19:22:54