簡單入門
hello world
scons由Sconstruct 作為入口产舞,控制如何進(jìn)行編譯操作。Sconstruct 本身是一個(gè)python文件菠剩,故需要遵循python的語法易猫,以及能使用一些python的方法。(如我們可以用print 來debug)
這有一段很簡單的hello.cpp
#include <iostream>
int main() {
std::cout << "hello world" << std::endl;
}
以及一個(gè)很簡單的Sconstruct
Program("hello.cpp")
Program是Scons中的一個(gè)編譯方法(builder_method)具壮, 告訴Scons 我們想要把hello.cpp 編譯成一個(gè)可執(zhí)行文件准颓。
保證Sconstruct 和hello.cpp 在同一個(gè)文件夾下哈蝇,執(zhí)行scons,就可以完成編譯攘已,生成可執(zhí)行文件hello炮赦。
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o hello.o -c hello.cpp
g++ -o hello hello.o
scons: done building targets.
可以看到,我們只指定了一個(gè)cpp文件贯被,scons會默認(rèn)給可執(zhí)行文件一個(gè)名字眼五,以及完成.o文件的生成,非常智能彤灶。當(dāng)然看幼,我們也能指定輸出文件的名字,Program("target_name", hello.cpp")
另外幌陕,除了Program 诵姜,還有其他很多builder_method, 如Object
, SharedLibrary
搏熄,StaticLibrary
棚唆,LoadableModule
,StaticObject
心例,CFile
編譯多個(gè)文件
編譯多個(gè)文件非常簡單
直接使用list
Program(["a.cpp", "b.cpp", "c.cpp"])
即可宵凌。-
也可以使用Glob方法
source = Glob("src/*.cpp") print source # python語法,可以打印出來debug Program(["hello.cpp"] + source)
用這種方式把src下的文件都加進(jìn)來
Program(Split("a.cpp, b.cpp c.cpp")
Split 也是SCons提供的一個(gè)方法止后,顧名思義了瞎惫。
編譯一個(gè)庫
把Program改為 Library (或者StaticLibrary,這兩者是一樣的)即可译株。
Library("t", Glob("src/*.cpp"))
這樣就能得到一個(gè)靜態(tài)庫了瓜喇。 如果如要一個(gè)動(dòng)態(tài)庫,則可以使用SharedLibrary歉糜。
鏈接一個(gè)庫
上邊我們學(xué)會如何編譯一個(gè)庫了乘寒,那么如何鏈接呢?也很簡單匪补,加個(gè)參數(shù)即可
source = Glob("src/*.cpp")
SharedLibrary("t", source)
Program(["hello.cpp"], LIBS=["t"], LIBPATH=".")
Program 可以理解為python 的一個(gè)方法伞辛,很多參數(shù)都有默認(rèn)值,我們要做的只用覆蓋其默認(rèn)值即可夯缺。如上始锚,我們指定引入LIBS。同樣的喳逛,LIBS參數(shù)也可以是個(gè)str瞧捌,LIBPATH也可以是個(gè)list,放上所有要查找的路徑,如['/usr/lib', '/usr/local/lib']姐呐,這里就不贅述了殿怜。
略微高級一點(diǎn)的功能
判斷是否需要重新編譯
SCons很智能,只會編譯需要編譯的內(nèi)容曙砂。比如我剛執(zhí)行完scons头谜,再次執(zhí)行,則會提示scons: . is up to date.
鸠澈。 那么他是如何做到的呢柱告?也不復(fù)雜,依賴一個(gè)Decider的方法笑陈,以及一個(gè).sconsign.dblite
文件际度。
默認(rèn)情況下,如果文件的md5值改變了涵妥,才會重新編譯乖菱。每次編譯,SCons都會把md5存起來蓬网,再次執(zhí)行時(shí)窒所,如果md5沒變,則不需要rebuild帆锋。
如果我們不希望使用md5吵取,而是使用文件修改時(shí)間呢?很簡單锯厢,增加Decider('timestamp-newer')
(默認(rèn)情況下為md5)皮官。也可以使用'MD5-timestamp
,則他們一起變了才會rebuild哲鸳。
我們前面也說到,Decider是一個(gè)方法盔憨,那很顯然徙菠,我們也可以自己寫個(gè)decider方法,詳細(xì)的可以看scons-user.pdf 6.1.5郁岩,這里不細(xì)寫了婿奔。。
env
env分為三種
external enviroment 保存在os.environ 中问慎,和scons其實(shí)沒太大關(guān)系萍摊,保存著一些系統(tǒng)定義的環(huán)境變量,如PATH之類
-
construction environment
這個(gè)比較重要如叼,我們可能希望不同的源文件使用不同的編譯參數(shù)冰木,這時(shí)候我們就能設(shè)置不同的編譯環(huán)境,指定哪個(gè)文件用哪種編譯。construction environment 中保存了構(gòu)建相關(guān)的一些參數(shù)踊沸。
使用方式如下
env1 = Environment(CXX = 'gcc') # 創(chuàng)建一個(gè)env print env1["CXX"] # 獲取參數(shù) env2 = env1.Clone(CXX = 'g++') # 復(fù)制一個(gè)env env1.Replace(CXX = 'g++') # 修改參數(shù) env1["CXX"] = "clang++" #再修改參數(shù) env1.MergeFlags("-g") #增加一個(gè)flag
就可以構(gòu)建出一個(gè)env歇终,除了CXX 被修改以外,其他參數(shù)均不變逼龟。另外评凝,我們也可以像一個(gè)dict一樣,去獲取env中的內(nèi)容腺律。
-
execution enviroment
這其實(shí)就是construction environment 中的一個(gè)變量ENV
env = Environment() print env["ENV"] env2 = Environment(ENV=os.environ) env3 = Environment(ENV = {"PATH" : os.environ["PATH"]})
幾個(gè)簡單的例子奕短,一看就明白了
命令行輸入的參數(shù)
比如我們想通過一個(gè)debug字段來控制是否開啟debug模式,怎么做呢匀钧?可以通過ARGUMENTS
env = Environment()
debug = ARGUMENTS.get("debug", 0)
if int(debug):
print "in debug mode"
scons debug=1
就可以了翎碑。
小結(jié)
上面只是我在看的時(shí)候做的一個(gè)小結(jié),詳細(xì)的可以看(文檔)[https://scons.org/doc/production/PDF/scons-user.pdf]榴捡,很多東西都沒寫杈女,在日常工作中可以一點(diǎn)一點(diǎn)去體會。