I have a C++ project with the source files spanning many directories, and with interdependencies in the headers (the headers of one directory include headers from other directory source).
I have a makefile looking like this :
CXX = g++
CFLAGS = -Wall -std=c++17
SRC = *.cpp ./num_utils/*.cpp ./shapes/*.cpp ./data_utils/*.cpp
all: $(SRC)
$(CXX) $(CFLAGS) $(SRC) -o main $(LDFLAGS)
I want to create a build directory where .o files get output, and modify the makefile so that I do not recompile every single file with every call to make
I get confused reading the docs, please help or point me to a beginner-friendly tutorial
This makefile is probably only dedicated to gnu-make (because of
the wildcard, patsubst, dir builtin commands and ifeq) in a unix environment (because of mkdir -p, rm -rf).
It recreates below the build directory the same directory hierarchy as the source files.
According to further questions in the comments, the ability to
choose between a debug build (opt=0 by default) and a release build
(opt=1 on the command line) has been added.
opt=0
CXX=g++
CFLAGS=-Wall -std=c++17
SRC=${wildcard *.cpp ./num_utils/*.cpp ./shapes/*.cpp ./data_utils/*.cpp}
OBJ=${patsubst %.cpp,build/%.o,${SRC}}
ifeq (${opt},0)
CFLAGS+=-g
else
CFLAGS+=-O3
endif
all: ${OBJ}
${CXX} ${CFLAGS} ${OBJ} -o main ${LDFLAGS}
build/%.o : %.cpp
mkdir -p ${dir $#}
${CXX} -o $# $< -c ${CFLAGS}
clean :
rm -rf main build
$ make clean
rm -rf main build
$ tree
.
├── data_utils
│ ├── f3.cpp
│ └── f33.cpp
├── main.cpp
├── makefile
├── num_utils
│ ├── f1.cpp
│ └── f11.cpp
└── shapes
├── f2.cpp
└── f22.cpp
3 directories, 8 files
$ make
mkdir -p build/
g++ -o build/main.o main.cpp -c -Wall -std=c++17 -g
mkdir -p build/./num_utils/
g++ -o build/./num_utils/f1.o num_utils/f1.cpp -c -Wall -std=c++17 -g
mkdir -p build/./num_utils/
g++ -o build/./num_utils/f11.o num_utils/f11.cpp -c -Wall -std=c++17 -g
mkdir -p build/./shapes/
g++ -o build/./shapes/f2.o shapes/f2.cpp -c -Wall -std=c++17 -g
mkdir -p build/./shapes/
g++ -o build/./shapes/f22.o shapes/f22.cpp -c -Wall -std=c++17 -g
mkdir -p build/./data_utils/
g++ -o build/./data_utils/f3.o data_utils/f3.cpp -c -Wall -std=c++17 -g
mkdir -p build/./data_utils/
g++ -o build/./data_utils/f33.o data_utils/f33.cpp -c -Wall -std=c++17 -g
g++ -g build/main.o build/./num_utils/f1.o build/./num_utils/f11.o build/./shapes/f2.o build/./shapes/f22.o build/./data_utils/f3.o build/./data_utils/f33.o -o main
$ make clean
rm -rf main build
$ make opt=1
mkdir -p build/
g++ -o build/main.o main.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./num_utils/
g++ -o build/./num_utils/f1.o num_utils/f1.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./num_utils/
g++ -o build/./num_utils/f11.o num_utils/f11.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./shapes/
g++ -o build/./shapes/f2.o shapes/f2.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./shapes/
g++ -o build/./shapes/f22.o shapes/f22.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./data_utils/
g++ -o build/./data_utils/f3.o data_utils/f3.cpp -c -Wall -std=c++17 -O3
mkdir -p build/./data_utils/
g++ -o build/./data_utils/f33.o data_utils/f33.cpp -c -Wall -std=c++17 -O3
g++ -Wall -std=c++17 -O3 build/main.o build/./num_utils/f1.o build/./num_utils/f11.o build/./shapes/f2.o build/./shapes/f22.o build/./data_utils/f3.o build/./data_utils/f33.o -o main
$ ./main
in main()
in f1()
in f2()
in f3()
in f11()
in f22()
in f33()
$ make --version
GNU Make 4.3
Built for x86_64-pc-linux-gnu
...
I would start with a template like this, where a list of object files is dynamically created from the C++ source files using wildcard and patsubt. You can then use a pattern rule to build the object files automatically. Specify a dependency for default make command to check if any in $(OBJS) needs building to avoid rebuilds:
OBJ=obj/
SRC=src/
INCLUDE=include/
OBJS=$(patsubst %.cpp, %.o, $(wildcard $(SRC)*.cpp))
$(OBJ)%.o : $(SRC)%.cpp
g++ -c $(INCLUDE) $< -o $#
all: $(OBJS)
g++ main.cpp -o main
Related
Makefile
# Assignments
#########################################################
CC := g++
SRC := src
BUILD := build
INCLUDE := include
TARGET := bin/driver
LIB := lib
TESTS := tests
CFLAGS := -g -Wall -Wextra
PATH := -I $(INCLUDE)
#########################################################
driver: Logbook.o Entry.o main.o
g++ Logbook.o Entry.o main.o -o driver
main.o: main.cpp
g++ -c main.cpp
Logbook.o:
g++ -c $(PATH) $(LIB)/Logbook.cpp
Entry.o:
g++ -c $(PATH) $(LIB)/Entry.cpp
test:
g++ -c $(PATH) $(LIB)/Logbook.cpp
clean:
rm -f *.o *.exe driver
STDOUT
mint#mint-VirtualBox ~/Desktop/Logbook $ ls
googletest include lib main.cpp Makefile README.md src
mint#mint-VirtualBox ~/Desktop/Logbook $ make
g++ -c -I include lib/Logbook.cpp
make: g++: Command not found
Makefile:47: recipe for target 'Logbook.o' failed
make: *** [Logbook.o] Error 127
mint#mint-VirtualBox ~/Desktop/Logbook $ ls
googletest include lib main.cpp Makefile README.md src
mint#mint-VirtualBox ~/Desktop/Logbook $ g++ -c -I include lib/Logbook.cpp
mint#mint-VirtualBox ~/Desktop/Logbook $ ls
googletest include lib Logbook.o main.cpp Makefile README.md src
mint#mint-VirtualBox ~/Desktop/Logbook $
The result expected is that g++ works while being called from inside the makefile but clearly doesn't
What exactly is going on here? there are tabs where there should be and running the compilation command while in the terminal works but the Makefile just doesn't want to agree that the g++ command exists.
Don't call the variable PATH, it overrides the default environment variable that tells the Makefile where to look for binaries. Just rename it to CCFLAGS or so.
CCFLAGS := -I $(INCLUDE)
Logbook.o:
g++ -c $(CCFLAGS) $(LIB)/Logbook.cpp
More details on PATH e.g. here: https://en.wikipedia.org/wiki/PATH_(variable)
i'm trying to use the boost_math libs on OS X (i'm not using Xcode), specifically the one containing the error function
I downloaded and compiled boost_1_60_0 myself (using bootstrap.sh and following the instructions.) I didn't use home-brew or something else, which might be why my installation seems so screwed up.
What i'm trying to include in my Szabo.hpp is this:
#include <boost/math/special_functions/erf.hpp>
My makefile goes like this:
LIB_FLAGS = -L/Documents/boost_1_60_0/stage/lib -lboost_math
ALL_OBJECTS = main.o Gaussienne.o Grille.o Szabo.o
all: $(ALL_OBJECTS)
g++ -o hydrogene $(ALL_OBJECTS) $(LIB_FLAGS)
Gaussienne.o: Gaussienne.cpp
g++ -o Gaussienne.o -c Gaussienne.cpp -W -Wall -ansi
main.o: Gaussienne.hpp Grille.hpp main.cpp Szabo.o
g++ -o main.o -c main.cpp -W -Wall -ansi
Grille.o: Grille.cpp Gaussienne.cpp
g++ -o Grille.o -c Grille.cpp -W -Wall -ansi
Szabo.o: Szabo.cpp Gaussienne.cpp
g++ -o Szabo.o -c Szabo.cpp -W -Wall -ansi
clean:
rm -rf *.o
mrproper: clean
rm -rf hydrogene
I get no linking error from g++, however i got:
In file included from Szabo.cpp:12:
./Szabo.hpp:21:10: fatal error: 'boost/math/special_functions/erf.hpp' file not found
#include <boost/math/special_functions/erf.hpp>
^
1 error generated.
Can you please provide help on how to fix this? Thanks in advance
Ok so apparently likes this, it works:
LIB_FLAGS = -L/Users/devolution/Documents/boost_1_60_0/stage/lib -lboost_math_tr1
I_FLAGS = -I/Users/devolution/Documents/boost_1_60_0/
ALL_OBJECTS = main.o Gaussienne.o Grille.o Szabo.o
all: $(ALL_OBJECTS)
g++ -o hydrogene $(ALL_OBJECTS) $(LIB_FLAGS)
Gaussienne.o: Gaussienne.cpp
g++ -o Gaussienne.o -c Gaussienne.cpp -ansi ${I_FLAGS}
main.o: Gaussienne.hpp Grille.hpp main.cpp Szabo.o
g++ -o main.o -c main.cpp -ansi ${I_FLAGS}
Grille.o: Grille.cpp Gaussienne.cpp
g++ -o Grille.o -c Grille.cpp -ansi ${I_FLAGS}
Szabo.o: Szabo.cpp Gaussienne.cpp
g++ -o Szabo.o -c Szabo.cpp -ansi ${I_FLAGS}
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper: clean
rm -rf hydrogene
Is there a way to pass I_FLAGS?
You've compiled Boost's separately-compiled libraries, which is great, but you didn't copy the headers to your toolchain's include path. Indeed, most of Boost is comprised of header-only libraries, so this is arguably the more crucial step of installing Boost.
The internet tells me you may be able to find the default header search path with the following command at shell:
gcc -x c++ -v -E /dev/null
(https://stackoverflow.com/a/19852298/560648)
When you find it, copy the distribution's boost subdirectory to it.
And, yes, having home-brew install Boost for you would have been much easier… probably one command!
I have a assign4a.cpp, list.h, and list.cpp file. I compiled them with my make file but don't know what command I would use to run the program.
What I tried to run have tried
a.out and ./a.out
both of them give me "Command not found"
Makefile
CFLAGS = -c -Wall -g
LFLAGS = -g -o assign4a
assign4a: assign4a.o list.o
g++ assign4a.o list.o $(LFLAGS)
assign4a.o: assign4a.cpp list.h
g++ $(CFLAGS) assign4a.cpp
list.o: list.cpp list.h
g++ $(CFLAGS) list.cpp
clean:
rm -f assign4a *.o *~ *#
./assign4a.
Your makefile will build the program and put a executable assign4a to the working folder.
And, your makefile is wrong.
It should be g++ $(CFLAGS) assign4a.cpp -o assign4a.o and g++ $(CFLAGS) list.cpp -o list.o.
You need to call
./assign4a
Makefile defines targets and dependencies between them. Here:
assign4a: assign4a.o list.o
g++ assign4a.o list.o $(LFLAGS)
assign4a is a target, that depends on files assign4a.o, list.o, and to build target is needed to run g++ assign4a.o list.o $(LFLAGS).
I am doing a c++ project with multiple source files and trying to get used to using makefiles. I want to be able to debug this program with gdb. If I use the following command in Terminal to compile, it works fine:
g++ -o main -g *.cpp
But if I just call make it doesn't generate a debug file (the .dSYM file) even though it compiles the program fine. I assume this has something to do with creating the individual object files first. Here is my makefile:
all: main.o sort.o bubble.o quickSort.o rbs.o
g++ -g -o main *.o -Wall -O2
main.o: main.cpp
g++ -c main.cpp
sort.o: sort.cpp sort.h
g++ -c sort.cpp
bubble.o: bubble.cpp bubble.h
g++ -c bubble.cpp
quickSort.o: quickSort.cpp quickSort.h
g++ -c quickSort.cpp
rbs.o: rbs.cpp rbs.h
g++ -c rbs.cpp
clean:
rm *.o
How do I create the main.dSYM debug file when using a makefile like this?
If you want the debug files, you must compile all of the components with -g.
The crude way to do this would be to add -g to every object rule:
all: main.o sort.o bubble.o quickSort.o rbs.o
g++ -g -o main *.o -Wall -O2
main.o: main.cpp
g++ -c -g main.cpp
sort.o: sort.cpp sort.h
g++ -c -g sort.cpp
bubble.o: bubble.cpp bubble.h
g++ -c -g bubble.cpp
quickSort.o: quickSort.cpp quickSort.h
g++ -c -g quickSort.cpp
rbs.o: rbs.cpp rbs.h
g++ -c -g rbs.cpp
But that doesn't leave you the option of building without debug information. And there's a lot of redundancy in this makefile. Let's take this in stages. First, we put in automatic variables to simplify the rules:
all: main.o sort.o bubble.o quickSort.o rbs.o
g++ -g -o main $^ -Wall -O2
main.o: main.cpp
g++ -c -g $<
sort.o: sort.cpp sort.h
g++ -c -g $<
bubble.o: bubble.cpp bubble.h
g++ -c -g $<
quickSort.o: quickSort.cpp quickSort.h
g++ -c -g $<
rbs.o: rbs.cpp rbs.h
g++ -c -g $<
Now we see that all of the *.o rules have the same command, which reminds us that Make already knows how to build foo.o from foo.cpp, with a command that looks like:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c
So all we have to do is add -g to CXXFLAGS, and we can omit the commands entirely:
CXXFLAGS += -g
all: main.o sort.o bubble.o quickSort.o rbs.o
g++ -g -o main $^ -Wall -O2
sort.o: sort.h
bubble.o: bubble.h
quickSort.o: quickSort.h
rbs.o: rbs.h
Now that that's in order, we can set up two top-level targets, main and debug, and change CXXFLAGS only for the latter:
debug: CXXFLAGS += -g
main debug: main.o sort.o bubble.o quickSort.o rbs.o
g++ -g -o $# $^ -Wall -O2
sort.o: sort.h
bubble.o: bubble.h
quickSort.o: quickSort.h
rbs.o: rbs.h
You can improve this even more, but that should get you started.
So, client.o and server.o are not being compiled... but the make file doesn't error...
I've checked the directory where all the code is and the sub folders. but client and server .o just aren't there... =\
here is my make file:
main_objects = src/main.o src/fann_utils.o src/Config.o
network_objects = src/neural_network_basic.o
hash_objects = src/hashes.o src/hashes/Murmur.o
cloud_objects = src/cloud/client.o src/cloud/server.o
all_objects = $(main_objects) $(hash_objects) $(network_objects) $(cloud_objects)
all: hPif clean
hPif : $(all_objects)
g++ -o hPif $(all_objects) -lfann -L/usr/local/lib
src/cloud/client.o : src/cloud/chat_client.cpp src/cloud/chat_message.hpp
g++ -c src/cloud/chat_client.cpp
src/cloud/server.o : src/cloud/chat_server.cpp src/cloud/chat_message.hpp src/cloud/chat_server.h
g++ -c src/cloud/chat_server.cpp
neural_network_basic.o : src/neural_network_basic.cpp src/neural_network_basic.h
g++ -c src/neural_network_basic.cpp
hashes/Murmur.o : src/hashes/Murmur.cpp src/hashes/Murmur.h
g++ -c src/hashes/Murmur.cpp
Config.o : src/Config.cpp src/Config.h
g++ -c src/Config.cpp
hashes.o : src/hashes.cpp src/hashes.h
g++ -c src/hashes.cpp
fann_utils.o: src/fann_utils.cpp fann_utils.h
g++ -c src/fann_utils.cpp
main.o: src/main.cpp src/main.h
g++ -c src/main.cpp
clean:
rm -rf src/cloud/*.o
rm -rf src/hashes/*.o
rm -rf src/*.o
rm -rf *.o
Console output looks like this:
g++ -c -o src/main.o src/main.cpp
g++ -c -o src/fann_utils.o src/fann_utils.cpp
g++ -c -o src/Config.o src/Config.cpp
g++ -c -o src/hashes.o src/hashes.cpp
g++ -c -o src/hashes/Murmur.o src/hashes/Murmur.cpp
g++ -c -o src/neural_network_basic.o src/neural_network_basic.cpp
g++ -c src/cloud/chat_client.cpp
g++ -c src/cloud/chat_server.cpp
g++ -o hPif src/main.o src/fann_utils.o src/Config.o src/hashes.o src/hashes/Murmur.o src/neural_network_basic.o src/cloud/client.o src/cloud/server.o -lfann -L/usr/local/lib
i686-apple-darwin10-g++-4.2.1: src/cloud/client.o: No such file or directory
i686-apple-darwin10-g++-4.2.1: src/cloud/server.o: No such file or directory
make: *** [hPif] Error 1
g++ -c src/cloud/chat_client.cpp will build an object file called chat_client.o, not client.o. Either add -o $# to the rule to create an object file with the same name as the target, or rename the file to chat_client.o everywhere it's mentioned in the makefile.