Makefile wildcard issue - makefile

I am trying to write a makefile to selectively include a certain file.
I have manage to get it working with the following:
OBJS := $(filter-out ./build/./src/class_1.cpp.o, $(OBJS))
OBJS := $(filter-out ./build/./src/class_2.cpp.o, $(OBJS))
OBJS_1 :=./build/./src/class_1.cpp.o $(OBJS)
OBJS_2 := ./build/./src/class_2.cpp.o $(OBJS)
But I would like to make it more generic and use a wildcard.
My understanding is that the following should work:
OBJS := $(filter-out $(wildcard ./build/./src/*), $(OBJS))
I also tried
OBJS := $(filter-out $(wildcard \./build/\./src/*), $(OBJS))
but not sure if the problem is with the special symbols or just a basic understanding.
however it then complains about having too many main functions (class 1 and class 2).
Is there something that I am missing with my understanding of wildcard and filters in make?
If I print out the value of $(OBJS) with the two different approaches, the values are identical, so I am not sure why one solution could work while the other one fails.
However, for some reason OBJS_1 doesn't seem to get the filter that was applied to $(OBJS)

$(wildcard ...) function finds which files actually exist in the filesystem (and some or all .o files might be created during make's execution, thus the result will be different depending on the last command). This is most certainly not what you want.
In your case you need only to perform the string substitution, and the 'match-all' pattern for strings in make is a percent-sign. So it should be:
OBJS:=$(filter-out ./build/./src/%,$(OBJS))
Also note that spaces in the makefile may have significance. For example, $(filter a, b) means that the second argument is " b", not just "b". Even though it wouldn't matter in your case, you should be more cautious with spaces.

Related

Makefile: order of adding prefix affects how a list of targets is built from a common dependency

Motivation:
I have a C project in which multiple .o files are to be generated from a common file. This main file uses preprocessor directives to conditionally include other .h files as needed, depending on target-specific variables defined in the makefile.
I've written this rule below, but depending on the order in which I apply my variable references I get different outcomes.
One small(ish) change, two different outputs
Consider two versions of code from my Makefile. In version A we have the following snippets:
MAIN_OBJ:= $(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4)
... omitted non-relevant rules (including an all: rule)
$(OBJECT_DIR)/$(MAIN_1): MFLAG = $(METHOD_1_FLAG)
$(OBJECT_DIR)/$(MAIN_2): MFLAG = $(METHOD_2_FLAG)
$(OBJECT_DIR)/$(MAIN_3): MFLAG = $(METHOD_3_FLAG)
$(OBJECT_DIR)/$(MAIN_4): MFLAG = $(METHOD_4_FLAG)
$(OBJECT_DIR)/$(MAIN_OBJ): $(SOURCE_DIR)/$(DEPENDENT_MAIN)
$(CC) -DUSE_$(MFLAG) $(CFLAGS) -o $# $<
This only successfully builds the first target, $(OBJECT_DIR)/$(MAIN_1). The remaining three never get compiled and make stops there.
Now in version B we redefine MAIN_OBJ so that the directory prefix is included within the target list itself:
MAIN_OBJ:= $(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4)
MAIN_OBJ:= $(addprefix $(OBJECT_DIR)/,$(MAIN_OBJ)
... omitted non-relevant rules (again)
$(OBJECT_DIR)/$(MAIN_1): MFLAG = $(METHOD_1_FLAG)
$(OBJECT_DIR)/$(MAIN_2): MFLAG = $(METHOD_2_FLAG)
$(OBJECT_DIR)/$(MAIN_3): MFLAG = $(METHOD_3_FLAG)
$(OBJECT_DIR)/$(MAIN_4): MFLAG = $(METHOD_4_FLAG)
$(MAIN_OBJ): $(SOURCE_DIR)/$(DEPENDENT_MAIN)
$(CC) -DUSE_$(MFLAG) $(CFLAGS) -o $# $<
This solution works, and compiles all 4 .o files, each with the proper $(MFLAG) value.
What's happening here?
This is probably a dumb question, but why does Version A only compile one .o file? I recognize version B is a generally better way to write rules.
Let me provide one more example that will perhaps illustrate my confusion.
Say we want to write a much more common type of rule: compiling targets from a list with a pattern rule for finding dependencies.
Doing something similar to Version A wouldn't result in a single .o being successfully generated:
MY_FILES:= $(wildcard $(SOURCE_DIR)/*.c))
MY_OBJ:= $(patsubst $(SOURCE_DIR)/%.c, %.o, $(MY_FILES))
...
$(OBJECT_DIR)/$(MY_OBJ): $(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
Clearly the above is a bad idea, and you should write something like this instead:
MY_FILES:= $(wildcard $(SOURCE_DIR)/*.c))
MY_OBJ:= $(patsubst $(SOURCE_DIR)/%.c, $(OBJECT_DIR)/%.o, $(MY_FILES))
...
$(MY_OBJ): $(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
But my question is this:
Why in this case does adding the directory prefix in the rule itself result in nothing being built, while in version A of my makefile the first target was successfully made?
"Version A" fails because make is just expanding things like you asked it to. A variable reference like this:
$(OBJECT_DIR)/$(MAIN_OBJ): ...
says "expand the variable OBJECT_DIR, then add a "/", then expand the variable MAIN_OBJ". So you get:
$(OBJECT_DIR)/$(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4): ...
So, only the first one is actually prefixed by the OBJECT_DIR value, not all of them (since you didn't show what the values were for all these variables I didn't complete the expansion).
Secondly, make always builds just the first target that it finds in the makefile (unless you override that with the command line or .DEFAULT). You don't say what the "non-relevant rules" are that you omitted, but unless one of them was an all target or similar that depends on all the MAIN_* targets, make will only build the first one which is the behavior you saw.
ETA Prepending to all words is trivial using various methods; see the GNU make manual.
One option:
$(addprefix $(OBJECT_DIR)/,$(MAIN_OBJ)): ...
Another option:
$(MAIN_OBJ:%=$(OBJECT_DIR)/%): ...
Another option:
$(patsubst %,$(OBJECT_DIR)/%,$(MAIN_OBJ)): ...

How can I write a makefile rule with dependencies that depend on parts of the target?

I want to write a rule that looks something like this:
A_vs_B.txt : A.txt B.txt
but a general rule. The problem is I can't have two %s (as far as I know). I was thinking of just making the target %.txt and then using string functions to parse out the A and B in the dependencies, but that will be fairly complicated. I'm wondering if there's a better way to write a rule like this.
Two choices:
Secondary expansion (your idea of string munging in the dependencies). Something like this (might be better/shorter ways but this is what came to me first).
A_v_B.txt: $$(addsuffix $$(suffix $$(lastword $$(subst _, ,$$#))),$$(firstword $$(subst _, ,$$#)) $$(lastword $$(basename $$(subst _, ,$$#))))
#echo $^
Generated targets/prerequisites. Though how you generate the targets/prerequisites you need depends on where/how the pairs are generated/etc.
H1 := $(REP1)
H2 := $(REP2)
SEP := _vs_
JOIN := $(SEP)
define mktgt
H1 += $R.pr1
H2 += $R.pr2
JOIN += $(SEP)
endef
$(foreach R,$(REP1) $(REP2) $(REP1)$(REP2),$(eval $(mktgt)))
PAIRS := $(join $(join $(H1),$(JOIN)),$(H2))
$(foreach P,$(PAIRS),$(eval $P.txt: $(addsuffix .txt,$(subst _vs_, ,$P))))
# Debugging output
$(foreach P,$(PAIRS),$(info $P.txt: $(addsuffix .txt,$(subst _vs_, ,$P))))
That creates (as you'll see from the debugging output) the target/prerequisite mappings. It doesn't give the targets any recipe. I assume you have a recipe already and that you've assigned it to all the appropriate targets.
If not then adding something like:
$(PAIRS):
#echo 'Use $^ to generate $#'
should work.

generating multiple executables from the same sources

To build multiple executables from the same source, I have to translate every source file with different Compiler Switches. For every variant, I have a set of defines to be set. I want to store the resulting object files into different subfolders. I have a variable, keeping all object file from all variants. Now I have problems to define a proper static rule to build the object files from the sources:
SOURCEEXT=.c
ALL_OBJECT_FILES := abcdefg/cctalkio.o tollcoll/cctalkio.o
source-from-object = $(addsuffix $(SOURCEEXT),$(basename $(notdir $(1))))
$(ALL_OBJECT_FILES): %.o: $(call source-from-object,%.o)
#echo $*.o
when I run make abcdefg/cctalkio.o, I get:
make: *** No rule to make target 'abcdefg/cctalkio.c', needed by 'abcdefg/cctalkio.o'. Schluss.
The same, when I simpify the rule to:
abcdefg/cctalkio.o: %.o: $(call source-from-object,%.o)
#echo $*.o
But when I change the rule to:
abcdefg/cctalkio.o: %.o: $(call source-from-object,abcdefg/cctalkio.o)
#echo $*.o
I get abcdefg/cctalkio.o as Output. So the stem seems to be abcdefg/cctalkio, thus %.o should be the same as abcdefg/cctalkio.o. But why is make behaving different in both cases?
When I "debug" the source-from-object function:
debug:
#echo $(call source-from-object,/abcdefg/cctalkio.o)
I get the expected result cctalkio.c, so it seem like the function is working.
Your $(call) in the prereq is happening immediately and so your function is actually being passed %.o (not the matched result as you expected).
You would have to use something like:
.SECONDEXPANSION:
abcdefg/cctalkio.o: %.o: $$(call source-from-object,%.o)
...
to get what you want I believe.
Alternatively you could probably loop over your object files and statically give them the correct prerequisites and just let the static pattern rule supply the body.

Using multiple % in Makefile

I have to convert a set of file (let's say format fa) into another format (fb) by a command (fa2fb). Each target fb depends only on one fa file.
Data structure is in a format like this:
source:
./DATA/L1/fa/L1.fa
./DATA/L2/fa/L2.fa
...
./DATA/Ln/fa/Ln.fa
target:
./DATA/L1/fb/L1.fb
./DATA/L2/fb/L2.fb
...
./DATA/Ln/fb/Ln.fb
How can I implement it with make?
I have tried this but of course it did not work:
./DATA/%/fb/%.fb : ./DATA/%/fa/%.fb
#fa2fb $< $#
Is there any simple solution without changing the data directories?
Many thanks!
Use secondary expansion and the subst function to create a rule where the prerequisites are constructed as a more complex function of the target name:
.SECONDEXPANSION:
DATA/%.fb: $$(subst fb,fa,$$#)
#fa2fb $< $#
Note that this approach assumes that fb will not occur anywhere else in the filename (which holds true if all of your filenames are of the form DATA/Ln/fb/Ln.fb, for some integer n).
This may be the sloppiest makefile I have ever written.
define template
$(2) : $(1)
echo hi
endef
sources=DATA/L1/fa/L1.fa DATA/L2/fa/L2.fa
$(foreach source,$(sources),$(eval $(call template,$(source),$(subst /fa/,/fb/,$(subst .fa,.fb,$(source))))))
The idea is to define a macro to generate your rules, then use foreach and eval+call to invoke it once for each source. The source is the first argument to the call, so it becomes $(1) in the macro. The second argument is just the transformation from a source file name to a destination file name; it becomes $(2) in the macro.
Replace echo hi with your own rule and you should be good to go. And be sure to write a nice big clear comment or someday someone will surely show up at your door with a baseball bat.
This is basically the same as Nemo's answer. I just tried to make the foreach call a bit more readable, by creating a list of modules, containing simply L1 L2 ... Ln, instead of the list of full source names.
MODULES := $(notdir $(wildcard ./DATA/L*))
define rule
./DATA/$(1)/fb/$(1).fb: ./DATA/$(1)/fa/$(1).fa
#fa2fb $< $#
endef
$(foreach module, $(MODULES), $(eval $(call rule,$(module))))

Sources from subdirectories in Makefile

I have a C++ library built using a Makefile. Until recently, all the sources were in a single directory, and the Makefile did something like this
SOURCES = $(wildcard *.cpp)
which worked fine.
Now I've added some sources that are in a subdirectory, say subdir. I know I can do this
SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)
but I'm looking for a way to avoid specifying subdir manually, that is, make wildcard look into subdirectories, or generating a list of subdirectories somehow and expanding it with several wildcard functions. At this point, having a non-recursive solution (that is, expanding only the first level) would be fine.
I haven't found anything - my best guess is using find -type d to list the subdirectories, but it feels like a hack. Is there any built-in way to do this?
This should do it:
SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp)
If you change you mind and want a recursive solution (i.e. to any depth), it can be done but it involves some of the more powerful Make functions. You know, the ones that allow you to do things you really shouldn't.
EDIT:
Jack Kelly points out that $(wildcard **/*.cpp) works to any depth, at least on some platforms, using GNUMake 3.81. (How he figured that out, I have no idea.)
Recursive wildcards can be done purely in Make, without calling the shell or the find command. Doing the search using only Make means that this solution works on Windows as well, not just *nix.
# Make does not offer a recursive wildcard function, so here's one:
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
# How to recursively find all files with the same name in a given folder
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html)
# How to recursively find all files that match a pattern
ALL_HTMLS := $(call rwildcard,foo/,*.html)
The trailing slash in the folder name is required. This rwildcard function does not support multiple wildcards the way that Make's built-in wildcard function does, but adding that support would be straightforward with a couple more uses of foreach.
If you don't want to use recursive makefiles, this might give you some ideas:
subdirs := $(wildcard */)
sources := $(wildcard $(addsuffix *.cpp,$(subdirs)))
objects := $(patsubst %.cpp,%.o,$(sources))
$(objects) : %.o : %.cpp
You can use several rules in wildcard:
SOURCES := $(wildcard *.cpp */*.cpp)
if you need more depth:
SOURCES := $(wildcard *.cpp */*.cpp */*/*.cpp */*/*/*.cpp)
Unfortunately, and unlike what we sometimes read, glob (**) is not supported by makefile and will be interpreted as normal wildcard (*).
For example **/*.cpp match dir/file.cpp but neither file.cpp nor dir/sub/file.cpp.
If you need infinite depth use shell and find:
SOURCES := $(shell find . -name "*.cpp")
Common practice is to put a Makefile in each subdir with sources, then
all: recursive
$(MAKE) -C componentX
# stuff for current dir
or
all: recursive
cd componentX && $(MAKE)
# stuff for current dir
recursive: true
It may be wise to put settings for each Makefile in a Makefile.inc in the root source directory. The recursive target forces make to go into the subdirectories. Make sure that it doesn't recompile anything in a target requiring recursive.
If you can use find shell command, you may define a function to use it.
recurfind = $(shell find $(1) -name '$(2)')
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \
...

Resources