用 Ninja and GN 来加速 C++构建

Ninja

Ninja 原意是忍者的意思,它是一个专注于速度的小型构建工具。它是一个构建系统。 它将文件的相互依赖关系(通常是源代码和输出可执行文件)作为输入,并快速编排构建它们。

运行Ninja,默认情况下,它会在当前目录中查找名为 build.ninja 的文件并构建所有过时的目标。 您可以指定要构建的目标(文件)作为命令行参数。

还有一个特殊的语法 target^ 用于将目标指定为某个规则的第一个输出,其中包含您在命令行中输入的源(如果存在)。 例如,如果您将目标指定为 foo.c^,那么 foo.o 将被构建(假设您的构建文件中有这些目标)。

一般情况下,我们不需要手写 ninja 文件,通过 gn 或 cmake 来描述项目结构和依赖关系,再通过它们来生成 build.ninja 文件

详见Ninja 手册 - https://ninja-build.org/manual.html

Example

byteorder.c

#include <stdio.h>

int main(int argc, char **argv)
{
    union {
        short s;
        char c[sizeof(short)];
    }un;
    un.s = 0x0102;

    if (sizeof(short) == 2) {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
   } else{
        printf("sizeof(short) = %ld\n", sizeof(short));
   }

   return 0;
}

build.ninja

cflags = -Wall

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

build byteorder.o: cc byteorder.c

可以通过 ninja -C build -j 20 来构建

gn

顾名思义,GN is “Generate Ninja” 一个用来生成 Ninja 的工具

用于为 Google Chrome 和相关项目(v8、node.js)以及 Google Fuchsia 生成构建文件的元构建系统。 gn 可以为 Chrome 支持的所有平台生成 Ninja 文件。

GN 有自己定义的一 套比较简单的描述性语言,详见 https://gn.googlesource.com/gn/+/main/docs/language.md

GN 中有三个重要的文件

  1. .gn

它定义了 GN 构建树的根节点

详见命令 “gn help dotfile”

  1. //build/config/BUILDCONFIG.gn

Exact location defined by “.gn” file
Sets up global variables and default settings

  1. BUILD.gn
    描述了构建目标,源码文件,及其依赖关系等

gn args

这个工具有两个作用,一是生成.ninja编译配置文件,二是查看当前编译的所有标记项。

生成.ninja

这个工具给用户提供一个接口,来对构建进行整体的配置。如在Chromium Android编译指南中,为Android版chromium做编译配置时,所执行的命令:

gn args out/Default

参数是output目录路径。这个命令启动系统默认的编辑器,创建out/Default/args.gn文件,我们在编辑器中加入我们自己特定的配置项,如:

target_os = "android"
target_cpu = "arm"  # (default)
is_debug = true  # (default)
# Other args you may want to set:
is_component_build = true
is_clang = true
symbol_level = 1  # Faster build with fewer symbols. -g1 rather than -g2
enable_incremental_javac = true  # Much faster; experimental

gn根据创建得这个out/Default/args.gn文件的内容来产生ninja文件。

查看当前编译的所有标记项

这个工具还可以查看当前编译的所有标记配置项。chromium中用到了许许多多的标记项,对于这些标记项中的许多项,即使用户不进行配置,chromium的编译系统也会提供默认的配置。了解到当前编译的所有标记配置项,对于我们了解实际编译时所用的编译参数非常重要。

对于上面输入的参数,产生的整个编译配置环境中,所有的标记配置项如下:

$gn args --list out/Default/

gn gen

usage: gn gen [<ide options>] <out_dir>
这个工具根据当前的代码树及配置,产生ninja文件,并把它们放在给定得目录下。输出目录可以是源码库的绝对地址,比如//out/foo,也可以是相对于当前目录的地址,如:out/foo。 上面的gn args <out_dir>等价于,在启动编辑器编辑参数,在编辑器编辑了参数退出之后,执行gn gen <out_dir>。

gn clean

usage: gn clean <out_dir>

这个命令用于对历史编译进行清理。它会删除输出目录下除了args.gn外得内容,并创建一个可以重新产生构建配置的Ninja构建环境。

gn desc

usage: gn desc <out_dir> <label or pattern> [<what to show>] [--blame] [--format=json]

显示关于一个给定target或config的信息。构建参数取自给出的<out_dir>。<label or pattern>可以是一个target标签,一个config标签,或一个标签模式(参考"gn help label_pattern")。标签模式只匹配targets。

如我们要查看 webrtc 中 gcc 模块相关得所有信息:

$ gn desc out/Default //modules/congestion_controller/goog_cc --tree

