primer make instalar entre ejecutar diferencia como comando archivos makefile gnu-make targets

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



makefile linux c (11)

Bajo Bash (al menos), esto se puede hacer automáticamente con la finalización de pestañas:

make(space)(tab)(tab)

He usado rake un poco (un programa Ruby make), 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 ya casi está disponible, a partir de 2007 - http://www.mail-archive.com/[email protected]/msg06434.html .

De todos modos, hice poco hack para extraer los objetivos de un archivo MAKE, que puede incluir en un archivo MAKE.

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

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

> make list list: copy: run: plot: turnin:


Combiné estas dos respuestas: https://.com/a/9524878/86967 y https://.com/a/7390874/86967 e hice algo de escape para que esto se pudiera usar 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


Como mklement0 señala , una característica para enumerar todos los objetivos de Makefile falta en GNU-make, y su respuesta y otras proporcionan formas de hacerlo.

Sin embargo, la publicación original también menciona rake , cuyas tareas cambian hace algo ligeramente diferente a solo enumerar todas las tareas en el rakefile. Rake solo le dará una lista de tareas que tienen descripciones asociadas. Las tareas sin descripciones no aparecerán en la lista . Esto le da al autor la capacidad de proporcionar descripciones de ayuda personalizadas y también omitir la ayuda para ciertos objetivos.

Si desea emular el comportamiento de rake, donde proporciona descripciones para cada objetivo , hay una técnica simple para hacer esto: insertar descripciones en los comentarios para cada objetivo que desee enumerar.

Puede colocar la descripción al lado del objetivo o, como hago a menudo, junto a una especificación PHONY sobre el objetivo, así:

.PHONY: target1 # Target 1 help text target1: deps @echo "Target 1" .PHONY: target2 # Target 2 help text target2: @echo "Target 2" ... .PHONY: help # Generate list of targets with descriptions help: @grep ''^.PHONY: .* #'' Makefile | sed ''s//.PHONY: /(.*/) # /(.*/)//1 /2/'' | expand -t20

Cuál rendirá

$ make help target1 Target 1 help text target2 Target 2 help text ... help Generate list of targets with descriptions

También puede encontrar un ejemplo de código corto en este artículo y here también.

Nuevamente, esto no resuelve el problema de listar todos los objetivos en un Makefile. Por ejemplo, si tiene un gran archivo MAKE que se generó o que alguien más escribió, y desea una forma rápida de enumerar sus objetivos sin excavar, esto no ayudará.

Sin embargo, si está escribiendo un archivo Makefile y desea generar un texto de ayuda de forma coherente y autodocumentada, esta técnica puede ser útil.


Este es un intento de mejorar el gran enfoque de @ nobar de la siguiente manera:

  • utiliza un comando más robusto para extraer los nombres de destino, lo que con suerte evita cualquier falso positivo (y también elimina el sh -c innecesario)
  • no se dirige invariablemente al archivo MAKE en el directorio actual ; respeta los -f <file> make explícitamente especificados con -f <file>
  • excluye los objetivos ocultos: por convención, se trata de objetivos cuyo nombre no comienza ni con una letra ni con un dígito
  • se las arregla con un solo objetivo falso
  • prefije el comando con @ para evitar que se repita antes de la ejecución

Curiosamente, la creación de GNU no tiene ninguna función para enumerar solo los nombres de los objetivos definidos en un archivo MAKE. La opción -p produce resultados que incluyen todos los objetivos, pero los entierra en mucha otra información.

Coloque la siguiente regla en un makefile para que GNU make implemente una list nombre del objetivo que simplemente enumera todos los nombres de los objetivos en orden alfabético, es decir: invocar como make list :

.PHONY: list list: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: ''/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}'' | sort | egrep -v -e ''^[^[:alnum:]]'' -e ''^$@$$'' | xargs

