Comment obtenir la liste des cibles dans un makefile?


202

J'ai utilisé un peu de rake (un programme make Ruby), et il a une option pour obtenir une liste de toutes les cibles disponibles, par exemple

> 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...
...

mais il ne semble pas y avoir d'option pour le faire dans GNU make.

Apparemment, le code est presque là pour cela, depuis 2007 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html .

Quoi qu'il en soit, j'ai fait peu de piratage pour extraire les cibles d'un makefile, que vous pouvez inclure dans un makefile.

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

Il vous donnera une liste des cibles définies. Ce n'est qu'un début - cela ne filtre pas les dépendances, par exemple.

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

2
J'ai rapidement lu les réponses, qui sont intéressantes, mais pour l'instant, je préfère rester clair, simple et portable en utilisant un alias (dans mon .bashrc): le alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' plus souvent, j'ai juste besoin d'examiner le makefile actuel, et l'achèvement de bash se développe mon alias.
RockyRoad


4
Est-ce trop banal juste grep : Makefile:?
cibercitizen1

Réponses:


130

Il s'agit d'une tentative d'améliorer la grande approche de @ nobar comme suit:

  • utilise une commande plus robuste pour extraire les noms cibles, ce qui, espérons-le, empêche les faux positifs (et supprime également les inutiles sh -c)
  • ne cible pas invariablement le makefile dans le répertoire courant ; respecte les makefiles explicitement spécifiés avec-f <file>
  • exclut les cibles cachées - par convention, ce sont des cibles dont le nom ne commence ni par une lettre ni par un chiffre
  • se contente d'une seule cible bidon
  • préfixe la commande avec @pour l'empêcher d'être répercutée avant l'exécution

Curieusement, GNU maken'a aucune fonctionnalité pour lister uniquement les noms des cibles définies dans un makefile. L' -poption produit une sortie qui inclut toutes les cibles, mais les enterre dans de nombreuses autres informations.

Placez la règle suivante dans un makefile pour GNU makepour implémenter une cible nommée listqui répertorie simplement tous les noms de cible dans l'ordre alphabétique - c'est-à-dire: invoquer en tant quemake 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 '^$@$$'

Important : lors du collage, assurez-vous que la dernière ligne est en retrait avec exactement 1 caractère de tabulation réel. (les espaces ne fonctionnent pas ) .

Notez que trier la liste de cibles résultante est la meilleure option, car ne pas trier ne produit pas un ordre utile dans la mesure où l'ordre dans lequel les cibles apparaissent dans le makefile n'est pas conservé.
De plus, les sous-cibles d'une règle comprenant plusieurs cibles sont invariablement sorties séparément et, par conséquent, en raison du tri, n'apparaissent généralement pas côte à côte; Par exemple, une règle commençant par a z:n'aura pas de cibles aet sera zlistée côte à côte dans la sortie, s'il y a des cibles supplémentaires.