gn ls

usage: gn ls <out_dir> [<label_pattern>] [--all-toolchains] [--as=...] [--type=...] [--testonly=...]
这个命令展示给定输出目录下,满足某个模式的所有的targets。默认情况下,只显示默认工具链的target会被匹配,除非明确地提供了工具链参数。如果没有指定标签参数,则显示所有的targets。模式不是常规的正则表达式(可以参考"gn help label_pattern")。

$ gn ls out/Default "//modules/congestion_controller/*"
//modules/congestion_controller:congestion_controller
//modules/congestion_controller:congestion_controller_unittests
//modules/congestion_controller/goog_cc:alr_detector
//modules/congestion_controller/goog_cc:delay_based_bwe
//modules/congestion_controller/goog_cc:estimators
//modules/congestion_controller/goog_cc:goog_cc
//modules/congestion_controller/goog_cc:goog_cc_unittests
//modules/congestion_controller/goog_cc:link_capacity_estimator
//modules/congestion_controller/goog_cc:loss_based_bwe_v1
//modules/congestion_controller/goog_cc:loss_based_bwe_v2
//modules/congestion_controller/goog_cc:probe_controller
//modules/congestion_controller/goog_cc:pushback_controller
//modules/congestion_controller/goog_cc:send_side_bwe
//modules/congestion_controller/goog_cc:test_goog_cc_printer
//modules/congestion_controller/pcc:bitrate_controller
//modules/congestion_controller/pcc:monitor_interval
//modules/congestion_controller/pcc:pcc
//modules/congestion_controller/pcc:pcc_controller
//modules/congestion_controller/pcc:pcc_unittests
//modules/congestion_controller/pcc:rtt_tracker
//modules/congestion_controller/pcc:utility_function
//modules/congestion_controller/rtp:congestion_controller_unittests
//modules/congestion_controller/rtp:control_handler
//modules/congestion_controller/rtp:transport_feedback

gn check

gn check <out_dir> [<label_pattern>] [--force]
这个工具可以用来检查头文件依赖关系得有效性。

$ gn check out/Default/ net
Header dependency check OK

gn help

展示帮助信息,可以用来获取关于上面所有的gn命令,及内置得targets,内建得预定义变量的所有相关信息。如:

$ gn help

自 CMake 版本 2.8.8 起,可以在 Linux 上生成 Ninja 文件的广泛使用的元构建系统。 较新版本的 CMake 也支持在 Windows 和 Mac OS X 上生成 Ninja 文件。

通过 GN 来生成 build.ninja

以 GN 中所自带的例子 simple build 为例

  • “.gn”
# The location of the build configuration file.
buildconfig = "//build/BUILDCONFIG.gn"
  • build/BUILDCONFIG.gn
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

if (target_os == "") {
  target_os = host_os
}
if (target_cpu == "") {
  target_cpu = host_cpu
}
if (current_cpu == "") {
  current_cpu = target_cpu
}
if (current_os == "") {
  current_os = target_os
}

is_linux = host_os == "linux" && current_os == "linux" && target_os == "linux"
is_mac = host_os == "mac" && current_os == "mac" && target_os == "mac"

# All binary targets will get this list of configs by default.
_shared_binary_target_configs = [ "//build:compiler_defaults" ]

# Apply that default list to the binary target types.
set_defaults("executable") {
  configs = _shared_binary_target_configs

  # Executables get this additional configuration.
  configs += [ "//build:executable_ldconfig" ]
}
set_defaults("static_library") {
  configs = _shared_binary_target_configs
}
set_defaults("shared_library") {
  configs = _shared_binary_target_configs
}
set_defaults("source_set") {
  configs = _shared_binary_target_configs
}

set_default_toolchain("//build/toolchain:gcc")
  • build/BUILD.gn
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

config("compiler_defaults") {
  if (current_os == "linux") {
    cflags = [
      "-fPIC",
      "-pthread",
    ]
  }
}

config("executable_ldconfig") {
  if (!is_mac) {
    ldflags = [
      "-Wl,-rpath=\$ORIGIN/",
      "-Wl,-rpath-link=",
    ]
  }
}
  • BUILD.gn
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

executable("hello") {
  sources = [ "hello.cc" ]

  deps = [
    ":hello_shared",
    ":hello_static",
  ]
}

shared_library("hello_shared") {
  sources = [
    "hello_shared.cc",
    "hello_shared.h",
  ]

  defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
}

static_library("hello_static") {
  sources = [
    "hello_static.cc",
    "hello_static.h",
  ]
}

参考资料

注:有些连接需要翻墙

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值