Importante : Al pegar esto, asegúrese de que la última línea esté sangrada exactamente con 1 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 genera un orden útil porque no se conserva el orden en el que aparecen los objetivos en el archivo MAKE.
Además, los sub-objetivos de una regla que comprende objetivos múltiples se emiten invariablemente por separado y, por lo tanto, debido a la clasificación, generalmente no aparecen uno al lado del otro; por ejemplo, una regla que comienza con az: no tendrá los objetivos z listados uno al lado del otro en la salida, si hay objetivos adicionales.

Explicación de la regla :

  • . PHONY: list
    • declara que la lista de objetivos es un objetivo falso, es decir, uno que no hace referencia a un archivo , por lo que debe tener su receta invocada incondicionalmente
  • $(MAKE) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Invoca de nuevo 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 incorporadas
      • -q solo prueba el estado actualizado de un objetivo (sin rehacer nada), pero eso por sí solo no impide la ejecución de comandos de receta en todos los casos; por lo tanto:
      • -f $(lastword $(MAKEFILE_LIST)) asegura que el mismo archivo MAKE sea dirigido como en la invocación original, independientemente de si fue apuntado implícita o explícitamente con -f ...
        Advertencia : Esto se romperá si su archivo MAKE contiene directivas; para solucionar esto, defina la variable THIS_FILE := $(lastword $(MAKEFILE_LIST)) antes que cualquier directiva de include y use -f $(THIS_FILE) lugar.
      • : es un objetivo deliberadamente no válido que está destinado a garantizar que no se ejecutan comandos ; 2>/dev/null suprime el mensaje de error resultante. Nota: Esto depende de la impresión de la base de datos, no obstante, que es el caso de GNU make 3.82. Lamentablemente, GNU no ofrece ninguna opción directa para imprimir la base de datos, sin ejecutar también la tarea predeterminada (o determinada); si no necesita apuntar a un Makefile específico, puede usar make -p -f/dev/null , como se recomienda en la página de man .
  • -v RS=

    • Esta es una expresión idiomática que divide la entrada en bloques de líneas contiguas no vacías.
  • /^# File/,/^# Finished Make data base/
    • Coincide con el rango de líneas en la salida que contiene todos los objetivos (verdadero a partir de GNU make 3.82) - al limitar el análisis a este rango, no es necesario tratar con falsos positivos de otras secciones de salida.
  • if ($$1 !~ "^[#.]")
    • Selectivamente ignora los bloques:
      • # ... ignora los no objetivos, cuyos bloques comienzan con # Not a target:
      • . ... ignora objetivos especiales
    • Todos los demás bloques deberían comenzar con una línea que contenga solo el nombre de un objetivo definido explícitamente seguido de :
  • egrep -v -e ''^[^[:alnum:]]'' -e ''^$@$$'' elimina los destinos no deseados del resultado:
    • ''^[^[: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 objetivo de la list
  • xargs
    • Efectivamente convierte las líneas de salida en una sola línea, lista separada por espacios; omita esto si desea que cada nombre de destino aparezca en su propia línea.

Este me fue útil porque quería ver los objetivos de compilación requeridos (y sus dependencias) por parte del objetivo. Sé que hacer objetivos no puede comenzar con un "." personaje. No sé qué idiomas son compatibles, así que fui con las expresiones de soporte de egrep.

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


Esto está lejos de ser limpio, pero hizo el trabajo, para mí.

make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^/(/s/|#/|/./)" | grep -v "Makefile:" | cut -d ":" -f 1

Yo uso make -p que vacía la base de datos interna, ditch stderr, usa un grep -A 100000 rápido y sucio grep -A 100000 para mantener el final de la salida. Luego limpio la salida con un par de grep -v , y finalmente uso el cut para obtener lo que está antes del colon, es decir, los objetivos.

Esto es suficiente para mis scripts de ayuda en la mayoría de mis Makefiles.

EDITAR: agregado grep -v Makefile que es una regla interna


Hay muchas soluciones viables aquí, pero como me gusta decir, "si vale la pena hacerlo una vez, vale la pena hacerlo nuevamente". Renuevé la sugerencia de usar (pestaña) (pestaña), pero como algunos han señalado, es posible que no tenga asistencia completa, o, si tiene muchos archivos incluidos, es posible que desee una forma más fácil de saber dónde se define un objetivo.

No he probado lo siguiente con sub-marcas ... Creo que no funcionaría. Como sabemos, recursivo hace considerado nocivo.

.PHONY: list ls ls list : @# search all include files for targets. @# ... excluding special targets, and output dynamic rule definitions unresolved. @for inc in $(MAKEFILE_LIST); do / echo '' ='' $$inc ''= ''; / grep -Eo ''^[^/.#[:blank:]]+.*:.*'' $$inc | grep -v '':='' | / cut -f 1 | sort | sed ''s/.*/ &/'' | sed -n ''s/:.*$$//p'' | / tr $$ /// | tr $(open_paren) % | tr $(close_paren) % / ; done # to get around escaping limitations: open_paren := /( close_paren := /)

Lo que me gusta porque:

  • enumere los objetivos por incluir archivo.
  • salida de definiciones de objetivos dinámicos sin formato (reemplaza los delimitadores de variables con módulo)
  • dar salida a cada objetivo en una nueva línea
  • parece más claro (opinión subjetiva)

Explicación:

  • archivo foreach en MAKEFILE_LIST
  • muestra el nombre del archivo
  • líneas grep que contienen dos puntos, que no tienen sangría, no comentarios, y no comienzan con un punto
  • excluir expresiones de asignación inmediata (: =)
  • cortar, ordenar, sangría y cortar dependencias de reglas (después de dos puntos)
  • delimitadores variables Munge para evitar la expansión

Muestra de salida:

= Makefile = includes ls list = util/kiss/snapshots.mk = rotate-db-snapshots rotate-file-snapshots snap-db snap-files snapshot = util/kiss/main.mk = dirs install %MK_DIR_PREFIX%env-config.php %MK_DIR_PREFIX%../srdb


No estoy seguro de por qué la respuesta anterior fue tan complicada:

list: cat Makefile | grep "^[A-z]" | awk ''{print $$1}'' | sed "s/://g"


Obviamente, esto no funcionará en muchos casos, pero si tu Makefile fue creado por CMake, es posible que puedas 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 tiene finalización de bash para make instalado, el script de finalización definirá una función _make_target_extract_script . Esta función está destinada a crear un script sed que se puede usar para obtener los objetivos como una lista.

Úselo así:

# Make sure bash completion is enabled source /etc/bash_completion # List targets from Makefile sed -nrf <(_make_target_extract_script --) Makefile


La respuesta de @nobar muestra útilmente cómo usar la finalización de pestañas para listar los objetivos de un archivo MAKE .

  • Esto funciona muy bien para las plataformas que proporcionan esta funcionalidad por defecto (por ejemplo, Debian, Fedora ).

  • En otras plataformas (p. Ej., Ubuntu ) debe cargar explícitamente esta funcionalidad, como lo implica la respuesta de @hek2mgl :

    • . /etc/bash_completion . /etc/bash_completion instala varias funciones de finalización de pestañas, incluida la de make
    • Alternativamente, para instalar solo la finalización de pestañas para make :
      • . /usr/share/bash-completion/completions/make
  • Para las plataformas que no ofrecen esta funcionalidad en absoluto , como OSX , puede obtener los siguientes comandos (adaptados desde here ) para implementarlo:

_complete_make() { COMPREPLY=($(compgen -W "$(make -pRrq : 2>/dev/null | awk -v RS= -F: ''/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}'' | egrep -v ''^[^[:alnum:]]'' | sort | xargs)" -- "${COMP_WORDS[$COMP_CWORD]}")); } complete -F _complete_make make

  • Nota: Esto no es tan sofisticado como la funcionalidad de completar pestañas que viene con las distribuciones de Linux: lo más notable es que se dirige invariablemente al archivo MAKE en el directorio actual , incluso si la línea de comando apunta a un archivo MAKE diferente con -f <file> .