What would be the minimal Makefile for a C project? - makefile

I find plenty of answers such as this one that doesn't use the implicit rules.
The minimum I can write is this:
SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))
EXEC=a.exe
all: $(EXEC)
$(EXEC): $(OBJ)
$(CC) $^ -o $#
clean:
$(RM) $(OBJ)
$(RM) $(EXEC)
But I am sure I can remove the linking part as well.
Is it possible to reduce this Makefile a bit more?
EDIT
With the help of Maxim Egorushkin I wrote this:
#Makefile
OBJS=$(patsubst %.c,%.o,$(wildcard *.c))
EXEC=a
$(EXEC): $(OBJS)
all : $(EXEC)
clean :
rm -f $(OBJS)
.PHONY: all clean
It does build my files, but it doesn't link anything:
$ make
cc -c -o bar.o bar.c
cc -c -o cow.o cow.c
cc -c -o foo.o foo.c
What should I change?
The dummy source files are created as follow:
echo "int main() {return 0;}" > cow.c
touch foo.c bar.c cow.c

The bare minimum would be:
all : a
a : a.o b.o c.o
clean :
rm -f a a.o
.PHONY: all clean
It expects source files a.c, b.c and c.c to produce executable a:
$ touch a.c b.c c.c
$ make
cc -c -o a.o a.c
cc -c -o b.o b.c
cc -c -o c.o c.c
cc a.o b.o c.o -o a
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'a' failed
make: *** [a] Error 1
However, you do not get automatic header dependency generation with the built-in GNU make rules. Extra 5 lines would be required for that.

Related

How can my makefile include subdirectories?

