From what I've been able to find, the wildcard symbol in a Makefile target : prerequisite line is a pattern rule that states "for every target X.o, if there exists a file named X.c (for example), do the following commands"
What I can't seem to figure out is why, in the Makefile below only one of the wildcard arguments is executed.
all : foo.o
%.o : %.c
echo first %.o : %.c
%.o : %.c
echo second %.o : %.c
foo.o: foo.c foo.h bar.h baz.h
When I run all, I get this output:
echo second %.o : %.c
second %.o : %.c
According to what I know, both wildcard statements should be displayed, as they both match the pattern. Can anyone explain why they aren't?
The second %.o: %.c rule overrides the first one. That is why output for the first rule is not output.
From the gnu-make manual:
You can override a built-in implicit rule (or one you have defined yourself) by defining a new pattern rule with the same target and prerequisites, but a different recipe.
Related
I am trying to have a Makefile rule that can generate an object file from a source file in a directory that is specified explicitly.
exe: foo.o bar.o
foo.o: path/to/foo.c
%.o: %.c
echo Making $# from $<
This example will find it needs to make "exe", then search to make "foo.o". The "foo.o" search will try pattern rules with stem "foo" and fail to use the rule because "foo.c" doesn't exist. I want to find a way to have it see that "foo.o" can be compiled from "path/to/foo.c" using the pattern rule.
In my case it doesn't make sense for me to have the rule be "%.o: path/to/%.c" because the path should be specified for each target that needs the source to be located in another directory.
The pattern rule works for "bar.o" being made from "bar.c" within the same directory and I want to keep that working.
The solution I am going with for now is:
define c-to-o-command
echo Making $# from $<
endef
exe: foo.o bar.o
foo.o: path/to/foo.c
$(c-to-o-command)
%.o: %.c
$(c-to-o-command)
This has a drawback that the command for the pattern rule is not visible in the Makefile at the same place. It also will need to be expanded for other pattern rules that may need to have this "out of path" dependency.
Having this simple makefile:
VPATH = include
CC := gcc
CFLAGS := -I include -Wall -pedantic
%: %.o include.o
$(CC) -o $# $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
When I trigger it with the name of a program (the same name as is source with .c extension), I would expect to trigger the first rule (since I provided just a name without extension) and the the second one, because for the first rule, there is %.o prerequisite, which is exactly the second rule.
Having these file in pwd:
client.c include makefile server6.c server.c
Now If I make make server:
It does
gcc -I include -Wall -pedantic server.c -o server
In other words, The second rule is not triggered. there is no step with makeing object files, even though the object file is in the first rule as prerequisite. So how is that possible? The make is simply ignoring the prerequisite and trying to make just with the first rule. How to fix that?
That's because make has a built-in rule for %: %.c and make will always choose a pattern rule that can directly create the target over a pattern rule that requires another pattern rule:
Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules.
You can run make -r to remove all the built-in rules, or else remove it yourself by adding:
% : %.c
to your makefile.
You can see all built-in rules by running make -p -f/dev/null
I want to allow pattern rules to generate the correct header dependencies for me. I've attempted do this by, but it's failing
For example, if I have files foo.cpp, foo.h, bar.cpp, bar.h and foo.h includes bar.h. with Makefile:
foo_H=foo.h $(bar_H)
bar_H=bar.h
%.o: %.cpp $(%_H)
$(CPP) $(CPPFLAGS) $< -o $#
but make will not update when foo.h or bar.h is changed.
why does this fail and how can it be fixed?
If you really want to do that you can use secondary expansion for it:
foo_H = foo.h $(bar_H)
bar_H = bar.h
.SECONDEXPANSION:
%.o: %.cpp $$($$*_H)
$(CPP) $(CPPFLAGS) $< -o $#
That's not the way gnu make works.
the variable bar_H is undefined when assigning foo_H. So foo_H will just have the value foo.h.
the pattern expansion will not work inside $(...). It just will look up the variable %_H which does not exists, i.e. is empty.
%< and %# is wrong. You probably intended to write $< and $#.
You makefile needs at least one non target. A patterned rule is not sufficient.
A patterned rule will not be used unless all dependencies exist. This might not be intended here.
Your patterned rule will not apply because it searches for a foo.c rather than foo.cpp.
The intended behavior is achieved by
foo.o : foo.h bar.h
bar.o : bar.h
%.o: %.cpp
$(CPP) $(CPPFLAGS) $< -o $#
Note that the dependencies are specified separately from the executable commands.
Another note: if you want to get rid of the include dependency hell you might want to have a look at cmake.
$(%_H) could not expand because as stated in
https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Note that expansion using ‘%’ in pattern rules occurs after any variable or function expansions, which take place when the makefile is read
so it seems like using patterns to achieve this kind of logic is a dead end
As an alternative, I used foreach and include as follows:
makedep.mk
$(CUR_OBJ): $(CUR_OBJ:.o=.cpp) $($(CUR_OBJ:.o=_H))
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $< -o $#
Makefile
foo_H=foo.h $(bar_H)
bar_H=bar.h
SRCS=foo.cpp bar.cpp
OBJS=$(SRCS:.cpp=.o)
$(foreach obj,$(OBJS),$(eval CUR_OBJ:=$(obj)) $(eval include makedep.mk))
since there are only make variables and no pattern matching % everything can expand properly
This question already has answers here:
Create rule in makefile for just a set of files
(2 answers)
Closed 5 years ago.
I'm working on a project using makefile. Some of the make rules have the following format:
a.o b.o c.o : %.o : %.c
gcc -c $< -o $#
What's the meaning of such a rule? I'm unable to find explanation in the official manual, but I guess it's used for applying pattern-matching on only the *.o files listed as targets. Is that correct?
Quoting from the GNU Make,
Static Pattern Rules.
Static pattern rules are rules which specify multiple targets and
construct the prerequisite names for each target based on the target
name. They are more general than ordinary rules with multiple targets
because the targets do not have to have identical prerequisites. Their
prerequisites must be analogous, but not necessarily identical.
The syntax for static pattern rules:
targets : target-pattern: prereq-patterns …
recipe
…
Pattern rule is mentioned as % in the target. It matches any target ends with .o here a.o, b.o and c.o.
Here ‘$<’ is the automatic variable that holds the name of the prerequisite and ‘$#’ is the automatic variable that holds the name of the target.
a.o b.o c.o : %.o : %.c
gcc -c $< -o $#
Googling doesn't help much in understand how the % variable is being used in the Makefile snippet below.
_OBJ = a.o b.o c.o
OBJ = $(patsubst %,$(OBJDIR)/%,$(_OBJ))
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(INC)
$(CC) -c -o $# $< $(CFLAGS)
Can anybody please help me out? Does it mean that if there are five .c files present under $(SRCDIR), that many *.o rules are being populated behind the scene?
That is an "implicit rule". The % makes the word $(OBJDIR)/%.o a pattern. It tells make that if it's trying to build a target and the name of the target matches that pattern (where the % can substitute for one or more characters--any characters), AND that a file that matches the pattern $(SRCDIR)/%.c (where the % here has the same value as in the target) either already exists or can be built, then make can use this recipe to build that target.
So, if make wants to build a file foo/bar.o and the variable OBJDIR has the value foo, then this pattern foo/%.o will match that file with the % matching bar (this is called the stem in the GNU make documentation).
Then if SRCDIR has the value blah and make can find (or create) a file named blah/bar.c, then this implicit rule can be used to build the target foo/bar.o by running this recipe ($(CC) -c -o $# $< $(CFLAGS)).