volatile
volatile

Reputation: 949

Makefile: create a build directory

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

Answers (2)

prog-fh
prog-fh

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

jackw11111
jackw11111

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

Related Questions