Makefile - prereq-patterns % in $(wildcard) - makefile

I want to add rules of .cc files to a static mode rule. And I try to use $(wildcard ) to enable the prereq-pattern which exists in folder in order to avoid a No rule to make target ... error. But % in $(wildcard ) isn't transformed to the file basename. $(wildcard %.cpp) and $(wildcard %.cc) turn to be nothing.
I want to know how to solve this and make .cc, .cpp in one static mode rule.
# before
# CXX_SOURCE_FILE = $(wildcard *.cpp)
CXX_SOURCE_FILE = $(wildcard *.cpp) $(wildcard *.cc)
C++ = g++
CXX_FLAGS = -g -Wall
c++ : $(basename $(CXX_SOURCE_FILE))
# before
# $(basename $(CXX_SOURCE_FILE)) : % : %.cpp
# $(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CXX_SOURCE_FILE)) : % : $(wildcard %.cpp) $(wildcard %.cc)
$(C++) $< -o $# $(CXX_FLAGS)

You cannot use wildcard like this because it will be evaluated during the parsing, before static pattern rules are considered. Unless you have source files that are literally %.cpp or %.cc your prerequisite list will be empty when the time comes to consider the rules.
A simple solution consists in separating your two sets of source files (CPP_SOURCE_FILE and CC_SOURCE_FILE) and use two different static pattern rules:
CPP_SOURCE_FILE = $(wildcard *.cpp)
CC_SOURCE_FILE = $(wildcard *.cc)
$(basename $(CPP_SOURCE_FILE)): %: %.cpp
$(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CC_SOURCE_FILE)): %: %.cc
$(C++) $< -o $# $(CXX_FLAGS)
There are other solutions but they are more complicated. If you use GNU make you can either use the foreach-eval-call construct or the secondary expansion.
Example with foreach-eval-call:
# $1: executable
define MY_rule
$1: $$(wildcard $1.cpp) $$(wildcard $1.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
endef
$(foreach e,$(basename $(CXX_SOURCE_FILE)),$(eval $(call MY_rule,$e)))
For executable foo this will call MY_rule with parameter foo, pass the result to eval that will expand it and instantiate it as a new rule. $(call MY_rule,foo) expands as:
foo: $$(wildcard foo.cpp) $$(wildcard foo.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
eval expands it as:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
This is exactly what you wanted for this executable. Note the need of $$ to escape the first expansion by eval.
Example with secondary expansion:
.SECONDEXPANSION:
$(basename $(CXX_SOURCE_FILE)): $$(wildcard $$#.cpp) $$(wildcard $$#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
After the first expansion, during the parsing of the Makefile, this becomes:
foo bar baz: $(wildcard $#.cpp) $(wildcard $#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
Note that if you were trying to use this rule in your Makefile, instead of your static pattern rule, this would not work for the very same reason: when the Makefile is parsed and the prerequisites are expanded the automatic variables are not yet set. So, unless you have files named .cpp or .cc your liste of prerequisites would also be empty.
But every rule after .SECONDEXPANSION: has its prerequisites expanded a second time. And the second time, different from the first, the automatic variables are set, including $#. The final result is equivalent to the 3 following rules:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
bar: $(wildcard bar.cpp) $(wildcard bar.cc)
$(C++) $< -o $# $(CXX_FLAGS)
baz: $(wildcard baz.cpp) $(wildcard baz.cc)
$(C++) $< -o $# $(CXX_FLAGS)
From the GNU make manual:
the true power of this feature only becomes apparent when you discover that secondary expansions always take place within the scope of the automatic variables for that target. This means that you can use variables such as $#, $*, etc. during the second expansion and they will have their expected values, just as in the recipe. All you have to do is defer the expansion by escaping the $.
Note: here again the $$ are essential to escape the first expansion.

Related

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:
LIST1 := hello.o world.o
LIST2 := hello.c world.c
# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
cc -c $^ -o $#
# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
cc -c $^ -o $#
Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?
I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.
You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as #MadScientist suggests, that would be best. If not (say the names differ, you can do something like):
LIST1 := hello.o bob.o
hello.o : hello.c
bob.o : sally.c
$(LIST1):
cc -c $< -o $#
Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:
LIST1 := hello.o bob.o
LIST2 := hello.c sally.c
all:
define recursive_def
$(firstword $(1)) : $(firstword $(2))
cc -c $$^ -o $$#
$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef
$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)
$(eval $(call recursive_def,$(LIST1),$(LIST2)))
The short answer is "no". Why don't you just write a pattern rule?
all: $(LIST1)
%.o : %.c
cc -c $^ -o $#
? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.
ETA
If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(SRCS))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<
If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<

Makefile: add prefix to nothing

In Bash, brace expansion just works:
$ echo client_win{,_throttle,_freq}.exe
client_win.exe client_win_throttle.exe client_win_freq.exe
In Makefile:
$(addsuffix .exe,client_win $(addprefix client_win, _throttle _freq )):client_win.c def.h
client_win.exe:
$(CC_W) -o $# $< -lws2_32
client_win_throttle.exe:
$(CC_W_REL) -DTHROTTLE -o $# $< -lws2_32
client_win_freq.exe:
$(CC_W_REL) -DFREQ -o $# $< -lws2_32
Is it possible to have client_win itself absorbed into $(addprefix client_win,...)?
Something like this?
$(addprefix client_win, NOTHING _throttle _freq )
This is not easy because make, unlike the shell, has no concept of "existing but zero length string". Make will expand something and look at the resulting string and if it contains no characters it's as if it didn't exist at all.
You could do something like this:
$(patsubst %,client_%.exe, win win_throttle win_freq)
To remove the "empty" option by adding more to it.
Or you can just write the "empty" one out:
client-win.exe $(patsubst %,client_win_%.exe, throttle freq)

Makefile with two targets and separate build folders

I am trying to use one Makefile with two similar targets and two separate build folders. The only difference between the targets is the addition of a CFLAG define.
Here is a snippet of what I have, however I can't get the build folder to evaluate to something different depending on the target. I used foo and bar to represent the different targets.
...
foo_BUILD_DIR := build_foo/
bar_BUILD_DIR := build_bar/
C_SRCS := main.c
CFLAGS := -std=c99 -Os -Wall
foo_CFLAGS := $(CFLAGS) -DBLE=1
C_OBJS := $(addprefix $(BUILD_DIR),$(subst .c,.o,$(C_SRCS)))
$(BUILD_DIR)%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $^ -o $#
foo:$(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $#
bar:$(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $#
You have three problems to solve here.
The first is building object files in the build directories. First we write a pattern rule to build foo objects:
foo_BUILD_DIR := build_foo # Don't put the trailing slash in the dir name, it's a pain.
CFLAGS := -std=c99 -Os -Wall
foo_CFLAGS := $(CFLAGS) -DBLE=1
$(foo_BUILD_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CC) $(foo_CFLAGS) $^ -o $#
Once that's working perfectly, we write another rule for the bar objects:
$(bar_BUILD_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $^ -o $#
The second problem is tidying up what we've written so far. That foo_CFLAGS variable is now the only thing making these two recipes different, so let's get rid of it with a target-specific variable assignment:
$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1
$(foo_BUILD_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $^ -o $#
Now we can combine the rules into one pattern rule with two targets:
$(foo_BUILD_DIR)/%.o: CFLAGS += -DBLE=1
$(foo_BUILD_DIR)/%.o $(bar_BUILD_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $^ -o $#
The third problem is getting the foo and bar rules to require the right objects. Obviously this rule:
foo:$(OBJS)
...
won't work, we need something specific to foo:
foo: $(addprefix $(foo_BUILD_DIR)/, $(OBJS))
...
This works, but it requires us to write a foo rule that specifies $(foo_BUILD_DIR), a bar rule that specifies $(bar_BUILD_DIR), and so on. Is there a lazier way? All we need is to take the target (e.g. foo) and get it into the prerequisite list. As you know, the automatic variable $# contains the target, but it isn't available in the prerequisite list, because the prerequisite list is expanded before a value is assigned to that variable-- unless we use Secondary Expansion. This is an advanced technique, but it lets us do a second expansion in the later phase (escaping our variables with an extra $ to protect them from the first expansion):
.SECONDEXPANSION:
foo: $(addprefix $$($$#_BUILD_DIR)/, $(OBJS))
...
And once that's working, we can add another target, or as many as we want:
foo bar: $(addprefix $$($$#_BUILD_DIR)/, $(OBJS))
...
There are one or two more refinements possible, but this is enough to start with.

Same rule for different directory in makefile

I am having rule like this.
$(OBJDIR)/%.s: %.c
$(CC) $(PPE-CFLAGS) $(DEFS) -S -o $# $<
i have a list like
dirs := $(OBJDIR) $(COMOBJDIR)
So, instead of writing duplicate code for each dir, can I make them into one? Something like iteration on demand?
You have hit one of the weak spots in Make: its inability to handle multiple wildcards at once. There is a way, but it's ugly.
First take your rule:
$(OBJDIR)/%.s: %.c
$(CC) $(PPE-CFLAGS) $(DEFS) -S -o $# $<
and put it into a variable, escaping the '$' symbols and replacing $(OBJDIR) with $(1):
define myrule
$(1)/%.s: %.c
$$(CC) $$(PPE-CFLAGS) $$(DEFS) -S -o $$# $$<
endef
Then you can call it using call and invoke it using eval:
$(eval $(call myrule, $(OBJDIR))
That's good enough for OBJDIR, but to do the same for a list of directories, use foreach:
$(foreach dir, $(OBJDIR) $(COMOBJDIR), $(eval $(call myrule, $(dir))))
Or just use your variable:
dirs := $(OBJDIR) $(COMOBJDIR)
$(foreach dir, $(dirs), $(eval $(call myrule, $(dir))))
Ugly, but effective.

Pattern rule with different dependencies for different files

In my Makefile I have a pattern rule
%.out: %.in
myscript $< $#
I want this rule to be triggered not only when the files quux.in or foobar.in are modified, but also when any of the files quux/* or foobar/* (respectively) are modified.
How can one express such a dependence in a (GNU) Makefile?
How about this? You could even have a variable like:
DIR_LIST = quux foobar home france china mexico mars
%.out: %.in
myscript $< $#
$(foreach dir,${DIR_LIST},${dir})/%.out: $(foreach dir,${DIR_LIST},${dir})/%.in
myscript $< $#
OR.....
%.out: %.in
myscript $< $#
quux/%.out: quux/%.in
myscript $< $#
foobar/%.out: foobar/%.in
myscript $< $#
I found this solution:
.SECONDEXPANSION:
%.out: %.in $$(call find, $(basename %), *)
my_script $< $#
find = $(foreach dir,$(1),$(foreach d,$(wildcard $(dir)/*),$(call find,$(d),$(2))) $(wildcard $(dir)/$(strip $(2))))
The recursive wildcard find function comes from https://plus.google.com/101663514639216293981/posts/h5Xr1i8kgfu.

Resources