Построение нескольких целей из одного исходного дерева с разными макросами препроцессора

Мои знания делать а также Autotools (который я пока не использую для этого проекта) в лучшем случае рудиментарен, несмотря на то, что много гуглит и экспериментирует в течение длительного периода времени. У меня есть исходная иерархия, подобная приведенной ниже, и я пытаюсь найти способ ее создания как можно более плавно.

Приложение состоит из основного приложения с источником в различных подпапках в app / src. Они создаются с соответствующим Makefile в корне этой папки.

Затем у меня есть несколько других утилит, которые находятся в разных папках в app / tools, каждый из которых имеет свой собственный 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

Для меня проблема в том, что некоторые из этих инструментов зависят от исходных файлов в исходной папке app / src, но с включенным макросом предварительной обработки EXTERNAL_TOOL. Поэтому объектные файлы, созданные при компиляции основного приложения и различных утилит, несовместимы.

В настоящее время для создания каждой части проекта мне нужно очистить исходное дерево между ними. Это больно и, конечно, не то, что я хочу в конце концов. Каков наилучший способ решить эту проблему? У меня были идеи, которые я не смог реализовать на практике:

  1. Отдельный каталог сборки для каждой части проекта
  2. При создании внешних инструментов, пометить их объектные файлы в главном дереве исходного кода приложения (util.file1.o?)

Я не уверен, что у меня есть время и терпение, необходимые для освоения make / autotools. Может ли один из других инструментов сборки (scons? Cmake?) Упростить выполнение такой задачи? Если так, то какой?

ОБНОВИТЬ: Вот что у меня сейчас

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

Я пришел к этому после интенсивного поиска в Google. Кажется, это работает, но эта часть не кажется особенно приятной (похоже на хак):

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

В частности, я не слишком заинтересован в том факте, что я создаю список объектов из источников ранее и добавляю суффикс, только чтобы сделать обратное здесь. Я не мог заставить его работать другим способом.

3

Решение

CMake имеет add_definitions а также remove_definitions команды. Вы можете использовать их для определения макросов для разных частей вашего проекта:

# 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

Другие решения

С SCons это можно сделать безболезненно. Вам определенно понадобится иерархия каталогов для объектов, созданных с помощью различных макросов препроцессора. С точки зрения SCons, создание таких каталогов сборки называется option_dir. Я бы порекомендовал следующую иерархическую структуру сборки SCons:

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/

Чтобы иметь возможность создавать одни и те же исходные файлы с разными макросами препроцессора, вам необходимо создать один и тот же файл с несколькими различными средами. Эти env могут быть установлены в скриптах src / module SConscript или из корневого SConstruct и переданы. Я предпочитаю второй вариант, так как он сделает скрипты SCons модуля src / module модульными и не будет знать (не зависит) макросов препроцессора.

Вот корневой скрипт сборки, который создает различные env и управляет сценариями сборки подкаталога:

Приложение / 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)

Это скрипт сборки для основного
Приложение / 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)

Это скрипт сборки для модуля libs, он будет вызываться дважды, каждый раз с другим env
Приложение / 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)
2

По вопросам рекламы [email protected]