Condition 0:
Say, I have several source codes, a.c, b.c, ..., z.c, and I want a rule to have each of them compiled. Here is a solution:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Condition 1:
Then I introduce a header c.h used in c.c, and another header e.h used in c.c and e.c, and things become complex:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
c.o: c.c c.h e.h
$(CC) -c -o $# $(CFLAGS) $<
e.o: e.c e.h
$(CC) -c -o $# $(CFLAGS) $<
My question:
Based on the solution of condition 1, is there something like add_dependency in make to simplify the solution and obtain something like the following one?
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
add_dependency(c.o, c.h e.h)
add_dependency(e.o, e.h)
Or, what do you think is a better solution to condition 1?
EDITED:
Thanks for the kind notice #ctheo :)
Yes I did have a look at autotools and understood that shall satisfy all my needs. However what I'm dealing with is an existing project and its Makefile contains other directives dealing with codes in C++, and I think for now I'd better just modify a few lines instead of port the whole Makefile to autotools, unless I couldn't find a satisfying solution without introducing autotools. :)
At first I did not expected to exist a solution for this. It seemed to me that it was covered by autotools. However, after some search, I found this section of GNU/make manual.
It states that :
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
So there is a solution for your query
c.o: c.h e.h
e.o: e.h
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Thanks for insisting. I learned something today :)
In addition, the .o files in your example all depend on a .h file with the same stem, so you can generalise that part of your rules too:
c.o: e.h
%.o: %.c %.h
$(CC) -c -o $# $(CFLAGS) $<
This way, your “normal” situations are covered entirely by the rule that triggers compilation and your “unusual” situations stand out because those are the only additional rules.
Related
I can write pattern rules like that to compile .cfiles to .ofiles.
%.o:%.c
$(CC) -c $< $(CFLAGS) -o $#
But it seems that this method will only work when all the c file are in the same directory.
If my project's struct is like this
|-folder1
|----a.c
|----b.c
|-folder2
|----c.c
|----d.c
|Makefile
I have to change my Makefile to this
%.o:folder1/%.c
$(CC) -c $< $(CFLAGS) -o $#
%.o:folder2/%.c
$(CC) -c $< $(CFLAGS) -o $#
If i have a lot of folders, I think repeating code like this is not the correct way to solve the problem.
Anyone has better solutions?
Lets say I have one directory with c files (.) and I want the object files to end up in two different directories: debug and release. Now I want to make the rule for this. This will end up being something like this:
$(DEBUGDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
$(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
These are two rules which are exactly the same. Since all possible differences between those rules are contained in CFLAGS there is no reason to even have two rules: I want to maintain only one. I tried this:
$(DEBUGDIR)%.o $(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
But now it will not compile the o-files for RELEASE when it already compiled for DEBUG. How can I merge these two rules into one?
You can't do it. Pattern rules with multiple targets define a recipe that creates multiple output files when run one time.
For this I'd just write the rule twice. Alternatively you can put the recipe into a variable and use it twice:
COMPILE = $(CC) $(CFLAGS) -c $< -o $#
$(DEBUGDIR)%.o : %.c
$(COMPILE)
$(RELEASEDIR)%.o : %.c
$(COMPILE)
I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.
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.
I am curious if it is possible to use a general rule as part of a more specific rule in Gnu Make. This is easier to explain with an example:
%.o:
$(FC) $(FLAGS) -o $# -c $<
some_file.o:
DO SOMETHING EXTRA
PASS ON TO GENERAL FOR %.o
That is, I want the target for some_file.o to first do something extra, and then do what is specified for %.o. Of course, I could just be redundant and write
some_file.o:
DO SOMETHING EXTRA
$(FC) $(FLAGS) -o $# -c $<
But that is not as convenient.
Add an extra rule that does not create the file itself:
%.o:
$(FC) $(FLAGS) -o $# -c $<
some_file.o: thing
thing:
DO SOMETHING EXTRA BUT DON'T CREATE some_file.o
Note that if thing is not created, this will cause some_file.o to be built every time.
No, that's not possible in any reasonable way. The best you can do is put the command into a variable, then reuse the variable:
FCCOMMAND = $(FC) $(FLAGS) -o $# -c $<
%.o :
$(FCCOMMAND)
some_file.o:
DO SOMETHING EXTRA
$(FCCOMMAND)