chromium中的GN構建系統

2022-03-20 05:07:56 字數 3421 閱讀 4508

chromium中的gn構建系統

原創雲水木石 最後發布於2017-06-23 17:16:35 閱讀數 6924 收藏

展開閱讀最新的chromium原始碼,發現專案的構建系統已經從gyp全面切換到gn了。在軟體開發中,經常有人忠告:不要重複造輪子。但谷歌可不管這個,造的輪子乙個接乙個,誰叫人家牛呢?chromiumi專案為啥要折騰構建系統呢?因為谷歌chrome瀏覽器追求乙個字:快。不僅瀏覽器的速度要快,構建系統也要追求快。

構建系統簡介

在**chromium的最新gn構建系統之前,回顧一下軟體開發中的構建系統。構建系統的需求是隨著軟體規模的增大而提出的。如果只是做軟體程式設計訓練,通常**量比較小,編寫的源**只有幾個檔案。比如你編寫了一段**放入helloworld.c檔案中,要編譯這段**,只需要執行以下命令:

gcc helloworld.c

1當軟體規模逐漸增加,這時可能有幾十個源**檔案,而且有了模組劃分,有的要編譯成靜態庫,有的要編譯成動態庫,最後鏈結成可執行**,這時命令列方式就捉襟見肘,需要乙個構建系統。常見的構建系統有gnu make。需要注意的是,構建系統並不是取代gcc這樣的工具鏈,而是定義編譯規則,最終還是會呼叫工具鏈編譯**。

當軟體規模進一步擴大,特別是有多平台支援需求的時候,編寫gnu makefile將是一件繁瑣和乏味的事情,而且極容易出錯。這時就出現了生成makefile的工具,比如cmake、automake等等,這種構建系統稱作元構建系統(meta build system)。在linux上軟體倉庫的概念還沒有普及的時候,通常我們安裝軟體的步驟是:

./configure

make

make install12

3第一步就是呼叫autotool工具,根據系統環境(linux的版本眾多,軟體安裝情況也不一樣),生成gnu makefile。

chromium中的構建系統

在我幾年前接觸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構建系統

gn是一種元構建系統,生成ninja構建檔案(ninja build files),相較gyp而言,具有如下優點:

可讀性更好,更容易編寫和維護。

速度更快,谷歌官方給的資料是20倍的速度提公升。

修改gn檔案後,執行ninja構建時會自動更新ninja構建檔案。以前用gyp的時候就有過修改了gyp,而忘記使用gyp命令重新生成ninja構建檔案的尷尬。

更簡單的模組依賴,提供了public_deps, data_deps等,在gyp中,只有一種目標依賴,導致依賴關係錯綜複雜,容易引入不必要的模組依賴。

提供了更好的工具查詢模組依賴圖譜。這在gyp構建系統中是乙個噩夢,要查乙個目標依賴哪些模組或者乙個模組被哪些目標依賴幾乎是不可能的。

更好的除錯支援。為了列印gyp中的變數值,我以前還專門寫過一篇博文《如何列印gyp構建系統中的變數值》,在gn中,只需要一條print語句就可以解決。

快速入門

執行gn

從命令列執行gn,這實際上是depot_tools下的乙個指令碼,所以需要確保depot_tools路徑包含在環境變數$path中。

配置乙個構建

在gyp中,有兩個特定的目錄debug和release目錄,分別用於生成debug版本和release版本。在gn中,採用了更靈活的方式,你隨便指定乙個目錄,比如為了測試,定義乙個test輸出目錄,可以採用如下的命令:

gn gen out/test

1那要是我要分別構建debug版本和release版本怎麼辦?gn通過傳遞引數來解決。也就是說,現在光通過輸出目錄是無法確定到底是debug版本和release版本,而要取決於傳遞的構建引數。

傳遞構建引數

將上面的命令稍微修改一下,即可設定構建引數:

gn args out/test

1您可以使用下面的命令列出可用的構建引數和它們的預設值:

gn args --list out/test

1我在chromium原始碼下執行,引數如此之多,要翻好幾屏,所以不需要記住所有的引數,只需知道幾個比較常用的引數:

is_component_build = true

is_debug = false12

前面乙個引數決定是否分動態庫build,現在chrome for android包含了build出了幾十個so,就是這麼來的,好處是節約修改**後的構建時間。後面乙個引數決定是build debug版本還是release版本。

從編寫**到build

編寫**,比如**檔案為test/hello_world.cc

編寫gn檔案,比如放在和上面**同一目錄下。

executable("hello_world") 12

345開啟原始碼根目錄下的build.gn,加入對上述目標的依賴:

group("root") 12

3456

7這裡//代表原始碼根目錄。

構建gn gen out/default

ninja -c out/default hello_world

out/default/hello_world12

3除錯列印static_library("hello") 12

34可以列印這個目標的配置資訊。

檢視目標資訊

gn desc out/default //test:hello_world

1這會列出很多詳細的資訊,包括配置引數、目標依賴,通過更複雜的命令引數,你還可以檢視某個巨集定義是在哪個目標定義,目標依賴的樹結構,比如:

gn desc out/default //base:base_i18n deps --tree

1更多引數的說明可以使用gn help desc檢視。

總結因為還沒有編寫複雜的gn檔案,所以對gn的優缺點還體會不深,不過對於gyp的幾個深有感受的痛點:

- 多層巢狀,導致gyp檔案難以閱讀和修改,想想chromium下的build/common.gypi這個檔案有多恐怖

- 列印支援

- 對於複雜的依賴缺少有效的手段去定位和排查

這在gn上得到了完美的解決,就衝這這一點,也要為谷歌點贊。雖然是重**明輪子,但輪子比原來的好用啊!

chromium中的GN構建系統

閱讀最新的chromium原始碼,發現專案的構建系統已經從gyp全面切換到gn了。在軟體開發中,經常有人忠告 不要重複造輪子。但谷歌可不管這個,造的輪子乙個接乙個,誰叫人家牛呢?chromiumi專案為啥要折騰構建系統呢?因為谷歌chrome瀏覽器追求乙個字 快。不僅瀏覽器的速度要快,構建系統也要追...

chromium中的效能優化工具syzyProf

我先開始介紹syzyprof。這個工具可以捕獲每個執行緒呼叫每個函式執行的時間,然後把結果生成乙個kcachegrind能夠識別的資料格式檔案,然後通過kcachegrind的展示結果。你就可以知道函式哪個函式執行了次數最多,消耗的時間最多,哪個執行緒在讀寫檔案,哪個執行緒在建立視窗介面,而且kca...

gazebo中的座標系

1 gazebo中link和joint中都有origin的元素。弄了半天好像是明白了。link定義了各個部件的幾何模型,joint定義了各幾何模型直接的座標位置。joint中的origin就是這種連線關係建立的座標系的原點和朝向。比如,就是在世界座標系的 1,0,1 這個點建立了乙個子座標系。而li...