how Makefiles work exactly - makefile

I'm writing a code for my gtk application written in C, and have some questions about it.
# Compiler
CC = gcc
CFLAGS = -Wall -g -o
RM = rm -f
# ADDITIONAL HEADER PATH
GTKINC = `pkg-config --cflags gtk+-3.0`
GTKLIB = `pkg-config --libs gtk+-3.0`
INC = $(GTKINC)
LIBLNK = $(GTKLIB)
# SOURCES, OBJECTS, EXECUTABLE
SRCS = hello.c
OBJS = $(SRCS:.c = .o)
EXEC = hello
.PHONY: clean
all: $(EXEC)
#echo compile complete
$(EXEC): $(OBJS)
$(CC) $(INC) $(CFLAGS) $(EXEC) $(OBJS) $(LIBLNK)
clean:
$(RM) *.o *~ $(EXEC)
previously, when I wrote Makefiles,I added lines for each object files
for example
blah blah
a.o: 1.h A.c B.c
$(CC) blah blah
blah blah
and then, I got a little lazy and tried to do make something more easy-to-modify file
googling up, and finally the product is the above code.
1. Does this actually do the same thing as what I did previously?(like in the example)
I found out the code compiles properly, but I'm not sure if it checks out-of-date
object files.(which is the whole meaning of 'make')
2. do you have to use 'depend' on header files in order to check out-of-date source files??
3. it's a bit out of subject, but what's the difference between
gcc -o hello.o hello.h hello.c and
gcc -c hello.c ?

2. do you have to use 'depend' on header files in order to check out-of-date source files
You should auto-generate dependencies on header files. See https://stackoverflow.com/a/9598716/412080

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))

Why does undefined reference disappear after adding a .cpp file with empty main function when building shared library

