zoukankan      html  css  js  c++  java
  • Ninja

    转自: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的一个阶段性总结。欢迎交流和反馈。

    扩展阅读

    祝大家玩的开心

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

    编程之美

  • 相关阅读:
    EBS SQL > Form & Report
    oracle sql 优化分析点
    MRP 物料需求计划
    MRPII 制造资源计划
    Barcode128 应用实务
    Oracle SQL语句优化技术分析
    APPSQLAP10710 Online accounting could not be created. AP Invoice 无法创建会计分录
    Oracle数据完整性和锁机制
    ORACLE Responsibility Menu Reference to Other User
    EBS 常用 SQL
  • 原文地址:https://www.cnblogs.com/x_wukong/p/4846179.html
Copyright © 2011-2022 走看看