How do you get the list of targets in a makefile?

后端 未结 20 1328
难免孤独
难免孤独 2020-11-30 16:50

I\'ve used rake a bit (a Ruby make program), and it has an option to get a list of all the available targets, eg

> rake --tasks
rake db:charset      # ret         


        
相关标签:
20条回答
  • 2020-11-30 17:16

    This one was helpful to me because I wanted to see the build targets required (and their dependencies) by the make target. I know that make targets cannot begin with a "." character. I don't know what languages are supported, so I went with egrep's bracket expressions.

    cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
    
    0 讨论(0)
  • 2020-11-30 17:20

    For AWK haters, and for simplicity, this contraption works for me:

    help:
      make -qpRr $(lastword $(MAKEFILE_LIST)) | egrep -v '(^(\.|:|#|\s|$)|=)' | cut -d: -f1
    

    (for use outside a Makefile, just remove $(lastword ...) or replace it with the Makefile path).

    This solution will not work if you have "interesting" rule names but will work well for most simple setups. The main downside of a make -qp based solution is (as in other answers here) that if the Makefile defines variable values using functions - they will still be executed regardless of -q, and if using $(shell ...) then the shell command will still be called and its side effects will happen. In my setup often the side effects of running shell functions is unwanted output to standard error, so I add 2>/dev/null after the make command.

    0 讨论(0)
  • 2020-11-30 17:22

    not sure why the previous answer was so complicated:

    list:
        cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 
    
    0 讨论(0)
  • 2020-11-30 17:23

    Focusing on an easy syntax for describing a make target, and having a clean output, I chose this approach:

    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:
    

    So treating the above as a Makefile and running it gives you something like

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

    Explanation for the chain of commands:

    • First, grep all targets and their preceeding line, see https://unix.stackexchange.com/a/320709/223029.
    • Then, get rid of the group separator, see https://stackoverflow.com/a/2168139/1242922.
    • Then, we collapse each pair of lines to parse it later, see https://stackoverflow.com/a/9605559/1242922.
    • Then, we parse for valid lines and remove those which do not match, see https://stackoverflow.com/a/8255627/1242922, and also give the output our desired order: command, then description.
    • Lastly, we arrange the output like a table.
    0 讨论(0)
  • 2020-11-30 17:25

    @nobar's answer helpfully shows how to use tab completion to list a makefile's targets.

    • This works great for platforms that provide this functionality by default (e.g., Debian, Fedora).

    • On other platforms (e.g., Ubuntu) you must explicitly load this functionality, as implied by @hek2mgl's answer:

      • . /etc/bash_completion installs several tab-completion functions, including the one for make
      • Alternatively, to install only tab completion for make:
        • . /usr/share/bash-completion/completions/make
    • For platforms that don't offer this functionality at all, such as OSX, you can source the following commands (adapated from here) to implement it:
    _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
    
    • Note: This is not as sophisticated as the tab-completion functionality that comes with Linux distributions: most notably, it invariably targets the makefile in the current directory, even if the command line targets a different makefile with -f <file>.
    0 讨论(0)
  • 2020-11-30 17:27

    Yet another additional answer to above.

    tested on MacOSX using only cat and awk on terminal

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

    will output of the make file like below:

    target1

    target2

    target3

    in the Makefile, it should be the same statement, ensure that you escape the variables using $$variable rather than $variable.

    Explanation

    cat - spits out the contents

    | - pipe parses output to next awk

    awk - runs regex excluding "shell" and accepting only "A-z" lines then prints out the $1 first column

    awk - yet again removes the last character ":" from the list

    this is a rough output and you can do more funky stuff with just AWK. Try to avoid sed as its not as consistent in BSDs variants i.e. some works on *nix but fails on BSDs like MacOSX.

    More

    You should be able add this (with modifications) to a file for make, to the default bash-completion folder /usr/local/etc/bash-completion.d/ meaning when you "make tab tab" .. it will complete the targets based on the one liner script.

    0 讨论(0)
提交回复
热议问题