Reputation: 949
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
Upvotes: 2
Views: 5548
Reputation: 16910
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
...
Upvotes: 3
Reputation: 1547
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
Upvotes: 0