2012-07-17 96 views
5

我有一个问题,重构基于scons的构建系统。我们有一个包含几个不同输出对象(dll,可执行文件,测试可执行文件)的C/C++源代码树,以及我们的源文件(尽管它大部分位于具有src/inc/目录的'模块'目录)中有点异构的布局。scons建设环境继承

当前设置的一个最大问题是,我们真的希望所有这些构建产品都默认使用一致的编译器选项进行构建。我们目前的布局有一个主SConstruct文件,在子目录中调用许多子SConscript文件,然后构建更大的构建产品(例如.a)。默认情况下,scons中的SConscript()函数不会将当前构造环境对象传递或继承到被调用的SConstruct文件。这意味着目前所有这些sub-SConstript文件都使用他们自己的不同构建环境。

我试图放在一起的新布局有一个主要的构建环境放在一起在源代码树根与所有必要的CFLAGS和构建定义我们需要。我希望将这个构建环境传递给sub-SConscript文件,以便我知道构建树中的每个文件.c.cpp都使用相同的命令行构建。

虽然我不确定如何在scons中做到这一点。有Import()Export()函数,但这些基本上都是丑陋的全局变量 - 调用的SConstruct文件对子文件结构文件对Export()编辑的全局变量所做的操作没有太多控制权。是否有任何干净的方式,基本上把当前的施工环境作为参数传递给子SConscript文件,而不必让它修改它呢?可能的东西喜欢:

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

### add other stuff that we want everything to use 

SConscript('somelibrary/SConstruct', inherited_environment=master_env.Clone()) 

### master_env has now been used to build a 
### .dll in somelibrary/, but any variations 
### made to somelibrary/SConstruct's inherited 
### env haven't contaminated master_env 

我知道我可以做这样的事情笨拙和排序总值:

clobber_env = Environment() 
master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

call_somelibrary_sconstruct(master_env) 

def call_somelibrary_sconstruct(env): 
    param_env = env.Clone() 
    Export('param_env') 
    SConstript('somelibrary/SConstruct') 

    # because we don't want any contamination of our global variable 
    # between SConscript calls. I'm not even sure if this is necessary 
    # or does what I think it does because I'm not sure how this ugly 
    # Export()'d global variable environment works with locals like 
    # param_env here. 
    param_env = clobber_env 
    Export('param_env') 

是否有这样做的一个优雅的方式?

更新:

所以我这个多一些玩耍了,它看起来像我只要做到这一点在主SConstruct文件:

def build_somelib(env): 
    Export(env=env.Clone()) 
    somelib = SConscript('somelib/SConscript') 
    return somelib 

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

build_somelib(master_env) 

,然后在somelib/SConscript

Import('env') 
env.Append(CXXFLAGS=['-weirdoption1', ... ]) 
lib = env.StaticLibrary('somelib', source=['source1.cpp', 'source2.cpp', ...]) 
Return("lib") 

那么主SCONStruct中的master_env未被污染。 Export(env=env.Clone())对我来说很重要,因为我不想依赖所有的子SConscripts来执行安全性克隆() - 该策略应该是父SConscript/SConstruct文件。

但是,根据策略,必须将env作为参数名称有点难看。

回答

7

我所知道的最好的方式是由你做主SConstruct只是这样做:

env = Environment() 

env.SConscript('src/SConscript', 'env') 
在你的src/SConscript文件

然后:

Import('env') 

然后,你可以参考ENV变量你会在你的SConstruct文件中。如果你不想在发生变异SConstruct在SRC/SConscript ENV,把事情处理好导入后:

env = env.Clone() 

敢肯定这是所有有给它。

+0

谢谢汤姆。有一点需要补充:如果'env'不一定是第二个参数,则可以使用语法:'exports ='env''。 – 2013-11-14 23:48:09

+0

不幸的是,这仍然留下克隆到子模块的自由裁量权,所以不能保证下一个模块会这样做。 – 2016-02-17 05:18:53

1

我grep的来源(在Ubuntu 12.04 Scons 2.1.0),并找出Export更新global_exports字典及其关键字。

所以这个代码可能会运行:

Export(param_env=env.Clone()) 
SConscript('somelibrary/SConstruct') 
Export(param_env=clobber_env) 

没有任何关于在文档中,所以这是一个特点。

ExportSConstript使用frame magic通过名称获取变量,即使它可能对尚未知道python的用户有益,但它是邪恶的。

1

在更新由OP提出的解决方案有一个严重的问题(与scons的-2.3.3和scons的-2.3.4测试):

def build_somelib(env): 
    Export(env=env.Clone()) 
    somelib = SConscript('somelib/SConscript') 
    return somelib 

master_env = Environment() 
master_env.Append(CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ]) 

build_somelib(master_env) 

使用上述并打开CacheDir(some_dir)(我也使用VariantDir,万一有什么区别)。在dir1中,使用scons --cache-debug=log进行完整构建。构建完成后,在代码相同的dir2中,也使用scons --cache-debug=log进行完整构建。所有文件都应该从构建缓存中复制,但是我发现绝大多数文件都没有被复制。大多数文件(但不是全部)在两个目录之间有MD5签名不匹配。此问题也可以通过修改'dir1'中的文件并重建,然后将修改应用于'dir2'以及重建来触发。你会看到相同的MD5不匹配。

此时,请执行scons -c,然后删除两个目录中的.sconsign.dblite文件(并删除构建高速缓存以获得更好的效果)。首先在dir1重建,当完成后,在'dir2'重建。您将得到正确的行为:MD5签名将匹配,文件将从构建缓存中复制。

根据汤姆的解决方案,我最终放弃了OP的解决方案,并将保留父环境的责任转移到所有子目录。不完全是我想要做的,但至少构建缓存现在按预期工作。