SCons 第三章 簡(jiǎn)化構(gòu)建過(guò)程

第三章 簡(jiǎn)化構(gòu)建過(guò)程

? 在本章節(jié)中,通過(guò)幾個(gè)簡(jiǎn)單的SCons工程構(gòu)建示例,向您展示無(wú)論是哪種編程語(yǔ)言,亦或哪種系統(tǒng)平臺(tái),軟件構(gòu)建都將會(huì)是一件非常簡(jiǎn)單的事情。

3.1 指定編譯輸出文件

? 當(dāng)調(diào)用Program構(gòu)建方法時(shí),它會(huì)構(gòu)建和源代碼文件(多份則采取第一個(gè)文件)相同名稱(chēng)的輸出文件,因此如果源代碼是hello.c,則構(gòu)建出來(lái)的可執(zhí)行文件則為hello(POSIX平臺(tái)),或者h(yuǎn)ello.exe(WINDOWS平臺(tái))。

Program('hello.c')

? 如果您想編譯出不同名稱(chēng)的可執(zhí)行文件,則需要在源文件的前面,指明輸出名稱(chēng)即可(如new_hello):

Program('new_hello', 'hello.c')

? (Scons需要先指明目標(biāo)文件名稱(chēng),后面才是源文件,這樣做的目的是和大多數(shù)的編程語(yǔ)言保持一致,python也是如此:“program = source files”)

? 現(xiàn)在執(zhí)行scons指令則會(huì)得到new_hello的編譯輸出:(POSIX平臺(tái))

> scons -Q
cc -o hello.o -c hello.c
cc -o new_hello hello.o

? 得到new_hello.exe的編譯輸出:(WINDOWS平臺(tái))

C:\> scons -Q
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:new_hello.exe hello.obj
embedManifestExeCheck(target, source, env)

3.2 編譯多個(gè)源文件

? 現(xiàn)在知道了如何編譯單個(gè)源文件,但是大多數(shù)情況下,需要構(gòu)建的工程,是由多個(gè)源文件構(gòu)成,而非單一文件,因此多源文件編譯時(shí),需要將文件名放入一個(gè)python列表(list)中:

