第二章 簡單例程
? 本章會介紹幾個簡單的SCons構建工程,以演示使用SCons在不同類型的系統上根據幾種不同的編程語言來構建程序是多么容易。
2.1 構建簡單的C/C++程序
? 這是一個C語言版的“Hello, World” (文件名:hello.c):
int main() {
printf("Hello, world!\n");
return 0;
}
? 下面介紹如何使用SCons對其進行構建。新建一個SConstruct文件,輸入一下內容:
Program("hello.c")
? 這個簡單的SCons配置描述了兩條信息:工程的構建類型(可執(zhí)行文件、庫文件等)和待編譯文件(hello.c)。Program是一種編譯方法,告訴SCons需要構建一種可執(zhí)行文件。
? 就這樣,現在運行scons命令來構建整個工程。在POSIX平臺系統上,例如Linux或UNIX,你將會看到如下輸出:
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.
? 在windows平臺,采用Micosoft Visual C++編譯器,你將會看到如下輸出:
C:\> scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:hello.exe hello.obj
embedManifestExeCheck(target, source, env)
scons: done building targets.
? 首先,您需要指定源文件的名稱,并且SCons會根據源文件名正確推斷出要構建的對象和可執(zhí)行文件的名稱。
? 其次,相同的輸入SConstruct文件,在兩個系統上會生成正確的輸出文件名。(POSIX:hello.o和hello;WINDWOS:hello.obj和hello.exe)。這是一個簡單的例子,來說明SCOns如何編寫并構建簡單的程序。
(請注意,對于本指南中所有的示例,我們不會同時提供windows和Linux兩種輸出示例,除非有特殊說明,否則輸出效果在兩個平臺上同樣有效)
2.2 構建中間文件
? Program構建方法只是SCons提供的眾多構建方法之一,另外一種構建方法是object,用以生成中間文件:
Object('hello.c')
? 現在你可以執(zhí)行scons命令,去構建整個工程,在POSIX工程中這將會僅僅構建hello.o。
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
scons: done building targets.
? 在windows平臺上,將會僅僅構建出來hello.obj(采用Microsoft Visual C++ 編譯器):
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /Fohello.obj /c hello.c /nologo
scons: done building targets.
2.3 簡單Java構建
? SCons構建Java工程也很簡單,不像Program和Object這些構建方法, Java構建方法需要你指明構建的輸出目標路徑:
Java('classes', 'src')
? 如果src路徑包含了一個hello.java文件,那么執(zhí)行scons命令后的輸出將會如下:
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
javac -d classes -sourcepath src src/hello.java
scons: done building targets.
? 我們會覆蓋更多的java編譯細節(jié),包含java架構和其他類型的文件,詳見第26章。
2.4 編譯后清除
? 采用SCons我們不需要增加特殊的指令在構建后執(zhí)行清除操作,相反,你可以簡單使用-c或者--clean選項,此時SCons會自動刪除構建的文件,所以你可以采用scons -c進行構建后的清理工作,在POSIX平臺上輸出如下:
> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.
> scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed hello.o
Removed hello
scons: done cleaning targets.
? 在windows平臺上輸出如下:
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:hello.exe hello.obj
embedManifestExeCheck(target, source, env)
scons: done building targets.
C:\>scons -c
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed hello.obj
Removed hello.exe
scons: donw cleaning targets.
? 請注意, SCons通過改變輸出來告訴你,它在Cleaning targets ... 和 donw cleaning targets.
2.5 SConstruct文件
? SConstruct文件,類似于Make系統中的Makefile文件,這是SCons讀取并控制編譯構建的輸入文件。
2.5.1 SConstruct文件是Python腳本
? SConstruct和Makefile的最大不同是:SConstruct文件是python腳本,如果你不太熟悉python,也不用擔心,這本指南會詳細介紹Python的相關用法,保證您會高效地使用SCons,而且python也是非常簡單易學的。
? 使用Python作為腳本語言的一個方面是,您可以在SConstruct中使用Python的注釋約定,將注釋放入文件中。也就是說,“?!焙托形仓g的所有內容都將被忽略:
# Arrange to build the "hello" program.
Program('hello.c') # "hello.c" is the source file.
? 在本指南剩余的部分您會發(fā)現,使用腳本語言可以大大簡化復雜的構建過程。
2.5 SCons函數和構建順序無關
? SConstruct有一點和一般python腳本不同,SCons函數的書寫調用順序,并不影響SCons真實的構建順序,這點和Makefile有點相似。換句話說,當你調用Program構建時(或者其他構建方法),SCons并非在此刻構建可執(zhí)行文件,相反,這僅僅是告訴SCons你想要獲得一個可執(zhí)行文件的構建結果。舉例來說,需要構建hello.c的源文件,SCons也僅僅是獲取了構建可執(zhí)行文件hello和源碼hello.c之間的關系。(在第6章會詳細介紹)
? 我們可以通過打印輸出,來區(qū)分SCons僅僅是調用構建方法如Program獲取構建信息,還是真實構建可執(zhí)行文件。通過python的print函數,我們可以看到SCons的Program構建過程:
print("Calling Program('hello.c')")
Program('hello.c')
print("Calling Program('goodbye.c')")
Program('goodbye.c')
print("Finished calling Program()")
? 當執(zhí)行scons指令時,我們可以看到輸出如下:
> scons
scons: Reading SConscript files ...
Calling Program('hello.c')
Calling Program('goodbye.c')
Finished calling Program()
scons: done reading SConscript files.
scons: Building targets ...
cc -o goodbye.o -c goodbye.c
cc -o goodbye goodbye.o
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.
? 注意到,SCons先構建了goodbye,即使在SConstruct中優(yōu)先定義了hello。
2.6 降低SCons輸出詳細程度
? 你已經知道了SCons構建時的一些輸出信息:
C:\>scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:hello.exe hello.obj
embedManifestExeCheck(target, source, env)
scons: done building targets.
? 這些輸出信息描述了SCons的工作順序,SCons會先讀取所有的配置文件(SConstruct和SConscript文件等),其次才是構建具體的目標。這些輸出信息還會描述一些錯誤信息,包括【配置文件讀取過程中的出錯和編譯執(zhí)行過程中的出錯等。
? 當然,這些輸出結果會導致輸出比較混亂,我們可以通過-Q參數來禁用:
C:\>scons -Q
cl /Fohello.obj /c hello.c /nologo
link /nologo /OUT:hello.exe hello.obj
embedManifestExeCheck(target, source, env)
? 因為我們希望本指南用戶重點關注SCons實際在做什么,所以我們將使用該-Q選項,從本指南中所有其他示例的輸出中刪除這些消息。