By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe.
Yes, a Makefile can have a directory as target. Your problem could be that the cd doesn't do what you want: it does cd and the git clone is carried out in the original directory (the one you cd ed from, not the one you cd ed to). This is because for every command in the Makefile an extra shell is created.
A rule appears in the makefile and says when and how to remake certain files, called the rule's targets (most often only one per rule). It lists the other files that are the prerequisites of the target, and the recipe to use to create or update the target.
Under Bash (at least), this can be done automatically with tab completion:
make
spacetabtab
This is an attempt to improve on Brent Bradburn's great approach as follows:
sh -c
)-f <file>
@
to prevent it from being echoed before executionCuriously, GNU make
has no feature for listing just the names of targets defined in a makefile. While the -p
option produces output that includes all targets, it buries them in a lot of other information and also executes the default target (which could be suppressed with -f/dev/null
).
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:
@LC_ALL=C $(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
LC_ALL=C
makes sure that make
's output in in English, as parsing of the output relies on that.Tip of the hat to Bastian Bittorf
$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null
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 ...
.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=
/^# File/,/^# Finished Make data base/
if ($$1 !~ "^[#.]")
#
... ignores non-targets, whose blocks start with # Not a target:
.
... ignores special targets:
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 itselfRunning make list
then prints all targets, each on its own line; you can pipe to xargs
to create a space-separated list instead.
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
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
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With