Interpreting a Generalized Makefile - 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

Related

Makefile - Compile Single Objects in different directory

I have been combing the web and I can't figure out the right way to get this to work. Just trying to create a simple Makefile which takes my source and only builds the changed files. I need all the .o files to be put in the same output folder. I currently have everything working except that if I change one file the whole thing rebuilds. For example, if I change main.c it will compile EOL.c as well. However if nothing changes it says nothing needs to be done.
NAME=Program
CC=arm-none-eabi-gcc
CFLAGS=-c -Wall -O0 -std=c99 \
-nostartfiles --specs=nano.specs \
-mthumb -fmessage-length=0 \
-fsigned-char -ffunction-sections \
-fdata-sections -mcpu=cortex-m0
BID?=_DEV
DEFINES= -DPROD -DBLD_ID=\"$(BID)\"
LDFLAGS= -nostartfiles
INCLUDES= -ISrc/App/Include -ISrc/Device/CMSIS/Include
SOURCES= Src/main.c Src/App/Source/Application.c Src/App/Source/EOL.c Src/Svc/Source/TimerManager.c
OBJECTS=$(OBJECTS1:.c=.o)
OBJECTS1=$(SOURCES:.S=.o)
OFILES1=$(notdir ${OBJECTS})
OFILES=$(addprefix $(OBJDIR)/,$(OFILES1))
OBJDIR=Output
.PHONY: all rebuild clean
all: $(OBJDIR) $(SOURCES) $(OBJDIR)/$(NAME).hex
%.hex: %.elf
arm-none-eabi-objcopy -O ihex $< $#
%elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(OFILES) -o $#
rebuild: clean all
.SECONDARY:
.c.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $#)
.S.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $#)
$(OBJDIR):
mkdir $(OBJDIR)
clean:
rm -f $(OBJDIR)/*.o $(OBJDIR)/*.elf $(OBJDIR)/*.hex $(OBJDIR)/*.bin
There are several problems with this makefile. Basically you have rules whose targets are not the files they actually produce, and a rule whose prerequisites are not the files it actually needs.
Suppose you have modified Src/main.c and try to rebuild Output/Program.elf using this rule:
%elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(OFILES) -o $#
The prerequisites ($(OBJECTS)) are actually Src/main.o Src/App/Source/EOL.o and so on. These files do not exist -- they never exist -- but there is a rule for them:
.c.o:
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $(OBJDIR)/$(notdir $#)
Make sees that Src/main.o depends on Src/main.c and must therefore be rebuilt, as must Output/Program.elf. So it invokes this rule -- which actually builds Output/main.o. But the elf rule demands all of the (imaginary) object files, so all of the sources must be recompiled-- into object files that already exist and are not out of date, but which Make wasn't paying attention to.
The first thing to do is fix the object rules, but there's a problem: although the rules are flawed, they have the advantage of helping Make to find the corresponding source files (before misusing them), like this:
Src/App/Source/EOL.o: Src/App/Source/EOL.c
...
How can we tell Make where to find the source file corresponding to Output/EOL.o? There's more than one way, but a good way is by using vpath:
vpath %.c Src/App/Source
Output/EOL.o: EOL.c
...
All we have to do is create a list of source directories, pass it to vpath, and modify the pattern rule:
SRCDIRS := $(dir $(SOURCES))
vpath %.c $(SRCDIRS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $#
(The .S.o rule can be fixed the same way.)
Then modify the elf rule to name -- and use -- its real prerequisites:
%elf: $(OFILES)
$(CC) $(LDFLAGS) $^ -o $#

Makefile wildcard rules for multiple file extensions

I have a number of assembly and C source files in a directory. I have mentioned a list of files to be compiled as C_OBJFILES and ASM_OBJFILES. I have added the rules as
%.o: %.S
$(AS) $(ASFLAGS) -o $# $<
%.o: %.c
$(CC) $(CFLAGS) -o $# $<
for generating the object files. Some of the assembly files has .s extension. Some has .S and remaining .asm. Is there a way to specify these different extensions in a single rule instead of separate %.o:%.asm and %.o:%.s?
Although it can be solved by a simple prename before make, I would like to explore the options with Makefile. Below is the complete Makefile I have written.
ASM_OBJLIST:=startup.o vectors.o lowlevel.o
C_OBJLIST:=test.o
LD_SCRIPT:=test.ld
CROSS_COMPILE:=arm-none-eabi-
AS:=$(CROSS_COMPILE)as
CC:=$(CROSS_COMPILE)gcc
LD:=$(CROSS_COMPILE)ld
OBJCOPY:=$(CROSS_COMPILE)objcopy
CFLAGS:= -c -mcpu=arm926ej-s -g
ASFLAGS:= -mcpu=arm926ej-s -g
BIN_TARGET:=test.bin
$(BIN_TARGET): $(C_OBJLIST) $(ASM_OBJLIST)
$(LD) -T $(LD_SCRIPT) -o $#.elf $^
$(OBJCOPY) -O binary $#.elf $#
%.o: %.S
$(AS) $(ASFLAGS) -o $# $<
%.o: %.c
$(CC) $(CFLAGS) -o $# $<
clean:
rm -f *.o *.elf *.bin
If handling multiple extensions in a single rule is possible, I can just use gcc for all source files instead of bothering to use as at all. (I guess)
Use static patterns and split the objects into two sets, there are a number of other improvements too
Make already has defaults for things like AS and CC, use them.
You're already using ASFLAGS and CFLAGS correctly (except for -c, see below), use the same pattern for other flags too
You missed a chance to express the bin->elf dependency
You can recycle the built-in recipes even if you need to redefine the rules (LINK.o, COMPILE.c which already has the -c flag), although the .c rule is currently superfluous as it's exactly the same as the built-in one.
clean should be PHONY
Never delete stuff with *, explicitly delete only the files you are responsible for.
I'd just use GCC to link but if you need to link with LD then you'll need to change the recipe.
ASM_OBJLIST := startup.o
S_OBLIST := vectors.o lowlevel.o
C_OBJLIST := test.o
LD_SCRIPT := test.ld
CROSS_COMPILE := arm-none-eabi-
AS := $(CROSS_COMPILE)$(AS)
CC := $(CROSS_COMPILE)$(CC)
OBJCOPY := $(CROSS_COMPILE)objcopy
CFLAGS := -mcpu=arm926ej-s -g
ASFLAGS := -mcpu=arm926ej-s -g
LDFLAGS := -Wl,-T $(LD_SCRIPT)
OBJFLAGS := -O binary
BIN_TARGET := test.bin
$(BIN_TARGET): $(BIN_TARGET).elf
$(OBJCOPY) $(OBJFLAGS) $< $#
$(BIN_TARGET).elf: $(C_OBJLIST) $(ASM_OBJLIST)
$(LINK.o) $^ $(LDLIBS) -o $#
$(ASM_OBJLIST): %.o: %.asm
$(S_OBJLIST): %.o: %.S
$(ASM_OBJLIST) $(S_OBJLIST):
$(COMPILE.S) -o $# $<
%.o: %.c
$(COMPILE.c) -o $# $<
.PHONY: clean
clean:
$(RM) $(C_OBJLIST) $(ASM_OBJLIST) $(BIN_TARGET).elf $(BIN_TARGET)

Understanding deeply using a specific case how makefiles are interpreted

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.

Makefile multiple sources ouputs variable expansion

suppose CC variable is a compiling command and we don't need any additional flags. Simple part of makefile compiling main.c and next.c to main.o and next.o:
all: main.o next.o
%.o : %.c
$(CC) $< -o $#
Now suppose I would like to have output files in variable:
all: $(OBJ)
OBJ = main.o next.o
%.o : %.c
$(CC) $< -o $#
Of course it won't work. I understand why but I can't find solution. Can you help me?

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.

Resources