Explication de la règle :

  • .PHONY: list
    • déclare que la liste des cibles est une cible bidon, c'est-à-dire une ne faisant pas référence à un fichier , qui devrait donc avoir sa recette invoquée sans condition
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Invoque à makenouveau afin d'imprimer et d'analyser la base de données dérivée du makefile:
      • -p imprime la base de données
      • -Rr supprime l'inclusion de règles et de variables intégrées
      • -qteste uniquement l'état à jour d'une cible (sans rien refaire), mais cela n'empêche pas en soi l'exécution des commandes de recette dans tous les cas; Par conséquent:
      • -f $(lastword $(MAKEFILE_LIST))garantit que le même makefile est ciblé que dans l'appel d'origine, qu'il ait été ciblé implicitement ou explicitement avec -f ....
        Avertissement : cela se cassera si votre makefile contient des includedirectives; pour résoudre ce problème, définissez la variable THIS_FILE := $(lastword $(MAKEFILE_LIST)) avant toutes les includedirectives et utilisez -f $(THIS_FILE)plutôt.
      • :est une cible délibérément invalide destinée à garantir qu'aucune commande n'est exécutée ; 2>/dev/nullsupprime le message d'erreur résultant. Remarque: Cela dépend -pnéanmoins de l'impression de la base de données, ce qui est le cas pour GNU make 3.82. Malheureusement, GNU make n'offre aucune option directe pour simplement imprimer la base de données, sans exécuter également la tâche par défaut (ou donnée); si vous n'avez pas besoin de cibler un Makefile spécifique, vous pouvez utiliser make -p -f/dev/null, comme recommandé dans la manpage.
  • -v RS=

    • Il s'agit d'un idiome awk qui divise l'entrée en blocs de lignes contiguës non vides.
  • /^# File/,/^# Finished Make data base/
    • Correspond à la plage de lignes dans la sortie qui contient toutes les cibles (vrai à partir de GNU 3.82) - en limitant l'analyse à cette plage, il n'est pas nécessaire de traiter les faux positifs des autres sections de sortie.
  • if ($$1 !~ "^[#.]")
    • Ignore sélectivement les blocs:
      • # ... ignore les non-cibles, dont les blocs commencent par # Not a target:
      • . ... ignore les cibles spéciales
    • Tous les autres blocs doivent chacun commencer par une ligne contenant uniquement le nom d'une cible explicitement définie suivie de :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' supprime les cibles indésirables de la sortie:
    • '^[^[:alnum:]]'... exclut les cibles cachées qui, par convention, sont des cibles qui ne commencent ni par une lettre ni par un chiffre.
    • '^$@$$'... exclut la listcible elle-même

L'exécution make listimprime ensuite toutes les cibles, chacune sur sa propre ligne; vous pouvez diriger vers xargspour créer une liste séparée par des espaces à la place.


C'est une excellente réponse, cependant, comment puis-je obtenir la description de chaque tâche? Actuellement, je le stocke en tant que commentaire au-dessus de la définition de tâche. Vous ne savez pas s'il est possible de l'inclure dans la liste de la même manière que rake --taskscela?
Piotr Kuczynski

1
@PiotrKuczynski: Question intéressante, mais je vous suggère de la poster en tant que nouvelle question (en pointant celle-ci pour référence).
mklement0

"Malheureusement, GNU make n'offre aucune option directe pour simplement imprimer la base de données." Il y a une -noption.
Bulletmagnet

@Bulletmagnet: Le but de l' -noption est de "Imprimer les commandes qui seraient exécutées ..." - en d'autres termes: une fonction de dry-run. Ce n'est pas non plus que votre citation manque l'italique du mot juste : make -pen lui - même imprime la base de données, mais exécute invariablement également la tâche par défaut ; le manuel recommande le maladroit make -p -f/dev/nullpour éviter cela.
mklement0

1
Répertoriera également toutes les cibles .PHONY, alors assurez-vous que vous n'en avez pas.PHONY: *
tekumara

189

Sous Bash (au moins), cela peut être fait automatiquement avec la complétion des onglets:

make spacetabtab


1
Testé: bash --version = 4.2.45 (1) -release. make --version = 3,81.
nobar

53
+1, mais notez que ce n'est pas une fonctionnalité bash , mais dépend de votre plate - forme . Les plates-formes se répartissent en trois catégories: celles où cette complétion est installée par défaut (par exemple, Debian 7, Fedora 20), celles où vous pouvez éventuellement l' installer (par exemple, Ubuntu 14, avec . /etc/bash_completion), et celles qui ne la prennent pas en charge du tout (par exemple, OSX 10.9)
mklement0

8
cela fonctionne sur OS X 10.10 (pas avec bash mais avec zsh).
Florian Oswald

4
Excellent conseil, mais a également besoin d'un bash-completionpackage. Trouvé à Fedora, RHEL, Gentoo, ect.
NoelProf

4
Cela ne fonctionne pas avec les cibles de création créées par programme AFAICT, par exemple$(RUN_TARGETS): run-%: ...
Matthias

32

Cela ne fonctionnera évidemment pas dans de nombreux cas, mais si votre a Makefileété créé par CMake, vous pourrez peut-être l'exécuter 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

Avez-vous une option à activer dans votre CMakeList pour l'obtenir? J'ai un makefile généré par CMake et je n'ai pas la pseudo cible d'aide disponible
Xavier T.

