當前位置:首頁 » 編程軟體 » ninja編譯能成功卻少了東西

ninja編譯能成功卻少了東西

發布時間: 2025-03-23 12:46:19

Ⅰ 一文讀懂ninja構建系統

許多大型項目,比如PyTorch,都把ninja作為構建系統的一部分。為了更好地理解這些項目,對ninja有一個初步的認識是非常必要的。

ninja是一種構建工具,用於調用各種工具(如代碼生成器、編譯器、鏈接器等)來編譯大型項目。與cmake/make等工具不同,ninja並不是為人直接編寫的,而是作為其他程序生成的目標。

ninja的設計哲學是避免任何模糊的內容。例如,makefile中可能會用dir/*.cpp來表示源文件,但需要查詢文件系統才能得到具體內容,這是一個既慢又不確定的操作。ninja將這些模糊的操作都交給了元構建系統(如cmake),只留下真正需要編譯的命令。

因此,本質上ninja就是一條一條地列出了具體要執行的命令,然後執行即可。

ninja會分析這一系列命令之間的依賴關系,並根據這個依賴關系實現兩個重要特點。

ninja的安裝方式有三種,具體可參見文檔。總的來說,有三種安裝方式:直接從GitHub下載、使用pip安裝、使用conda安裝。如果需要保證安全,可以通過ninja的GitHub release頁面下載;如果圖方便,可以使用各種社區維護的安裝方式。

ninja的構建配置文件一般叫做build.ninja。雖然我們一般不直接編寫它,但需要大致看懂它,以便調試或理解構建過程。

下面以一個簡單的例子來說明常見的ninja配置:

有兩個頭文件a1.h和a2.h,分別定義了一個變數a,但是有不同的值。一份源文件a.cpp里根據宏的不同來包含這兩個文件中的某一個。一份build.ninja文件包含了ninja的構建配置(注意最後的換行是必要的)。

有了這份build.ninja,我們可以通過ninja或者ninja compile_with_default_cxxflags來構建默認的代碼,得到可執行文件compile_with_default_cxxflags;也可以通過ninja compile_with_shadow_cxxflags得到可執行文件compile_with_shadow_cxxflags。我們也可以修改a1.h或者a2.h,觀察ninja是否會重新編譯。

這份build.ninja里的大部分內容簡單易懂,唯一難以理解的就是用於增量編譯的depfile = $out.d。

首先,$out是ninja的默認變數,表示構建的目標文件名。所以$out.d就是目標文件名加上.d。比如build compile_with_default_cxxflags里,depfile就是compile_with_default_cxxflags.d。

然後我們需要理解增量構建的目標:我們的build compile_with_default_cxxflags構建條目中,只傳入了a.cpp這一個文件,但是實際上我們的代碼裡麵包含了a1.h或者a2.h。如何能夠讓ninja知道增量構建的時候需要檢查a1.h或者a2.h呢?這就需要編譯器的支持了:g++的-MM -MF $out.d參數會將文件與頭文件的依賴關系輸出到$out.d中,下次ninja就會通過這個文件的內容來判斷具體需要檢查發生改變的文件。

例如,compile_with_default_cxxflags.d文件里,就有以下內容:

下次ninja再build compile_with_default_cxxflags的時候,就會檢查這個文件,然後查看a.cpp與a1.h的修改時間,如果任何一個文件被修改了,就重新編譯。另外,如果compile_with_default_cxxflags文件不在了,ninja也會重新編譯。

很多ninja.build里存在phony規則。這是一個內置規則,意思是「假冒的」,就是一個不存在規則的規則。我們可以理解為:

其中冒號:是unix系統里的一個命令,不管參數是什麼,永遠正常退出。因此,phony規則不會做什麼,但是會在輸入和輸出之間建立依賴關系。

不帶參數的ninja命令會構建文件里的default構建目標。我們也可以用ninja compile_with_shadow_cxxflags來手動構建某個目標。

構建多個目標(比如PyTorch有上千個目標)的時候,ninja會展示一個進度條,進度條展現的內容就是rule下面的description欄位的內容。

ninja的高級用法一般都在ninja -t下面,例如ninja -t clean可以清理全部生成文件、ninja -t browse可以打開一個網頁瀏覽器查看文件之間的依賴圖(默認查看的是名為all的依賴圖):

通過這個瀏覽器界面,我們可以很方便地查看什麼文件依賴於什麼文件。打開http://localhost:8000/?libtorch.so就可以看到完整的libtorch.so對應的依賴,再也不用對著CMakeLists.txt瞎猜了。(還可以通過ninja -t graph直接導出依賴圖的dot graph文件,但是大型項目的依賴圖一般都非常復雜,看起來不方便。)

最後,ninja -t targets all得到的是全部的構建目標,可以用於grep搜索想要的內容;ninja -C /path/to/dir -f /path/to/file可以讓ninja切換到/path/to/dir去執行命令、並讀取/path/to/file配置文件來執行。-f的默認參數是build.ninja,-C的默認參數為.,也就是當前路徑。一般來說-f參數用得很少,-C參數用得比較多。

本文簡單介紹了ninja的一些原理及用法。雖然簡單,但依然起了個「一文讀懂ninja構建系統」的標題,就是因為ninja真的很小,它的全部文檔差不多也就這些值得我們關心的內容。

熱點內容
c語言的環境變數 發布:2025-03-26 05:20:57 瀏覽:956
哪個牌子的安卓手機界面好看 發布:2025-03-26 05:10:11 瀏覽:976
小樹茶存儲 發布:2025-03-26 05:04:56 瀏覽:571
pt上傳慢 發布:2025-03-26 04:31:17 瀏覽:53
阿里雲伺服器哪個好用 發布:2025-03-26 04:26:09 瀏覽:242
windows編程技術 發布:2025-03-26 04:19:47 瀏覽:422
養生密碼的產品怎麼樣 發布:2025-03-26 04:10:26 瀏覽:384
php中斷for 發布:2025-03-26 04:04:07 瀏覽:878
怎麼輸入管理員密碼 發布:2025-03-26 04:01:30 瀏覽:672
網路雲存儲伺服器 發布:2025-03-26 04:01:22 瀏覽:641