(16 封私信 / 12 条消息) 一文读懂ninja构建系统 - 知乎

深入理解OpenHarmony中的BUILD.gn:从语法到模块化构建_build.gn语法-CSDN博客

我们讨论的是GN(Generate Ninja)构建系统,它是Chromium等项目使用的构建工具。build.gn文件是GN构建系统的项目配置文件,它用于定义构建目标、依赖关系、编译选项等。

GN构建系统的基本概念:

  1. 目标(Targets):构建的基本单位,比如可执行文件、库、静态库等。

  2. 依赖(Dependencies):目标之间的依赖关系。

  3. 配置(Configs):一组编译设置,可以应用于目标。

  4. 工具链(Toolchains):定义编译工具、编译器等。

build.gn文件使用一种类似于Python的语法,但是是静态的,并且是声明式的。

下面是一个简单的build.gn文件示例:

gn

# 定义一个可执行文件
executable("hello") {
  sources = [
    "hello.cc",
  ]

  deps = [
    "//base",
  ]

  configs = [
    "//build:default_config",
  ]
}

上面的例子定义了一个名为“hello”的可执行文件,它由hello.cc源文件构建,依赖于“//base”目标(可能是一个基础库),并且使用了一个默认的配置。

GN规则(Rules)是构建系统的基本构建块,它们定义了如何从输入文件生成输出文件。规则可以自定义,也可以使用内置的规则。

内置规则包括:

  • executable: 生成可执行文件。

  • static_library: 生成静态库。

  • shared_library: 生成共享库。

  • source_set: 将多个源文件组合成一个单元,但不链接为库。

  • group: 将多个目标组合在一起。

除了内置规则,你还可以自定义规则。自定义规则使用template关键字定义,它允许你定义自己的构建步骤。

下面是一个自定义规则的示例:

gn

template("my_rule") {
  # 这里定义规则的行为
  # 使用invoke命令来调用脚本或工具
  invoke("my_tool") {
    # 指定输入和输出
    inputs = [ invoker.sources ]
    outputs = [ "$target_gen_dir/$target_name.out" ]
    # 可以传递参数给工具
    args = [
      "--input",
      rebase_path(inputs, root_build_dir),
      "--output",
      rebase_path(outputs, root_build_dir),
    ]
    # 如果需要,可以指定依赖的目标
    deps = invoker.deps
  }
}

# 使用自定义规则
my_rule("my_target") {
  sources = [ "input.txt" ]
  deps = [ "//some:dependency" ]
}

在GN中,你还可以使用条件语句(根据操作系统、CPU架构等)来调整构建。

例如:

gn

static_library("mylib") {
  sources = [
    "common.cc",
  ]

  if (is_win) {
    sources += [ "win.cc" ]
  } else if (is_linux) {
    sources += [ "linux.cc" ]
  }
}

GN还支持很多内置变量和函数,例如:

  • current_toolchain: 当前工具链

  • current_cpu: 当前CPU架构

  • current_os: 当前操作系统

  • rebase_path: 调整路径的相对性

此外,GN还支持配置(config)和目标(target)的继承和组合,使得构建配置可以模块化。

更详细的内容,建议查阅GN的官方文档:https://gn.googlesource.com/gn/+/main/docs/reference.md

以上是对build.gn规则的简要介绍,希望对你有所帮助。

好的,我们来详细讲解一下 build.gn 的规则。GN 是 Generate Ninja 的缩写,是 Chromium 项目主导的下一代元构建系统,用于替代 GYP。它的核心是生成 ninja 构建文件。

build.gn 文件使用一种类似 Python 的领域特定语言,其规则定义了如何将源代码、库和资源文件等构建成最终的目标(如可执行文件、静态库等)。

核心概念

  1. 目标: 构建的基本单元,每个 build.gn 文件都定义了一个或多个目标。

  2. 依赖: 目标之间的依赖关系,GN 会自动处理依赖顺序。

  3. 配置: 一组编译器标志、定义、包含目录等设置,可以应用到目标上。

  4. 工具链: 定义了构建时使用的编译器、链接器等工具以及默认配置。

  5. 作用域: GN 文件中的变量和规则都在一个作用域内生效。


基本文件结构

一个典型的 build.gn 文件看起来像这样:

gn

# 这是一个注释

# 导入其他 .gn 文件,可以包含配置、工具链定义或通用规则
import("//build/toolchain/gcc.gni")
import("//build/config/cpp.gni")

