我对制作和 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。因此,编译主应用程序和varous实用程序生成的目标文件不兼容。
目前要构建项目的每个部分,我必须清理它们之间的源代码树。这很痛苦,当然不是我想要的。解决这个问题的最佳方法是什么?我没有能够付诸实践的想法是:
我不太确定我是否有足够的时间和耐心来掌握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
我经过广泛的谷歌浏览后发现了这一点。这似乎有效,但这部分看起来并不特别好(感觉有点像黑客):
$(OBJECTS): | mkdir
$(CXX) -c $(CXXFLAGS) -o $@ $(patsubst %.o,%.cpp,$(subst .util/,,$@))
特别是我不太热衷于我之前从源创建对象列表并添加后缀的事实,只是在这里做反向。我似乎无法以任何其他方式工作。
答案 0 :(得分:5)
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(...)
答案 1 :(得分:2)
这可以通过SCons轻松完成。对于使用不同预处理器宏构建的对象,您肯定需要构建目录层次结构。在SCons术语中,创建这样的构建目录称为variant_dir。我建议使用以下SCons Hierarchical构建结构:
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/
为了能够使用不同的预处理器宏构建相同的源文件,您需要使用多个不同的环境构建相同的文件。这些环境可以在src / module SConscript脚本中设置,也可以从根SConstruct设置并传递下来。我更喜欢第二个选项,因为它会使src /模块SCons脚本模块化,并且不知道(不可知)预处理器宏。
这是根构建脚本,它创建不同的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)
这是main的构建脚本 应用程序/ 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)
这是模块库的构建脚本,它将被调用两次,每次都使用不同的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)