Nan. Sur OSX au moins avec un CMake récent (j'utilise en fait des nightlies mais je crois que quand j'ai écrit cela, j'utilisais 3.3), lancez-le touch CMakeLists.txt && cmake . && make helpet cela devrait fonctionner. Je peux seulement deviner que vous utilisez un ancien cmake, ou que vous n'utilisez pas le générateur Unix Makefiles?
Timmmm

J'utilise CMake 3.6.2 avec un générateur Unix sous Windows. Je vais fouiller pour chercher une explication car cela semble pratique.
Xavier T.

26

J'ai combiné ces deux réponses: https://stackoverflow.com/a/9524878/86967 et https://stackoverflow.com/a/7390874/86967 et j'ai fait quelques échappements pour que cela puisse être utilisé depuis l'intérieur d'un makefile.

.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

10
J'ai également (récemment) découvert que la tabulation sous Bash listera les cibles disponibles.
nobar

1
+1 pour une excellente approche, mais quelques améliorations pourraient être apportées: (a) la spécification explicite sh -c "…"n'est pas nécessaire, car c'est ce qui est makeutilisé par défaut pour appeler les commandes de recette; (b) la commande que vous utilisez est trop simpliste, entraînant des faux positifs (comme vous le constatez); (c) si vous préfixez la commande avec @, elle ne sera pas répercutée sur stdout avant l'exécution, évitant ainsi la nécessité de l'utiliser -slors de l'invocation.
mklement0

1
il y a une cible make beaucoup plus simple que vous pourriez ajouter: list: cat Makefile | grep "^ [Az]" | awk '{print $$ 1}' | sed "s /: // g | sort"
thamster

2
L'approche cat / sed échoue à plusieurs niveaux. Il ne développe pas les variables et ne répertorie pas non plus les cibles résultant de l'inclusion d'autres fichiers.
Troy Daniels

1
@ mklement0: Je préfère utiliser make -s(via un alias Bash) plutôt que de préfixer les commandes dans le makefile avec @. Il y a des cas où cela @peut être utile, notamment comme préfixe pour des echocommandes (où l'affichage de la commande serait redondant), mais en général je n'aime pas l'utiliser. De cette façon, je peux voir les "recettes" quand j'en ai besoin (en n'utilisant pas-s ), mais pas typiquement. Voici la documentation associée: GNU Make Manual, 5.2 Recipe Echoing .
nobar

14

Si vous avez bash complétion pour makeinstallé, le script de complétion définira une fonction _make_target_extract_script. Cette fonction est destinée à créer un sedscript qui peut être utilisé pour obtenir les cibles sous forme de liste.

Utilisez-le comme ceci:

# Make sure bash completion is enabled
source /etc/bash_completion 

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile

3
Utile, mais notez que toutes les plates-formes n'ont pas de script /etc/bash_completionet / ou de fonction _make_target_extract_script- vous semblez être sur Ubuntu> 12. Si vous ciblez à la /usr/share/bash-completion/completions/makeplace, votre approche fonctionnera sur des plates-formes supplémentaires, telles que Fedora 20. Il existe des plates-formes (plus anciennes) qui ont ce fichier, mais pas la fonction (par exemple, Debian 7 et Ubuntu 12); d'autres plates-formes, telles que OSX, ne sont pas livrées avec une tabulation complète du maketout. Il serait peut-être utile d'afficher la définition de fonction réelle.
mklement0

1
Merci pour votre commentaire. Ceci est très apprécié. Oui, je l'ai testé sur Ubuntu 14.04
hek2mgl

11

Comme remarquer mklement0 , une fonction pour répertorier toutes les cibles Makefile manque dans GNU-make, et sa réponse et d'autres fournissent des moyens de le faire.

Cependant, le message d'origine mentionne également rake , dont le changement de tâches fait quelque chose de légèrement différent de simplement lister toutes les tâches dans le rakefile. Rake ne vous donnera qu'une liste de tâches qui ont des descriptions associées. Les tâches sans description ne seront pas répertoriées . Cela permet à l'auteur de fournir à la fois des descriptions d'aide personnalisées et d'omettre l'aide pour certaines cibles.

Si vous souhaitez imiter le comportement de rake, où vous fournissez descriptions pour chaque cible , il existe une technique simple pour ce faire: incorporer des descriptions dans les commentaires pour chaque cible que vous souhaitez répertorier.

Vous pouvez soit mettre la description à côté de la cible ou, comme je le fais souvent, à côté d'une spécification PHONY au-dessus de la cible, comme ceci:

.PHONY: target1 # Target 1 help text
target1: deps
    [... target 1 build commands]

.PHONY: target2 # Target 2 help text
target2:
    [... target 2 build commands]

...                                                                                                         

.PHONY: help # Generate list of targets with descriptions                                                                
help:                                                                                                                    
    @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20

Qui donnera

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions

Vous pouvez également trouver un exemple de code court dans cet essentiel et ici aussi.

Encore une fois, cela ne résout pas le problème de la liste de toutes les cibles dans un Makefile. Par exemple, si vous avez un gros Makefile qui a peut-être été généré ou que quelqu'un d'autre a écrit, et que vous voulez un moyen rapide de lister ses cibles sans le fouiller, cela n'aidera pas.

Toutefois, si vous écrivez un Makefile et que vous souhaitez générer un texte d'aide de manière cohérente et auto-documentée, cette technique peut être utile.


C'est une excellente technique - agréable et simple mais donne également des descriptions!
Brian Burns

Grande technique. J'ai modifié cela un peu pour utiliser la echocommande comme description de la commande ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng

@PengheGeng Merci pour le message. Je tiens à préciser qu'il ne @echo "Target 1"s'agit que d'un espace réservé et non d'une "commande d'écho de description". Le texte d'aide généré ne provient pas du @echo. Dans un vrai Makefile, ceux-ci echoseraient remplacés par une commande de construction ou quelque chose comme ça. Je vais modifier le message pour le rendre plus clair.
jsp

5

Ma réponse préférée à cela a été publiée par Chris Down à Unix & Linux Stack Exchange. Je vais citer.

Voici comment le module de complétion bash pour makeobtient sa liste:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'

Il imprime une liste de cibles délimitées par des sauts de ligne, sans pagination.

L'utilisateur Brainstone suggère un tuyau sort -upour supprimer les entrées en double:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u

Source: Comment lister toutes les cibles en make? (Unix et Linux SE)


4

La réponse de @ nobar montre utilement comment utiliser la complétion d'onglet pour lister les cibles d'un makefile .

  • Cela fonctionne très bien pour les plates-formes qui fournissent cette fonctionnalité par défaut (par exemple, Debian, Fedora ).

  • Sur d'autres plateformes (par exemple, Ubuntu ), vous devez explicitement charger cette fonctionnalité, comme l' indique la réponse de @ hek2mgl :

    • . /etc/bash_completion installe plusieurs fonctions de tabulation, dont celle pour make
    • Alternativement, pour installer uniquement la complétion des onglets pour make:
      • . /usr/share/bash-completion/completions/make
  • Pour les plateformes qui n'offrent pas du tout cette fonctionnalité , comme OSX , vous pouvez source les commandes suivantes (adaptées d' ici ) pour l'implémenter:
_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
  • Remarque: Ce n'est pas aussi sophistiqué que la fonctionnalité de tabulation fournie avec les distributions Linux: plus particulièrement, elle cible invariablement le makefile dans le répertoire courant , même si la ligne de commande cible un makefile différent avec -f <file>.

4

En me concentrant sur une syntaxe simple pour décrire une cible de création et ayant une sortie propre, j'ai choisi cette approche:

help:
    @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \
     | grep -v -- -- \
     | sed 'N;s/\n/###/' \
     | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \
     | column -t  -s '###'


#: Starts the container stack
up: a b
  command

#: Pulls in new container images
pull: c d 
    another command

make-target-not-shown:

# this does not count as a description, so leaving
# your implementation comments alone, e.g TODOs
also-not-shown:

Donc, traiter ce qui précède comme un Makefile et l'exécuter vous donne quelque chose comme

> make help
up          Starts the container stack
pull        Pulls in new container images

Explication de la chaîne de commandes:


Très belle solution. Je l'utilise depuis quelques années maintenant: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort avec l' ##avant le commentaire sur la même ligne que la cible. Mais je pense que votre solution permet avant la lisibilité.
thoroc

Un makefile composé des deux premières lignes de rapports grep: parentheses not balancedsur ma machine OSX 10.15.
Malcolm Crum

@Crummy désolé, mon erreur. Merci de l'avoir signalé. A corrigé. make nécessite d'échapper aux signes dollar qui ne sont pas censés commencer les noms de variables.
Richard Kiefer

Attention, StackOverflow convertit les tabulations en espaces lors de l'affichage des sections de code ci-dessus, mais les Makefiles nécessitent des tabulations. Vous pouvez modifier la publication, puis copier les sections, afin que les onglets soient conservés.
Richard Kiefer

2

Beaucoup de solutions réalisables ici, mais comme j'aime le dire, "si cela vaut la peine d'être fait une fois, cela vaut la peine de le faire à nouveau." J'ai voté pour la suggestion d'utiliser (tab) (tab), mais comme certains l'ont noté, il se peut que vous n'ayez pas de prise en charge de l'achèvement ou, si vous avez plusieurs fichiers d'inclusion, vous voudrez peut-être un moyen plus simple de savoir où une cible est définie.

Je n'ai pas testé ce qui suit avec des sous-marques ... Je pense que cela ne fonctionnerait pas. Comme nous le savons, le récursif le rend dangereux.

.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 := \)

Ce que j'aime parce que:

  • liste les cibles par fichier d'inclusion.
  • produire des définitions de cibles dynamiques brutes (remplace les délimiteurs de variables par modulo)
  • sortie chaque cible sur une nouvelle ligne
  • semble plus clair (opinion subjective)

Explication:

  • fichier foreach dans MAKEFILE_LIST
  • afficher le nom du fichier
  • lignes de grep contenant deux points, qui ne sont pas en retrait, pas de commentaires, et ne commencent pas par un point
  • exclure les expressions d'affectation immédiate (: =)
  • couper, trier, mettre en retrait et couper les dépendances aux règles (après deux-points)
  • délimiteurs variables munge pour empêcher l'expansion

Exemple de sortie:

 = 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

1

Celui-ci m'a été utile car je voulais voir les cibles de build requises (et leurs dépendances) par la cible make. Je sais que faire des cibles ne peut pas commencer par un "." personnage. Je ne sais pas quelles langues sont prises en charge, j'ai donc opté pour les expressions de support egrep.

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

1

C'est loin d'être propre, mais ça a fait le boulot, pour moi.

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

J'utilise make -pqui vide la base de données interne, stitchr de fossé, utilise un rapide et sale grep -A 100000pour garder le bas de la sortie. Ensuite, je nettoie la sortie avec quelques grep -v, et finalement j'utilisecut pour obtenir ce qui est avant les deux points, à savoir les cibles.

Cela suffit pour mes scripts d'aide sur la plupart de mes Makefiles.

EDIT: ajouté grep -v Makefilequ'il s'agit d'une règle interne


1

Il s'agit d'une modification de la réponse très utile de jsp ( https://stackoverflow.com/a/45843594/814145 ). J'aime l'idée d'obtenir non seulement une liste de cibles mais aussi leurs descriptions. Makefile de jsp met la description en commentaire, ce que j'ai souvent trouvé sera répété dans la commande echo de description de la cible. Donc, à la place, j'extrais la description de la commande echo pour chaque cible.

Exemple de Makefile:

.PHONY: all
all: build
        : "same as 'make build'"

.PHONY: build
build:
        @echo "Build the project"

.PHONY: clean
clean:
        @echo "Clean the project"

.PHONY: help
help:
        @echo -n "Common make targets"
        @echo ":"
        @cat Makefile | sed -n '/^\.PHONY: / h; /\(^\t@*echo\|^\t:\)/ {H; x; /PHONY/ s/.PHONY: \(.*\)\n.*"\(.*\)"/    make \1\t\2/p; d; x}'| sort -k2,2 |expand -t 20

Sortie de make help:

$ make help
Common make targets:
    make all        same as 'make build'
    make build      Build the project
    make clean      Clean the project
    make help       Common make targets

Remarques:

  • Identique à la réponse de jsp , seules les cibles PHONY peuvent être répertoriées, ce qui peut ou non fonctionner pour votre cas
  • En outre, il répertorie uniquement les cibles PHONY qui ont une commande echoou :comme première commande de la recette. :signifie "ne rien faire". Je l'utilise ici pour les cibles qui ne nécessitent aucun écho, comme la allcible ci-dessus.
  • Il existe une astuce supplémentaire pour que la helpcible ajoute le ":" dans la make helpsortie.

0

Encore une autre réponse supplémentaire à ce qui précède.

testé sur MacOSX en utilisant uniquement cat et awk sur le terminal

cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'

affichera le fichier make comme ci-dessous:

target1

target2

target3

dans le Makefile, ce doit être la même instruction, assurez-vous que vous échappez les variables en utilisant la variable $$ plutôt que la variable $.

Explication

chat - crache le contenu

| - le tube analyse la sortie vers le prochain awk

awk - exécute regex à l'exclusion de "shell" et n'accepte que les lignes "Az", puis imprime la première colonne $ 1

awk - supprime encore une fois le dernier caractère ":" de la liste

c'est une sortie approximative et vous pouvez faire des choses plus funky avec juste AWK. Essayez d'éviter sed car ce n'est pas aussi cohérent dans les variantes BSD c'est-à-dire que certains travaux sur * nix mais échouent sur BSD comme MacOSX.

Plus

Vous devriez pouvoir l'ajouter (avec des modifications) à un fichier pour make , dans le dossier bash-complétion par défaut /usr/local/etc/bash-completion.d/ ce qui signifie que lorsque vous "créez un onglet ", il terminera la cibles basées sur le script one liner.


vous pouvez également utiliser make -qp plutôt que cat. il deviendra donc make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {print substr ($ 0, 1 , longueur (0 $) -1) | "sort -u"} '
Jimmy MG Lim

0

Je fais habituellement:

grep install_targets Makefile

Il reviendrait avec quelque chose comme:

install_targets = install-xxx1 install-xxx2 ... etc

J'espère que ça aide


0

Pour un script bash

Voici un moyen très simple de le faire dans bash- basé sur le commentaire de @ cibercitizen1 ci - dessus :

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'

Voir aussi la réponse plus officielle de @ Marc.2377, qui dit comment le module de complétion Bash le makefait.


-4

Je ne sais pas pourquoi la réponse précédente était si compliquée:

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

8
La réponse précédente est si compliquée, car elle couvre tous les scénarios que votre réponse ne couvre PAS: (a) l'inclusion de cibles définies via des variables (par exemple, $(SHELLS): ...), (b) l'inclusion de cibles qui commencent par un chiffre, (c) non inclusion de définitions de variables , (d) ciblant le makefile approprié s'il a makeété spécifié avec un chemin de makefile explicite. (a) est la lacune cruciale: même si vous avez ciblé de manière fiable le bon makefile, l'analyse du fichier brut ne fonctionnera pas dans le cas général, en raison du manque d'expansion des variables.
mklement0

6
En aparté, re compliqué: votre commande peut être simplifiée à ce qui suit - mais le point principal est que ce n'est pas assez robuste : awk -F: '/^[A-z]/ {print $$1}' Makefile. Enfin, un point largement académique: utiliser [A-z]plutôt que [:alpha:]signifie que vous allez manquer des cibles qui commencent par un caractère étranger tel que á.
mklement0

@ mklement0 votre première commande awk fonctionne bien et est la plus simple jusqu'à présent, bien que l'utilisation de [: alpha:] semble la casser pour une raison quelconque - il manque des cibles dans un fichier de test.
Brian Burns

@ bburns.km: Mon mauvais: j'aurais dû dire [[:alpha:]]plutôt que [:alpha:]( [:alpha:]représente l'ensemble de lettres sensible aux paramètres régionaux à l' intérieur d' une classe de caractères ( [...]), d'où le besoin effectif de double [[ / ]].
mklement0

4
Pourquoi cette réponse est- elle si compliquée? Vous parvenez à collecter plusieurs des péchés inutiles dans ce court extrait. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefileutilise un seul processus et, espérons-le, une expression régulière plus correcte (bien que vous puissiez bien sûr avoir des cibles avec des soulignements, des nombres, etc., comme indiqué dans les commentaires précédents).
tripleee
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.