Ninja - chromium核心構建工具


轉自:http://guiquanz.me/2014/07/28/a_intro_to_Ninja/

 

Ninja - chromium核心構建工具Jul 28, 2014

[在線編輯]

緣由

經過上次對chromium核心代碼的初步了解之后,我轉頭去研究了一番ninja,並對其進行了一些改造(愛折騰的,都是小NB)。今天就來簡單介紹一下ninja及其使用。(BTW: 細節的內容,大家閱讀ninja 的手冊就好了,我這里不會關注。)

ninja一個專注於速度的小型構建系統(Ninja is a small build system with a focus on speed)。ninja是其作者為了解決chromium代碼編譯慢這個問題(具體一點,就是發生在將Chrome移植到非Windows平台過程中的事情。欲知詳情,請閱讀Ninja, a new build system)而誕生的。其設計受到the tup build systemredo的啟發。ninja核心是由C/C++編寫的,同時有一部分輔助功能由pythonshell實現。

ninja可以很好的組合gypCMake一起使用,后者為其生成.ninja文件。

ninja項目的最終編譯產出物是一個可執行文件ninja。

下載代碼 並 編譯


mkdir -p ~/ninja && cd ~/ninja
git clone https://github.com/martine/ninja
cd ninja
python ./bootstrap.py

