Ninja構建系統入門

1. 介紹

開篇先介紹、先甩資料給你們看,以後再本身演示一下基本使用。Ninja 是Google的一名程序員推出的注重速度的構建工具,通常在Unix/Linux上的程序經過make/makefile來構建編譯,而Ninja經過將編譯任務並行組織,大大提升了構建速度。html

官網:ninja-build.orgpython

Github:github.com/ninja-build/ninjaandroid

2. 參考資料

《The Performance Of Open Source Application》第三章git

使用Ninja代替make程序員

零壹軒Ninja相關文章(推薦!)github

Ninja編譯過程分析shell

Ninja - chromium核心構建工具數據庫

3. 使用

3.1. cmake生成

通常是經過cmake來生成ninja的配置,進而進行編譯。先從cmake-examples入門:github.com/ttroy50/cmake-examples瀏覽器

好比01-basic\B-hello-headers項目,運行指令:cmake -Bbuild -GNinja 便可生成ninja工程。緩存

運行ninja編譯:

3.2. 手動寫ninja配置文件

本文重點演示一下手寫ninja配置文件方法,Demo工程結構:

./build.ninja
./src/jfz.cpp

其中jfz.cpp:

#include "Hello.h"

int main(int argc, char *argv[])
{
    printf("sandeepin poi!");
    return 0;
}

build.ninja(注意結尾要有空行):

# 指定ninja最小須要版本
ninja_required_version = 1.5

# 變量
GCC = D:\Library\MinGW\bin\g++.exe
cflags = -Wall

# 編譯規則,指定depfile,能夠用於生成ninja_deps文件
rule compile_jfz
  command = $GCC -c $cflags -MD -MF $out.d $in -o $out
  description = 編譯 $in 成爲 $out
  depfile = $out.d
  deps = gcc
build jfz.o : compile_jfz src/jfz.c

# 連接規則
rule link_jfz
  command = $GCC $DEFINES $INCLUDES $cflags $in -o $out
  description = 連接 $in 成爲 $out
build jfz.exe : link_jfz jfz.o

# 編譯all,就是作任務build jfz.exe
build all: phony jfz.exe

# 默認編譯什麼(單獨運行ninja)
default all

運行效果:

第一次運行按任務先編譯,再連接,最終產生了可執行文件,第二次運行因爲沒改文件,ninja不處理。ninja支持以下參數:

--version  # 打印版本信息
-v         # 顯示構建中的全部命令行(這個對實際構建的命令覈對很是有用)

-C DIR     # 在執行操做以前,切換到`DIR`目錄
-f FILE    # 制定`FILE`爲構建輸入文件。默認文件爲當前目錄下的`build.ninja`。如 ./ninja -f demo.ninja

-j N       # 並行執行 N 個做業。默認N=3(須要對應的CPU支持)。如 ./ninja -j 2 all
-k N       # 持續構建直到N個做業失敗爲止。默認N=1
-l N       # 若是平均負載大於N,不啓動新的做業
-n         # 排練(dry run)(不執行命令,視其成功執行。如 ./ninja -n -t clean)

-d MODE    # 開啓調試模式 (用 -d list 羅列全部的模式)
-t TOOL    # 執行一個子工具(用 -t list 羅列全部子命令工具)。如 ./ninja -t query all
-w FLAG    # 控制告警級別

ninja -d list相關:

debugging modes:
  stats        print operation counts/timing info 打印統計信息
  explain      explain what caused a command to execute 解釋致使命令執行的緣由
  keepdepfile  don't delete depfiles after they're read by ninja 讀取depfile後,不刪除它
  keeprsp      don't delete @response files on success 讀取@response後,不刪除它
  nostatcache  don't batch stat() calls per directory and cache them 不對每一個目錄批量處理stat()調用和緩存它們
multiple modes can be enabled via -d FOO -d BAR 多模式調用能夠接着幾個-d

ninja -w list相關,主要指定幾種狀況下告警級別是多少:

