使用 Ninja 代替 make

摘自:https://www.jianshu.com/p/d118615c1943

22017.01.14 11:41:44字数 1408阅读 26336

前言

在传统的 C/C++ 等项目构建时,通常会采用 make 系统使用 Makefile 文件来进行整个项目的编译构建,通过 Makefile 中指定的编译所依赖的规则使得程序的构建非常简单,并且在复杂项目中可以避免由于少部分源码修改而造成的很多不必要的重编译。但是它仍然不够好,因为其大而且复杂,有时候我们并不需要 make 那么强大的功能,相反我们需要更灵活,速度更快的编译工具。Ninja 作为一个新型的编译工具,小巧而又高效,它就是为此而生。

这篇文章介绍 Ninja 的安装以及如何使用 Ninja 来构建项目

首先,我们需要安装 Ninja,只需要去官网下载一个 release 的二进制版本,放在系统目录(比如 /usr/bin)中就可以了,非常的简单。另外,现在大多数 Linux 发行版都有自己的包管理工具,直接使用包管理工具来下载也很简单。

下面简单介绍下通过编译 Ninja 源码的方式来安装
首先,确保已经安装了这些依赖:g++,graphviz,gtest,git,re2c 和 python2.7+。

获取源码
$ git clone git://github.com/ninja-build/ninja.git && cd ninja
$ git checkout release
$ cat README $ ls
COPYING HACKING.md README RELEASING bootstrap.py configure.py doc/ misc/ src/

我们可以去 HACKING.md 中查看更多信息。

编译

一切就绪之后,执行下列命令来编译 ninja

$ ./configure.py --bootstrap

上述命令会在当前目录下生成一个叫 ninja (Windows 下是 ninja.exe)的可执行文件,然后我们把这个文件拷到系统目录(比如 /usr/bin)就完成安装了。

编译过程解析

实际上 ninja 本身也是通过 ninja 系统来编译完成的。
具体过程就是:执行 ./configure.py --bootstrap 之后先编译源码(生成一个 a.out),然后在当前目录生成一个 ninja.build(这个文件类似于 make 工具的 Makefile,语法和规则非常类似)。然后再根据这个 ninja.build 来重新编译生成可执行文件 ninja,在 ninja 根据 ninja.build 来编译时会自动创建一个 build 目录用于存放编译过程中的临时文件,比如 *.o 等。

执行./configure.py 时还可以指定其他选项:

--bootstrap    bootstrap a ninja binary from nothing
--verbose    enable verbose build
--platform     choose known platforms
--host       choose host known_platforms
--debug      enable debugging extras
--profile      enable profiling
--with-gtest
--with-python   use EXE as the Python interpreter
--force-pselect   ppoll() is used by default where available

可以通过 ./configure.py -h 可以查看更多帮助。
如果我们想要开启 Ninja 的其他特性(比如:Bash completion, Emacs 和 Vim 编辑模式等),编译完成之后,我们需要把 /misc 目录中的文件拷贝到合适的位置。

测试

现在,我们可以测试一下 ninja 是否成功安装并且可以使用。

当直接执行 ninja 命令是,它会在当前目录下默认寻找 build.ninja 文件来进行编译。
ninja 的语法格式是:

$ ninja [options] TARGETs

上述 options 如果没有则可以省略。比如,直接执行 ./ninja ninja_test 将会生成可执行文件 ninja_test,然后再执行 ninja_test 就可以看到测试结果。

如下:

$ ./ninja ninja_test
$ ./ninja_test
[214/226] SubprocessTest.SetWithLotsRaise [ulimit -n] above 1025 (currently 1024) to make this test go
[226/226] ElideMiddle.ElideInTheMiddle
passed

或者,我们还可以直接执行 ./ninja all,这样,ninja 就会执行 ninja.build 中指定的所有目标了。

$ ./ninja all
[10/10] LINK canon_perftest

上述 ninja_test 和 all 都是 ninja.build 中的 build rule,概念类似于 Makefile 中的 target recipe。

测试完成之后,我们就把 ninja 拷贝到一个系统目录中 /usr/bin 来完成整个的安装。

提示: build.ninja 文件类似于 Makefile,熟悉它的语法规则之后我们也可以手动编写。另外,可以通过 ninja -f NINJA_FILE 的方式来指定 .ninja 文件

