Why can't gnu make figure out this sequence of rules? - gnu-make

I have this Makefile:
%: %.x
cp $< $#
build/%: src/%
cp $< $#
And a directory structure that looks like this:
Makefile
build/
src/
hello.x
Why does make behave as follows:
$ make build/hello
make: *** No rule to make target 'build/hello'. Stop.
Why can't it see that
it can translate src/hello.x into src/hello using the first rule, and
copy src/hello into build/hello using the second rule?

According to GNU make manual, that is:
If you do not mark the match-anything rule as terminal, then it is non-terminal. A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.
Your first rule is a non-terminal match-anything rule, so it cannot apply to the target src/hello which indicates a specific type of data. Debug log with make build/hello -d also shows the process:
......
Considering target file `build/hello'.
Looking for an implicit rule for `build/hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `build/hello,v'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `build/RCS/hello,v'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `build/RCS/hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `build/s.hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `build/SCCS/s.hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/hello'.
Looking for a rule with intermediate file `src/hello'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/hello,v'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/RCS/hello,v'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/RCS/hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/s.hello'.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/SCCS/s.hello'.
No implicit rule found for `build/hello'.
Finished prerequisites of target file `build/hello'.
No need to remake target `build/hello'.
make: Nothing to be done for `build/hello'.
You should mark your first rule the match-anything rule as terminal by defining it with a double colon.
When a rule is terminal, it does not apply unless its prerequisites actually exist. Prerequisites that could be made with other implicit rules are not good enough. In other words, no further chaining is allowed beyond a terminal rule.
Change your makefile to:
%:: %.x
cp $< $#
build/%: src/%
cp $< $#
Test with make build/hello:
cp src/hello.x src/hello
cp src/hello build/hello
rm src/hello
The debug log below shows how it works:
......
Looking for a rule with intermediate file `src/hello'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `hello'.
Trying implicit prerequisite `src/hello.x'.
Found an implicit rule for `build/hello'.
Considering target file `src/hello.x'.
Finished prerequisites of target file `src/hello.x'.
No need to remake target `src/hello.x'.
Considering target file `src/hello'.
File `src/hello' does not exist.
Pruning file `src/hello.x'.
Finished prerequisites of target file `src/hello'.
Must remake target `src/hello'.
cp src/hello.x src/hello
Putting child 0x08a51438 (src/hello) PID 30908 on the chain.
Live child 0x08a51438 (src/hello) PID 30908
Reaping winning child 0x08a51438 PID 30908
Removing child 0x08a51438 PID 30908 from chain.
Successfully remade target file `src/hello'.
Finished prerequisites of target file `build/hello'.
Must remake target `build/hello'.
cp src/hello build/hello
Putting child 0x08a51438 (build/hello) PID 30909 on the chain.
Live child 0x08a51438 (build/hello) PID 30909
Reaping winning child 0x08a51438 PID 30909
Removing child 0x08a51438 PID 30909 from chain.
Successfully remade target file `build/hello'.
Removing intermediate files...
rm src/hello

Related

Can I persuade Make to give me a better error message when prerequisites are given through a variable with secondary expansion?