# 声明一个配置(可选)
config("my_target_config") {
  include_dirs = [ "include" ]
  defines = [ "MY_DEFINE" ]
  cflags = [ "-Wall" ]
}

# 声明一个构建目标
executable("my_program") {
  # 指定源文件
  sources = [
    "main.cc",
    "util.cc",
  ]

  # 指定依赖的配置
  configs = [
    ":my_target_config", # 引用本文件内定义的配置
    "//common:base_config", # 引用其他目录下的配置
  ]

  # 指定依赖的其他目标(库)
  deps = [
    "//base", # 依赖 base 库
    "//net:http", # 依赖 net 目录下的 http 目标
  ]

  # 目标特有的设置(会覆盖 configs 中的设置)
  include_dirs = [ "src" ]
  defines = [ "LOCAL_DEFINE" ]
}

主要目标类型(规则)

GN 提供了多种内置的规则来创建不同类型的目标:

  1. executable: 构建可执行文件。

    gn

    executable("my_app") {
      sources = [ "main.cc" ]
      deps = [ "//base" ]
    }
  2. static_library: 构建静态库(.a 或 .lib)。

    gn

    static_library("my_lib") {
      sources = [ "lib.cc" ]
    }
  3. shared_library: 构建动态库/共享库(.so 或 .dll)。

    gn

    shared_library("my_shared_lib") {
      sources = [ "shared.cc" ]
    }
  4. source_set: 将一组源文件组合成一个逻辑单元,但不直接生成库文件。它只编译,其目标产物可以被其他依赖它的目标链接。

    gn

    source_set("my_sources") {
      sources = [ "a.cc", "b.cc" ]
    }
  5. group: 将多个目标组合成一个逻辑目标。它本身不构建任何东西,只是将其依赖的目标聚合起来。

    gn

    group("all_my_tools") {
      deps = [
        ":tool_a",
        ":tool_b",
      ]
    }
  6. action: 运行一个脚本或命令来生成文件。这是实现自定义构建步骤的关键。

    gn

    action("generate_version_header") {
      script = "//scripts/generate_version.py"
      inputs = [ "version.in" ]
      outputs = [ "$target_gen_dir/version.h" ]
      args = [ rebase_path("version.in", root_build_dir) ]
    }
  7. copy: 复制文件。

    gn

    copy("my_data") {
      sources = [ "data.json" ]
      outputs = [ "$root_out_dir/data/{{source_file_part}}" ]
    }

关键变量和指令

变量
  • sources: 构建目标所需的源文件列表。

  • deps: 此目标所依赖的其他目标列表。

  • configs: 应用于此目标的配置列表。

  • public_configs: 不仅应用于本目标,还会传递给依赖本目标的其他目标。

  • include_dirs: 头文件搜索路径。

  • defines: 预处理器宏定义。

  • cflagscflags_ccflags_ccldflags: 编译器/链接器标志。

  • output_name: 覆盖默认的输出文件名。

  • visibility: 控制哪些其他目标可以依赖此目标。例如 visibility = [ "*" ] 表示对所有目标可见。

指令和函数
  • import(): 导入另一个 .gni 文件。

  • config(): 定义一个配置块。

  • set_sources_assignment_filter(): 过滤源文件列表,常用于条件编译。

  • rebase_path(): 将文件路径转换为相对于另一个目录的路径。

  • foreach(): 循环。


条件判断

GN 支持基于目标平台、CPU 架构等进行条件判断。

gn

static_library("platform_specific") {
  sources = [ "common.cc" ]
  if (is_win) {
    sources += [ "win.cc" ]
  } else if (is_mac) {
    sources += [ "mac.cc" ]
  } else if (is_linux) {
    sources += [ "linux.cc" ]
  }

  if (target_cpu == "x64") {
    defines = [ "IS_64_BIT" ]
  }
}

总结

build.gn 的规则核心是声明式地描述构建目标及其属性依赖关系

  1. 选择目标类型:根据要构建的内容(可执行文件、库等)选择合适的规则(executablestatic_library 等)。

  2. 指定源文件:通过 sources 变量列出所有源文件。

  3. 管理依赖:通过 deps 列出所有直接依赖的目标。GN 会自动处理传递性依赖。

  4. 应用配置:通过 configs 应用编译设置,或直接在目标内部设置 cflagsdefines 等。

  5. 处理平台差异:使用条件语句(if)来处理不同操作系统或架构的差异。

这种设计使得构建脚本非常清晰、模块化,并且能够高效地并行处理依赖,最终生成快速的 Ninja 构建文件。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