2011-08-27 148 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 

這最後一個命令(和默認命令)建立所有的變體。