How to make a proper C makefile - c

so far I have learned this kind of makefile :
finalcode : code.o
gcc -g -ansi -Wall -pedantic code.o -o finalcode
code.o : code.c
gcc -c -ansi -Wall -pedantic code.c -o code.o
I'm interested in learning the better version
all:
clean:
etc..
where can I learn how to write a more "professional" makefile?
thanks in advance!

So you just want the typical "phony" targets? That's simple, make all the first rule (so it's the default) and have it depend on anything you want to have built, e.g.:
all: finalcode
Then, in clean, just write a script to delete whatever should be cleaned, e.g.:
clean:
rm -f *.o
Finally, don't forget to make these rules "phony", so make knows they don't actually create files with these names:
.PHONY: all clean
Done.
As for "professional", that's quite subjective, but I'd start by defining variables for the compiler (CC), flags (CFLAGS), includes and so on and use these. If you are fine with a bit loss of portability, use pattern rules e.g. for creating the object files like
%.o: %.c
$(CC) -c -o$# $(CFLAGS) $(INCLUDES) $<

Related

GNU Makefile : How to use pattern-rule adding a compilation flag to a match-anything pattern-rule by using pattern-specific variable value?

I have created several test files test_*.c, each testing a single function of a c library I built.
I first wrote a Makefile for compiling each c file to produce its corresponding binary:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
This works as expected, so when i type make test_<name_of_my_function> and if the 'test_<name_of_my_function>.c' file exists, it compiles it to create the 'test_<name_of_my_function>' binary.
But now i want to add a rule that creates the binary in debug mode by adding the gcc flag -g to the command if i run the command make debug_test_<name_of_my_function>.
I tried adding the pattern-specific rule debug_% and use a pattern-specific value for appending -g to CFLAGS:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
debug_%: CFLAGS += -g
debug_%: %
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
But when i run for example debug_test_function1, i get the following ouptut :
make: *** No rule to make target 'debug_test_function1'. Stop.
Note that whatever prerequisite rule i use for the target debug_%, it isn't executed (even if the prerequisite is not a pattern rule).
Note also that if i replace in the makefile
debug_%: CFLAGS += -g
debug_%: %
by
debug%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} -g $< -L${PROJECT_PATH} -lmyproject -o $#
it works. But i'd lose the benefit of using a pattern-specific variable here.
Any clue oh how to use pattern-specific variable values to do it?
Thank you for your help !
This:
debug_%: %
does not define a pattern rule. It deletes a pattern rule. See the GNU make manual. So, you've not defined any rules here that know how to build debug_test_function1 (because there's no file debug_test_function1.c to build it from and the only rule you have available is the match-anything rule).
You have to provide the recipe here, you cannot omit it. But obviously you can still add a pattern-specific variable; why not?:
debug_%: CFLAGS += -g
debug_%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
I'm not really sure what "benefit of pattern-specific variables" you are referring to since you don't seem to build an other prerequisites that need to inherit the pattern-specific variable. But the above should work.

Why am I getting this error Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop

My working directory looks like this:
main.c
Makefile
my_memmove.h
my_memmove.c
c-timer-lib
timer.c
timer.h
My makefile looks like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib
TARGET := output
output: main.o my_memmove.o timer.o
$(CC) $(CFLAGS) main.o my_memmove.o timer.o -o $(TARGET)
main.o: main.c
gcc -c main.c
my_memmove.o: my_memmove.c my_memmove.h
gcc -c my_memmove.c
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
clean:
rm *.o $(TARGET)
I don't understand why I keep getting the "Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop." error. I believe that it's because the timer.c and timer.h files can't be found.
So much confusion here! :)
First, this is definitely wrong:
$(CC) $(CFLAGS) -I main.o ...
The -I main.o tells the compiler that it should use main.o as the name of a directory to search for include files. That clearly won't work. You should remove the -I here.
On to your problem: you have to realize that there are two completely different programs at play here: make which figures out how to run commands, and the commands that are being run, in this case the compiler gcc.
The -I option is an option to the compiler so that the compiler knows where to look for header files that are included by your source code with #include.
That option means nothing to make; it doesn't understand that option. It's just some text to pass to the compiler. Make is looking for the source file timer.c and it can't find it because you haven't told make where it is.
You have to write your rule to look in the correct place, like this:
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
(you should always use -o $# so that your compile line puts the output file where make expects to find it, which will be put into the $# variable by make before it evaluates your recipe.)
ETA
Also, are you sure that -DUNITS="ms" is right? We can't tell without seeing how UNITS is used in the source, but I suspect you probably need an extra level of quotes here, like -DUNITS='"ms"'
Really, you are trying to do too much in this makefile. Make already knows how to correctly build object files from source files. If you don't force the issue by writing your own rules, then make's built-in rules will do the job for you. Your makefile can be written like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib -DUNITS='"ms"'
TARGET := output
$(TARGET): main.o my_memmove.o c-timer-lib/timer.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
my_memmove.o: my_memmove.h
c-timer-lib/timer.o: c-timer-lib/timer.h
clean:
rm *.o $(TARGET)
make doesn't know which headers your source requires so you have to add the prerequisites by hand, although you can add extra rules to allow it to figure that out for itself.

Makefile -std=c99 error

all: matrices.c calculations.o
gcc -std=c99 matrices.c calculations.o -o -lm PROGRAM2_EXE
lib: matrices.h calculations.c
gcc -c -std=c99 calculations.c -o calculations.o
clean:
rm matrices.o calculations.o PROGRAM2_EXE
This is my makefile for my project. Inside my matrices and my calculations.c there are multiple for loops. The error it gives me is error: 'for' loop initial declarations are only allowed in c99 mode but i have my -std=c99 in my file. My questions is
How do i fix my makefile to run with the for loops?
This action:
gcc -std=c99 matrices.c calculations.o -o -lm PROGRAM2_EXE
is telling gcc to produce an executable called -lm, which is probably not what you want.
Since you have no rule to produce connections.o, make will use its default rule to build it from connections.c, which is likely something like (from gmake):
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
Since you don't set -std=c99 in CFGLAGS or CPPFLAGS, it won't be used.
You don't have a rule for calculations.o. That means that the makefile does not specify how to generate calculations.o. You only have a rule for generating all and lib.
Gmake has some default rules. One of them is that if you do not have a rule for filename.o then it is compiled using $(CC) $(CPPFLAGS) $(CFLAGS) -c filename.c.
Your make all line is:
all: matrices.c calculations.o
When you issue make or make all, gmake checks the dependencies first. matrices.c already exists so that's fine. But if calculations.o does not exist, then it decides it needs to build calculations.o. You didn't specify a rule for calculations.o, so the implicit rule is used, which doesn't have -std=c99 in it.
Note that your lib rule is badly written. All rules should either create a file of the corresponding name, or be declared as .PHONY. It seems as if you think that make should somehow deduce that it needs to do make lib if the calculations.o file does not exist, but that isn't how make works.
To fix your problem , just change lib: to calculations.o:. Also, it would be good style to fix the all line. The rule does not make all, it makes PROGRAM2_EXE, so:
.PHONY: all
all: PROGRAM2_EXE
PROGRAM2_EXE: matrices.c calculations.o
gcc -std=c99 matrices.c calculations.o -o PROGRAM2_EXE -lm
(Edit: as Chris Dodd points out, the -o switch must be immediately followed by the filename)
It would be better style to have a rule matrices.o that compiles matrices.c, and then a rule PROGRAM2_EXE: matrices.o calculations.o that links the two.
I use the following CFLAGS:
CFLAGS = -Wall -g -std=c99
It works very good for me.

A Makefile with Multiple Executables

I am trying to write a makefile which uses macros to create multiple executables from multiple files at once. I tried searching through previously answered questions but, because I am fairly new to programming in C as well as working with gcc, I was not able to find an answer to my question.
Here is what I have so far:
CC=gcc
CFLAGS=-I.
OBJ = ex1.c ex3.c
EXECUTABLE = ex1 ex3
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
clean:
rm -f $(EXECUTABLE)
I would like the line
$(EXECUTABLE): $(OBJ)
to create executables ex1 and ex3 from files ex1.c ex3.c respectively.
For this particular case, where each executable has a single source file with .c extension, all you need is a one line Makefile:
all: ex1 ex3
The built-in default rules for make then work already:
$ make
cc -O2 -pipe ex1.c -o ex1
cc -O2 -pipe ex3.c -o ex3
Behind the scene, make is using the POSIXly mandated built-in single suffix rule
.c:
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $<
Vary the command to your liking with make CC=gcc CFLAGS=-O2 LDFLAGS=-s and similar.
Trivia of the day: in fact, if you are willing to name the targets when invoking make, you can use an empty or even run without any Makefile:
$ make -f /dev/null CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
$ rm -f Makefile ex1 ex3
$ make CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
Make magic!
As a rule of thumb, don't reinvent the wheel (or rules), use the rules that are already there. It simplifies your and make's life a lot. This makes for small and sexy makefiles to impress the ladies with :-)
Some suggestions (assuming you use GNU make, not something else)
First, run once make -p, you'll understand what builtin rules make is knowing. Look in particular for COMPILE.c and LINK.c
Then, I suggest
CFLAGS= -g -Wall -I.
(because you really want -g for debugging, and -Wall to get most warnings)
And you probably don't need
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
However, I suggest adding before most other rules
.PHONY: all clean
all: $(EXECUTABLES)
Actually, I would code your Makefile (for GNU make!) as follow
# file Makefile
CC= gcc
RM= rm -vf
CFLAGS= -Wall -g
CPPFLAGS= -I.
SRCFILES= ex1.c ex2.c ## or perhaps $(wildcard *.c)
OBJFILES= $(patsubst %.c, %.o, $(SRCFILES))
PROGFILES= $(patsubst %.c, %, $(SRCFILES))
.PHONY: all clean
all: $(PROGFILES)
clean:
$(RM) $(OBJFILES) $(PROGFILES) *~
## eof Makefile
Remember that tab is a significant character in Makefile-s (action part of rules). In this answer, lines starting with four spaces at least should really start with a tab character.
Once everything is debugged consider running make clean to clean everything, and then make -j CFLAGS=-O2 all to compile in parallel everything with optimizations.
At last, I recommend using remake and running remake -x to debug complex Makefile-s
Of course, I'm supposing that your directory has only single-file programs.
BTW, there are other build automation tools. Perhaps you might consider using omake or ninja. For building large programs (millions of source code lines) consider also automake, ccache, cmake, icecream. In some cases, consider generating some C code with GPP, GNU bison, SWIG, etc... or using your own Python or Guile script (or C meta-program). See also this draft report.
Don't forget to use a version control system like git for your source files. It is also time to learn such a tool.
The following answer includes multiple executable such as initiate, process1, process2, ..., process4.
LOCAL_INCLUDE=./
all: clean process_first process_second init
process_first:
gcc -g -o process1 -I$(LOCAL_INCLUDE) process1.c -lzmq -L. -L./.
gcc -g -o process2 -I$(LOCAL_INCLUDE) process2.c -lzmq -L. -L./.
process_second:
gcc -g -o process3 -I$(LOCAL_INCLUDE) process3.c -lzmq -L. -L./.
gcc -g -o process4 -I$(LOCAL_INCLUDE) process4.c -lzmq -L. -L./.
init:
gcc -g -o initiate -I$(LOCAL_INCLUDE) initiate.c -lzmq -lconfig -lpthread -L. -L./. -ldl -lrt
clean:
rm -rf init_manager.o init_manager
rm -rf process1 process2 process3 process4
NOTE: It is a good practice to clean and touch all the executable files before making them again.
You're close, but you need a pattern rule:
$(EXECUTABLE): % : %.c
And then a default rule to make it build both:
all: $(EXECUTABLE)

