Jay Taylor's notes
back to listing indexHow do you get the list of targets in a makefile?
[web search]
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 '^$@$$' | xargs
Note: On pasting this, make sure that the last line is indented by exactly 1 tab.
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) -prRn -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null- Invokes
makeagain in order to print and parse the database derived from the makefile:-pprints the database-Rrsuppresses inclusion of built-in rules and variables-qonly 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 containsincludedirectives; to address this, define variableTHIS_FILE := $(lastword $(MAKEFILE_LIST))before anyincludedirectives and use-f $(THIS_FILE)instead.:is a deliberately invalid target that is meant to ensure that no commands are executed;2>/dev/nullsuppresses the resulting error message. Note: This relies on-pprinting 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.
- Invokes
-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
:
- Selectively ignores blocks:
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 thelisttarget itself
xargs- Effectively converts the output lines to a single-line, space-separated list; omit this if you want each target name to appear on its own line.
