Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass target name to list of sub-makefiles?

I have a setup like this:

/Makefile
/foo/Makefile
/foo/bar/Makefile
/foo/baz/Makefile

The top-level Makefile contains a task which calls the /foo/Makefile. This Makefiles creates a list of makefiles in the subdirectories (bar, baz in the example). For each subdir, it calls the Makefiles:

$(SUB_DIRS):
    $(MAKE) -C $@

Which is fine for, say, the all task. But if I want to do something else, I get stuck. Is there a possibility to pass the target to the list of sub-makefiles? For example:

$(SUB_DIRS):
    $(MAKE) -C $@ <task>

clean: $(SUB_DIRS)-clean # or something?

Or is my whole concept wrong?

like image 797
musicmatze Avatar asked May 16 '14 17:05

musicmatze


People also ask

What does $@ mean in Makefiles?

The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run. $%

Can makefile target be a directory?

Yes, a Makefile can have a directory as target. However, you shouldn't. When a file is added or removed from a directory, its mtime is updated. This can cause weird behaviour by causing multiple targets depending on a single directory to become implicitly rebuilt by one another.


2 Answers

I finally got it work. The approach is:

SUB_DIRS        = $(wildcard */.)
SUB_DIRS_ALL    = $(SUB_DIRS:%=all-%)
SUB_DIRS_TEST   = $(SUB_DIRS:%=test-%)
SUB_DIRS_CLEAN  = $(SUB_DIRS:%=clean-%)

#
# Standard task
#
all: $(SUB_DIRS_ALL)

test_uml: $(SUB_DIRS_TEST)

clean: $(SUB_DIRS_CLEAN)

$(SUB_DIRS_ALL):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:all-%=%)

$(SUB_DIRS_TEST):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:test-%=%) test

$(SUB_DIRS_CLEAN):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:clean-%=%) clean

I found this solution here: http://lackof.org/taggart/hacking/make-example/

like image 132
musicmatze Avatar answered Sep 19 '22 10:09

musicmatze


You could simply use the MAKECMDGOALS variable:

Make will set the special variable MAKECMDGOALS to the list of goals you specified on the command line. If no goals were given on the command line, this variable is empty.

$(SUB_DIRS):
    +$(MAKE) -C $@ $(MAKECMDGOALS)

The + sign is important so the underlying job server also handles the recursive make calls with the right amount of threads/core.


You can also use the $(foreach ) function like this:

clean:
    $(foreach DIR, $(SUB_DIRS), $(MAKE) -C $(DIR) $@;)

Do note as @musicmatze mentionned in the comments that Make flags (like -j) won't be passed to the sub-make processes correctly here.

like image 38
Chnossos Avatar answered Sep 19 '22 10:09

Chnossos