SCons:使用分层构建单独调试/发布构建目录

时间:2011-08-27 18:51:40

标签: scons

我刚开始学习使用SCons,期待它解决了我的一些问题。我正在创建一个源层次结构来理解SCons的基础知识。

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

  • test / foo:包含main.cpp,main.h
  • test / bar:包含自己的main.cpp,main.h
  • test / common:包含foo和bar
  • 使用的utils.cpp和utils.h
  • test / external / moo:一些外部库的源代码,包含'configure',它产生'Makefile'(不使用SCons),所以SCons需要在'configure'之后调用'make';我怀疑使用构建目录时这部分可能会很棘手
  • test / build / debug:build dir for debug
  • test / build / release:build dir for release

这是我想做的事情:

  • 有两种类型的构建:debug / release,唯一的区别是debug指定-DDEBUG到g ++

  • 使用构建目录,以便在源树中不创建.o文件。让我们将这些构建目录称为“构建/调试”和“构建/发布”

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

  • 让构建完全平行(scons -j9为8核?)

  • 有一些与调试/发布无关的方法来指定要链接的库。类似的东西:

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

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

提前致谢: - )

3 个答案:

答案 0 :(得分:6)

我为多个平台的构建(而不是调试/发布)执行此操作,但概念是相同的。基本思想是在项目根目录中需要2个文件 - 一个用于设置构建目录的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 --debug-build”。

所有目录设置和相关的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步骤的输出,libmoo.a作为程序的输入,所有依赖项Just Work,因此并行构建工作正常。当您过多地捏造依赖关系时,并行构建只会中断。

答案 1 :(得分:1)

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

  • 能够知道sconscript文件中的当前变体(不仅仅是在父文件中)
  • 并且能够在单个scons命令中构建多个变体

sconstruct文件(父级)中,我们定义一个名为ListVariable的{​​{1}},其中包含我们允许的变体列表(例如variants)。< / p>

然后,为了能够知道['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 de Clone我们可以使用genv变量在本地环境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=debug

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

答案 2 :(得分:0)

在SCons Wiki中定义多种构建模式('debug','release')有一个很好的解决方案:

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