SCons库和子库

我有一个基于SCons的分层构建系统。 我有一个根SConstruct调用SConscript构建一个共享库,然后调用另一个SConscript构建一个依赖于共享库的可执行文件。

所以这是我的问题:我对linux上的共享库的理解是,当你想为将要使用共享库的可执行文件做最后的ld链接时,共享库必须作为源包含在可执行文件的ld命令行中引用它(除非它在标准位置,在这种情况下-l选项有效)。

所以这就像我的SCons文件一样:

=== rootdir / SConstruct

 env=DefaultEnvironment() shared_lib = SConscript('foolib/SConscript') env.Append( LIBS=[shared_lib] ) executable = SConscript('barexec/SConscript') 

=== rootdir / foolib / SConscript

 env=DefaultEnvironment() env.Append(CPPPATH=Glob('inc')) penv = env.Clone() penv.Append(CPPPATH=Glob('internal/inc')) lib = penv.SharedLibrary( 'foo', source=['foo.c', 'morefoo.c'] Return("lib") 

=== rootdir / barexec / SConscript

 env=DefaultEnvironment() exe = env.Program( 'bar', source=['main.c', 'bar.c', 'rod.c'] ) Return("exe") 

所以这里的问题是这一行:

 env.Append( LIBS=[shared_lib] ) 

对于需要它们的任何其他库,这将是一个很好的方法将生成的库添加到命令行,除了因为SCons正在通过SConscripts进行两遍运行(首先生成它的依赖树,然后执行工作) , rootdir/foolib/libfoo.so结束所有产品的命令行,即使libfoo.so本身:

 gcc -g -Wall -Werror -o libfoo.so foo.o morefoo.o libfoo.so 

那么如何用SCons做得最好呢? 现在我已经使用了这个黑客:

=== rootdir / SConstruct

 env=DefaultEnvironment() shared_lib = SConscript('foolib/SConscript') env['shared_lib'] = shared_lib executable = SConscript('barexec/SConscript') 

=== rootdir / barexec / SConscript

 env=DefaultEnvironment() exe = env.Program( 'bar', source=['main.c', 'bar.c', 'rod.c'] + env['shared_lib'] ) Return("exe") 

是否有更多SCons-y方式这样做?

您应该允许构建找到共享库。

SCons文档中查找LIBPATHRPATH变量; 这些是设置搜索路径的“Scons-y”方式,以便任何生成的-l选项可以正确地找到库。

提到上面的内容,这里是你应该看到gcc根据SCons的设置做的事情(如果没有,你可能必须手动完成)。

-l选项总是查找共享库,前提是您还要为编译器提供库的位置。 有两次需要:在编译时( -L选项)和运行时( -rpath生成的链接器选项)。

LIBPATH SCons设置应该为编译时搜索路径生成类似于-L/some/directory/path path的内容。

RPATH SCons设置应生成一个链接器选项以嵌入搜索路径; 例如-Wl,-rpath -Wl,\$ORIGIN/../lib将嵌入一个搜索路径,该路径相对于可执行文件进行搜索,以便将可执行文件置于bin搜索安装的并行lib目录中。

这是组织SConsctruct / SConscript文件的更好方法。 通常使用Hierarchical构建,您应该与其他子目录共享env。 请注意,我也克隆了barexec目录中的主要env,因此foolib仅用于链接该二进制文件。

=== rootdir / SConstruct

 import os env=DefaultEnvironment() subdirs = [ 'foolib', 'barexec' ] # The exports attribute allows you to pass variables to the subdir SConscripts for dir in subdirs: SConscript( os.path.join(dir, 'SConscript'), exports = ['env']) 

=== rootdir / foolib / SConscript

 # inports the env created in the root SConstruct # # Any changes made to 'env' here will be reflected in # the root/SConstruct and in the barexec/SConscript # Import('env') # Adding this 'inc' dir to the include path for all users of this 'env' env.Append(CPPPATH=Glob('inc')) penv = env.Clone() # Adding this include only for targets built with penv penv.Append(CPPPATH=Glob('internal/inc')) penv.SharedLibrary( 'foo', source=['foo.c', 'morefoo.c']) 

=== rootdir / barexec / SConscript

 Import('env') clonedEnv = env.Clone() # The foo lib will only be used for targets compiled with the clonedEnv env # Notice that specifying '#' in a path means relative to the root SConstruct # for each [item] in LIBS, you will get -llib on the compilation line # for each [item] in LIBPATH, you will get -Lpath on the compilation line clonedEnv.Append(LIBS=['foo'], LIBPATH=['#foolib']) clonedEnv.Program( 'bar', source=['main.c', 'bar.c', 'rod.c'] ) 

除了Brady决定之外,我还使用静态/全局变量来存储目标名称和路径。 这让我可以更好地控制构建。

 # site_scons/project.py class Project: APP1_NAME = "app1_name" APP2_NAME = "app2_name" MYLIB1_NAME = "mylib1_name" # etc APP_PATH = "#build/$BuildMode/bin" # BuildMode - commonly in my projects debug or release, `#` - root of project dir LIB_PATH = "#build/$BuildMode/lib" @staticmethod def appPath(name) : return os.path.join(APP_PATH, name) @staticmethod def libPath(name) : return os.path.join(LIB_PATH, name) 

定义目标:

 from project import Project ... env.SharedLibrary(Project.libPath(Project.MYLIB1_NAME), source=['foo.c', 'morefoo.c']) 

应用:

 from project import Project ... env.Append(LIBPATH = [Project.LIB_PATH]) env.Append(LIBS = [Project.MYLIB1_NAME]) env.Program(Project.appPath(Project.MYAPP1_NAME), source=[...]) 

在我的项目中它工作正常,scons自动查找依赖于库而无需任何其他命令。 如果我想更改库的名称,我只需更改我的Project类。