How to trace Makefile targets for troubleshooting?

后端 未结 3 1961
孤街浪徒
孤街浪徒 2020-12-14 08:07

We have a long and complicated Makefile in our build system. Is there a good way to trace exactly which targets get executed for a given make invocation?

3条回答
  •  离开以前
    2020-12-14 08:59

    You can get some information about what targets are being built and why by redefining the SHELL variable in GNU make:

    __ORIGINAL_SHELL:=$(SHELL)
    SHELL=$(warning Building $@$(if $<, (from $<))$(if $?, ($? newer)))$(TIME) $(__ORIGINAL_SHELL)
    

    For example, in trace-targets.mk:

    __ORIGINAL_SHELL:=$(SHELL)
    SHELL=$(warning Building $@$(if $<, (from $<))$(if $?, ($? newer)))$(TIME) $(__ORIGINAL_SHELL)
    
    all: aa.stamp ba.stamp
    
    %.stamp:
        echo stamp > $(@)
    
    stamp-clean:
        rm -vf *.stamp
    
    clean: stamp-clean
    
    .PHONY: %.phony
    %.phony:
        echo $(@)
    
    aa.stamp: ab.stamp
    ab.stamp: ac.stamp
    
    ba.stamp: bb.stamp
    bb.stamp: bc.phony
    

    Running trace-targets.mk after clean:

    $ make -f trace-targets.mk
    trace-targets.mk:9: Building ac.stamp
    echo stamp > ac.stamp
    trace-targets.mk:9: Building ab.stamp (from ac.stamp) (ac.stamp newer)
    echo stamp > ab.stamp
    trace-targets.mk:9: Building aa.stamp (from ab.stamp) (ab.stamp newer)
    echo stamp > aa.stamp
    trace-targets.mk:18: Building bc.phony
    echo bc.phony
    bc.phony
    trace-targets.mk:9: Building bb.stamp (from bc.phony) (bc.phony newer)
    echo stamp > bb.stamp
    trace-targets.mk:9: Building ba.stamp (from bb.stamp) (bb.stamp newer)
    echo stamp > ba.stamp
    

    Then running trace-targets.mk again without cleaning:

    $ make -f trace-targets.mk
    trace-targets.mk:18: Building bc.phony
    echo bc.phony
    bc.phony
    trace-targets.mk:9: Building bb.stamp (from bc.phony) (bc.phony newer)
    echo stamp > bb.stamp
    trace-targets.mk:9: Building ba.stamp (from bb.stamp) (bb.stamp newer)
    echo stamp > ba.stamp
    

    Practically, what I do in my makefiles is I add this snippet:

    ifneq ($(filter all targets,$(VERBOSE)),)
    __ORIGINAL_SHELL:=$(SHELL)
    SHELL=$(warning Building $@$(if $<, (from $<))$(if $?, ($? newer)))$(TIME) $(__ORIGINAL_SHELL)
    endif
    

    Then I run my makefiles as follow to see the tracing:

    make VERBOSE=all
    # or
    make VERBOSE=targets
    

    The reason for the all/targets is because I also have other verbose stuff like this:

    ifneq ($(filter all vars,$(VERBOSE)),)
    dump_var=$(info var $(1)=$($(1)))
    dump_vars=$(foreach var,$(1),$(call dump_var,$(var)))
    else
    dump_var=
    dump_vars=
    endif
    
    # used like
    
    $(call dump_vars,SHELL VERBOSE)
    

    And sometimes I want to selectively enable/disable debugging aspects.

    If you have many makefiles it may make sense to put this in a common file and include it from others.


    Credit by John Graham-Cumming who described this method in Tracing rule execution in GNU Make.

提交回复
热议问题