How to trace Makefile targets for troubleshooting?

2020-02-08 07:19发布

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条回答
我只想做你的唯一
2楼-- · 2020-02-08 08:07

Use make -d or make --debug[=flags] options:

‘-d’

Print debugging information in addition to normal processing. The debugging information says which files are being considered for remaking, which file-times are being compared and with what results, which files actually need to be remade, which implicit rules are considered and which are applied—everything interesting about how make decides what to do. The -d option is equivalent to ‘--debug=a’ (see below).

‘--debug[=options]’

Print debugging information in addition to normal processing. Various levels and types of output can be chosen. With no arguments, print the “basic” level of debugging. Possible arguments are below; only the first character is considered, and values must be comma- or space-separated.

a (all) All types of debugging output are enabled. This is equivalent to using ‘-d’.

b (basic) Basic debugging prints each target that was found to be out-of-date, and whether the build was successful or not.

v (verbose) A level above ‘basic’; includes messages about which makefiles were parsed, prerequisites that did not need to be rebuilt, etc. This option also enables ‘basic’ messages.

i (implicit) Prints messages describing the implicit rule searches for each target. This option also enables ‘basic’ messages.

j (jobs) Prints messages giving details on the invocation of specific subcommands.

m (makefile) By default, the above messages are not enabled while trying to remake the makefiles. This option enables messages while rebuilding makefiles, too. Note that the ‘all’ option does enable this option. This option also enables ‘basic’ messages.

Another option is to use remake - a patched version of GNU Make that adds improved error reporting, the ability to trace execution, and a debugger.

查看更多
小情绪 Triste *
3楼-- · 2020-02-08 08:14

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

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

查看更多
Deceive 欺骗
4楼-- · 2020-02-08 08:24

ElectricMake can generate an XML-marked-up version of your build log with lots of information that would help in this situation:

  • The full command-lines for all commands invoked during the build (even those that were marked as "silent" commands with the @ modifier).
  • The origin (makefile and line number) of the commands invoked.
  • Runtime of the commands.
  • Dependency relationships between the targets in the build.
  • Structural relationship between targets and recursive makes in the build.
  • Files read/written by the commands invoked in the build.

Here's a sample of that output:

<job id="J0824ab08" thread="5e72bb0" node="linbuild1-2" type="rule" name="../../i686_Linux/testmain/testmain.d" file="../config/rules.mak" line="109">
<command line="110">
<argv>echo Rebuilding '../../i686_Linux/testmain/testmain.d'</argv>
<output src="prog">Rebuilding ../../i686_Linux/testmain/testmain.d
</output>
</command>
<command line="111-114">
<argv>set -e; g++ -MM -w  -DUSE_PROFILING -DUSE_LOGGING -DHAVE_UNIX -DHAVE_LINUX -I.. testmain.cpp \
        | sed 's!\(testmain\)\.o[ :]*!../../i686_Linux/testmain/\1.o '../../i686_Linux/testmain/testmain.d' : !g' \
        &gt; '../../i686_Linux/testmain/testmain.d'; \
        [ -s '../../i686_Linux/testmain/testmain.d' ] || touch '../../i686_Linux/testmain/testmain.d'</argv>
</command>
<opList>
<op type="read" file="/home/ericm/src/testmain/testmain.cpp"/>
<op type="read" file="/home/ericm/src/minidumper/ExceptionReport.h"/>
<op type="read" file="/home/ericm/src/util/ECAssert.h"/>
<op type="create" file="/home/ericm/i686_Linux/ecloud/testmain/testmain.d" found="0"/>
</opList>
<timing invoked="1.919926" completed="3.600491" node="linbuild1-2"/>
<waitingJobs idList="J0824ae38"/>
</job>

How to Quickly Navigate an Unfamiliar Makefile shows an example of using the annotated build log to find your way around a makefile.

Data Mining ElectricAccelerator Annotation shows how you can use the annotated build log to generate a bill-of-materials for the build.

ElectricMake is GNU Make compatible, so it can process makefiles that work with GNU make.

Disclaimer: I'm the architect and lead developer of ElectricAccelerator.

查看更多
登录 后发表回答