Program(['prog.c', ['file1.c', 'fil2.c'])

? 編譯輸出為:(POSIX平臺(tái))

> scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o prog.o -c prog.c
cc -o prog prog.o file1.o file2.o

? (WINDOWS平臺(tái))

C:\>scons -Q
cl /Fofile1.obj /c file1.c /nologo
cl /Fofile2.obj /c file2.c /nologo
cl /Foprog.obj /c prog.c /nologo
link /nologo /OUT:program.exe prog.obj file1.obj file2.obj
embedManifestExeCheck(target, source, env)

3.3 采用Glob創(chuàng)建列表

? 您也可以采用Glob函數(shù)匹配所有符合條件的源文件,匹配原則采用標(biāo)準(zhǔn)腳本通配符“*”,“?”。[abc]將匹配a,b,c;[!abc]將匹配除abc意外的任意字符。這使得多個(gè)源文件的構(gòu)建變得簡(jiǎn)單了很多。

Program('program', Glob('*.c'))

? SCons的幫助手冊(cè)有更多關(guān)于Glob函數(shù)的具體用法細(xì)節(jié),可以參考。

3.4 單一文件構(gòu)建 VS 文件列表構(gòu)建

? 構(gòu)建工程目前有兩種形式,一種是采用文件列表,一種是采用單一文件直接構(gòu)建的方式:

# 文件列表
Program('hello', ['file1.c', 'file2.c'])

# 單一文件
Program('hello', 'hello.c')

? 當(dāng)然您也可以在文件列表中,只存儲(chǔ)一份文件:

Program('hello', ['hello.c'])

? 其實(shí)SCons內(nèi)部都是將源文件以列表的形式存儲(chǔ),只是為了方便起見(jiàn),允許用戶(hù)直接輸入單一文件。

重要提示

? 盡管SCons支持多種輸入方式,但是python語(yǔ)言更為嚴(yán)格,因此在進(jìn)行l(wèi)ist和string格式的文件相加則會(huì)產(chǎn)生python語(yǔ)法錯(cuò)誤:

common_sources = ['file1.c', 'file2.c']
# 下述代碼將會(huì)報(bào)錯(cuò), string和list相加
Program('program1', common_sources + 'program1.c')
# 下述代碼正確, list與list相加
Program('program2', common_sources + ['program2.c'])

3.5 讓列表文件易于讀寫(xiě)

? 對(duì)于文件列表而言,其缺點(diǎn)是每一個(gè)文件名稱(chēng)都需要用引號(hào)包起來(lái),無(wú)論是單引號(hào)還是雙引號(hào),當(dāng)列表比較長(zhǎng)時(shí),看起來(lái)都比較麻煩。SCons提供了很多工具函數(shù)使得這一工作變得很簡(jiǎn)單。

? SCons提供了Split函數(shù)用于分割字符串文件中的一個(gè)或多個(gè)空格,亦或一個(gè)或多個(gè)tab,分割后以文件列表的形式存儲(chǔ):

Program('program', Split('main.c file1.c file2.c'))

? (如果您熟悉python的話(huà),您會(huì)發(fā)現(xiàn)這和python標(biāo)準(zhǔn)字符串string模板的split()函數(shù)很相似,但是和split()不同的是,Split()不需要輸入一定為string,其他輸入也可以(如列表),它會(huì)自動(dòng)將其進(jìn)行分割成列表,確保輸出格式的正確性。)

? 直接將Split()函數(shù)嵌入到Program中,顯得比較粗魯,可以進(jìn)一步采用臨時(shí)變量增加代碼的可讀性:

src_files = Split('main.c file1.c file2.c')
Program('program', src_files)

? 最后,Split函數(shù)不關(guān)系輸入中有多少個(gè)空格,因此您可以跨行編輯列表,進(jìn)一步提高可讀性:

src_file = Split("""" main.c
                      file1.c 
                      file2.c""")
Program('program', src_files)

? 請(qǐng)注意,在此示例中,我們使用了Python的“三重引用”語(yǔ)法,該語(yǔ)法允許一個(gè)字符串包含多行。三個(gè)引號(hào)可以是單引號(hào)或雙引號(hào)。

3.6 關(guān)鍵字參數(shù)

? SCons同樣支持輸入或輸出文件的關(guān)鍵字定義。輸出文件的關(guān)鍵字是target,輸入源文件的關(guān)鍵字是source:

src_files = Split('main.c file1.c file2.c')
Program(target='program', source=src_files)

? 因?yàn)殛P(guān)鍵字已經(jīng)指明了該參數(shù)的含義,因此關(guān)鍵字的順序不做要求:

src_files = Split('main.c file1.c file2.c')
Program(source=src_files, target='program')

? 是否選擇使用關(guān)鍵字,以及采用關(guān)鍵字時(shí)的順序指定,這些都是是個(gè)人喜好,SCons不做特殊要求。

3.7 編譯多個(gè)工程

? 如果您想采用同一個(gè)SConstruct文件,構(gòu)建多個(gè)工程,最簡(jiǎn)單的方式是調(diào)用Program多次構(gòu)建:

Program('foo.c')
Program('bar', ['bar1.c', 'bar2.c'])

? SCons則會(huì)輸出如下:

> scons -Q
cc -o bar1.o -c bar1.c
cc -o bar2.o -c bar2.c
cc -o bar bar1.o bar2.o
cc -o foo.o -c foo.c
cc -o foo foo.o

? 請(qǐng)注意,SCons不一定按照您在SConstruct文件中指定程序的順序來(lái)構(gòu)建。 但是,SCons確實(shí)認(rèn)識(shí)到必須先構(gòu)建各個(gè)目標(biāo)中間文件,然后才能構(gòu)建最終輸出程序。

3.8 多工程編譯共享中間文件

? 代碼復(fù)用是常見(jiàn)的編程方式,創(chuàng)建庫(kù)文件(動(dòng)態(tài)或靜態(tài)庫(kù))是廣為人知的一種方式。具體庫(kù)文件的創(chuàng)建參見(jiàn)后續(xù)章節(jié)。

? 同一份源碼文件對(duì)應(yīng)多個(gè)工程,最直接的方式是每個(gè)工程都加入該源碼:

Program(Split('foo.c common1.c common2.c'))
Program('bar', Split('bar1.c bar2.c common1.c common2.c'))

? 當(dāng)采用這種方式構(gòu)建時(shí),SCons會(huì)意識(shí)到common1.c和common2.c的復(fù)用,因此會(huì)將其僅僅編譯一份中間文件,盡管生成的目標(biāo)文件分別鏈接到各自的中間文件:

% scons -Q
cc -o bar1.o -c bar1.c
cc -o bar2.o -c bar2.c
cc -o common1.o -c common1.c
cc -o common2.o -c common2.c
cc -o bar bar1.o bar2.o common1.o common2.o
cc -o foo.o -c foo.c
cc -o foo foo.o common1.o common2.o

? 如果兩個(gè)或多個(gè)程序共享許多公共源文件,則可以將公共源文件創(chuàng)建為一個(gè)列表,以便維護(hù)和更改。同時(shí)采用python的+運(yùn)算符進(jìn)行其他列表的擴(kuò)充:

common = ['common1.c', 'common2.c']
foo_files = ['foo.c'] + common
bar_files = ['bar1.c', 'bar2.c'] + common
Program('foo', foo_files)
Program('bar', bar_files)

? 這和前面的寫(xiě)法是完全等價(jià)的。

3.9 構(gòu)建方法參數(shù)的覆蓋

? 您也可以通過(guò)在構(gòu)建方法(如Program等)中增加對(duì)應(yīng)參數(shù),或關(guān)鍵字參數(shù),來(lái)指定相關(guān)的參數(shù),最終參數(shù)會(huì)以此為準(zhǔn)。

env.Program('hello', 'hello.c', LIBS=['gl', 'glut'])

? 或者生成一個(gè)非標(biāo)準(zhǔn)后綴的動(dòng)態(tài)庫(kù):

env.SharedLibrary('word', 'word.cpp',
SHLIBSUFFIX='.ocx',
LIBSUFFIXES=['.ocx'])

? 您也可以采用parse_flags關(guān)鍵字將命令行樣式參數(shù)合并到適當(dāng)?shù)臉?gòu)造變量中。本例將’include‘增加到CPPPATH變量中, 將‘EBUG’加入到CPPDEFINES變量中,以及將'm'加入到LIBS變量中:

enc = Program('hello', 'hello.c', parse_flags='-Iinclude -DEBUG -lm')

? 在對(duì)構(gòu)建方法的調(diào)用中,不會(huì)克隆編譯環(huán)境,而是通過(guò)調(diào)用OverrideEnvironment(), 它會(huì)創(chuàng)建一個(gè)整個(gè)Environment()更輕便編譯環(huán)境。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Python簡(jiǎn)介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡(jiǎn)介】: Python 是一個(gè)...
    _小老虎_閱讀 6,338評(píng)論 0 10
  • http://python.jobbole.com/85231/ 關(guān)于專(zhuān)業(yè)技能寫(xiě)完項(xiàng)目接著寫(xiě)寫(xiě)一名3年工作經(jīng)驗(yàn)的J...
    燕京博士閱讀 7,804評(píng)論 1 118
  • Python語(yǔ)言特性 1 Python的函數(shù)參數(shù)傳遞 看兩個(gè)如下例子,分析運(yùn)行結(jié)果: 代碼一: a = 1 def...
    時(shí)光清淺03閱讀 568評(píng)論 0 0
  • Python語(yǔ)言特性 1 Python的函數(shù)參數(shù)傳遞 看兩個(gè)如下例子,分析運(yùn)行結(jié)果: 代碼一: a = 1 def...
    伊森H閱讀 3,177評(píng)論 0 15
  • 一生中,總有那么幾年,要練習(xí)一個(gè)人生活。有時(shí)候需要左支右絀、三頭六臂,以及十八般武藝。有時(shí)候,很累。有時(shí)候,很孤獨(dú)...
    Kainna閱讀 314評(píng)論 -1 1

友情鏈接更多精彩內(nèi)容