Is it possible to write pattern rule like:
%.o: %.c %.h
<some action>
so it accepts not one but any number of headers, because I have:
main.o: main.c $(HEADERS)
so it doesen't fit to standard implicit rule, because of many .h files that main.c depends on, so is it possible to make an implicit rule, that would accept such input, or should I just write
$(CC) $(CFLAGS) $(DEFINE_OPT) $(INCLUDE) -c $<
explicitly?
You can write:
%.o: %.c $(HEADERS)
However, in general, you probably don't want all source files to be dependent on all header files. You should look into auto-generating the prerequisite lists; the Make manual talks about this a bit: http://www.gnu.org/software/make/manual/make.html#Automatic-Prerequisites.
In GNUMake you can write
main.o: $(HEADERS)
and the built-in implicit rule will work. If you want to handle dependencies automatically, Advanced Auto-Dependency Generation is superior to the one in the GNUMake manual.
Related
In a Makefile I encountered:
.SUFFIX: .c
Is that a misspelling of .SUFFIXES: .c, because I can't find anything about .SUFFIX only. Does this do anything at all?
If the Makefile only uses pattern rules, do I even need that hanging around in the Makefile at all?
Assuming you are using GNU make, unless there is really a user target named .SUFFIX, this is probably a misspelling of .SUFFIXES: .c. And if there is no recipe you can safely remove it: without a recipe it's useless.
If it was .SUFFIXES: .c and if it had a recipe it would redefine the implicit rules for:
%: %.c
<recipe>
which is:
LINK.c = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#
Let's say I am using the implicit rule to build an .o file from a .c file.
If I want to add a specific additional dependency for one particular .o file, it is as easy as adding a rule without a recipe:
file.o : header.h
This makes file.o depend on header.h in addition to file.c.
What if I want to do that for all .o files? The following doesn't work:
%.o : header.h
For this to make sense, header.h must a header that is (and has to be) included by every .c file
and is hence a prerequisite of every .o file. If that is your situation you
need to write your own pattern rule, like:
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
But the usual approach to managing header file dependencies is Auto-Dependency Generation
Later
My goal was to avoid duplicating the existing implicit rule (the recipe part) for $(CC) compilation. Is that possible?
You have to define a new pattern rule that adds header.h to the %.c prerequisite,
and has the appropriate recipe. In fact I ought
to have advised you also to cancel the builtin pattern rule:
%.o: %.c
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
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
Lets suppose I want the benefits provided by implicit rules while also showing a progress message in the form of:
Compiling [main.cpp]
(...)
Linking...
Writing the %.o: %.cpp rule with the message replaces the implicit rule.
And writing the whole rule explicitly defeats the goal of using implicit rules.
So, any suggestions?
PS: If this isn't currently possible with make, it's ok.
PPS: NO CMAKE
PPPS: NO AUTOFOOLS
Something like this:
%.o: %.cpp
#echo compiling $<
$(CC) -c $(CXXFLAGS) $(DEFS) $< -o $#
Because $(CXX) is used to compile C++ sources and $(CC) is used to link the objects together, I can prepend an echo to both.
CC = #echo "Linking..."; g++
CXX = #echo "Compiling [$<]"; g++
This will output the desired results.
With the following makefile snippet:
main: main.o f1.o f2.o
$(CC) $(CFLAGS) -o program main.o f1.o f2.o
main.o: main.cc
$(CC) $(CFLAGS) -c main.cc
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
f2.o: f2.cc
$(CC) $(CFLAGS) -c f2.cc
If I just change one file, only that file get recompiled when I rerun make, as desired. However, I'm having a hard time generalizing this without having to list each file individually. When I try something like:
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(patsubst %.o,%.cc,$#)
It builds each object file individually, but each object file depends on ALL my sources, so a change in any one file causing a full recompile. What's a good way to accomplish this?
Basically,
you do have to list each .o file's dependencies individually.
For example, each .o is likely to depend on a different bunch of headers.
Taking your f1.o, you need something like:
f1.o: include/i.h
f1.o: another.h dir/and-another.h
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
(you can have as many dependency lines for a target as you like).
Maintaining that list is a nightmare.
Broken dependency lists render your Makefile worse than useless—you might as well use a batch file.
All is not lost!
If you are tidy,
you can get the compiler to do it automatically,
and pretty much for free.
Makes your Makefile tidier to boot.
Win Win.
As Ismail Badawi commented, pattern rules provide a nice solution. They are a type of implicit rule for make. Basically, implicit rules are automatic recipes based off the file extension. For example, make knows how to convert .c files into .o files implicitly. By default make will run the following recipe for .c files (see the rule catalogue):
$(CC) $(CPPFLAGS) $(CFLAGS) -c
You can modify the process either by setting the variables CC, CPPFLAGS, and CFLAGS, or by defining a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -c $<
The "$<" above matches the name of the first prerequisite, which will be the .c file in this example. See Beta's comment and automatic variables.