Observe:
OBJECT_FILES=
.PHONY: all
all: project.exe
.SECONDEXPANSION:
%.exe:: $$(OBJECT_FILES);
project.exe: OBJECT_FILES += module.o
Assume module.o doesn't exist on disk (because I forgot to create it, or whatever).
Debate about why I don't just use project.exe: module.o aside (this is an MCVE! I do more things with $OBJECT_FILES elsewhere, in reality) how can I get a better diagnostic?
$ make all
make: *** No rule to make target `project.exe', needed by `all'. Stop.
I'd prefer:
$ make all
make: *** No rule to make target `module.o', needed by `project.exe'. Stop.
Can Make be co-erced to do this without fundamentally changing my design?
Or, at least, why is it doing this?
$ make -v | head -n 2
GNU Make 3.82
Built for x86_64-redhat-linux-gnu
The message make would have to display could become rather complicated. The reason for that is because of the implicit pattern rule, make is actually trying one after the other every rule whose target match project.exe and there could be an indefinite number. Consider for example the following:
OBJECT_FILES=
.PHONY: all
all: project.exe
.SECONDEXPANSION:
%.exe:: $$(OBJECT_FILES);
%.exe:: does-not-exist-on-unix;
%.exe:: does-not-exist-on-amiga;
%.exe:: does-not-exist-except-perhaps-by-redmond;
project.exe: OBJECT_FILES += does-not-exist
Using make with the -dr options, this is what we get:
Considering target file 'project.exe'.
File 'project.exe' does not exist.
Looking for an implicit rule for 'project.exe'.
Trying pattern rule with stem 'project'.
Trying implicit prerequisite 'does-not-exist'.
Trying pattern rule with stem 'project'.
Trying rule prerequisite 'does-not-exist-on-unix'.
Trying pattern rule with stem 'project'.
Trying rule prerequisite 'does-not-exist-on-amiga'.
Trying pattern rule with stem 'project'.
Trying rule prerequisite 'does-not-exist-except-perhaps-by-redmond'.
No implicit rule found for 'project.exe'.
The line Trying implicit prerequisite 'does-not-exist' is the "best" way make tells you the prerequisite of the first pattern rule (the one with the secondary expansion of OBJECT_FILES) was attempted.
Also, if any of rules has its prerequisites found, then you won't get any error message: make simply allows implicit pattern rules to fail "silently", and it's actually happening a lot if you don't disable built-in rules. For example, built-in rules can produce an object file (.o target) out of several types of source files, like .cpp (C++), .c (C), .p (Pascal), .f (Fortran)... So depending on which source file is actually there, the right rule will be picked up, and the other rules will be silently "dropped". If you've got both a .c and a .cpp file, I don't know what happens!
If you can rewrite your makefile so that you don't have a pattern rule anymore, e.g. like this:
OBJECT_FILES=
EXE_FILES := project.exe project2.exe
.PHONY: all
all: $(EXE_FILES)
.SECONDEXPANSION:
$(EXE_FILES):: $$(OBJECT_FILES);
project.exe: OBJECT_FILES += does-not-exist
project2.exe: OBJECT_FILES += does-not-exist-either
Then make will output the messages you want (albeit not in the expected order):
$ make -k all
make: *** No rule to make target 'does-not-exist-either', needed by 'project2.exe'.
make: Target 'project2.exe' not remade because of errors.
make: *** No rule to make target 'does-not-exist', needed by 'project.exe'.
make: Target 'all' not remade because of errors.

writing a recursive make recipe with prerequisite on parent directory