更多选项

 

实际上, ninja 还提供了一个 Python based generator ,它实际上是一个 Python 模块 misc/ninja_syntax.py,通过它我们可以较方便的生成 build.ninja 文件。比如,在我们的 Python 文件中引入该模块之后,就可以直接通过调用 ninja.rule(name='foo', command='bar', depfile='$out.d') 来生成符合 ninja 语法的内容。下面是一个简单例子:

from ninja_syntax import Writer

with open("build.ninja", "w") as buildfile:
n = Writer(buildfile) if platform.is_msvc():
n.rule("link",
command="$cxx $in $libs /nologo /link $ldflags /out:$out",
description="LINK $out")
else:
n.rule("link",
command="$cxx $ldflags -o $out $in $libs",
description="LINK $out")

另外,我们还可以在执行 cmake 时通过 -G 选项指定生成器为 ninja 来生成 build.ninja。
比如:

$ cd build
$ cmake -GNinja ../proj_src_dir

Ninja 工具集

Ninja 还集成了 graphviz 等一些对开发非常有用的工具,通过执行 ./ninja -t list 可以查看 ninja 中集成了哪些工具。

下面是一个常见的工具集列表:

ninja subtools:

browse        # 在浏览器中浏览依赖关系图。(默认会在 8080 端口启动一个基于python的http服务)
clean # 清除构建生成的文件
commands # 罗列重新构建制定目标所需的所有命令
deps # 显示存储在deps日志中的依赖关系
graph # 为指定目标生成 graphviz dot 文件。
如 ninja -t graph all |dot -Tpng -ograph.png
query # 显示一个路径的inputs/outputs
targets # 通过DAG中rule或depth罗列target
compdb # dump JSON兼容的数据库到标准输出
recompact # 重新紧凑化ninja内部数据结构

手动编写 .ninja 文件

.ninja 的语法规则跟 Makefile 类似,虽然有许多 generator 工具 可以用来自动生成 .ninja 文件,但是在某些场合可能需要手动编写或修改 .ninja 文件,下面做个简单介绍:

# VARIABLE: (referenced like $name or alternate ${name})
cflag = -g -Wall -Werror # RULE:
rule RULE_NAME
command = gcc $cflags -c $in -o $out
description = ${out} will be treat as "$out" # BUILD statement:
build TARGET_NAME: RULE_NAME INPUTS # PHONE rule:(creating alias)
build ALIAS: phony INPUTS ... # DEFAULT target statement(cumulative):
default TARGET1 TARGET2
default TARGET3 $ ninja
build TARGET1 TARGET2 TARGET3

例子: build.ninja

ninja_required_version = 1.3

#variable
cc = g++
cflags = -Wall # rule
rule cc
command = gcc $cflags -c $in -o $out
description = compile .cc # build
build foo.o: cc foo.c

.ninja_log 可以用来指定保存 build 时产生的 log。

子模块 和 include 指令

subninja 指令可以用来引入其他 .ninja 文件,从而引入一个新的 scope。这意味着,子模块中可以引用父模块中的变量。
比如:

subninja obj/content/content_resources.ninja
subninja obj/extensions/extensions_strings.ninja
subninja obj/third_party/expat/expat_nacl.ninja

include 指令也是用来引入其他 .ninja 文件,但是不同的是,引入的其他 .ninja 文件会被引入当前 scope,子模块中不可以访问父模块中的变量。

include obj/content/content_resource.ninja
include obj/extensions/extensions_strings.ninja
include obj/third_party/expat/expat_nacl.ninja

参考
https://github.com/ninja-build/ninja
https://ninja-build.org/manual.html

https://www.jianshu.com/p/d118615c1943

