Create multiple targets from the same source tree using different preprocessor macros

My knowledge of make and autotools (which I am not yet using for this project) is rudimentary at best, despite a lot of searches and experimentation over a long period of time. I have an original hierarchy as shown below that I am trying to find a way to build as much as possible.

The app is made up of the main app, with the source in different subfolders in app / src. They are created with an appropriate Makefile in the root folder of that folder.

Then I have several other utilities that are in different folders in the / tools application, each with its 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 source app / src folder, but with the EXTERNAL_TOOL preprocess macro enabled. Thus, the object files generated by compiling the main application and the varous utility are not compatible.

Currently, to create each part of the project, I need to clear the source tree in between. This is painful and certainly not what I want in the end. What would be the best way to solve this? Ideas I had that I could not put into practice:

  • Split build directory for each part of the project
  • When creating external tools, tagging their object files in the main tree of the source application somehow (util.file1.o?)

I'm not too sure if I have the time and patience required to master make / autotools. Could one of the other build tools (scons? Cmake?) Make this task easier to accomplish? If so, which one?

UPDATE: This is what I have 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 to this after doing extensive internet searching. It seems to work, but this part doesn't really seem particularly nice (seems a bit hacky):

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

      

In particular, I'm not too keen on the fact that I was creating a list of objects from sources earlier and adding a suffix, only to do the opposite here. I couldn't get it to work in any other way.

+3


source to share


2 answers


CMake has commands add_definitions

and remove_definitions

. 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(...)

      

+5


source


This can be done painlessly with SCons. You will definitely need a build directory hierarchy for objects built using various preprocessor macros. In SCons terms, creating directories like this is called variant_dir. I would recommend the following SCons assembly hierarchical structure:

app/SConstruct
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/SConscript_modules
app/src/SConscript_main
app/tools/util1/file1.cpp
app/tools/util1/file1.hpp
app/tools/util2/file2.cpp
app/tools/util2/file2.hpp
app/tools/SConscript
app/build/main/
app/build/target1/modules/
app/build/target2/modules/
app/build/tools/utils/

      

To be able to create the same source files with different preprocessor macros, you will need to create the same file with several different environments. These envs can be configured in src / module SConscript scripts or from root SConstruct and piped down. I prefer the second option as it makes the src / module SCons modular and is not aware (agnostic) of preprocessor macros.

Here is a root build script that creates various envs and organizes the build scripts for the subdirectory:

app / SConstruct



defines1 = ['MACRO1']
defines2 = ['MACRO2']

env1 = Environment(CPPDEFINES = defines1)
env2 = Environment(CPPDEFINES = defines2)

includePaths = [
  'src/module1',
  'src/module2',
  'src/module3',
]
env1.Append(CPPPATH = includePaths)
env2.Append(CPPPATH = includePaths)

# Build different versions of the module libs
SConscript('src/SConscript_modules',
           variant_dir = '#build/target1/modules',
           exports = {'env':env1},
           duplicate=0)
SConscript('src/SConscript_modules',
           variant_dir = '#build/target2/modules',
           exports = {'env':env2},
           duplicate=0)

# Build main with env1
SConscript('src/SConscript_main',
           variant_dir = '#build/main',
           exports = {'env':env2},
           duplicate=0)

# Build tools with env2
SConscript('tools/SConscript',
           variant_dir = '#build/utils',
           exports = {'env':env2},
           duplicate=0)

      

This is the assembly script for the main application / SRC / SConscript _main

Import('env')

sourceFiles = ['main.cpp']
# If you want to modify the env here, Clone() it first, otherwise
# the changes will be visible to all other SConscripts
env.Program(target = 'main', source = sourceFiles)

      

This is the build script for the libs modules, it will be called twice, each time with a different env application / SRC / SConscript _modules

Import('env')

module1SourceFiles = ['file1.cpp']
module2SourceFiles = ['file2.cpp']
module3SourceFiles = ['file3.cpp']

# If you want to modify the env here, Clone() it first, otherwise
# the changes will be visible to all other SConscripts
env.Library(target = 'module1', source = module1SourceFiles)
env.Library(target = 'module2', source = module2SourceFiles)
env.Library(target = 'module3', source = module3SourceFiles)

      

+1


source







All Articles