(updated for clarity) (solution added at bottom)
I found a makefile online which builds all the cpp files in that directory and compiles them.
But I can't work out how I can include files inside a subdirectory.
Here's a breakdown of what happens:
I create the files test.cpp & test.hpp and place them inside the sub-directory '/gui' which is contained within my working directory, they contain the function testFunction().
Without including test.hpp, I type "make" into terminal and I receive the error:
:
g++ -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:6:2: error: 'testFunction' was not declared in this scope
testFunction();
^~~~~~~~~~~~
make: *** [<builtin>: main.o] Error 1
If I include (#include "gui/test.hpp"), I then receive a different error:
:
g++ -c -o main.o main.cpp
g++ main.o -Wall -o testfile
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x14): undefined reference to `testFunction()'
collect2: error: ld returned 1 exit status
make: *** [makefile:34: testfile] Error 1
But if I then add "-I/gui" or (at a guess) "-I./gui" to CFLAGS, I get the exact same error message.
Here's the makefile for reference:
TARGET = testfile
LIBS =
CC = g++
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
HEADERS = $(wildcard *.hpp)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
Thanks in advance!
Updated makefile since accepted answer:
(Changes were to include directories, CC replaced with CXX, and %.c replaced with %.cpp)
TARGET = testfile
DIRS =
LDLIBS =
CXX = g++
CXXFLAGS= -g -Wall
# this ensures that if there is a file called default, all or clean, it will still be compiled
.PHONY: default all clean
default: $(TARGET)
all: default
# substitute '.cpp' with '.o' in any *.cpp
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp $(addsuffix /*.cpp, $(DIRS))))
HEADERS = $(wildcard *.h)
# build the executable
%.o: %.cpp $(HEADERS)
$(CXX) $(CXXFLAGS) -c $< -o $#
# if make is interupted, dont delete any object file
.PRECIOUS: $(TARGET) $(OBJECTS)
# build the objects
$(TARGET): $(OBJECTS)
$(CXX) $(OBJECTS) -Wall $(LDLIBS) -o $#
clean:
-rm -f *.o $(addsuffix /*.o, $(DIRS))
-rm -f $(TARGET)
To understand what's happening here you have to look up the definitions of declaration versus definition in C++ (and other languages). You should definitely do that.
A declaration (typically put into a header file) is like the address of your house. If someone wants to send you a letter, they need your address. If your main function wants to call another function like testFunction(), it needs the declaration of the function.
The first error happens because you don't have the header file included, so the compiler doesn't have the declaration of the function you want to call, which means it won't compile your calling function.
But for the letter to actually arrive, you need your actual house. The address is the declaration and your house is the definition... in this case the actual function implementation. That lives in test.cpp file. When you link your code together, the linker (in this scenario I guess the linker is like the postal service :p :) ) will try to link up the call to the definition.
However, you can see that you are not compiling the test.cpp file nor are you linking the object file:
g++ main.o -Wall -o testfile
here we see main.o, but not gui/test.o.
Why not? This line:
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp))
Matches all *.cpp files and converts them into .o files. But *.cpp matches only files in the current directory, like main.cpp. If you want to put files in a different directory you have to tell make where they are; for example:
OBJECTS = $(patsubst %.cpp, %.o, $(wildcard *.cpp gui/*.cpp))

How to convert a source c files to corresponding .o files using suffix rule in makefile?

Suppose we have a.c b.c c.c .So the make file will like this
app: a.o b.o c.o
gcc -o app.o a.o b.o c.o
a.o: a.c
gcc -c a.c
b.o: b.c
gcc -c b.c
c.o: c.c
gcc -c c.c
In the future more C files may be added. So do I need to make target of .o extensions for each .c file. I got to know about suffix rules which uses the .source-extension.target-extension. But I could understand how to use this suffix rule in the make file. Please provide me the command to be included in make file and please describe the syntax.I am newbie to makefile.
You can use the below makefile.
app: a.o b.o c.o
gcc -o $# $^
a.o : a.h
b.o : b.h
c.o : c.h
%.o: %.c
gcc -c $<
Where $# is the target(app), $^ is the list of dependencies and $< is the corresponding c file to compile to object file
Below is the sample makefile for compiling c code.
TARGET = a.out
SRCS = a.c b.c c.c
OBJS = $(SRCS:.c=.o)
CFLAGS = -g -ggdb -O2 -Wall -Werror
CC = gcc
RM = rm
.PHONY: all clean
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET) : $(OBJS)
$(CC) $^ -o $#
clean:
$(RM) *.o
$(RM) $(TARGET)

A simple Makefile that doesn't create the executable file

I have the following Makefile:
CC = gcc
OBJS = a.o b.o c.o
EXEC = prog
DEBUG = #-g for debug
CFLAGS = -std=c99 -Wall -Werror $(DEBUG)
$(EXEC) : $(OBJS)
a.o : a.c a.h b.h
b.o : b.c b.h
c.o : c.c c.h b.h
clean:
rm -f $(OBJS) $(EXEC)
It creates the object files but it doesn't create the executable file - prog.
How do I fix it?
Thanks!
$(EXEC): $(OBJS)
$(CC) -o $# $(CFLAGS) $(OBJS)
Basically, when you list multiple objects as dependencies, the implicit rules can't be used, so you have to write the command to execute yourself. The $# is a shorthand for $(EXEC) in this case; it is the target being created.

Multi-use Makefiles?

I have the files main.c, version1.c, version2.c and header.h
version1.c and version2.c are two different implementations of the same header file (header.h), and this header file is used by main.c.
Now, I want to
$ make v1
cc -c main.c
cc -c version1.c
cc -o prog main.o version1.o
or
$ make v2
cc -c main.c
cc -c version2.c
cc -o prog main.o version2.o
depending on which version of code I'm using.
I tried Conditionally appending to a variable inside a Makefile target and wrote
.PHONY: v1 v2
OBJ = main.o
v1: OBJ += version1.o
v2: OBJ += version2.o
v1 v2: prog
prog: $(OBJ)
cc -o prog $(OBJ)
%.o: %.c header.h
cc -c $<
But this quite simply does not work:
$ make v1
cc -c main.c
cc -o prog main.o version1.o
cc: version1.o: No such file or directory
make: *** [prog] Error 1
it seems that make evaluates $(OBJ) before the append when it appears in the dependency list, but after it when it appears in the command list.
Is this a bug in make? Or am I just doing it wrong? How do I do this correctly?
The target-specific modification of the variable (v1: OBJ += version1.o) applies in the body of the rule, not in the prerequisite list. Here's how I'd do it:
.PHONY: v1 v2
v1: version1.o
v2: version2.o
v1 v2: main.o
cc -o prog $^
%.o: %.c header.h
cc -c $<

Creating a FORTRAN makefile

I have a FORTRAN source code consisting of many different .F and .h files. I need to build an executable from it, but I'm having some problems. The makefile that I produced so far (which may have errors as I'm new to this) is:
# compiler
FC = /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons
# link flags
FLFLAGS = -g -fbacktrace
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F)) \
$(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FCFLAGS) $# $<
%.o: %.F
$(FC) $(FLFLAGS) -o $# $<
%.mod: %.h
$(FC) $(FLFLAGS) -o $# $<
clean:
rm -f *.o *.mod
When I try to make the program, however, I'm getting a slew of undefined reference errors. I mean, every function and subroutine call in the very first compiled .F file gives back an undefined reference error. I thought this was because gfortran was trying to link the files instead of just compiling them and then linking at the end, but I thought the '-c' option was supposed to prevent that.
UPDATE:
As commenters have pointed out, I mixed up the compile and link flags. Furthermore, you shouldn't compile *.h files. Here is the latest, corrected makefile:
# compiler
FC = /usr/bin/gfortran-4.4
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check -std=legacy
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# program name
PROGRAM = blah
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $<
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Now when I run make, it will compile each *.F file in the code, but it fails at the linking stage. I get a bunch of undefined reference errors in the very first *.F file. The compiler seems to be going over each *.F file individually in the linking stage, which I'm not sure is correct. Then I get an error:
/usr/lib/gcc/x86_64-linux-gnu/4.4.5/libgfortranbegin.a(fmain.o): In function `main':
(.text+0x26): undefined reference to `MAIN__'
collect2: ld returned 1 exit status
However, if I type the command:
gfortran -o blah *.o
The executable will be built, so it seems like I did something wrong in the makefile for the linking stage.
UPDATE: 5/9/2011
Sverre pointed out the final problem with my makefile. In my first target that builds the program, I use the shortcut command for only the first dependency ($<), but I need to include all dependencies (i.e. all *.o files) using the ($^) shortcut. The final, working makefile is as follows:
# compiler
FC := /usr/bin/gfortran-4.5
# compile flags
FCFLAGS = -g -c -fdefault-real-8 -fbacktrace -fno-align-commons -fbounds-check
# link flags
FLFLAGS =
# source files and objects
SRCS = $(patsubst %.F, %.o, $(wildcard *.F))
# $(patsubst %.h, %.mod, $(wildcard *.h))
# program name
PROGRAM = vipre
all: $(PROGRAM)
$(PROGRAM): $(SRCS)
$(FC) $(FLFLAGS) -o $# $^
%.o: %.F
$(FC) $(FCFLAGS) -o $# $<
# %.mod: %.h
# $(FC) $(FCFLAGS) -o $# $<
clean:
rm -f *.o *.mod
Are you using GNU make? If so,
$(FC) $(FLFLAGS) -o $# $<
may be the culprit. $< is the name of the first prerequisite, but you want all the *.o files. Try using $^ instead.

Resources