使用 Ninja 代替 make的更多相关文章

  1. hdu 4000Fruit Ninja 树状数组

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...

  2. Ninja Blocks物联网平台简介

    Ninja Blocks是一个物联网控制平台,其平台架构包括硬件层.处理器层.软件层以及平台层,请看下图: 最底层是硬件层,包括传感器(Sensors)和驱动器(Actuators),例如温度传感器. ...

  3. sdut 2416:Fruit Ninja II(第三届山东省省赛原题,数学题)

    Fruit Ninja II Time Limit: 5000MS Memory limit: 65536K 题目描述 Have you ever played a popular game name ...

  4. Ninja - chromium核心构建工具

    转自:http://guiquanz.me/2014/07/28/a_intro_to_Ninja/ Ninja - chromium核心构建工具Jul 28, 2014 [在线编辑] 缘由 经过上次 ...

  5. SDUT 2416:Fruit Ninja II

    Fruit Ninja II Time Limit: 5000MS Memory limit: 65536K 题目描述 Have you ever played a popular game name ...

  6. 《JavaScript Ninja》之正则表达式

    正则表达式 是一个拆分字符串并查询相关信息的过程. 练习网站:JS Bin 正则表达式测试网站:Regular Expression Test Page for JavaScript 正则表达式进修 ...

  7. 《JavaScript Ninja》之闭包

    闭包 闭包是什么,它们是如何工作的 闭包 是一个函数在创建时允许该自身函数访问并操作该自身函数之外的变量时所创建的作用域. 即:闭包可以让函数访问所有的变量和函数,只要这些变量和函数存在于该函数声明时 ...

  8. hdu 4000 Fruit Ninja 树状数组

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4000 Recently, dobby is addicted in the Fruit Ninja. ...

  9. 《Secrets of the JavaScript Ninja》:JavaScript 之运行时代码

    最近,在阅读 jQuery 之父 John Resig 力作:Secrets of the JavaScript Ninja(JavaScript忍者秘籍).关于第九章提及的 JavaScript 之 ...

  10. Sdut 2416 Fruit Ninja II(山东省第三届ACM省赛 J 题)(解析几何)

    Time Limit: 5000MS Memory limit: 65536K 题目描述 Haveyou ever played a popular game named "Fruit Ni ...

随机推荐

  1. 《The One!团队》:BETA Scrum metting1

    项目 内容 作业所属课程 所属课程 作业要求 作业要求 团队名称 < The One !> 作业学习目标 (1)掌握软件黑盒测试技术:(2)学会编制软件项目总结PPT.项目验收报告:(3) ...

  2. 行为型模式(三) 迭代器模式(Iterator)

    一.动机(Motivate) 在软件构建过程中,集合对象内部结构常常变化各异.但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素:同时这种"透明 ...

  3. nginx+keepalived高可用 (主从+双主)

    1.Nginx+keepalived 主从配置这种方案,使用一个vip地址,前端使用2台机器,一台做主,一台做备,但同时只有一台机器工作,另一台备份机器在主机器不出现故障的时候,永远处于浪费状态,对于 ...

  4. python不使用系统库中的排序方法判断一个数组是否是有序数组

    2. 给定一组整数, 已知其每两个数都互不相同,判断这些数字是否能排成一个有序的数组? 例:li = [1,3,4,2] 是有续的 可以排序为li =[1,2,3,4] li = [2,4,6,8] ...

  5. BZOJ 4332: JSOI2012 分零食 FFT+分治

    好题好题~ #include <bits/stdc++.h> #define N 50020 #define ll long long #define setIO(s) freopen(s ...

  6. Windows异常的分发处理流程

    根据异常来源,一般分硬件异常和软件异常,它们处理的流程大致一样,下面简单讲一下. 如果是硬件异常,CPU会根据中断类型号转而执行对应的中断处理程序.CPU会在IDT中查找对应的函数来处理,各个异常处理 ...

  7. QSetting介绍

    简介 QSettings类提供了持久的跨平台应用程序设置. 用户通常期望应用程序记住它的设置(窗口大小.位置等)所有会话.这些信息通常存储在Windows系统注册表,OS X和iOS的属性列表文件中. ...

  8. 案例:3D切割轮播图

    一.3d转换 3D旋转套路:顺着轴的正方向看,顺时针旋转是负角度,逆时针旋转是正角度 二.代码 <!DOCTYPE html> <html lang="en"&g ...

  9. C结构体指针的初步使用

    #include <stdio.h> #include <string.h> struct Books { char title[50]; //char author[100] ...

  10. 洛谷P2751 工序安排Job Processing

    题目 任务调度贪心. 需要明确一点,任务调度贪心题,并不是简单地应用排序的贪心,而是动态的运用堆,使每次选择是都能保持局部最优,并更新状态使得下次更新答案可以取到正确的最小值. 这是A过程的解. 然后 ...