Run make in each subdirectory
MakefileGnu MakeMakefile Problem Overview
I have a directory (root_dir
), that contains a number of sub-directories (subdir1, subdir2, ...
).
I want to run the make
in each directory in root_dir
, using a Makefile placed in it.
(Obviously supposed that each of subdir...
has inside its own Makefile).
So there are essentially two questions:
- How to get a list of directories in Makefile (automatically)?
- How to run
make
for each of the directories inside a make file?
As I know in order to run make
in a specific directory I need to do the following:
$(MAKE) -C subdir
Makefile Solutions
Solution 1 - Makefile
There are various problems with doing the sub-make inside a for loop in a single recipe. The best way to do multiple subdirectories is like this:
SUBDIRS := $(wildcard */.)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
.PHONY: all $(SUBDIRS)
(Just to point out this is GNU make specific; you didn't mention any restrictions on the version of make you're using).
ETA Here's a version which supports multiple top-level targets.
TOPTARGETS := all clean
SUBDIRS := $(wildcard */.)
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)
Solution 2 - Makefile
Try this :
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
This may help you link
Edit : you can also do :
The simplest way is to do:
CODE_DIR = code
.PHONY: project_code
project_code:
$(MAKE) -C $(CODE_DIR)
The .PHONY rule means that project_code is not a file that needs to be built, and the -C flag indicates a change in directory (equivalent to running cd code before calling make). You can use the same approach for calling other targets in the code Makefile.
For example:
clean:
$(MAKE) -C $(CODE_DIR) clean
Solution 3 - Makefile
This is another approach to MadScientist's answer. .PHONY
is a GNU-specific feature that can be used to force make
into recursing into each subdirectory. However, some non-GNU versions of make
do not support .PHONY
, so an alternative is a force target.
> 4.7 Rules without Recipes or Prerequisites > > If a rule has no prerequisites or recipe, and the target of the rule > is a nonexistent file, then make imagines this target to have been > updated whenever its rule is run. This implies that all targets > depending on this one will always have their recipe run. > > An example will illustrate this:
> clean: FORCE > rm $(objects) > FORCE: > Here the target ‘FORCE’ satisfies the special conditions, so the > target clean that depends on it is forced to run its recipe. There is > nothing special about the name ‘FORCE’, but that is one name commonly > used this way. > > As you can see, using ‘FORCE’ this way has the same results as using > ‘.PHONY: clean’. > > Using ‘.PHONY’ is more explicit and more efficient. However, other > versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many > makefiles. See Phony Targets.
The following is a minimal example that recurses make
into each subdirectory, each of which presumably contains a Makefile
. If you simply run make
, only the first subdirectory, which is non-deterministic, is processed. You may also run make subdir1 subdir2 ...
.
# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Recurse `make` into each subdirectory.
$(SUBDIRS): FORCE
$(MAKE) -C $@
# A target without prerequisites and a recipe, and there is no file named `FORCE`.
# `make` will always run this and any other target that depends on it.
FORCE:
Here is another example with top-level phony targets: all
and clean
. Note that the all
and clean
targets, passed from command-line via $(MAKECMDGOALS)
, are handled by each subdirectory's all
and clean
targets respectively.
# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Top-level phony targets.
all clean: $(SUBDIRS) FORCE
# Similar to:
# .PHONY: all clean
# all clean: $(SUBDIRS)
# GNU's .PHONY target is more efficient in that it explicitly declares non-files.
# Recurse `make` into each subdirectory
# Pass along targets specified at command-line (if any).
$(SUBDIRS): FORCE
$(MAKE) -C $@ $(MAKECMDGOALS)
# Force targets.
FORCE:
Solution 4 - Makefile
You can also define a function in the Makefile (also you of course need an additional makefile in each subdirectory). This is shell-dependent, but can be useful:
define FOREACH
for DIR in packages/*; do \
$(MAKE) -C $$DIR $(1); \
done
endef
.PHONY: build
build:
$(call FOREACH,build)
.PHONY: clean
clean:
$(call FOREACH,clean)
.PHONY: test
test:
$(call FOREACH,test)
Solution 5 - Makefile
Since I was not aware of the MAKECMDGOALS variable and overlooked that MadScientist has its own implementation of multiple top-level targets, I wrote an alternative implementation. Maybe someone find it useful.
SUBDIRS := $(wildcard */.)
define submake
for d in $(SUBDIRS); \
do \
$(MAKE) $(1) --directory=$$d; \
done
endef
all:
$(call submake,$@)
install:
$(call submake,$@)
.PHONY: all install $(SUBDIRS)
Solution 6 - Makefile
Only a small icing on the cake after MadScientist's answer in order to make all the individual targets in the sub-directories available from the top level (you will need to have the SUBDIRS
variable defined in order to use the following snippet – you can use MadScientist's answer for that):
# Make all the individual targets in the sub-directories available from the top
# level; as in, for instance, `make foo/my_program` or `make bar/clean`
$(foreach __dir__,$(SUBDIRS),$(__dir__)/%):
@$(MAKE) -C '$(@D)' '$(@F)'
With the code above you can run, for instance,
make foo/my_program
or
make bar/clean
Furthermore, by pasting the code above you can even use an individual target from a sub-directory as a prerequisite for a target in the top level. For example:
my_target: my_subdirectory/my_prerequisite
'my_subdirectory/my_prerequisite' > 'my_target'
…With the example above, launching make my_target
from the top level will first build the my_subdirectory/my_prerequisite
program, then the latter will be run for building the my_target
file.
Solution 7 - Makefile
There is a library called prorab for GNU make which supports inclusion of standalone makefiles in subdirectories.
Some info on github: https://github.com/cppfw/prorab/blob/master/wiki/HomePage.adoc
Basically, with prorab invoking all makefiles in subdirectories looks like this:
include prorab.mk
$(eval $(prorab-build-subdirs))
Solution 8 - Makefile
In reference to https://stackoverflow.com/posts/17845120/revisions
This is what I learned from that post.
Top Level Makefile
# set the default goal.
# I want the default to really just dump contents of dirs
# as a stub. For instance, I don't want it to
# push code or
.DEFAULT_GOAL := deploy
TOPTARGETS := all clean
SUBDIRS := docs src
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
echo "make arg is" $(MAKECMDGOALS)
$(MAKE) -C $@ $(MAKECMDGOALS)
SUBCLEAN = $(addsuffix .clean,$(SUBDIRS))
clean: $(SUBCLEAN)
$(SUBCLEAN): %.clean:
$(MAKE) -C $* clean
deploy:
echo do deploy stub
The src/
and docs/
common to this Makefile
directory, all have a corresponding Makefile
.
Here is an example of the docs setup:
# set the default goal.
.DEFAULT_GOAL := list_docs
list_docs:
ls -l
clean:
echo "docs: make clean"
-rm "*.backup"
Solution 9 - Makefile
I did this a little different than any of the answers because I didn't want to have to define each possible make target
SUBDIRS := $(patsubst %/,%,$(wildcard */))
.PHONY: all $(MAKECMDGOALS) $(SUBDIRS)
$(MAKECMDGOALS) all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)