Reputation: 571
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
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
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
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