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

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

    Plenty of workable solutions here, but as I like saying, "if it's worth doing once, it's worth doing again." I did upvote the sugestion to use (tab)(tab), but as some have noted, you may not have completion support, or, if you have many include files, you may want an easier way to know where a target is defined.

    I have not tested the below with sub-makes...I think it wouldn't work. As we know, recursive makes considered harmful.

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

    Which I like because:

    • list targets by include file.
    • output raw dynamic target definitions (replaces variable delimiters with modulo)
    • output each target on a new line
    • seems clearer (subjective opinion)

    Explanation:

    • foreach file in the MAKEFILE_LIST
    • output the name of the file
    • grep lines containing a colon, that are not indented, not comments, and don't start with a period
    • exclude immediate assignment expressions (:=)
    • cut, sort, indent, and chop rule-dependencies (after colon)
    • munge variable delimiters to prevent expansion

    Sample Output:

     = 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
    
    0 讨论(0)
  • 2020-11-30 17:39

    To expand on the answer given by @jsp, you can even evaluate variables in your help text with the $(eval) function.

    The proposed version below has these enhanced properties:

    • Will scan any makefiles (even included)
    • Will expand live variables referenced in the help comment
    • Adds documentation anchor for real targets (prefixed with # TARGETDOC:)
    • Adds column headers

    So to document, use this form:

    RANDOM_VARIABLE := this will be expanded in help text
    
    .PHONY: target1 # Target 1 help with $(RANDOM_VARIABLE)
    target1: deps
        [... target 1 build commands]
    
    # TARGETDOC: $(BUILDDIR)/real-file.txt # real-file.txt help text
    $(BUILDDIR)/real-file.txt:
        [... $(BUILDDIR)/real-file.txt build commands]
    

    Then, somewhere in your makefile:

    .PHONY: help # Generate list of targets with descriptions
    help:
        @# find all help in targets and .PHONY and evaluate the embedded variables
        $(eval doc_expanded := $(shell grep -E -h '^(.PHONY:|# TARGETDOC:) .* #' $(MAKEFILE_LIST) | sed -E -n 's/(\.PHONY|# TARGETDOC): (.*) # (.*)/\2  \3\\n/'p | expand -t40))
        @echo
        @echo ' TARGET   HELP' | expand -t40
        @echo ' ------   ----' | expand -t40
        @echo -e ' $(doc_expanded)'
    
    0 讨论(0)
  • 2020-11-30 17:40

    Under Bash (at least), this can be done automatically with tab completion:

    make spacetabtab

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

    I combined these two answers: https://stackoverflow.com/a/9524878/86967 and https://stackoverflow.com/a/7390874/86967 and did some escaping so that this could be used from inside a 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
    
    0 讨论(0)
  • 2020-11-30 17:40

    My favorite answer to this was posted by Chris Down at Unix & Linux Stack Exchange. I'll quote.

    This is how the bash completion module for make gets its list:

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

    It prints out a newline-delimited list of targets, without paging.

    User Brainstone suggests piping to sort -u to remove duplicate entries:

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

    Source: How to list all targets in make? (Unix&Linux SE)

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

    As mklement0 points out, a feature for listing all Makefile targets is missing from GNU-make, and his answer and others provides ways to do this.

    However, the original post also mentions rake, whose tasks switch does something slightly different than just listing all tasks in the rakefile. Rake will only give you a list of tasks that have associated descriptions. Tasks without descriptions will not be listed. This gives the author the ability to both provide customized help descriptions and also omit help for certain targets.

    If you want to emulate rake's behavior, where you provide descriptions for each target, there is a simple technique for doing this: embed descriptions in comments for each target you want listed.

    You can either put the description next to the target or, as I often do, next to a PHONY specification above the target, like this:

    .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
    

    Which will yield

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

    You can also find a short code example in this gist and here too.

    Again, this does not solve the problem of listing all the targets in a Makefile. For example, if you have a big Makefile that was maybe generated or that someone else wrote, and you want a quick way to list its targets without digging through it, this won't help.

    However, if you are writing a Makefile, and you want a way to generate help text in a consistent, self-documenting way, this technique may be useful.

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