I am trying to write a recursive make recipe. In this recipe, each target is dependent on a file with an equal name on the parent directory. A minimal (non-working) example:
foo/.dirstamp:
mkdir $(dir $#)
touch $#
.SECONDEXPANSION:
%/.dirstamp: $$(dir $$*).dirstamp
mkdir $(dir $#)
touch $#
With this example, I would expect make foo/bar/qux/lol/.dirstamp to generate the whole directory tree (if it does not exist), touching all .dirstamp files along the way. However, it does not work:
$ ls # note that there is nothing, make is meant to create the dir tree
Makefile
$ make --debug=v foo/bar/qux/lol/.dirstamp
GNU Make 4.0
[...]
Reading makefiles...
Reading makefile 'Makefile'...
Updating goal targets....
Considering target file 'foo/bar/qux/lol/.dirstamp'.
File 'foo/bar/qux/lol/.dirstamp' does not exist.
Finished prerequisites of target file 'foo/bar/qux/lol/.dirstamp'.
Must remake target 'foo/bar/qux/lol/.dirstamp'.
make: *** No rule to make target 'foo/bar/qux/lol/.dirstamp'. Stop.
It works fine as long as the recursive recipe only needs to be expanded twice, e.g., make foo/bar/.dirstamp works fine.
How can this work for an arbitrary number of levels? How can I handle a recursive expansion for the target and prerequisites names?
Note: my real problem is that the prerequisites of my recipes are in a root
directory different from the target so I am using the recipe above to duplicate the directory tree. I know about mkdir -p which seems to work fine in GNU systems. I am still interested on knowing how I would solve the recursion problem for arbitrary levels. which no longer works because part of the team is using Mac and mounting this directories over smb.
More details on the actual problem: prerequisites are in data/x/y/z while targets go into results/x/y/z. However, the results directory tree does not exist and needs to be created as needed. To solve this, I made the creation of parent directories an order-only prerequisite (via the .dirstamp files on my minimal example above).
can't copy data into results, that's several TB of data;
can't have the targets created in data, that's read-only;
can't use mkdir -p because the results directory will not be local, mounted over smb, and others may use non-GNU systems;
After an hint from #EtanReisner on the question:
make won't apply a rule more than once. That's a built-in (intentional) limitation. Without working around that with manual recursion or manually building the set of targets and using a static pattern rule (which may or may not actually work I'm not sure) there's not much you can do about this.
I worked up this solution:
RESULT_DIRS := $(patsubst data/%, results/%, $(shell find data/* -type d -print))
DIRSTAMPS := $(addsuffix /.dirstamp, $(RESULT_DIRS))
results/.dirstamp:
mkdir $(dir $#)
touch $#
.SECONDEXPANSION:
$(DIRSTAMPS): $$(dir $$(patsubst %/.dirstamp, %, $$#)).dirstamp
mkdir $(dir $#)
touch $#
It will duplicate the data directory tree in results as the dirstamp files are required. They are required by making them prerequisites of the other recipes (note the | which makes them order-only prerequisites):
results/%/foo.analysis: data/%/foo.data | results/%/.dirstamp
$(SOME_ANALYSIS_PROGRAM) $^ > $#

How to write a makefile executing make one directory level up

Can I write a wrapper makefile that will cd one level up and execute there make with all the command options I have given the wrapper?
In more detail:
Directory project contains a real Makefile with some different targets.
Directory project/resources contains the wrapper Makefile which should call Makefile in project.
When I am in my shell in directory project/resources, I execute
make TARGET
and the Makefile there just cds one directory up and calls
make TARGET
in the directory project.
Is this possible? And how?
You could use a very simple Makefile for all your sub-directories:
%:
$(MAKE) -C .. $#
% is a last resort match-anything pattern rule that will match any target... for which there is no implicit rule (GNU make has an incredibly large number of implicit rules). So, if none of your targets are covered by an implicit rule, this should work. Else you will have to tell make not to use the implicit rules it knows. This can be done (with GNU make) by calling make with the -r option:
cd project/resources
make -r <anything>
will call make in project for target <anything>. The main drawback is that the -r flag is passed to the sub-make and so the implicit rules will not apply neither in project, which can be a problem. If it is you can obtain the same effect by adding an empty .SUFFIXES target to theMakefile in project/resources:
.SUFFIXES:
%:
$(MAKE) -C .. $#
With my version of GNU make (3.82) it works like a charm and the sub-make has all the default implicit rules.
Yes, you can have a makefile which works for "any" target.
The GNU make manual discusses this in the Overriding Part of Another Makefile section:
Sometimes it is useful to have a makefile that is mostly just like another makefile. You can often use the ‘include’ directive to include one in the other, and add more targets or variable definitions. However, it is invalid for two makefiles to give different recipes for the same target. But there is another way.
In the containing makefile (the one that wants to include the other), you can use a match-anything pattern rule to say that to remake any target that cannot be made from the information in the containing makefile, make should look in another makefile. See Pattern Rules, for more information on pattern rules.
For example, if you have a makefile called Makefile that says how to make the target ‘foo’ (and other targets), you can write a makefile called GNUmakefile that contains:
foo:
frobnicate > foo
%: force
#$(MAKE) -f Makefile $#
force: ;
If you say ‘make foo’, make will find GNUmakefile, read it, and see that to make foo, it needs to run the recipe ‘frobnicate > foo’. If you say ‘make bar’, make will find no way to make bar in GNUmakefile, so it will use the recipe from the pattern rule: ‘make -f Makefile bar’. If Makefile provides a rule for updating bar, make will apply the rule. And likewise for any other target that GNUmakefile does not say how to make.
The way this works is that the pattern rule has a pattern of just ‘%’, so it matches any target whatever. The rule specifies a prerequisite force, to guarantee that the recipe will be run even if the target file already exists. We give the force target an empty recipe to prevent make from searching for an implicit rule to build it—otherwise it would apply the same match-anything rule to force itself and create a prerequisite loop!
One option: use a wrapper file to execute the commands to do that. Just be sure your target make files don't include the child directory that has the wrapper, or else you can create an endless loop. For example,
clean:
pushd .. && make clean && popd
Using the comment of user Renaud Pacalet and the answer to a different question the following one-liner is as close as I could get. The whole Makefile reads:
IGNORE := $(shell $(MAKE) -C .. $(MAKECMDGOALS))
This solutions comes with a few caveats:
Command line option -B does not get passed through to the subsequent make call.
The output of the subsequently called make process (in the project directory) is not printed to stdout.
The wrapper make process reports for any given target at the end :
make: *** No rule to make target TARGET. Stop.

Makefile: Generate list with subdirectories

Let's suppose I have this directory structure:
-src
|
|-- subdir1
|
|
|-- subdir2
| |
| |-- subdir3
I want to generate automatically a variable that finds the name of each subdir.
So something like:
BASE_DIR = src
# magic_recursive_wildcard_here := ...
DIRS = $(call magic_recursive_wildcard_here)
all:
#echo dirs: $(DIRS)
And I want the output from all to be:
dirs: src subdir1 subdir2 subdir3
Is there any way to do that?
EDIT: If possible, I need a solution that works on both windows and Unix.
EDIT 27/4/2015: I tried Chnossos's answer and the output is this:
[21:59:27] ~\Desktop\makefileproj\src> make -d
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-pc-mingw32
Reading makefiles...
Reading makefile `makefile'...
CreateProcess(NULL,CHDIR,...)
process_begin: CreateProcess(NULL, CHDIR, ...) failed.
CreateProcess(F:\Programs\CmdTools\coreutils\bin\DIR.exe,DIR /A:D /B /S .,...)
DIR: /A\:D: No such file or directory
DIR: /B: No such file or directory
DIR: /S: No such file or directory
Main thread handle = 0x000000e0
.: dira dirb Makefile
Updating makefiles....
Considering target file `makefile'.
Looking for an implicit rule for `makefile'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.o'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.c'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cc'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cpp'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.p'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.f'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.r'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.s'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.mod'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.sh'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile,v'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `RCS/makefile,v'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `RCS/makefile'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `s.makefile'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `SCCS/s.makefile'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.o'.
Looking for a rule with intermediate file `makefile.o'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.c'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cc'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cpp'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.p'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.f'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.r'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.s'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.mod'.
Trying pattern rule with stem `makefile.o'.
Trying implicit prerequisite `makefile.o,v'.
Trying pattern rule with stem `makefile.o'.
Trying implicit prerequisite `RCS/makefile.o,v'.
Trying pattern rule with stem `makefile.o'.
Trying implicit prerequisite `RCS/makefile.o'.
Trying pattern rule with stem `makefile.o'.
Trying implicit prerequisite `s.makefile.o'.
Trying pattern rule with stem `makefile.o'.
Trying implicit prerequisite `SCCS/s.makefile.o'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.c'.
Looking for a rule with intermediate file `makefile.c'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.y'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.l'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.w'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.w'.
Trying pattern rule with stem `makefile.c'.
Trying implicit prerequisite `makefile.c,v'.
Trying pattern rule with stem `makefile.c'.
Trying implicit prerequisite `RCS/makefile.c,v'.
Trying pattern rule with stem `makefile.c'.
Trying implicit prerequisite `RCS/makefile.c'.
Trying pattern rule with stem `makefile.c'.
Trying implicit prerequisite `s.makefile.c'.
Trying pattern rule with stem `makefile.c'.
Trying implicit prerequisite `SCCS/s.makefile.c'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.y'.
Looking for a rule with intermediate file `makefile.y'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.y'.
Trying implicit prerequisite `makefile.y,v'.
Trying pattern rule with stem `makefile.y'.
Trying implicit prerequisite `RCS/makefile.y,v'.
Trying pattern rule with stem `makefile.y'.
Trying implicit prerequisite `RCS/makefile.y'.
Trying pattern rule with stem `makefile.y'.
Trying implicit prerequisite `s.makefile.y'.
Trying pattern rule with stem `makefile.y'.
Trying implicit prerequisite `SCCS/s.makefile.y'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.l'.
Looking for a rule with intermediate file `makefile.l'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.l'.
Trying implicit prerequisite `makefile.l,v'.
Trying pattern rule with stem `makefile.l'.
Trying implicit prerequisite `RCS/makefile.l,v'.
Trying pattern rule with stem `makefile.l'.
Trying implicit prerequisite `RCS/makefile.l'.
Trying pattern rule with stem `makefile.l'.
Trying implicit prerequisite `s.makefile.l'.
Trying pattern rule with stem `makefile.l'.
Trying implicit prerequisite `SCCS/s.makefile.l'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.w'.
Looking for a rule with intermediate file `makefile.w'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.w'.
Trying implicit prerequisite `makefile.w,v'.
Trying pattern rule with stem `makefile.w'.
Trying implicit prerequisite `RCS/makefile.w,v'.
Trying pattern rule with stem `makefile.w'.
Trying implicit prerequisite `RCS/makefile.w'.
Trying pattern rule with stem `makefile.w'.
Trying implicit prerequisite `s.makefile.w'.
Trying pattern rule with stem `makefile.w'.
Trying implicit prerequisite `SCCS/s.makefile.w'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.w'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cc'.
Looking for a rule with intermediate file `makefile.cc'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.cc'.
Trying implicit prerequisite `makefile.cc,v'.
Trying pattern rule with stem `makefile.cc'.
Trying implicit prerequisite `RCS/makefile.cc,v'.
Trying pattern rule with stem `makefile.cc'.
Trying implicit prerequisite `RCS/makefile.cc'.
Trying pattern rule with stem `makefile.cc'.
Trying implicit prerequisite `s.makefile.cc'.
Trying pattern rule with stem `makefile.cc'.
Trying implicit prerequisite `SCCS/s.makefile.cc'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.cpp'.
Looking for a rule with intermediate file `makefile.cpp'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.cpp'.
Trying implicit prerequisite `makefile.cpp,v'.
Trying pattern rule with stem `makefile.cpp'.
Trying implicit prerequisite `RCS/makefile.cpp,v'.
Trying pattern rule with stem `makefile.cpp'.
Trying implicit prerequisite `RCS/makefile.cpp'.
Trying pattern rule with stem `makefile.cpp'.
Trying implicit prerequisite `s.makefile.cpp'.
Trying pattern rule with stem `makefile.cpp'.
Trying implicit prerequisite `SCCS/s.makefile.cpp'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.p'.
Looking for a rule with intermediate file `makefile.p'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.web'.
Trying pattern rule with stem `makefile.p'.
Trying implicit prerequisite `makefile.p,v'.
Trying pattern rule with stem `makefile.p'.
Trying implicit prerequisite `RCS/makefile.p,v'.
Trying pattern rule with stem `makefile.p'.
Trying implicit prerequisite `RCS/makefile.p'.
Trying pattern rule with stem `makefile.p'.
Trying implicit prerequisite `s.makefile.p'.
Trying pattern rule with stem `makefile.p'.
Trying implicit prerequisite `SCCS/s.makefile.p'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.web'.
Looking for a rule with intermediate file `makefile.web'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.web'.
Trying implicit prerequisite `makefile.web,v'.
Trying pattern rule with stem `makefile.web'.
Trying implicit prerequisite `RCS/makefile.web,v'.
Trying pattern rule with stem `makefile.web'.
Trying implicit prerequisite `RCS/makefile.web'.
Trying pattern rule with stem `makefile.web'.
Trying implicit prerequisite `s.makefile.web'.
Trying pattern rule with stem `makefile.web'.
Trying implicit prerequisite `SCCS/s.makefile.web'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.f'.
Looking for a rule with intermediate file `makefile.f'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.r'.
Trying pattern rule with stem `makefile.f'.
Trying implicit prerequisite `makefile.f,v'.
Trying pattern rule with stem `makefile.f'.
Trying implicit prerequisite `RCS/makefile.f,v'.
Trying pattern rule with stem `makefile.f'.
Trying implicit prerequisite `RCS/makefile.f'.
Trying pattern rule with stem `makefile.f'.
Trying implicit prerequisite `s.makefile.f'.
Trying pattern rule with stem `makefile.f'.
Trying implicit prerequisite `SCCS/s.makefile.f'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.r'.
Looking for a rule with intermediate file `makefile.r'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.l'.
Trying pattern rule with stem `makefile.r'.
Trying implicit prerequisite `makefile.r,v'.
Trying pattern rule with stem `makefile.r'.
Trying implicit prerequisite `RCS/makefile.r,v'.
Trying pattern rule with stem `makefile.r'.
Trying implicit prerequisite `RCS/makefile.r'.
Trying pattern rule with stem `makefile.r'.
Trying implicit prerequisite `s.makefile.r'.
Trying pattern rule with stem `makefile.r'.
Trying implicit prerequisite `SCCS/s.makefile.r'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.r'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.s'.
Looking for a rule with intermediate file `makefile.s'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.s'.
Trying implicit prerequisite `makefile.s,v'.
Trying pattern rule with stem `makefile.s'.
Trying implicit prerequisite `RCS/makefile.s,v'.
Trying pattern rule with stem `makefile.s'.
Trying implicit prerequisite `RCS/makefile.s'.
Trying pattern rule with stem `makefile.s'.
Trying implicit prerequisite `s.makefile.s'.
Trying pattern rule with stem `makefile.s'.
Trying implicit prerequisite `SCCS/s.makefile.s'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.mod'.
Looking for a rule with intermediate file `makefile.mod'.
Avoiding implicit rule recursion.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.mod'.
Trying implicit prerequisite `makefile.mod,v'.
Trying pattern rule with stem `makefile.mod'.
Trying implicit prerequisite `RCS/makefile.mod,v'.
Trying pattern rule with stem `makefile.mod'.
Trying implicit prerequisite `RCS/makefile.mod'.
Trying pattern rule with stem `makefile.mod'.
Trying implicit prerequisite `s.makefile.mod'.
Trying pattern rule with stem `makefile.mod'.
Trying implicit prerequisite `SCCS/s.makefile.mod'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.c'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.cc'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.cpp'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.p'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.f'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.r'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.s'.
Trying pattern rule with stem `makefile'.
Rejecting impossible implicit prerequisite `makefile.mod'.
Trying pattern rule with stem `makefile'.
Trying implicit prerequisite `makefile.sh'.
Looking for a rule with intermediate file `makefile.sh'.
Avoiding implicit rule recursion.
Trying pattern rule with stem `makefile.sh'.
Trying implicit prerequisite `makefile.sh,v'.
Trying pattern rule with stem `makefile.sh'.
Trying implicit prerequisite `RCS/makefile.sh,v'.
Trying pattern rule with stem `makefile.sh'.
Trying implicit prerequisite `RCS/makefile.sh'.
Trying pattern rule with stem `makefile.sh'.
Trying implicit prerequisite `s.makefile.sh'.
Trying pattern rule with stem `makefile.sh'.
Trying implicit prerequisite `SCCS/s.makefile.sh'.
No implicit rule found for `makefile'.
Finished prerequisites of target file `makefile'.
No need to remake target `makefile'.
Updating goal targets....
Considering target file `all'.
File `all' does not exist.
Finished prerequisites of target file `all'.
Must remake target `all'.
Successfully remade target file `all'.
make: Nothing to be done for `all'.
Considering your edit, you basically have 2 solutions :
Use a linux shell under Windows and use $(shell find $(BASE_DIR) -type d).
Use a condition on the OS you're running on :
BASE_DIR := .
ifeq ($(OS),Windows_NT)
DIRS := $(patsubst $(shell CHDIR )\\%,%,$(shell DIR /A:D /B /S $(BASE_DIR)))
else
DIRS := $(shell find $(BASE_DIR) -type d)
endif
$(info $(DIRS)) # print the variable
.PHONY: all
all:
Note that the space after CHDIR in $(shell CHDIR ) is mandatory.
John Graham-Cunning wrote this neat recursive wildcard function for make:
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)
$(filter $(subst *,%,$2),$d))
But I don't think that can do files vs. directories.
The only other solution I have is to shell out to find for this.
dirs := $(shell find '$(BASE_DIR)' -type d)
As Marc Fraioli points out if you want just the bare directory names in the variable then you want:
dirs := $(notdir $(shell find '$(BASE_DIR)' -type d))
For Windows this might work. I tested the dir command but not how make handles it.
dirs := $(notdir $(shell dir /s /b /ad $(BASE_DIR)))
How you determine which platform you are on to control which you use is a different question but there are a number of ways to do that.
Yes, try this:
BASE_DIR = src
DIRS = $(shell find $(BASE_DIR) -type d -exec basename {} \;)
all:
#echo dirs: $(DIRS)
running:
$ ls -lR src
src:
total 8
drwxrwxr-x. 2 mfraioli mfraioli 4096 Apr 24 07:41 subdir1
drwxrwxr-x. 3 mfraioli mfraioli 4096 Apr 24 07:41 subdir2
src/subdir1:
total 0
src/subdir2:
total 4
drwxrwxr-x. 2 mfraioli mfraioli 4096 Apr 24 07:41 subdir3
src/subdir2/subdir3:
total 0
$ make
dirs: src subdir1 subdir2 subdir3
This is an old entry but thought I'd add my two-cents to it.
The way I did it in my personal projects is as follows for both Linux and Windows compiles:
ifeq ($(OS), Windows_NT)
DIRS := $(shell powershell 'Get-ChildItem -Path $(SRC_DIR) -Directory -Recurse | Resolve-Path -Relative')
else
DIRS := $(shell find $(SRC_DIR)/* -type d)
endif
^^^ Note: The reason I did $(SRC_DIR)/* instead of just $(SRC_DIR) for the find command is to avoid having src/ show up in the list since I usually only keep main.cpp there and all my other code in sub-directories.

Passing rules to make recursively

It's probably trivial to do this but I can't see how.
I want to have a parent Makefile to decide which Makefile to call recursively based on the value of a variable passed in the command line.
I.e., I want to be able to call my main Makefile with:
make some_rule TARGET=a
or
make some_rule TARGET=b
and have my main Makefile decide based on the value of TARGET which makefile to invoke to run make some_rule. (For example, decide whether to call sub_directory_a/Makefile or sub_directory_b/Makefile to execute rule some_rule.)
Note: I have many different rules, so I do not want my main Makefile to list all the possible rules and for each of them call recursively the correct Makefile. I am hoping my main Makefile can only be a few lines long and not have to be updated whenever I create new rules.
You could do what you describe with
default_target:
%:
$(MAKE) -C some_directory_$(TARGET) $#
The %: rule is a pattern rule in which the pattern matches all rules (called a match-anything rule by the GNU make manual); $# is the current target. Note that the default_target: rule doesn't have a recipe, so calling make without a target will use the recipe of the match-anything rule (the only one that applies and has a recipe) to try to build default_target.
The caveat of this approach is that targets cannot be declared phony. If you want to have phony targets, you'll have to specify the recipe for those targets again, for example
PHONY_TARGETS = all clean distclean
.PHONY: $(PHONY_TARGETS)
$(PHONY_TARGETS):
$(MAKE) -C some_directory_$(TARGET) $#
%:
$(MAKE) -C some_directory_$(TARGET) $#
Unfortunately, I do not know a trick to declare all targets phony, which is what you'd really want to do.
Note that you can use ifeq etc. with the variables you set at the command line if you want to allow more fancy values for TARGET than parts of directory names, such as
%:
ifeq ($(TARGET),gibson)
echo 'Planet $# was successfully hacked.'
else
$(MAKE) -C some_directory_$(TARGET) $#
endif
Also note that a more common way to set common variables for many Makefiles is to put them into a file, often common.mk, and include it from the other Makefiles:
include ../common.mk # to include common.mk from some_directory_a/Makefile
But you'll have to decide yourself which approach is a better fit for your project.

Resources