scons,CPPPATH和多个库

时间:2016-11-04 13:54:37

标签: c++ shared-libraries scons

问题描述

我正在尝试使用scons构建一个模块化系统来编译多个共享库,其中一些共享库依赖于其他库。虽然我可以通过一些不同的解决方法进行编译,但每个都有一些缺点,如“尝试解决方案”部分所述。

.
├── SConstruct
└── src
    ├── libA
    │   ├── a.cc
    │   ├── a.hh
    │   └── SConscript
    ├── libB
    │   ├── b.cc
    │   ├── b.hh
    │   └── SConscript
    └── SConscript

此处,b.cc包含a.hh,这是两个库之间的依赖关系。

每个文件的内容如下所示。

# In SConstruct
VariantDir('build', 'src', duplicate=False)
SConscript('build/SConscript')

# In src/SConscript
env = Environment()
SConscript(['libA/SConscript', 'libB/SConscript'],
           exports='env')

# In src/libA/SConscript
Import('env')

env.Append(CPPPATH=['.'])
env.SharedLibrary('a.cc')

# In src/libB/SConscript
Import('env')

env.Append(CPPPATH=['.'])
env.SharedLibrary('b.cc')

在这里,我遇到了一个问题。当我运行scons时,我得到以下结果。

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/libA/a.os -c -fPIC -Ibuild/libA -Isrc/libA -Ibuild/libA -Isrc/libA src/libA/a.cc
g++ -o build/libA/liba.so -shared build/libA/a.os
g++ -o build/libB/b.os -c -fPIC -Ibuild/libB -Isrc/libB -Ibuild/libB -Isrc/libB src/libB/b.cc
src/libB/b.cc:3:16: fatal error: a.hh: No such file or directory
 #include "a.hh"
                ^
compilation terminated.
scons: *** [build/libB/b.os] Error 1
scons: building terminated because of errors.

我从this older question了解到,-Ibuild/libA-Isrc/libA的重复是有意义的,并且是有意的。但是,-Isrc/libA在编译a.cc时会传递两次,而在编译b.cc时则不会传递。

尝试解决方案

这似乎是由于将字符串传递给CPPPATH而不是Dir()节点引起的。然后使用当前SConscript的路径扩展字符串,而不是使用当前的SConscript进行扩展。为避免这种情况,我在CPPPATH=['.']CPPPATH=[Dir('.')]中将src/libA/SConscript修改为src/libB/SConscript。这不起作用,因为CPPPATH中只包含build/libA,而不是src/libA,如下所示。

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/libA/a.os -c -fPIC -Ibuild/libA -Ibuild/libB src/libA/a.cc
g++ -o build/libA/liba.so -shared build/libA/a.os
g++ -o build/libB/b.os -c -fPIC -Ibuild/libA -Ibuild/libB src/libB/b.cc
src/libB/b.cc:3:16: fatal error: a.hh: No such file or directory
 #include "a.hh"
                ^
compilation terminated.
scons: *** [build/libB/b.os] Error 1
scons: building terminated because of errors.

其次,我用duplicate=False对此进行了测试。结合第一个测试,使用Dir('.'),这成功编译了库。但是,这并不理想,因为任何调试符号都指向build目录中的源文件。对于大型项目,在编译之后,我想删除build目录以节省空间,这会使调试变得更难,因为gdb无法再找到源文件。

接下来,我尝试使用abolute路径。也就是说,在libA中,我添加了CPPPATH=['#/src/libA'],而在libB中,我添加了CPPPATH=['#/src/libB']。这已成功编译duplicate=False。但是,这可能是一个可能包含在许多不同的顶级SConstructs中的库。通过将路径硬编码到库的SConscript中,它限制了该库的使用。

最后,我尝试根本不使用VariantDir。除了使用Dir('.')作为每个库的路径之外,这还可以,但会将所有中间文件保留在src目录中。这会使目录结构变得混乱,并且使维护多个构建(例如调试/发布)变得非常棘手。

是否存在可避免这些问题的设计用法?

1 个答案:

答案 0 :(得分:1)

您声明“通过将路径硬编码到库的SConscript中,它会限制此库的使用。”。但是替代方案是什么?在构建描述中的某个时刻,您必须具体了解应该搜索哪些路径的隐式依赖项(如头或库)。如果你随后移动你的文件夹,那么构建将会中断...独立于你的构建工具选择。

使用SCons“#”路径,从顶级SConstruct开始指定,工作正常,是您的问题的一个解决方案。 另一种选择是使用相对路径,从当前的SConstruct向上或向下开始。因此,对于src/libB/SConscript,您可以使用:

Import('env')

env.AppendUnique(CPPPATH=['.', '../libA'])
env.SharedLibrary('b.cc')

这至少可以让您同时将“libA”和“libB”移动到新的位置。但我认为你不能做得更好......