Run make in each subdirectory

MakefileGnu Make

Makefile 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:

  1. How to get a list of directories in Makefile (automatically)?
  2. 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

Source

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)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexView Question on Stackoverflow
Solution 1 - MakefileMadScientistView Answer on Stackoverflow
Solution 2 - MakefileArmandView Answer on Stackoverflow
Solution 3 - MakefileAaron ArthursView Answer on Stackoverflow
Solution 4 - MakefileMateusz CharytoniukView Answer on Stackoverflow
Solution 5 - Makefilerobertm.tumView Answer on Stackoverflow
Solution 6 - MakefilemadmurphyView Answer on Stackoverflow
Solution 7 - MakefileigagisView Answer on Stackoverflow
Solution 8 - MakefilenetskinkView Answer on Stackoverflow
Solution 9 - MakefilesbingnerView Answer on Stackoverflow