(BTW:以上過程編譯生成可執行文件ninja。需要預先安裝 graphviz及其開發庫,gtestgitre2cpython

測試

由於在編譯ninja的過程中bootstrap.py腳本通過調用configure.pyplatform_helper.py生成了ninja項目的構建文件build.ninja,所以我們只需要執行./ninja ninja_test就可以通過ninja構建生成測試文件ninja_test。這樣就可以執行測試了。


./ninja ninja_test
./ninja all

ninja 工具介紹

在介紹ninja的文法之前,還是先了解一下ninja的使用吧。執行./ninja -h顯示幫助信息。具體參數說明,如下:


usage: ninja [options] [targets...]

if targets are unspecified, builds the 'default' target (see manual).

options:
  --version  # 打印版本信息(如當前版本是1.5.1)

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

  -j N     # 並行執行 N 個作業。默認N=3(需要對應的CPU支持)。如 ./ninja -j 2 all
  -l N     # 如果平均負載大於N,不啟動新的作業
  -k N     # 持續構建直到N個作業失敗為止。默認N=1
  -n       # 排練(dry run)(不執行命令,視其成功執行。如 ./ninja -n -t clean)
  -v       # 顯示構建中的所有命令行(這個對實際構建的命令核對非常有用)

  -d MODE  # 開啟調試模式 (用 -d list 羅列所有的模式)
  -t TOOL  # 執行一個子工具(用 -t list 羅列所有子命令工具)。如 ./ninja -t query all

ninja還集成了graphviz等一些對開發非常有用的工具。具體如下:(也就是執行 ./ninja -t list 的結果)


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內部數據結構

ninja文件示例

聊了半天,ninja的構建文件長什么模樣呢?以下的demo就是一個執行echo,打印一行文字的ninja構建文件,和make的Makefile很類似。


rule demo
  command = echo "this is a demo of $foo"

build out: demo
  foo = bar

編寫你自己的ninja文件

Ninja和Make非常相似。他執行一個文件之間的依賴圖,通過檢測文件修改時間,運行必要的命令來更新你的構建目標

一個構建文件(默認文件名為:build.ninja)提供一個rule(規則)表——長命令的簡短名稱,和運行編譯器的方式一下。同時,附帶提供build(構建)語句列表,表明通過rule如何構建文件——哪條規則應用於哪個輸入產生哪一個輸出。

從概念上講,build語句描述項目的依賴圖;而rule語句描述當給定一個圖的一條邊時,如何生成文件。

語法示例

這是一個用於驗證絕大部分語法的.ninja文件,將作為后續描述相關的示例。具體內容,如下:


cflags = -Wall

rule cc
  command = gcc $cflags -c $in -o $out

build foo.o: cc foo.c

變量

ninja支持為字符串聲明簡短可讀的名字。一個聲明的語法,如下:


cflags = -g

可以在=右邊使用,並通過$進行引用(類似shellperl的語法)。具體形式,如下:


rule cc
  command = gcc $cflags -c $in -o $out

變量還可以用${in}($和成對的大括號)來引用。

當給定變量的值不能被修改,只能覆蓋(shadowed)時,變量更恰當的叫法是綁定("bindings")。

rule 規則

規則為命令行聲明一個簡短的名稱。他們由關鍵字rule一個規則名稱打頭的行開始,然后緊跟着一組帶縮進格式的 variable = value行組成。

以上示例中聲明了一個名為cc的rule,連同一個待運行的命令。在rule(規則)上下文中,command變量用於定義待執行的命令,$in展開(expands)為輸入文件列表(foo.c),而$out為命令的輸出文件列表(foo.o)。參考手冊中羅列了所有特殊的變量。

buid 構建語句

build語句聲明輸入和輸出文件之間的一個關系。構建語句由關鍵字build開頭,格式為build outputs: rulename inputs。這樣的一個聲明,所有的輸出文件來源於(derived from)輸入文件。當缺輸出文件或輸入文件變更時,Ninja將會運行此規則來重新生成輸出。

以上的簡單示例,描述了使用cc規則如何構建foo.o文件。

build block范圍內(包括相關規則的執行),變量$in表示輸入列表,$out表示輸出列表。

一個構建語句,可以和rule一樣,緊跟一組帶縮進格式的key = value對。當在命令中變量執行時,這些變量將覆蓋(shadow)任何變量。比如:


cflags = -Wall -Werror
rule cc
  command = gcc $cflags -c $in -o $out

# 如果沒有制定,build的輸出將是$cflags
build foo.o: cc foo.c

# 但是,你可以在特殊的build中覆蓋cflags這樣的變量
build special.o: cc special.c
  cflags = -Wall

# cflags變量僅僅覆蓋了special.o的范圍
# 以下的子序列build行得到的是外部的(原始的)cflags
build bar.o: cc bar.c

從代碼中生成Ninja文件

Ninja發行包中的misc/ninja_syntax.py是一個很小的python模塊,用於生成Ninja文件。你可以使用python,執行如ninja.rule(name='foo', command='bar', depfile='$out.d')的調用,生成合適的語法。如果這樣還不錯,可以將其整合到你的項目中。

更多細節

phony 規則

可以使用特殊的規則phony,創建其他target(編譯構建目標)的別名。比如:


build foo: phony some/file/in/a/faraway/subdir/foo

這樣使得ninja foo構建更長的路徑。從語義上講,phony規則等同於一個沒有做任何操作的普通規則,但是phony規則通過特殊的方式進行處理,這樣當其運行時不會被打印,記日志,也不作為構建過程中打印出來的命令計數。

還可以用phony為構建時可能還不存在的文件創建dummy目標。

default 目標語句

默認情況下,如果沒有在命令行中指定target,那么Ninja將構建任何地方沒有作為輸入命名的每一個輸出。可以通過default目標語句來重寫這個行為。一個default語句,讓Ninja構建一個給定的輸出文件子集,如果命令行中沒有指定構建目標

默認目標語句,由關鍵字default打頭,並且采用default targets的格式。一個default目標語句必須出現在,聲明這個目標作為一個輸出文件的構建語句之后。他們是累積的(cumulative),所以可以使用多個default語句來擴展默認目標列表。比如:


default foo bar
default baz

Ninja構建日志

Ninja構建日志保存在構建過程的跟目錄或.ninja文件中builddir變量對應的目錄的.ninja_log文件中。

C/C++頭文件依賴

Ninja目前支持depfiledeps模式的C/C++頭文件依賴生成。 如


rule cc
  depfile = $out.d
  command = gcc -MMD -MF $out.d [other gcc flags here]

-MMD標識告訴gcc要生成頭文件依賴,-MF則說明要寫到哪里。

deps按照編譯器的名詞來管理。具體如下:(針對微軟的VC:msvc)


rule cc
  deps = msvc
  command = cl /showIncludes -c $in /Fo$out

Pools

為了支持並發作業,Ninja還支持pool的機制(和用-j並行模式一樣)。此處不詳細描述了。具體示例,如下:


# No more than 4 links at a time.
pool link_pool
  depth = 4

# No more than 1 heavy object at a time.
pool heavy_object_pool
  depth = 1

rule link
  ...
  pool = link_pool

rule cc
  ...

# The link_pool is used here. Only 4 links will run concurrently.
build foo.exe: link input.obj

# A build statement can be exempted from its rule's pool by setting an
# empty pool. This effectively puts the build statement back into the default
# pool, which has infinite depth.
build other.exe: link input.obj
  pool =

# A build statement can specify a pool directly.
# Only one of these builds will run at a time.
build heavy_object1.obj: cc heavy_obj1.cc
  pool = heavy_object_pool
build heavy_object2.obj: cc heavy_obj2.cc
  pool = heavy_object_pool
The console pool

更加詳細的語法

請閱讀參考手冊,此處只做概要說明。

一個ninja構建文件,由一系列的聲明構成。一個聲明可以是一個:

  • rule聲明,由rule rulename開頭,然后緊跟一系列帶縮進的變量定義行

  • 一個build邊,其格式為build output1 output2: rulename input1 input2。隱士依賴用| dependency1 dependency2表達;Order-only依賴用行末的|| dependency1 dependency2表達。

  • 變量聲明,形如variable = value

  • 默認目標語句,形如default target1 target2

  • 引入更多的文件,形如subninja pathinclude path

  • 一個pool聲明,形如pool poolname

詞法

Ninja僅支持ASCII字符集。

注釋以為#開始一直到行末。

新行是很重要的。像build foo bar的語句,是一堆空格分割分詞(token),到換行結束。一個分詞中的新行空格必須進行轉譯。

目前只有一個轉譯字符,$,其具有以下行為:


$ followed by a newline

轉譯換行,讓當前行一直擴展到下一行。


$ followed by text

這是, 變量引用。


${varname}

這是,另$varname的另一種語法。


$ followed by space

這表示一個空格。(僅在path列表中,需要用空格分割文件名)


$:

這表示一個冒號。(僅在build行中需要。此時冒號終止輸出列表)


$$

這個表示,字面值的$

一個build或default語句,最先被解析,作為一個空格分割的文件名列表,然后每一個name都被展開。也就是說,變量中的一個空格將作為被展開后文件名中的一個空格。


spaced = foo bar
build $spaced/baz other$ file: ...
# The above build line has two outputs: "foo bar/baz" and "other file".

在一個name = value語句中,value前的空白都會被去掉。出現跨行時,后續行起始的空白也會被去掉。


two_words_with_one_space = foo $
    bar
one_word_with_no_space = foo$
    bar

其他的空白,僅位於行開始處的很重要。如果一行的縮進比前一行多,那么被人為是其父邊界的一部分。如果縮進比前一行少,那他就關閉前一個邊界

頂層變量

Ninja支持的頂層變量有builddirninja_required_version。具體說明,如下:

  • builddir: 構建的一些輸出文件的存放目錄。
  • ninja_required_version:指定滿足構建需求的最小Ninja版本。

rule變量

一個rule塊包含一個key = value的列表聲明,這直接影響規則的處理。以下是一些特殊的key:

  • command (required): 待執行的命令。這個字符串($variables被展開之后),被直接傳遞給sh -c,不經過Ninja翻譯。每一個規則只能包含一條command聲明。如果有多條命令,需要使用&&符號進行鏈接。

  • depfile: 指向一個可選的Makefile,其中包含額外的隱式依賴。這個明確的為了支持C/C++的頭文件依賴。

  • deps: (1.3版本開始支持)如果存在,必須是gcc或msvc,來指定特殊的依賴。產生的數據庫保存在builddir指定目錄.ninja_deps文件中。

  • msvc_deps_prefix: (1.5版本開始支持)定義必須從msvc的/showIncludes輸出中去掉的字符串。僅在deps = msvc而且使用非英語的Visual Studio版本時使用。

  • description: 命令的簡短描述,作為命令運行時更好的打印輸出。打印整行還是對應的描述,由-v標記控制。如果一個命令執行失敗,整個命令行總是在命令輸出之前打印。

  • generator: 如果存在,指明這條規則是用來重復調用生成器程序。通過兩種特殊的方式,處理使用生成器規則構建文件:首先,如果命令行修改了,他們不會重新構建;其次,默認不會被清除。

  • in: 空格分割的文件列表被作為一個輸入傳遞給引用此rule的構建行,如果出現在命令中需要使用${in}(shell-quoted)。(提供$in僅僅為了圖個方便,如果你需要文件列表的子集或變種,請構建一個新的變量,然后傳遞新的變量。)

  • in_newline: 和$in一樣,只是分割符為換行而不是空格。(僅為了和$rspfile_content一起使用,解決MSVC linker使用固定大小的緩沖區處理輸入,而造成的一個bug。)

  • out: 空格分割的文件列表被作為一個輸出傳遞給引用此rule的構建行,如果出現在命令中需要使用${out}

  • restat: 如果存在,引發Ninja在命令行執行完之后,重新統計命令的輸出。

  • rspfile, rspfile_content: 如果存在(兩個同時),Ninja將為給定命令提供一個響應文件,比如,在調用命令之前將選定的字符串(rspfile_content)寫到給定的文件(rspfile),命令執行成功之后闡述文件。

這個在Windows系統非常有用,因為此時命令行的最大長度非常受限,必須使用響應文件替代。具體使用方式,如下:


rule link
  command = link.exe /OUT$out [usual link flags here] @$out.rsp
  rspfile = $out.rsp
  rspfile_content = $in

build myapp.exe: link a.obj b.obj [possibly many other .obj files]

構建依賴

Ninja目前支持3種類型的構建依賴。分別是:

  • 羅列在build行中的顯式的依賴。他們可以作為規則中的$in變量。這是標准依賴格式。

  • depfile屬性或構建語句末尾的| dep1 dep2語法獲得的隱式依賴。這個和顯式依賴一樣,但是不能在$in中使用(不可見)。

  • 通過構建行末|| dep1 dep2語法表示的次序唯一(Order-only)依賴。他們過期的時候,輸出不會被重新構建,直到他們被重建,但修改這種依賴不會引發輸出重建。

變量展開

變量在路徑(在build或default語句)和name = value右邊被展開。

name = value語句被執行,右手邊的被立即展開(根據以下的規則),從此$name擴展為被展開結果的靜態字符串。永遠也不會存在,你將需要使用雙轉譯("double-escape")來保護一個值被第二次展開。

所有變量在解析過程,遇到的時候立即被展開,除了一個非常重要的例外:rule塊中的變量僅在規則被使用的時候才被展開,而不是聲明的時候。在以下的示例中,demo打印出"this is a demo of bar"而不是"this is a demo of $foo"。


rule demo
  command = echo "this is a demo of $foo"

build out: demo
  foo = bar

評估和邊界

頂層(Top-level)變量聲明的邊界,是相關的文件。

subninja關鍵自,用於包含另一個.ninja文件,其表示新的邊界。被包含的subninja文件可以使用父文件中的變量,在文件邊界中覆蓋他們的值,但是這不影響父文件中變量的值。

同時,可以用#include語句在當前邊界內,引入另一個.ninja文件。這個有點像C中的#include語句。

構建塊中聲明的變量的邊界,就是其所屬的塊。一個構建塊中展開的變量的所有查詢次序為:

  • 特殊內建變量($in, $out);
  • build/rule塊中構建層的變量;
  • 構建行所在文件中的文件層變量(File-level);
  • 使用subninja關鍵字引入那個文件的(父)文件中的變量。

最后再看一下編譯ninja的構建文件


# This file is used to build ninja itself.
# It is generated by configure.py.

ninja_required_version = 1.3

# The arguments passed to configure.py, for rerunning it.
configure_args = --platform=linux

builddir = build
cxx = g++
ar = ar
cflags = -g -Wall -Wextra -Wno-deprecated -Wno-unused-parameter -fno-rtti $
    -fno-exceptions -fvisibility=hidden -pipe $
    -Wno-missing-field-initializers '-DNINJA_PYTHON="python"' -O2 -DNDEBUG $
    -DUSE_PPOLL
ldflags = -L$builddir

rule cxx
  command = $cxx -MMD -MT $out -MF $out.d $cflags -c $in -o $out
  description = CXX $out
  depfile = $out.d
  deps = gcc

rule ar
  command = rm -f $out && $ar crs $out $in
  description = AR $out

rule link
  command = $cxx $ldflags -o $out $in $libs
  description = LINK $out

# browse_py.h is used to inline browse.py.
rule inline
  command = src/inline.sh $varname < $in > $out
  description = INLINE $out
build $builddir/browse_py.h: inline src/browse.py | src/inline.sh
  varname = kBrowsePy

build $builddir/browse.o: cxx src/browse.cc || $builddir/browse_py.h

# the depfile parser and ninja lexers are generated using re2c.
rule re2c
  command = re2c -b -i --no-generation-date -o $out $in
  description = RE2C $out
build src/depfile_parser.cc: re2c src/depfile_parser.in.cc
build src/lexer.cc: re2c src/lexer.in.cc

# Core source files all build into ninja library.
build $builddir/build.o: cxx src/build.cc
build $builddir/build_log.o: cxx src/build_log.cc
build $builddir/clean.o: cxx src/clean.cc
build $builddir/debug_flags.o: cxx src/debug_flags.cc
build $builddir/depfile_parser.o: cxx src/depfile_parser.cc
build $builddir/deps_log.o: cxx src/deps_log.cc
build $builddir/disk_interface.o: cxx src/disk_interface.cc
build $builddir/edit_distance.o: cxx src/edit_distance.cc
build $builddir/eval_env.o: cxx src/eval_env.cc
build $builddir/graph.o: cxx src/graph.cc
build $builddir/graphviz.o: cxx src/graphviz.cc
build $builddir/lexer.o: cxx src/lexer.cc
build $builddir/line_printer.o: cxx src/line_printer.cc
build $builddir/manifest_parser.o: cxx src/manifest_parser.cc
build $builddir/metrics.o: cxx src/metrics.cc
build $builddir/state.o: cxx src/state.cc
build $builddir/util.o: cxx src/util.cc
build $builddir/version.o: cxx src/version.cc
build $builddir/subprocess-posix.o: cxx src/subprocess-posix.cc
build $builddir/libninja.a: ar $builddir/browse.o $builddir/build.o $
    $builddir/build_log.o $builddir/clean.o $builddir/debug_flags.o $
    $builddir/depfile_parser.o $builddir/deps_log.o $
    $builddir/disk_interface.o $builddir/edit_distance.o $
    $builddir/eval_env.o $builddir/graph.o $builddir/graphviz.o $
    $builddir/lexer.o $builddir/line_printer.o $builddir/manifest_parser.o $
    $builddir/metrics.o $builddir/state.o $builddir/util.o $
    $builddir/version.o $builddir/subprocess-posix.o

# Main executable is library plus main() function.
build $builddir/ninja.o: cxx src/ninja.cc
build ninja: link $builddir/ninja.o | $builddir/libninja.a
  libs = -lninja

# Tests all build into ninja_test executable.
test_cflags = -g -Wall -Wextra -Wno-deprecated -Wno-unused-parameter $
    -fno-rtti -fno-exceptions -fvisibility=hidden -pipe $
    -Wno-missing-field-initializers -DNINJA_PYTHON="python" -O2 -DNDEBUG $
    -DUSE_PPOLL -DGTEST_HAS_RTTI=0
build $builddir/build_log_test.o: cxx src/build_log_test.cc
  cflags = $test_cflags
build $builddir/build_test.o: cxx src/build_test.cc
  cflags = $test_cflags
build $builddir/clean_test.o: cxx src/clean_test.cc
  cflags = $test_cflags
build $builddir/depfile_parser_test.o: cxx src/depfile_parser_test.cc
  cflags = $test_cflags
build $builddir/deps_log_test.o: cxx src/deps_log_test.cc
  cflags = $test_cflags
build $builddir/disk_interface_test.o: cxx src/disk_interface_test.cc
  cflags = $test_cflags
build $builddir/edit_distance_test.o: cxx src/edit_distance_test.cc
  cflags = $test_cflags
build $builddir/graph_test.o: cxx src/graph_test.cc
  cflags = $test_cflags
build $builddir/lexer_test.o: cxx src/lexer_test.cc
  cflags = $test_cflags
build $builddir/manifest_parser_test.o: cxx src/manifest_parser_test.cc
  cflags = $test_cflags
build $builddir/ninja_test.o: cxx src/ninja_test.cc
  cflags = $test_cflags
build $builddir/state_test.o: cxx src/state_test.cc
  cflags = $test_cflags
build $builddir/subprocess_test.o: cxx src/subprocess_test.cc
  cflags = $test_cflags
build $builddir/test.o: cxx src/test.cc
  cflags = $test_cflags
build $builddir/util_test.o: cxx src/util_test.cc
  cflags = $test_cflags
build ninja_test: link $builddir/build_log_test.o $builddir/build_test.o $
    $builddir/clean_test.o $builddir/depfile_parser_test.o $
    $builddir/deps_log_test.o $builddir/disk_interface_test.o $
    $builddir/edit_distance_test.o $builddir/graph_test.o $
    $builddir/lexer_test.o $builddir/manifest_parser_test.o $
    $builddir/ninja_test.o $builddir/state_test.o $
    $builddir/subprocess_test.o $builddir/test.o $builddir/util_test.o | $
    $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread

# Ancillary executables.
build $builddir/build_log_perftest.o: cxx src/build_log_perftest.cc
build build_log_perftest: link $builddir/build_log_perftest.o | $
    $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread
build $builddir/canon_perftest.o: cxx src/canon_perftest.cc
build canon_perftest: link $builddir/canon_perftest.o | $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread
build $builddir/depfile_parser_perftest.o: cxx src/depfile_parser_perftest.cc
build depfile_parser_perftest: link $builddir/depfile_parser_perftest.o | $
    $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread
build $builddir/hash_collision_bench.o: cxx src/hash_collision_bench.cc
build hash_collision_bench: link $builddir/hash_collision_bench.o | $
    $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread
build $builddir/manifest_parser_perftest.o: cxx $
    src/manifest_parser_perftest.cc
build manifest_parser_perftest: link $builddir/manifest_parser_perftest.o | $
    $builddir/libninja.a
  libs = -lninja -lgtest_main -lgtest -lpthread

# Generate a graph using the "graph" tool.
rule gendot
  command = ./ninja -t graph all > $out
rule gengraph
  command = dot -Tpng $in > $out
build $builddir/graph.dot: gendot ninja build.ninja
build graph.png: gengraph $builddir/graph.dot

# Generate the manual using asciidoc.
rule asciidoc
  command = asciidoc -b docbook -d book -o $out $in
  description = ASCIIDOC $out
rule xsltproc
  command = xsltproc --nonet doc/docbook.xsl $in > $out
  description = XSLTPROC $out
build $builddir/manual.xml: asciidoc doc/manual.asciidoc
build doc/manual.html: xsltproc $builddir/manual.xml | doc/style.css
build manual: phony || doc/manual.html

# Generate Doxygen.
rule doxygen
  command = doxygen $in
  description = DOXYGEN $in
doxygen_mainpage_generator = src/gen_doxygen_mainpage.sh
rule doxygen_mainpage
  command = $doxygen_mainpage_generator $in > $out
  description = DOXYGEN_MAINPAGE $out
build $builddir/doxygen_mainpage: doxygen_mainpage README COPYING | $
    $doxygen_mainpage_generator
build doxygen: doxygen doc/doxygen.config | $builddir/doxygen_mainpage

# Regenerate build files if build script changes.
rule configure
  command = ${configure_env}python configure.py $configure_args
  generator = 1
build build.ninja: configure | configure.py misc/ninja_syntax.py

default ninja

# Packaging
rule rpmbuild
  command = misc/packaging/rpmbuild.sh
  description = Building rpms..
build rpm: rpmbuild

build all: phony ninja ninja_test build_log_perftest canon_perftest $
    depfile_parser_perftest hash_collision_bench manifest_parser_perftest

針對ninja的優化

Ninja是一塊非常好的構建工具,其實也是一個特殊的編譯器,其中有很多值得學習和借鑒的地方。比如,使用re2c將正則表達式編譯為c代碼(PHP也是用了這個工具,干了類似的事情),使用graphviz生成dot格式的依賴文件等等。當然,我不太喜歡其對python的依賴。安裝了其他依賴工具和庫之后,還需要安裝python,否則沒法編譯ninja。經過分析之后,我為ninja定制了一個Makefile編譯方案,同時修改了部分python文件,這樣在沒有python的情況下依然可以編譯和使用ninja。如果需要使用ninja -t browse和構建ninja_test等測試目標,那還是需要安裝python。當然,要去掉這些依賴也不是很難的事情,如果需要哪天有空我可能就將其修改了。修改后的版本一貫的放在github上,需要的自取。僅將此文作為學習ninja的一個階段性總結。歡迎交流和反饋。

擴展閱讀

祝大家玩的開心

編程之道,就在[編程之美]

編程之美


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM