閱讀最新的chromium原始碼,發現專案的構建系統已經從gyp全面切換到gn了。在軟體開發中,經常有人忠告:不要重複造輪子。但谷歌可不管這個,造的輪子乙個接乙個,誰叫人家牛呢?chromiumi專案為啥要折騰構建系統呢?因為谷歌chrome瀏覽器追求乙個字:快。不僅瀏覽器的速度要快,構建系統也要追求快。
在**chromium的最新gn構建系統之前,回顧一下軟體開發中的構建系統。構建系統的需求是隨著軟體規模的增大而提出的。如果只是做軟體程式設計訓練,通常**量比較小,編寫的源**只有幾個檔案。比如你編寫了一段**放入helloworld.c檔案中,要編譯這段**,只需要執行以下命令:
gcc helloworld.c
當軟體規模逐漸增加,這時可能有幾十個源**檔案,而且有了模組劃分,有的要編譯成靜態庫,有的要編譯成動態庫,最後鏈結成可執行**,這時命令列方式就捉襟見肘,需要乙個構建系統。常見的構建系統有gnu make。需要注意的是,構建系統並不是取代gcc這樣的工具鏈,而是定義編譯規則,最終還是會呼叫工具鏈編譯**。
當軟體規模進一步擴大,特別是有多平台支援需求的時候,編寫gnu makefile將是一件繁瑣和乏味的事情,而且極容易出錯。這時就出現了生成makefile的工具,比如cmake、automake等等,這種構建系統稱作元構建系統(meta build system)。在linux上軟體倉庫的概念還沒有普及的時候,通常我們安裝軟體的步驟是:
./configure
make
make install
第一步就是呼叫autotool工具,根據系統環境(linux的版本眾多,軟體安裝情況也不一樣),生成gnu makefile。
在我幾年前接觸chromium開源專案的時候,chromium採用的是gyp(generate your projects)構建系統,這也是一種元構建系統。軟體工程師根據gyp規則編寫構建工程檔案(通常以gyp, gypi為字尾),gyp工具根據gyp檔案生成gnu makefile。接著chromium專案又整出了ninja構建系統,但這個ninja並不是用來取代gyp的,而是取代gnu make的,據谷歌官方的說法是速度有了好幾倍的提公升。對於我們開發者而言,不需要去深入了解ninja或gnu makefile這樣構建系統,因為這只是一種中間輸出,所以ninja的出現,與我們關係不大,原來怎麼寫gyp,現在還是怎麼寫,只是構建命令稍微做了改變。
最近再看chromium的原始碼,發現裡面熟悉的gyp檔案都不見了,取而代之的是gn檔案(以gn和gni為檔名字尾),瞬時感覺一夜回到解放前。然而稍微研究了乙個gn檔案,還是那些熟悉的模組、依賴、條件等等元素,和gyp差別不大,而且總體上比原來的gyp檔案更清晰。
gn是一種元構建系統,生成ninja構建檔案(ninja build files),相較gyp而言,具有如下優點:
從命令列執行gn,這實際上是depot_tools下的乙個指令碼,所以需要確保depot_tools路徑包含在環境變數$path中。
在gyp中,有兩個特定的目錄debug和release目錄,分別用於生成debug版本和release版本。在gn中,採用了更靈活的方式,你隨便指定乙個目錄,比如為了測試,定義乙個test輸出目錄,可以採用如下的命令:
gn gen out/test
那要是我要分別構建debug版本和release版本怎麼辦?gn通過傳遞引數來解決。也就是說,現在光通過輸出目錄是無法確定到底是debug版本和release版本,而要取決於傳遞的構建引數。
將上面的命令稍微修改一下,即可設定構建引數:
gn args out/test
您可以使用下面的命令列出可用的構建引數和它們的預設值:
gn args --list out/test
我在chromium原始碼下執行,引數如此之多,要翻好幾屏,所以不需要記住所有的引數,只需知道幾個比較常用的引數:
is_component_build = true
is_debug = false
前面乙個引數決定是否分動態庫build,現在chrome for android包含了build出了幾十個so,就是這麼來的,好處是節約修改**後的構建時間。後面乙個引數決定是build debug版本還是release版本。
編寫**,比如**檔案為test/hello_world.cc
編寫gn檔案,比如放在和上面**同一目錄下。
executable("hello_world")
開啟原始碼根目錄下的build.gn,加入對上述目標的依賴:
group("root")
這裡//代表原始碼根目錄。
構建
gn gen out/default
ninja -c out/default hello_world
out/default/hello_world
列印
static_library("hello")
可以列印這個目標的配置資訊。
檢視目標資訊
gn desc
out/default
//test:hello_world
這會列出很多詳細的資訊,包括配置引數、目標依賴,通過更複雜的命令引數,你還可以檢視某個巨集定義是在哪個目標定義,目標依賴的樹結構,比如:
gn desc
out/default
//base:base_i18n deps --tree
更多引數的說明可以使用gn help desc檢視。
因為還沒有編寫複雜的gn檔案,所以對gn的優缺點還體會不深,不過對於gyp的幾個深有感受的痛點:
- 多層巢狀,導致gyp檔案難以閱讀和修改,想想chromium下的build/common.gypi這個檔案有多恐怖
- 列印支援
- 對於複雜的依賴缺少有效的手段去定位和排查
這在gn上得到了完美的解決,就衝這這一點,也要為谷歌點贊。雖然是重**明輪子,但輪子比原來的好用啊!
what is gn?
gn quick start guide
chromium中的GN構建系統
chromium中的gn構建系統 原創雲水木石 最後發布於2017 06 23 17 16 35 閱讀數 6924 收藏 展開閱讀最新的chromium原始碼,發現專案的構建系統已經從gyp全面切換到gn了。在軟體開發中,經常有人忠告 不要重複造輪子。但谷歌可不管這個,造的輪子乙個接乙個,誰叫人家牛...
chromium中的效能優化工具syzyProf
我先開始介紹syzyprof。這個工具可以捕獲每個執行緒呼叫每個函式執行的時間,然後把結果生成乙個kcachegrind能夠識別的資料格式檔案,然後通過kcachegrind的展示結果。你就可以知道函式哪個函式執行了次數最多,消耗的時間最多,哪個執行緒在讀寫檔案,哪個執行緒在建立視窗介面,而且kca...
gazebo中的座標系
1 gazebo中link和joint中都有origin的元素。弄了半天好像是明白了。link定義了各個部件的幾何模型,joint定義了各幾何模型直接的座標位置。joint中的origin就是這種連線關係建立的座標系的原點和朝向。比如,就是在世界座標系的 1,0,1 這個點建立了乙個子座標系。而li...