user1830663
user1830663

Reputation: 571

Makefile for many c++ executables

I am working on a project where I constantly need to create new c++ executables. They all rely on some common headers and sources files, so I am wondering how to simplify the compilation and Makefile writing. The best I have come up with so far is something like this:

file1: $(BUILDDIR)/[email protected] $(COMMON_OBJECTS) $(COMMON_LIBS)
    $(CCCOM) $(CCFLAGS) $(BUILDDIR)/[email protected] $(COMMON_OBJECTS) -o $(BINDIR)/$@ $(LIBFLAGS)

and then I have to copy this target for each executable I want to add. Ideally I want to define this rule once for arbitrary target and then simply call make any_file_name.

Is something like that possible? How do people organize c++ project with lots of executables? (I am new to c++ and coming from python that is a very natural thing)

Upvotes: 0

Views: 202

Answers (3)

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136485

Here is an example makefile with automatic header dependency generation for you:

BUILD := debug
BUILD_DIR := ${BUILD}

CXX := g++

cppflags.debug :=
cppflags.release := -DNDEBUG
cppflags := ${cppflags.${BUILD}} ${CPPFLAGS}

cxxflags.debug :=
cxxflags.release := -O3
cxxflags := ${cxxflags.${BUILD}} ${CXXFLAGS}

ldflags := ${LDFLAGS}
ldlibs := ${LDLIBS}

exes := # Executables to build.

### Define executables begin.

exes += exe1
exe1.obj := exe1.o

exes += exe2
exe2.obj := exe2.o

### Define executables end.

all : ${exes:%=${BUILD_DIR}/%}

.SECONDEXPANSION:

${BUILD_DIR}:
    mkdir -p $@

# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${@D}
    ${CXX} -o $@ ${ldflags} $^ ${ldlibs}

# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : %.cc | $${@D}
    ${CXX} -o $@ -c ${cppflags} ${cxxflags} -MD -MP $<

# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif

clean:
    rm -rf $(BUILD_DIR)

.PHONY: all clean

Usage example:

$ cat exe1.cc 
#include <iostream>
int main() { std::cout << "Hello, world!\n"; }

$ cat exe2.cc 
#include <iostream>
int main() { std::cout << "Hello, world!\n"; }

$ make
mkdir -p debug
g++ -o debug/exe1.o -c     -MD -MP exe1.cc
g++ -o debug/exe1  debug/exe1.o 
g++ -o debug/exe2.o -c     -MD -MP exe2.cc
g++ -o debug/exe2  debug/exe2.o 

$ make BUILD=release 
mkdir -p release
g++ -o release/exe1.o -c -DNDEBUG  -O3  -MD -MP exe1.cc
g++ -o release/exe1  release/exe1.o 
g++ -o release/exe2.o -c -DNDEBUG  -O3  -MD -MP exe2.cc
g++ -o release/exe2  release/exe2.o 

$ make clean
rm -rf debug

$ make BUILD=release clean
rm -rf release

Upvotes: 0

HEKTO
HEKTO

Reputation: 4191

To simplify everything I'm assuming you have sources file1.cpp, file2.cpp and so on, and all your files reside in the same directory. Then Makefile fragment below will do what you want:

all: $(basename $(wildcard file?.cpp))

file%: file%.cpp

To make everyhing:

make all

To make file1:

make file1

To make file1 and file2:

make file1 file2

Upvotes: 0

DevSolar
DevSolar

Reputation: 70372

You could make it so that each executable corresponds to a single .cpp file in a directory (e.g. executables/foo.cpp, executables/bar.bpp), and then work from there -- this will save you from having to touch the Makefile every time you add another one.

You should, probably, also set up your project to create a shared library, which the (light-weight) executables link to. (The executables effectively just doing some command-line parsing, and offloading the actual work to library functions.) This way, you will not end up with the code from those $(COMMON_OBJECTS) being replicated in every executable.

Upvotes: 0

Related Questions