Run make in each subdirectory

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
97459 次浏览

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

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)

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))

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)

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.

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:

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)

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"


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)