Understand the dependency levels of makefiles - c

Assume that the project has the following files, where the first files is dependent on the files under it's category in the unordered list:
main.c
global.h (contains enumerations and #define macros)
sdlevent.h (generic header file)
sdlevent.c (contains implementations of sdlevent.h)
sdlshape.h (generic header file)
sdlshape.c (contains implementations of sdlshape.h)
Now, I have the following makefile:
CC = gcc
CFLAGS = -g -w -std=c99
LIBS = -lSDL2 -lSDL2_image -lSDL2_ttf
SRCS = main.c sdlshape.c sdlevent.c
OBJS = $(SRCS:.c=.o)
EXE = play
all: $(EXE)
.c.o:
$(CC) -c $(CFLAGS) $<
$(EXE): $(OBJS)
$(CC) -o $(EXE) $(OBJS) $(LIBS)
$(OBJS): global.h sdlevent.h sdlshape.h
run : all
./$(EXE)
clean:
rm -f *.o *~ $(EXE)
The target $(EXE) is dependent on the target .c.o. Do I absolutely need to define the target $(EXE) after the target .c.o?
I don't think so, because even though the target $(EXE) is dependent on the target $(OBJS), the target ($EXE) is declared before $(OBJS).

Do I absolutely need to define the target $(EXE) after the target .c.o?
First, .c.o is not a target, it's a suffix rule.
Second, make does not care what sequence targets are written in, so the answer is "no". The whole makefile is read and when a target is missing, a lookup is performed for a rule to create the target. Technically, make creates a directed acyclic graph (DAG) of targets and dependencies before it considers building anything. Variable references are replaced when they are used, not when they are read (exception: GNU make's := assignment operator).
Try playing around with the order of targets. You can even move the variable assignments to the bottom.
I'm sure there are a few esoteric corners in GNU make where things work slightly differently, but in a simple makefile as yours, not straying too far from a POSIX makefile, that's how it works.

Related

No rule to make target - makefile

This is my makefile:
CC=gcc
CFLAGS=-c -O2 -Wall -fcommon -I./INC
#umiestnenie zdrojakov kniznice
SRC_LIB_DIR=SRC_LIB
#automateicke generovanie zdrojakov kniznice
SRC_LIB := $(wildcard $(SRC_LIB_DIR)/*.c)
OBJ_LIB=$(SRC_LIB:.c=.o)
#meno vykonatelneho programu
EXECUTABLE=test_rx test_tx
#vymenovanie zdrojakov aplikacie
SRC_EXE=demo_rx.c demo_tx.c
OBJ_EXE=$(SRC_EXE:.c=.o)
all: $(SRC_EXE) $(SRC_LIB) $(EXECUTABLE)
%: %00.o
$(CC) -o $# $+
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f $(EXECUTABLE).exe *.o *.a SRC_LIB/*.o
The folder looks like this:
example_RS232
|__INC (rs232.h, example_modified_rs232.h)
|__SRC_LIB (rs232.c, example_modified_rs232.c)
|__demo_rx.c
|__demo_tx.c
|__makefile
Compiled in C in mingw on Windows.I'm trying to compile the demo_rx.c and demo_tx.c files into the test_rx and test_tx executables. I get an error when compiling:
make: *** No rule to make target 'test_tx', needed by 'all'. Stop.
I don't know why I have got this error.
Basically, you should try to never use "match-anything" rules. A match-anything rule is a rule where the target is just %. That rule can (as the name implies) match ANY target. It could match foo, foo.o, foo.c, foo.h, or any other thing anywhere in the makefile.
This makes these types of rules REALLY inefficient as make has to consider this rule, and the prerequisites, etc. for every target. It's also easy to get into loops this way.
Because of this, make installs a whole bunch of extra restrictions on match-anything rules that don't exist for other pattern rules. You can read all about this in the GNU make manual discussion but the best take-away is, "don't use them".
I recommend you replace this with a static pattern rule:
$(EXECUTABLE) : %: %00.o
$(CC) -o $# $+

No rule to make target 'main.o', needed by 'out'. Stop

I keep getting this error and I can't figure out what I am doing wrong. I am using an template so I can get in the dir bin the executable. The dir include the header files. The dir obj for the object files created and the src for the .c files.
My makefile
OBJ_dir = obj
INC_DIR = include
OBJECTS = main.o client.o private.o memory.o process.o proxy.o server.o
main.o = main.h memory-private.h stdio.h stdlib.h string.h syscall.h unistd.h wait.h sysexits.h memory.h
client.o = client.h
private.o = private.h
memory.o = memory.h memory_private.h
process.o = process.h
proxy.o = proxy.h
server.o = server.h
CC = gcc
CFLAGS = -Wall –I $(INC_DIR)
LIBS = -lm
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
clean:
rm –f *.o out
rm –f out
There are many issues here. It's probably a good idea to read at least the first few chapters of the GNU make manual to understand how make and makefiles work.
Take this rule:
out: $(OBJECTS)
$(CC) $(addprefix $(OBJ_dir)/,$(OBJECTS)) -o bin/out $(LIBS)
First, it's not right to list a different target than the file you actually build. Here you told make you'd build a target named out, but your recipe actually builds a target named bin/out. That's wrong.
Second, but similarly, it's not right to have your target depend on one set of prerequisites (the files defined by $(OBJECTS)) but then have the recipe of your rule use a completely different set of prerequisites (by adding a $(OBJ_dir)/ prefix to all the files).
This tells make "please build files main.o, client.o, etc., but what my command will actually use is files obj/main.o, obj/client.o, etc.". It doesn't make sense to tell make to build targets that you aren't going to actually use.
This should be:
bin/out: $(addprefix $(OBJ_dir)/,$(OBJECTS))
$(CC) $^ -o $# $(LIBS)
In general if you ever find yourself writing a recipe where you are modifying the automatic variables like $# or $^ instead of using them as-is, you're almost certainly doing something wrong.
Next your pattern rule has other issues:
%.o: src/%.c $($#)
$(CC) $(CFLAGS) -o $(OBJ_dir)/$# -c $<
First, you cannot use automatic variables like $# in a prerequisite list. Those values are only set when expanding the recipe of a rule. They are not set (empty) when evaluating the prerequisite list. So $($#) expands to the empty string here and does nothing.
Second you have the same problem as above where you are not creating $# you are creating $(OBJ_dir)/$# which is wrong. You should write your rule like this:
$(OBJ_dir)/%.o: src/%.c
$(CC) $(CFLAGS) -o $# -c $<
so that the target lists the file you want to build, and the recipe uses $# without modification.
As for your prerequisites, you should just create them directly rather than trying to use fancy variables (which can't work). As the comment above suggests, just change:
proxy.o = proxy.h
to:
proxy.o : proxy.h
(and all the rest) and it will work. Note, though, that make always builds the first explicit target it sees by default so you may have to re-arrange your makefile a little bit if you want bin/out to be the default target.

Makefile does not iterate over all the source files?

I want to compile many source file and build a library from them.
My makefile looks approximately like this:
SOURCES := /home/test/src/\*.c
OBJECTS := $(SOURCES:.c=.o)
.PHONY: compileLibrary
compileLibrary:
$(CC) -fPIC -c $(SOURCES) -o $(OBJECTS)
$(CC) -shared -o libshared.so $(OBJECTS)
How ever the process does not iterate over each source file, it seems that makefile does not replace the * in SOURCES by its value.
*.c, on its own, is not expanded, you have to use the wildcard function (like $(wildcard *.c))
It is *.c, not \*.c. \ is escape and removes the special meaning of *.
Obviously your makefile shouldn't contain absolute path. Normally the current directory has to be the one where the makefile is in, so take advantage of it.
You should be actually using the features of make:
libshared.so: $(OBJECTS)
$(CC) -shared -o $# $<
compileLibrary: libshared.so
(note: you can probably do without the compilation rule, because the default is likely good enough)

Resulting file names as a input of a variable

I have many functions in different files.
eg: OBJ_SRC=sum.c sub.c mul.c div.c remainder.c
When I am creating a library I do like this:
libarithmatic.a: $(OBJ_SRC)
gcc -c $(OBJ_SRC) # creates sum.o sub.o..
ar rcs libarithmatic.a $(OBJS) #<--- problem #OBJS
How to store the output of gcc -c $(OBJ_SRC): add.o sub.o mul.o.. (newly created/updated file names) into OBJS variable?
The usual way is with patsubst
OBJS=$(patsubst %.c,%.o,$(OBJ-SRC))
Now calling gcc as part of the target to build the library is a bad idea. It misses the main point of using make at all as you are asking gcc to blindly recompile all the objects instead of having make find which have changed. The usual rule is:
libarithmatic.a: $(OBJS)
ar rcs libarithmatic.a $(OBJS)
You can put in the pattern rule for compiling the .c files, but if you'd just put in
%.o: %.c
gcc -c $<
you don't have to bother as that is implicit. Well, the default implicit rule is really
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
where CC defaults to suitable compiler and you can override it and CPPFLAGS and CFLAGS default to empty and you can set them to whatever flags you want to use for compilation. CPPFLAGS is for both C and C++, CFLAGS is for C only, CXXFLAGS is for C++ only (C++ compiler is CXX).
On a side-note, I'd suggest looking at CMake, which supports generating build files for various platforms, IDEs and the new ultra-fast ninja. The corresponding CMakeLists.txt would be as trivial as
project(arithmatic)
add_library(arithmatic sum.c sub.c mul.c div.c remainder.c)
and making it a shared library as trivial as adding SHARED keyword when you want to.
Note, that the % placeholder does not have to be at the beginning. If you want to put the objects in different directory from the sources, you can write things like
OBJS=$(patsubst src/%.c,obj/%.o,$(SOURCES))
(the sources have to be listed with the directory prefix in this case) or perhaps
OBJS=$(patsubst %.c,.objs/%.o,$(SOURCES))
And you can similarly use the pattern in the rules, so
obj/%.o: src/%.c
mkdir -p obj
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
or
.objs/%.o: %.c
mkdir -p .objs
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# $<
You have to make sure the output directory exists as the compiler won't create it (so I include the mkdir in the rules) and you have to explicitly specify compiler output, because it would create it in current directory otherwise.

What is the proper standard for Makefiles?

I'm currently writing small simple C programs. As of now my Makefiles have consisted of text something along the lines of:
program_name:
clang -o program_name program_name.c
Is this all I need? I wasn't sure if I needed to establish dependencies between .o and .h files, even if they don't necessarily exist in my project.
You are working too hard. You should simplify your Makefile to 2 lines:
CC=clang
program_name: some.h
There is no need to specify the dependency on program_name.o or program_name.c, since those are implied. There is also no need to give the rule explicitly, since you are using the default rule. Dependencies on header files do need to be spelled out, however.
I use GNU Make myself. Not sure what you're using. For GNU Make, refer to:
http://www.gnu.org/prep/standards/html_node/Makefile-Conventions.html#Makefile-Conventions
http://www.gnu.org/software/make/
Is this all I need?
No.
I wasn't sure if I needed to establish dependencies between .o and .h files
Generally, you should, especially if you're using custom data types (and even if not: a change in a function signature can break the whole program if the ABI/calling conventions on your platform consist of black magic).
The template I'm using is usually:
CC = gcc
LD = $(CC)
CFLAGS = -c -Wall
LDFLAGS = -lwhatever -lfoo -lbar
TARGET = myprog
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) $(LDFLAGS) -o $# $^
%.c: %.h
%.o: %.c
$(CC) $(CFLAGS) -o $# $^

Resources