Search code examples
c++buildmakefilecmakescons

Building multiple targets off same source tree with different preprocessor macros


My knowledge of make and autotools (which I'm not yet using for this project) is rudimentary at best despite plenty of googling and experimenting over a long period of time. I have a source hierarchy like below that I'm trying to find way to build has seamlessly as possible.

The application is made up of a main application with source in various subfolders under app/src. These are built with the respective Makefile in the root of that folder.

Then I have multiple other utilities that reside different folders under app/tools that each have their own Makefile.

app/src/module1/file1.cpp
app/src/module1/file1.hpp
app/src/module2/file2.cpp
app/src/module2/file2.hpp
app/src/module3/file3.cpp
app/src/module3/file3.hpp
app/src/main.cpp
app/src/main.hpp
app/src/Makefile
app/tools/util1/file1.cpp
app/tools/util1/file1.hpp
app/tools/util1/Makefile
app/tools/util2/file2.cpp
app/tools/util2/file2.hpp
app/tools/util2/Makefile

The problem for me is that some of these tools depend on source files inside the app/src source folder, but with a preprocess macro EXTERNAL_TOOL enabled. So the object files generated from compiling the main app and the varous utilities are not compatible.

Currently to build each portion of the project I'm having to clean the source tree in between. This is painful and certainly not what I want in the end. What would be the best way to go about solving this? Ideas I've had that I've no been able to put into practice are:

  1. Separate build directory for each portion of the project
  2. When building the external tools, tagging their object files in the main app source tree somehow (util.file1.o?)

I'm not too sure I have the time and patience needed to master make / autotools. Might one of the other build tools (scons? cmake?) make this kind of task easier to accomplish? If so which one?

UPDATE: This is what I've got now

SOURCES := util1.cpp util2.cpp util3.cpp \
    ../../src/module1/file1.cpp \
    ../../src/module1/file2.cpp \
    ../../src/module1/file3.cpp \
    ../../src/module2/file4.cpp \
    ../../src/module3/file5.cpp \
    ../../src/module3/file6.cpp \
    ../../src/module4/file7.cpp \
    ../../src/module4/file8.cpp \
    ../../src/module3/file9.cpp \
    ../../src/module4/file10.cpp \
    ../../src/module5/file11.cpp \
    ../../src/module3/file12.cpp \
    ../../src/module1/file13.cpp \
    ../../src/module3/file14.cpp \
    ../../src/module3/file15.cpp

OBJECTS = $(join $(addsuffix .util/, $(dir $(SOURCES))), $(notdir $(SOURCES:.cpp=.o)))

.PHONY: all mkdir
all: util
util: $(OBJECTS)
    $(CXX) $(CXXFLAGS) $(OBJECTS) $(LIBS) -o util

$(OBJECTS): | mkdir
    $(CXX) -c $(CXXFLAGS) -o $@ $(patsubst %.o,%.cpp,$(subst .util/,,$@))

mkdir:
    @mkdir -p $(sort $(dir $(OBJECTS)))

clean:
    -@rm -f $(OBJECTS) util
    -@rmdir $(sort $(dir $(OBJECTS))) 2>/dev/null

I came about this after extensive googling SO browsing. This seems to work, but this part doesn't really seem particular nice (feels like a bit of a hack):

$(OBJECTS): | mkdir
    $(CXX) -c $(CXXFLAGS) -o $@ $(patsubst %.o,%.cpp,$(subst .util/,,$@))

In particular I'm not too keen on the fact I'm creating the list of objects from sources earlier on and adding the suffix, only to do the reverse down here. I couldn't seem to get it working any other way.


Solution

  • CMake has add_definitions and remove_definitions commands. You can use them to define macros for different parts of your project:

    # building tools #
    add_definitions(-DEXTERNAL_TOOL)
    add_subdirectory($TOOL1$ $BUILD_DIR$)
    add_subdirectory($TOOL2$ $BUILD_DIR$)
    ...
    
    # building main app #
    remove_definitions(-DEXTERNAL_TOOL)
    add_executable(...)