How do I make a simple makefile for gcc on Linux?

I have three files: program.c, program.h and headers.h.
program.c includes program.h and headers.h.
I need to compile this on Linux using gcc compiler. I'm not sure how to do this. Netbeans created one for me, but it's empty.
Interesting, I didn't know make would default to using the C compiler given rules regarding source files.
Anyway, a simple solution that demonstrates simple Makefile concepts would be:
HEADERS = program.h headers.h
default: program
program.o: program.c $(HEADERS)
gcc -c program.c -o program.o
program: program.o
gcc program.o -o program
clean:
-rm -f program.o
-rm -f program
(bear in mind that make requires tab instead of space indentation, so be sure to fix that when copying)
However, to support more C files, you'd have to make new rules for each of them. Thus, to improve:
HEADERS = program.h headers.h
OBJECTS = program.o
default: program
%.o: %.c $(HEADERS)
gcc -c $< -o $#
program: $(OBJECTS)
gcc $(OBJECTS) -o $#
clean:
-rm -f $(OBJECTS)
-rm -f program
I tried to make this as simple as possible by omitting variables like $(CC) and $(CFLAGS) that are usually seen in makefiles. If you're interested in figuring that out, I hope I've given you a good start on that.
Here's the Makefile I like to use for C source. Feel free to use it:
TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
It uses the wildcard and patsubst features of the make utility to automatically include .c and .h files in the current directory, meaning when you add new code files to your directory, you won't have to update the Makefile. However, if you want to change the name of the generated executable, libraries, or compiler flags, you can just modify the variables.
In either case, don't use autoconf, please. I'm begging you! :)
For example this simple Makefile should be sufficient:
CC=gcc
CFLAGS=-Wall
all: program
program: program.o
program.o: program.c program.h headers.h
clean:
rm -f program program.o
run: program
./program
Note there must be <tab> on the next line after clean and run, not spaces.
UPDATE Comments below applied
all: program
program.o: program.h headers.h
is enough. the rest is implicit
The simplest make file can be
all : test
test : test.o
gcc -o test test.o
test.o : test.c
gcc -c test.c
clean :
rm test *.o
Depending on the number of headers and your development habits, you may want to investigate gccmakedep. This program examines your current directory and adds to the end of the makefile the header dependencies for each .c/cpp file. This is overkill when you have 2 headers and one program file. However, if you have 5+ little test programs and you are editing one of 10 headers, you can then trust make to rebuild exactly those programs which were changed by your modifications.

Resources