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

后端 未结 20 1331
难免孤独
难免孤独 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:28

    I usually do:

    grep install_targets Makefile

    It would come back with something like:

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

    I hope this helps

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

    This is an attempt to improve on @nobar's great approach as follows:

    • uses a more robust command to extract the target names, which hopefully prevents any false positives (and also does away with the unnecessary sh -c)
    • does not invariably target the makefile in the current directory; respects makefiles explicitly specified with -f <file>
    • excludes hidden targets - by convention, these are targets whose name starts neither with a letter nor a digit
    • makes do with a single phony target
    • prefixes the command with @ to prevent it from being echoed before execution

    Curiously, GNU make has no feature for listing just the names of targets defined in a makefile. The -p option produces output that includes all targets, but buries them in a lot of other information.

    Place the following rule in a makefile for GNU make to implement a target named list that simply lists all target names in alphabetical order - i.e.: invoke as 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 '^$@$$'
    

    Important: On pasting this, make sure that the last line is indented by exactly 1 actual tab char. (spaces do not work).

    Note that sorting the resulting list of targets is the best option, since not sorting doesn't produce a helpful ordering in that the order in which the targets appear in the makefile is not preserved.
    Also, the sub-targets of a rule comprising multiple targets are invariably output separately and will therefore, due to sorting, usually not appear next to one another; e.g., a rule starting with a z: will not have targets a and z listed next to each other in the output, if there are additional targets.

    Explanation of the rule:

    • .PHONY: list
      • declares target list a phony target, i.e., one not referring to a file, which should therefore have its recipe invoked unconditionally
    • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

      • Invokes make again in order to print and parse the database derived from the makefile:
        • -p prints the database
        • -Rr suppresses inclusion of built-in rules and variables
        • -q only tests the up-to-date-status of a target (without remaking anything), but that by itself doesn't prevent execution of recipe commands in all cases; hence:
        • -f $(lastword $(MAKEFILE_LIST)) ensures that the same makefile is targeted as in the original invocation, regardless of whether it was targeted implicitly or explicitly with -f ....
          Caveat: This will break if your makefile contains include directives; to address this, define variable THIS_FILE := $(lastword $(MAKEFILE_LIST)) before any include directives and use -f $(THIS_FILE) instead.
        • : is a deliberately invalid target that is meant to ensure that no commands are executed; 2>/dev/null suppresses the resulting error message. Note: This relies on -p printing the database nonetheless, which is the case as of GNU make 3.82. Sadly, GNU make offers no direct option to just print the database, without also executing the default (or given) task; if you don't need to target a specific Makefile, you may use make -p -f/dev/null, as recommended in the man page.
    • -v RS=

      • This is an awk idiom that breaks the input into blocks of contiguous non-empty lines.
    • /^# File/,/^# Finished Make data base/
      • Matches the range of lines in the output that contains all targets (true as of GNU make 3.82) - by limiting parsing to this range, there is no need to deal with false positives from other output sections.
    • if ($$1 !~ "^[#.]")
      • Selectively ignores blocks:
        • # ... ignores non-targets, whose blocks start with # Not a target:
        • . ... ignores special targets
      • All other blocks should each start with a line containing only the name of an explicitly defined target followed by :
    • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' removes unwanted targets from the output:
      • '^[^[:alnum:]]' ... excludes hidden targets, which - by convention - are targets that start neither with a letter nor a digit.
      • '^$@$$' ... excludes the list target itself

    Running make list then prints all targets, each on its own line; you can pipe to xargs to create a space-separated list instead.

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

    This is far from clean, but did the job, for me.

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

    I use make -p that dumps the internal database, ditch stderr, use a quick and dirty grep -A 100000 to keep the bottom of the output. Then I clean the output with a couple of grep -v, and finally use cut to get what's before the colon, namely, the targets.

    This is enough for my helper scripts on most of my Makefiles.

    EDIT: added grep -v Makefile that is an internal rule

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

    For a Bash Script

    Here's a very simple way to do this in bash -- based on the comment by @cibercitizen1 above:

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

    See also the more authoritative answer by @Marc.2377, too, which says how the Bash completion module for make does it.

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

    If you have bash completion for make installed, the completion script will define a function _make_target_extract_script. This function is meant to create a sed script which can be used to obtain the targets as a list.

    Use it like this:

    # Make sure bash completion is enabled
    source /etc/bash_completion 
    
    # List targets from Makefile
    sed -nrf <(_make_target_extract_script --) Makefile
    
    0 讨论(0)
  • 2020-11-30 17:32

    This obviously won't work in many cases, but if your Makefile was created by CMake you might be able to run 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
    
    0 讨论(0)
提交回复
热议问题