Makefile: Generate list with subdirectories - recursion

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.

Related

Zsh glob: Get everything except stuff in a certin folder

Trying to find all files except those inside vendor/ folders, but why is this failing?
setopt extendedglob
for file in **/*~vendor/; do
done
See if this does what you're looking for:
setopt extendedglob
print -l ^vendor/**/*(.)
The *~ negation syntax usually needs parentheses in order to determine where the expression after the tilde ends. Your pattern is requesting all files and folders except those where the glob result name ends with vendor/. The glob result never includes the trailing slash, so you end up with all of the files and folders.
Adding parens will change the behavior of that pattern, but probably not in a useful way. This will result in a list of all of the directories where the last component is not vendor:
print -l **/(*~vendor)/
so x/y, x/y/vendor/z, and vendor/a will be included, but x/y/vendor will not.
The parentheses limit the 'not' pattern to just one piece of the path. In order to exclude matches at the top-level, the tested component needs to be at the front of the pattern:
print -l (*~vendor)/**/*
The very first pattern above uses the ^ syntax to produce the same results. The (.) glob qualifier in that pattern limits the globbing to plain files, so directories are not included.
Another variation that may be useful - this will exclude directories that have any component named vendor. It is similar to find -prune:
print -l (^vendor/)#*(.)
This will produce a list of all files except those in subdirectories with names like vendor/x, a/vendor and a/vendor/b.

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

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

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.

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.

Rsync: Escape include/exclude wildcards

I am running rsync --include-from=my_includes_file --exclude="*" source dest, and building the include file from a big find command (similar to find documents/* -newer ~/.lasttime). However, many of my filenames include the "wildcard" characters used by rsync (*, ?, [, ]), and occasionally I have a problem with the include comment character too (#).
Is there a universal way to escape these? Using \[ seems to fix this one, but I'm not sure if it works for all of them or if I'm just getting lucky
Is there an include prefix to force a "simple string match"?
You are using
--include-from=FILE read include patterns from FILE
While you should use
--files-from=FILE read list of source-file names from FILE

Resources