2011-08-27 67 views
3

我刚开始学习使用SCons,期望它可以解决make中的一些问题。我正在创建一个源层次结构来理解SCons的基础知识。SCons:使用分层构建分离调试/发布版本dirs

让我们先从这个文件夹结构:

  • 测试/富:包含main.cpp中,main.h
  • 测试/条:包含了自己的main.cpp,main.h
  • 测试/ common:包含foo和bar使用的utils.cpp和utils.h
  • test/external/moo:某些外部库的源代码,包含产生'Makefile'(不使用SCons)的'configure',所以SCons需要在'configure'之后调用'make';我怀疑这部分可能会非常棘手,当使用构建迪尔斯
  • 测试/建设/调试:建立调试
  • 测试DIR /建设/释放:建立发布目录

这里是想什么我要做到:

  • 有两种类型的构建:调试/释放其中唯一的区别是,调试指定-DDEBUG到g ++

  • 使用建立迪尔斯所以没有的.o文件是在我的源码树中创建的。我们称这些构建目录为“build/debug”和“build/release”

  • 能够调用./configure并在另一个不使用SCons的项目上创建,然后将它产生的libmoo.a链接到我的项目

  • 具有建立是完全平行(scons的-j9对于8芯?)

  • 有无指定库链接的一些调试/释放无关的方式。喜欢的东西:

    env.Program(target='foo', source=['foo/main.cpp', '#build/(DEBUG_OR_RELEASE)/lib/libsomething.a']) 
    

什么会非常基本的SConstruct/SConscript文件做上面的样子?即使只是在正确的方向指针也会很棒!

在此先感谢:-)

+0

一种方法是将选项传递给scons。 scons不支持命令行选项,尽管看起来你不能使用简短的表单。然后有两个版本的一切取决于该标志是否存在。 –

回答

5

我做到这一点的构建多平台(而非调试/发布),但概念是相同的。其基本思路是你需要项目根目录中的两个文件 - 一个SConstruct来设置构建目录(或者scons中已知的“变体目录”),然后是描述实际构建步骤的SConscript。

在SConstruct文件你指定variant目录及其对应的源目录:

SConscript(dirs='.', 
      variant_dir=variant_dir, 
      duplicate=False, 
      exports="env") 

现在你要variant_dir依赖的标志。你会使用AddOption或Variables来做到这一点。下面是一个完整的顶级SConstruct的一个例子做到这一点:

# build with `scons --debug-build` for debug. 
AddOption(
    '--debug-build', 
    action='store_true', 
    help='debug build', 
    default=False) 

env = Environment() 

if GetOption('debug_build'): 
    env.ParseFlags('-DDEBUG') 
    variant_dir = 'build/debug' 
else: 
    variant_dir = 'build/release' 

SConscript(dirs='.', 
      variant_dir=variant_dir, 
      duplicate=False, 
      exports="env") 

AddOption是最容易使用的,但是如果你使用的变量,那么你可以缓存运行之间的结果,而不必拼出“scons的 - 每次构建“。

所有目录设置和关联的cruft位于SConstruct中。现在SConscript文件非常简单,根本不需要担心构建目录。

Import('env') 

env.Program(target='foo_prog', source=['foo/main.cpp', 'lib/libmoo.a']) 
# foo_prog since foo already exists as the name of the directory... 

这是关于最简单的方法,我发现设置不同的生成目录没有得到奇怪的错误。它也非常灵活 - 只需修改顶层脚本中的“env”,就可以添加不同的平台构建,而无需更改构建的实际内容。

在你的问题的作品只有扳手是直接从SCons的编译autoconf的风格项目的方式。最简单的方法可能是使用一些Command()调用,但SCons喜欢了解每个步骤的输入和输出,所以这可能会变得怪异。此外,您必须依赖具有正确VPATH设置的autoconf构建 - 如果您尝试在源树之外进行编译,则某些项目不起作用。无论如何,这是一种编译autoconf的项目将是这样的:

import os 
Import('env') 

# get the path to the configure script from the "moo" source directory 
conf = env.File('moo/configure').srcnode().abspath 

# Create the "moo" build directory in the build dir 
build_dir = env.Dir('.').path 
moo_dir = os.path.join(build_dir, 'moo') 
Mkdir(moo_dir) 

# run configure from within the moo dir 
env.Command('moo/Makefile', 'moo/Makefile.am', 
    conf, chdir=moo_dir) 
# run make in the moo dir 
env.Command('moo/libmoo.a', 'moo/Makefile', 
    'make', chdir=moo_dir) 

env.Program(target='foo_prog', source=['foo/main.cpp', 'moo/libmoo.a']) 

运行从源目录配置阶段,而当前的工作目录是某处在构建层次是尴尬。 make步骤不太麻烦,但仍需要了解当前的构建目录。由于您将“libmoo.a”指定为make step的输出,并将libmoo.a指定为程序的输入,所有依赖项Just Work,所以并行构建工作正常。并行构建只有在你太依赖依赖的时候才会崩溃。

0

有一个很好的解决方案来定义多个构建模式( '调试', '释放')在SCons的维基:

http://www.scons.org/wiki/SconstructMultiple

这就是richq SConstruct文件会是什么样子:

#get the mode flag from the command line 
#default to 'release' if the user didn't specify 
mymode = ARGUMENTS.get('mode', 'release') 

#check if the user has been naughty: only 'debug' or 'release' allowed 
if not (mymode in ['debug', 'release']): 
    print "Error: expected 'debug' or 'release', found: " + mymode 
    Exit(1) 

#tell the user what we're doing 
print '**** Compiling in ' + mymode + ' mode...' 

env = Environment() 

if mode == 'debug': 
    env.Append(CPPDEFINES = ['DEBUG']) 
    variant_dir = 'build/debug' 
else: 
    variant_dir = 'build/release' 

SConscript(dirs = '.', variant_dir = variant_dir, duplicate = False, exports = "env") 

你再调用scons mode=release(或只是作为scons释放是默认模式),或scons mode=debug

1

我知道这是一个老问题,我只是想替代添加到:

  • 能够知道在sconscript文件的当前变种(不仅是在父)
  • 和能够在一个单一的scons的建设多个变种命令

sconstruct文件(父),我们定义了一个名为ListVariablevariants与我们允许变种(如:['release', 'debug'])的列表。

然后为了能够知道sconscript文件中的当前变体,我们只是定义了我们定义的循环选项并将其导出到sconscript

我用genv变量名谱写全球环境

# sconstruct 
opts = Variables() 
opts.AddVariables(
    ListVariable('variants', 'list of variants to build', 'all', names = ['debug','release']), 
) 

genv = Environment(options = opts) 

for variant in genv['variants']: 
    SConscript('sconscript', exports=['genv', 'variant'], variant_dir='#build/'+variant, duplicate=False) 

sconscript文件中,我们Clonegenv,我们可以使用variant变量做我们的设置在本地环境env

# sconscript 
Import('*') 
import os.path 

env = genv.Clone()  

if variant == 'debug': 
    env.Append(CPPFLAGS = ['/Zi']) 

src  = 'src/hello.cpp' 
app,ext = os.path.splitext(os.path.basename(src)) 

obj = env.Object ('obj/'+app, src) 
bin = env.Program('bin/'+app, obj) 

使用ListVariable允许我们拨打

scons variants=release 

scons variants=all 

这最后一个命令(和默认命令)建立所有的变体。