用 Ninja and GN 来加速 C++构建-程序员宅基地

技术标签: python  c++  java  linux  docker  

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",
  ]
}

参考资料

注:有些连接需要翻墙

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fanyamin/article/details/123655298

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search