I have makefile that builds shared library libsimpletron.so:
#shell
MKDIR_P = mkdir -p
#compiler
CC = g++
#cpp flags
FLAGS = -std=c++1z
CPPFLAGS = -fPIC -Wall -Wextra
LDFLAGS = -shared
#directories
INC_DIR = ../inc
LIB_DIR = ../lib
BIN_DIR = ../bin
OBJ_DIR = ./obj
ALG_DIR = ./algebra
SOURCES = $(shell echo *.cpp)
HEADERS = $(shell echo $(INC_DIR)/*.h)
_OBJECTS = $(SOURCES:.cpp=.o)
OBJECTS = $(patsubst %,$(OBJ_DIR)/%,$(_OBJECTS))
ALGEBRA = $(LIB_DIR)/libalgebra.so
TARGET = $(LIB_DIR)/libsimpletron.so
.PHONY: directories
all : directories $(ALGEBRA) $(TARGET)
directories: $(OBJ_DIR) $(BIN_DIR) $(LIB_DIR)
$(OBJ_DIR):
$(MKDIR_P) $(OBJ_DIR)
$(BIN_DIR):
$(MKDIR_P) $(BIN_DIR)
$(LIB_DIR):
$(MKDIR_P) $(LIB_DIR)
$(ALGEBRA):
$(MAKE) -C $(ALG_DIR)
$(OBJ_DIR)/%.o: %.cpp $(HEADERS)
$(CC) -c $(FLAGS) $(CPPFLAGS) -o $# $<
$(TARGET) : $(OBJECTS)
$(CC) $(LDFLAGS) -o $# $^
.PHONY: clean
clean:
rm -f $(OBJ_DIR)/*.o
make command builds library successfully (I think) :
g++ -c -std=c++1z -fPIC -Wall -Wextra -o obj/builder.o builder.cpp
...similar lines for each .cpp file...
g++ -shared -o ../lib/libsimpletron.so obj/builder.o obj/gradient_trainer.o obj/layer.o obj/neuron.o obj/perceptron.o obj/simpletron.o obj/trainer.o
Then I am trying to use this library. I compile my test xor as follows:
#compiler
CC = g++
#cpp flags
FLAGS = -std=c++1z
PUGI = -l pugixml
#directories
LIB_DIR = /home/lrdprdx/Projects/SimplePerceptron/lib
SIMPLETRON = -lsimpletron
ALGEBRA = -lalgebra
XOR = xor
SOURCE = xor.cpp
#config file
CONFIG = config.xml
$(XOR) : $(SOURCE) $(CONFIG)
$(CC) $(FLAGS) -L$(LIB_DIR) $(SIMPLETRON) $(ALGEBRA) $(PUGI) -o $(XOR) $(SOURCE)
But when I try to compile this I get errors of undefined reference to .... OK, though I do not understand why those errors exist, I found that adding a .cpp file with an empty main function to the directory with other .cpp files fixes all the stuff:
//empty.cpp
int main()
{
return 0;
}
And after rebuild the shared library I make and execute xor successfully.
The question is: what is going on here?
I doubt that adding the extra file really fixed anything. Most likely some other side-effect helped.
Your problem is that your link line is incorrect. GCC, like most UNIX linkers, is a single-pass linker. That means it only walks all the libraries one time looking for unresolved symbols. And that means that the order of the arguments to the linker is critically important: you have to ensure that if item A references symbols in item B, that A comes before B on the link line.
In your example, you are putting all your libraries first, and your source files last. So, when make starts looking at your libraries it hasn't seen your sources yet, and there are no symbols it needs to link. By the time it compiles your sources, there are no libraries left to resolve symbols from.
Your link line should be arranged with sources and object files first, then libraries (in referencer ... referencee order):
$(CC) $(FLAGS) $(SOURCE) -L$(LIB_DIR) $(SIMPLETRON) $(ALGEBRA) $(PUGI) -o $(XOR)

extra CFLAGs with Makefile

I'm reading through Foundations of GTK+ and in so doing decided to write a simple makefile that would let me run "make " to compile the example program I'd just written. I also stumbled upon a list of compiler directives here that the Gnome team specified will help moving from GTK2 to GTK3, so I wanted to include those.
I'm a make noob for all intents and purposes, so this is what I came up with:
CC = gcc
CFLAGS += -Wall
GTK_DFLAGS = -DGTK_DISABLE_SINGLE_INCLUDES -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE
GTK_CFLAGS = $(shell pkg-config --cflags gtk+-3.0)
GTK_LDFLAGS = $(shell pkg-config --libs gtk+-3.0)
%.o: %.c
$(CC) $(CFLAGS) $(GTK_DFLAGS) $(GTK_CFLAGS) -c -o $# $<
%: %.o
$(CC) $(CFLAGS) $(GTK_DFLAGS) $(GTK_CFLAGS) $(GTK_LDFLAGS) -o $# $<
.PHONY: clean
clean:
rm -f *.o *~
And as you might guess, it doesn't work quite right. I know running pkg-config from inside the makefile isn't an ideal solution, but this is for my small-scale learning projects and not for deployment of any sort. That said, the output is weird to me; it seems like make just ignores any variables after CFLAGS.
Something like:
[patrick#blackbox ch2]$ make helloworld
gcc -Wall helloworld.c -o helloworld
helloworld.c:1:21: fatal error: gtk/gtk.h: No such file or directory
#include <gtk/gtk.h>
^
compilation terminated.
<builtin>: recipe for target 'helloworld' failed
make: *** [helloworld] Error 1
If I add have the contents of GTK_DFLAGS simply tacked onto the end of CFLAGS, they appear on the command line, but the pkg-config variables are still missing.
It's obvious to me that I messed something simple up, but after an hour of vaguely worded Googling, I'm fresh out of ideas as to what it is.
Found the answer, and of course the vocabulary I was missing when asking this question/doing earlier searches.
CC = gcc
CFLAGS += -Wall -std=c11
GTK_DFLAGS = -DGTK_DISABLE_SINGLE_INCLUDES -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE
GTK_CFLAGS := $(shell pkg-config --cflags gtk+-3.0)
GTK_LDFLAGS := $(shell pkg-config --libs gtk+-3.0)
%: %.c
$(CC) $(CFLAGS) $(GTK_DFLAGS) $(GTK_CFLAGS) $(GTK_LDFLAGS) -o $* $*.c
.PHONY: clean
clean:
rm -f *~
This does what I want, which is to compile a single .c file of any name into a program of the same name with the GTK flags I was looking to use.
Thanks to those who contributed!
You need a target for helloworld in your Makefile. Something like this:
helloworld: helloworld.o
$(CC) -o helloworld helloworld.o $(LDFLAGS) $(GTK_LDFLAGS)

Multiple targets and libraries in Makefile

I have this folder/files structure:
./libs/
helpers.c
helpers.h
./a_app.c
./b_app.c
./c_app.c
Each app depends on helpers lib and GStreamer, so I need to compile helpers.o (inside libs/ folder) and then link each app.
Currently I have this Makefile:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LDFLAGS =
LDFLAGS += `pkg-config --libs gstreamer-app-0.10`
all: examples
examples: helpers.o a_app
$(info *** examples ***)
helpers.o:
$(info *** helpers.o ***)
$(CC) $(LFLAGS) libs/helpers.c -o libs/helpers.o $(LDFLAGS)
a_app: a_app.o
$(CC) $(CFLAGS) libs/helpers.o a_app.o -o a_app $(LDFLAGS)
a_app.o: a_app.c
$(info *** a_app.o ***)
$(CC) $(LFLAGS) a_app.c $(LDFLAGS)
While I could add b_appand c_app I'm looking for another (more elegant) way of doing it. Can't I just say that I have a, b and c _app and let Makefile compile them all and link them against GStreamer and helpers?
Also, is there any way to make Makefile compile files without needing to tell it -o name_of_file (and perhaps make it compile them in the folder that they are, because of the helpers library).
Okay, so - as we discussed in the comments, make can figure out how to make the .o files, so those rules are unnecessary. To make a generalized rule for all your *_app files (assuming they all have the same dependency on helpers.h, you can do this:
%_app: %_app.o libs/helpers.o
Make uses the % as a wildcard, and in the rule/dependency line the wildcard will expand to the same thing in the dependencies as it did in the rule. In the actual execution, you can use $* to get the same string. So a single rule for all your *_app executables winds up looking a bit like this:
%_app: %_app.o libs/helpers.o
$(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)
I was testing this on my machine (hence comments instead of answers, and wound up writing this Makefile:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LFLAGS += `pkg-config --cflags gstreamer-app-0.10`
LDFLAGS =
LDFLAGS += `pkg-config --libs gstreamer-app-0.10`
new: clean all
clean:
rm -rf *.o */*.o *_app
all: examples
examples: a_app b_app
%_app: %_app.o libs/helpers.o
$(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)
Does that all make sense?
EDIT: It occurs to me that GNU Make can run some commands on the command line and store the string for its own purposes.
$(shell ls *_app.c | sed 's/.c//') will expand into all the apps you have in the current directory. so you can say:
examples: $(shell ls *_app.c | sed 's/\.c//')
Or, as I think is a little better:
...
ALLAPPS = $(shell ls *_app.c | sed 's/\.c//')
...
all: $(ALLAPPS)
That way make can be used to make everything, and make ?_app can be used to compile one app at a time.
Super ultra mega double EDIT:
Using a bald % operator as a target will bust up Make's ability to auto generate .o files. Here's the solution we worked out in chat:
CC = gcc
CFLAGS = -g -Wall -w
LFLAGS = -g -Wall -w -c
CFLAGS += $(shell pkg-config --cflags gstreamer-app-0.10)
LFLAGS += $(shell pkg-config --cflags gstreamer-app-0.10)
LDFLAGS =
LDFLAGS += $(shell pkg-config --libs gstreamer-app-0.10)
TARGETS = $(shell ls *.c | sed 's/\.c//')
new: clean all
clean:
rm -rf *.o */*.o *_app
all: examples
examples: $(TARGETS)
.SECONDEXPANSION:
$(TARGETS): libs/helpers.o $$#.o
$(CC) $(CFLAGS) libs/helpers.o $#.o -o $# $(LDFLAGS)

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