warning flags:
  dupbuild={err,warn}  multiple build lines for one target
  phonycycle={err,warn}  phony build statement references itself
  depfilemulti={err,warn}  depfile has multiple output paths on separate lines

ninja -t list相關,主要集成了graphviz等一些對開發很是有用的工具。

ninja subtools:
    browse  # 在瀏覽器中瀏覽依賴關係圖。(默認會在8080端口啓動一個基於python的http服務)
     clean  # 清除構建生成的文件
  commands  # 羅列從新構建制定目標所需的全部命令
      deps  # 顯示存儲在deps日誌中的依賴關係
     graph  # 爲指定目標生成 graphviz dot 文件。如 ninja -t graph all |dot -Tpng -o graph.png
     query  # 顯示一個路徑的inputs/outputs
   targets  # 經過DAG中rule或depth羅列target
    compdb  # dump JSON兼容的數據庫到標準輸出
 recompact  # 從新緊湊化ninja內部數據結構

這裏主要列舉幾種參數執行效果:

-n是假執行,實際未產生文件,因爲假執行,keepdepfile沒起到效果,這個受限於編譯器分析依賴,下面的統計信息就是stats效果,explain解釋了爲何執行這些任務。

這裏-v打印每一個任務執行了哪些指令,可見到keepdepfile生效了,保存了依賴.d文件。

ninja工具舉例:

一、顯示依賴

二、顯示執行指令

三、顯示目標

四、繪依賴圖(要安裝graphviz,直接打印出dot文本)

轉圖片(支持png、svg等,大圖推薦svg渲染,相關dot參數見graphviz文檔):

ninja -t graph | dot -Tpng -o jfz.png

這個demo比較簡單,實際上依賴分析功能須要編譯器提供,或者任務本身輸出依賴文件,ninja只作一個任務編排和執行功能。

4. 信息補充

4.1. 環境變量

經過環境變量NINJA_STATUS能夠控制ninja打印進度狀態的樣式,有幾個佔位符:

%s 起始edges的數量。
%t 完成構建必須運行的edges總數。
%p 起始edges的百分比。
%r 當前運行的edges數。
%u 要開始的剩餘edges數。
%f 完成的edges數。
%o 每秒完成edges的總速率
%c 當前每秒完成edges的速率(由-j或其默認值指定的構建的平均值)
%e 通過的時間(以秒爲單位)。(自Ninja 1.2起可用。)
%% 一個普通的%字符。
默認進度狀態爲"[%f/%t] "(請注意尾隨空格以與構建規則分開)。可能的進度狀態的另外一個示例多是"[%u/%r/%f] "。

嘗試改成export NINJA_STATUS="[%p/%f/%t %e] "(Windows下set NINJA_STATUS="[%p/%f/%t %e] ")的效果以下:

4.2. ninja_log每項含義

依次爲:開始時間、結束時間、mtime、output文件路徑名、命令行hash。

其中mtime是輸入文件們的最後修改時間的時間戳算出來的值,經測試,開始時間、結束時間、命令行hash均不會影響增量的斷定。

4.3. mtime檢查文件測試

假設如今時間是2019-12-31 15:35:55,將輸入.c文件修改時間改成以前的,不會觸發從新編譯;將輸入.c文件修改時間改成將來的,每次都觸發編譯。

4.4. frontend_file參數

特別的,AOSP定製版的ninja有frontend_file參數,能夠將控制檯輸出信息轉爲流存儲,經過其它的工具如tail -f xxx查看信息。soong源碼中就是這樣讀取ninja日誌的,效率更高,以前應該是靠cat捕獲日誌的吧。見這個提交

4.5. ninja檢測的是任務名的文件是否生成

若是我讓輸出文件和任務名不同,ninja每次都會從新編譯:

這點要注意,爲了利用ninja的增量特性,除非無可奈何,不要讓輸出文件和任務名不一樣。

源碼編譯

本文僅嘗試官方版的編譯,AOSP版本能夠依賴不一樣,GCC版本要求不一樣,須要注意。

相關文章
相關標籤/搜索