轉載請注明來源:https://www.cnblogs.com/hookjc/
一、SConstruct File {{{1
1. Sconstruct 文件 是scons用來控制編譯的文件
2. Sconstruct 文件 是一個python腳本
3. SConstruct 文件 是一個類似於makefile一樣的東西, 告訴 scons做什么,而不是嚴格的規定soncs做這件事的步驟
二、scons選項 {{{1
-c Cleaning up After a Build
-Q Making the scons output less verbose
三、SConstruct 腳本的編寫基礎 {{{1
1. builder method {{{2
Program : generate executable file
Object : generate Object file
Java : 編譯java程序, User Guide 2.3, Chapter 25
Library : 靜態庫, 也可以使用 StaticLibrary替代
SharedLibrary: 動態庫
2. 指定目標名 {{{2
Program('hello.c') # 生成 hello.exe
Program('new_hello', 'hello.c') # 生成 new_hello.exe
3. 編譯多個文件 {{{2
Program(['prog.c', 'file1.c', 'file2.c']) # 生成 prog.exe
Program('program', ['prog.c', 'file1.c', 'file2.c']) # 生成program.exe
Program('program', ['prog.c', 'file1.obj', 'file2.obj']) # 可以在文件列表中指定.obj文件
3.1 使用Glob 編譯所有匹配的文件
Program('program', Glob('*.c') )
Glob原型為:Glob(self, pattern, ondisk=True, source=False, strings=False)
其中pattern 支持unix系統下的文件名匹配: *(任意多個字符), ?(單個字符) 和 [](括號中的任一字符)
3.2 使用Split
Program('program', Split('main.c file1.c file2.c'))
Split以空白字符為分隔符,將字符串分割,因此,你也可以這樣寫:
Program('program', Split("""
main.c
file1.c
file2.c
""") )
3.3 使用關鍵字參數
Program(target = 'program', source = 'hello.c')
4. 指定編譯選項 {{{2
$CPPFLAGS 指定編譯選項
$LINKFLAGS 指定鏈接選項, 如 /DEBUG
$CPPDEFINES指定預編譯器
$LIBS 指定所需要鏈接的庫文件
$LIBPATH 指定庫文件(.lib)的搜索目錄
$CPPPATH 指定[.h, .c, .cpp]等文件搜索路徑
例如:
Library('foo', Split('f1.c f2.c f3.c') )
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
注:LIBS和LIBPATH若為一個可以使用字符串,若為多個則使用列表
四、使用Environments {{{1
一個environment是一個影響程序執行的值得集合。
(1) 外部環境 External Environment
外部環境是運行Scons時 用戶的環境變量。它們可以通過os.environ獲取
(2) 構建環境 Construction Environment
它包含一些變量,這些變量會影響Scons構建目標的行為
(3) 執行環境 Execution Environment
執行環境用於Scons執行外部命令(external command), 以構建一個或多個目標。
注意:它與外部環境不相同
1. Construction Environment {{{2
> 創建 construction Environment
env = Environment()
一個Environment是一個 (name,value)的集合,可以這樣查看它的內容:
for item in env.Dictionary():
print '(%s:%s)' % (item, env[item])
> 查看變量
env['CC'] #查看 CC ,即C語言編譯器
env.subst('$CC') # 功能同上
它的優勢在於,它會將出現在結果中的環境變量轉換成最終的值
使用AllowSubstException()函數,使得當subst中的變量不存在時報告錯誤,
AllowSubstException()
env.subst('$missing') # 出現異常,NameError
> 修改環境變量
拷貝一個環境變量
使用env.Clone #詳見user guide 7.2.7
替換一個已經存在的環境變量
env.Replace
為一個沒有被定義的變量設置默認值
env.SetDefault
為一個已存在的環境變量增加一個值
env.Append, 例如:
env.Append(CCFLAGS = '-option -O3 -O1')
env.Append(CCFLAGS = ['-option', 'O3'])
為一個環境變量增加一個唯一的值
env.AppendUnique
在最前邊添加一個值
env.Prepend
在最前邊添加一個唯一的值
env.PrependUnique
合並環境變量
env.MergeFlags, 例如:
flags = {'CCFLAGS':'-option -O3 -O1'}
env.MergeFlags(flags)
flags = {'CPPPATH' : ['/user/opt/include', 'user/local/include']}
env.MergeFlags(flags)
#若參數不是Dictionary, 內部調用ParseFlags將其轉化為Dictionary
env.MergeFlags('-whatever -I/usr/opt/include -O3 -I/usr/local/include')
> 一些實用的變量
判斷是否是windows:
env['PLATFORM'] == 'win32'
2. Execution Environment {{{2
當scons構建一個目標文件時,它所使用的外部環境和執行scons時的環境變量是不同的。
scons使用$ENV 構建變量 中 存儲的目錄 作為它執行命令的外部環境變量
> PATH
POSIX 系統中默認的PATH是 /user/local/bin:/user/bin
Window系統中默認的PATH是 command interpreter在注冊表中的值
1. 在構建環境中顯示初始化PATH
path = ['/user/local/bin', '/bin', '/user/bin']
env = Environment(ENV = {'PATH':path})
上面這種方式,只設置了ENV,如果你想保留其他的變量,可以這么做:
env['ENV']['PATH'] = ['/user/local/bin', '/bin', '/user/bin']
2. 從 外部環境 初始化 PATH
import os
env = Environment(ENV = {'path' : os.environ['PATH']})
你也可以將完整的外部變量傳遞給執行環境變量:
import os
env = Environment(ENV = os.environ)
這樣做的缺點是:如果環境變量目錄中,有多個目錄包含編譯器如gcc,那么,
scons將執行第一個被找到的gcc
3. 使用env.PrependENVPath 和 env.AppendENVPath
例如:將'/user/local/bin' 插入 $PATH中第一個位置
env.PrependENVPath('PATH', '/user/local/bin')
例如:將'/user/local/bin' 插入 $LIB中最后一個位置
env.AppendENVPath('lib', '/user/local/lib')
五、Controlling Build Output {{{1
1. 使用Help 函數 來說明SConstruct腳本
例如:
Help('this is a debug version')
在控制台上使用 scons -h 命令查看此幫助信息
你可以在腳本中多次使用Help,幫助信息會被連接到一起
六、scons 命令行參數 {{{1
用戶可以為scons指定三種類型的參數:
> Options : 以 一個或兩個(-) 開頭 , 詳細參考 User Guide 10.1
> Variables : 形式為:variable=value, 詳細參考 10.2
> Target : 如果不是一個 Option 或 Variable ,那么就是一個Target , 詳細參考 User Guide 10.3
1. 讀取命令行的Variable參數
命令行:scons debug=1
SConstruct腳本如下:
debug = ARGUMENTS.get('debug', 0)
if int(debug) :
pass # do something
2. Command-Line Targets
scons提供 COMMAND_LINE_TARGETS 供用戶訪問命令行參數中的 Targets列表,例如:
if 'bar' in COMMAND_LINE_TARGETS:
print "Don't forget to copy 'bar' to the archivel"
Default(Program('foo.c'))
Program('bar.c')
> 使用 Default函數 定義 默認目標
當你沒有在命令行參數中指定目標時,scons會編譯每一個目標
例子:
env = Environment()
hello = env.Program('hello.c')
env.Program('goodbye.c')
Default(hello) #如果沒有在命令行指定Target,則會編譯hello
使用DEFAULT_TARGETS獲取 默認目標, 例如:
prog1 = Program('prog1.c')
Default(prog1)
print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
使用 BUILD_TARGETS 獲取要編譯的目標
七、控制目標文件的路徑 {{{1
1. BINDIR {{{2
>使用Install:如,
test = env.Program('test.cpp')
env.Install('bin', 'test.exe') #表示要將test.exe 放到bin目錄下
或
env.Install('bin', test)
>在指定目標名的時候指定其目錄,如:
env.Program('bin/test', 'test.cpp')
>將目標放到其他目錄下,並修改名字
test = env.Program('test.cpp')
env.InstallAs('bin/testapp.exe', 'test.exe') #表示將test.exe 拷貝到 bin/testapp.exe
或 這樣寫
env.InstallAs('bin/testapp', test)
當 需要對多個目標做此操作時,可以這樣做:
env = Environment()
hello = env.Program('hello.c')
goodbye = env.Program('goodbye.c')
env.InstallAs(['/usr/bin/hello-new', '/usr/bin/goodbye-new'], [hello, goodbye]) #多個目標
env.Alias('install', '/usr/bin')
2. obj文件路徑 {{{2
使用VariantDir函數指定
3. 一份代碼構建多個版本的Target {{{2
通常會有這樣的需求,一份源碼,既要構建它的debug版本,又要構建它的release版本,這種情況下,
>我們需要為不同版本指定不能的obj名字,否則就會產生沖突,導致scons不能工作。簡單的示例如下:
opt = Environment(CCFLAGS = '-O2')
dbg = Environment(CCFLAGS = '-g')
o = opt.Object('foo-opt', 'foo.c') // 生成 foo-opt.o
opt.Program(o)
d = dbg.Object('foo-dbg', 'foo.c') // 生成 foo-dbg.o
dbg.Program(d)
>或者將不同版本的obj放到不同的路徑下:
o = opt.Object('opt/foo', 'foo.c') // 生成 foo-opt.o
opt.Program(o)
d = dbg.Object('dbg/foo', 'foo.c') // 生成 foo-dbg.o
dbg.Program(d)
