Understanding deeply using a specific case how makefiles are interpreted - makefile

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.

Related

Single make rule for multiple output files in different directories

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)

Is default goal is first rule in makefile

I have simple makefile:
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
gcc -o hellomake hellomake.o hellofunc.o -I.
According to makefile description "first rule in makefile is default goal". According to my understanding the first rule is:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
But I suppose this is not "default goal" since goal is to create hellomake executable? Where is my mistake?
According to the gnu make manual, By default, make starts with the first target (not targets whose names start with ‘.’).
%.o : ... does not count as an actual target, but rather is a pattern, which is resolved to actual goals when needed.

Add dependencies to existing make targets

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.

Interpreting a Generalized Makefile

I came across this code and am having a hard time grasping it. The code in this makefile is very generalized I am having problem with the shortcuts
CC = gcc
CFLAGS = -Wall
DEPS = primes.h
OBJ = go.o primes.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
go: $(OBJ)
gcc $(CFLAGS) -o $# $^
What does the target %.o mean ? If you wish to enter this target what will you write ?
What does its dependency mean ?
What does $# $< mean ?
What does $# $^ mean ?
The %.o applies to all files ending in the .o suffix, similarly %.c applies to all files ending in the .c suffix. The $< is the first item in the dependencies list. The special macros $# and $^, which are the left and right sides of a rule having :, respectively, to make the overall compilation rule more general.
Thus,
go: $(OBJ)
gcc $(CFLAGS) -o $# $^
expands to:
gcc -Wall -o go go.o primes.o
And each of the object files, go.o and primes.o is checked against timestamp if they got modified.
for example,
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
expands to for go.o as:
go.o : go.c primes.h
i.e. if go.o has timestamp earlier than timestamps of either go.c or primes.h, this rule is fired.
And, the rule is:
gcc -Wall -c -o go.o go.c
$< expands to go.c (first dependency) in this case

Difference of two pattern rules and integration on makefile

I'm learning makefile and I'm little bit confused about the use of pattern rule and how to use it:
I have two questions:
difference form of pattern rules
In some examples I saw this form:
.c.o:
$(CC) $(CFLAGS) $< -o $#
Other times I saw this:
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
Is this the same form or there are many differences?
How to integrate the pattern rule in my makefile
I have a makefile like this:
.PHONY: all brsserver brsclient clean
CC = gcc
CFLAGS = -Wall -pedantic -g -lpthread
# source files for server
SOURCES_SERV = brsserver.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# source files for client
SOURCES_CLI = brsclient.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# object file for server
OBJECTS_SERV = $(SOURCES_SERV:.c = .o)
# object file for client
OBJECTS_CLI = $(SOURCES_SERV:.c = .o)
# executable file server
SERV_EXE = brsserver
# executable file client
CLI_EXE = brsclient
I did this:
$(SERV_EXE): $(OBJECTS_SERV)
$(CC) $(CFLAGS) -o $# $^ newDeck.o
$(CLI_EXE): $(OBJECTS_CLI)
$(CC) $(CFLAGS) -o $# $^
But I want to use the pattern rule to do make brsserver and make brsclient from command.
it's enough do this?
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
As you can see, I have to complie only the brsserver including a module called newDeck.o.
The .c.o form is a suffix rule. This form is defined in the POSIX standard for the make program.
The %.o : %.c is a pattern rule. This is a GNU make feature, not part of the POSIX standard (I think there may be a few other make implementations that have something similar).
In this case, they are equivalent. However pattern rules in general are much more flexible than suffix rules; for example you can't represent a pattern rule like this:
foo%.o : bar%.c
as a suffix rule.

Resources