SHBuild

  位于 Tools/SHBuild ,是可以用来递归遍历目录编译链接本机程序和调用其它相关功能的命令行工具。当前仅支持 MinGW32/MinGW64 环境。其它平台详见以下章节。

  直接(不带参数)运行 SHBuild 查询使用方法和选项等说明。

构建

  本节说明 SHBuild 的构建。关于使用 SHBuild 构建用户程序,参见前述概要和之后的章节。

  除非另行指定,其它章节也适用于本节内构建的非最终阶段 SHBuild 。本章仅补充仅适用于这些 SHBuild 的特点和功能。

  关于使用 bash 构建库、SHBuild 、测试项目和基于 SHBuild 上的用户程序,参见关于 MinGW Sysroot 的说明

  当前只支持本机构建

  除了指定调用编译器等工具的名称外的其它情形对 SHBuild 是透明(transparent) 的,即 SHBuild 不使用目标平台的标识执行不同逻辑。这样,也可能不经修改调用命令的情况下成功交叉构建,但当前未测试。

引导

  SHBuild 支持引导(bootstrapping) ,即在受支持的构建环境中直接构建 SHBuild ,不依赖预先构建的 SHBuild 二进制映像。

  运行脚本 Tools/Scripts/SHBuild-build.sh 生成 SHBuild 可执行文件。

  脚本直接选取 YSLib 中的源文件作为依赖进行构建。因为直接调用编译器驱动链接,不支持显式指定并行编译,相对比较慢。编译的结果是静态链接的,二进制映像较大。

  这个过程只需要 C++ 工具链和 shell ,不需要直接调用 make ,但 GCC 使用 -flto 进行优化仍然需要 GNU make 。

  如能成功使用以下的多阶段构建方法(会按需调用引导脚本),一般不建议使用直接构建的版本。

自举

  SHBuild 支持自举(self hosting) ,即可使用构建的 SHBuild 继续构建自身。

  除需 SHBuild 可执行程序外,对外部环境的要求和引导一致。

  SHBuild 一直使用简单的源代码结构,设计初期即支持自举,现时仍不限制自举需要的版本。但由于仅测试相同版本的自举构建,因此一般建议使用相同版本。

  以下多阶段构建在引导的基础上自举构建 SHBuild 。

  此外,也可以直接使用 SHBuild-self-host.shSHBuild-self-host-DLL.sh 进行直接自举。这两个脚本主要用于内部测试。

多阶段构建

  使用工具脚本安装 Sysroot 时,按需构建 SHBuild 。当前这个过程分为两步:

  运行Sysroot 安装脚本可直接完成以下多个阶段的构建和目标程序的部署(deployment) :

  • Stage 1 ,即第一阶段:引导
    • 这个阶段运行 Tools/Scripts/SHBuild-build.sh 构建 stage 1 SHBuild 。
      • 若已存在构建了的 stage 1 SHBuild 可执行程序,Sysroot 安装脚本不再重新构建 stage 1 SHBuild 。
        • 可指定非空的 SHBuild_Rebuild_S1 环境变量值以要求 Sysroot 安装脚本无视已存在的 stage 1 SHBuild 的可执行程序而重新构建。
      • 脚本检查 GNU parallel 的可用性。默认使用 GNU parallel 并行构建。
      • 原理 为可维护性,stage 1 SHBuild 的构建直接使用静态链接,且过程依赖避免系统库(工具链提供的环境)以外的外部二进制依赖项和网络连接。
        • 不依赖外部工具的串行构建可能相当费时,但仍可被接受。
    • 引导结果为 stage 1 SHBuild 程序,主要用于下一阶段使用,不保证具有所有 SHBuild 的功能特性。
      • 可执行程序不被另行部署。
      • 一般不建议直接使用。
    • 原理 因为 stage 1 的目的是引导宿主构建的 SHBuild 并构建 YSLib 和其它依赖 YSLib 的应用,所以使用不依赖 YSLib 项目输出的原始的宿主环境
      • 依照开发说明配置的宿主环境是受支持的可用于运行构建工具的环境作为 stage 1 构建和运行环境。
        • 构建时依赖这个环境的脚本运行环境运行构建脚本,并依赖其中的工具链进行编译链接。
      • 显然地,stage 1 不使用已被部署的 SHBuild 可执行程序。
      • 因为不假设 NPLA1 实现(默认由 SHBuild 提供)的可用性,构建 stage 1 SHBuild 的脚本shell 脚本而非 NPLA1 脚本
  • Stage 2 ,即第二阶段:自举
    • 这个阶段在 Sysroot 安装脚本内调用成功引导的 stage 1 SHBuild 运行 NPLA1 脚本程序继续构建。
      • 继续构建通过运行 Tools/Scripts/SHBuild-YSLib-build.txt 实现,步骤包括:
        • 构建 YBase 和 YFramework 库。
        • 自举构建 SHBuild ,链接到之前构建的 YFramework 和 YBase 动态库。
      • Sysroot 安装脚本可通过 SHBuild 环境变量指定 YSLib 库构建过程中使用的 SHBuild 命令。
        • 若不指定变量 SHBuild ,默认值是(先前应已被检查并确保按需构建的)stage 1 SHBuild 的路径。
        • 原理 默认不需要另行部署 SHBuild 即可完成自举和之后的安装。但若在当前宿主环境中已存在可用的 SHBuild 可执行程序,指定 SHBuild 可避免 Sysroot 安装脚本中默认的不必要的 stage 1 SHBuild 构建。
    • 自举结果为 stage 2 SHBuild 。
      • 这是当前最终生成的 SHBuild ,链接和运行依赖上述 YBase 和 YFramework 动态库。
      • 当前 stage 2 SHBuild 总是需要 release 动态库,因此除非先前已部署(足够新版本的兼容的)对应配置的库,不包含这个目标时 stage 2 SHBuild 会符合预期地构建失败。
    • 原理 构建 YSLib 库是整个 Sysroot 环境安装的主要目标,是构建 stage 2 SHBuild 前的必要步骤,整体一般比构建 stage 1 SHBuild 更加费时,但是:
      • 借助 SHBuild ,这些构建目标的编译过程是确保可并行的。
      • NPLA1 脚本接收的环境变量可通过调用 Sysroot 安装脚本指定,允许更灵活地控制构建使用的并行任务数等选项,且同时允许选择性仅构建和安装部分构建配置(包括 debug 或 release 模式,静态或动态库)的目标而节约开销。
  • 使用 SHBuild 运行当前 YSLib 存储库中的特定的 NPLA1 脚本可选地构建其它目标,包括 Tools 中的 SHBuild 以外的二进制工具。
    • 默认使用新近生成的 stage 2 SHBuild 可执行程序。
    • 可通过 SHBuild 环境变量指定使用的 SHBuild 命令以被 NPLA1 脚本递归地调用。
    • 这同时作为直接的部署后环境可用性测试,因而不提供指定其它 SHBuild 工具的选项。
  • 安装 stage 2 SHBuild 和(可选的)其它工具。

  两个阶段需要的外部环境对应称为 stage 1 环境和 stage 2 环境;部署 stage 2 SHBuild(和可选的目标)后的环境是部署后环境。

  作为更一般的开发环境和最终用户部署基于 Sysroot 的 YSLib 的应用的运行环境,stage 2 和部署后环境相对 stage 1 环境具有更多的假设和更少的限制:

  • 用于构建时,假定 PATH 中存在兼容的 SHBuild 可执行程序的命令。
    • 在 Sysroot 构建 YSLib 的库时,默认使用先前 stage 1 SHBuild ,其它情形默认使用 stage 2 SHbuild 。
    • 应确保 SHBuild 程序和使用的 NPLA1 脚本的版本匹配,一般来自同一个 Sysroot 安装。
      • SHBuild 没有与更新版本的脚本匹配,运行可能失败,这不被支持。
        • 此时仍建议重新构建 stage 1 SHBuild ;参见以上 stage 1 的说明。
      • 但除非另行指定,NPLA1 脚本的内容不依赖具体实现环境,且仅通过 SHBuild 调用。
      • 这些实际脚本通过可直接复制到兼容的安装的位置部署。
        • 但这些位置不保证作为公开接口而保持不变;同时需注意在运行环境中具有可读权限。
      • 因此除非必要,一般仍建议使用 Sysroot 默认配置进行部署。
    • 除非另行指定,Sysroot 构建不依赖 stage 1 和 stage 2 的 SHBuild 中可能具有的差异。
      • 因此,可(通过环境变量)指定任意的预先安装的和 NPLA1 脚本匹配版本的 SHBuild 程序。
    • 一般建议开发环境中把某个 Sysroot 的 bin 目录加入 PATH 环境变量,以使用其中的 SHBuild 命令。
      • 使用这个环境开发时,运行环境和 stage 2 构建环境相同,且可使用 stage 2 SHBuild 和其它工具。
      • 需要使用不同的 SHBuild 程序时仍可通过 SHBuild 环境变量指定。否则,变量 SHBuild 的默认值是 SHBuild ,因此 PATH 环境变量应存在名为 SHBuild 可执行程序。这被这个环境中默认满足。
      • 在 Windows 系统中,被 Sysroot 构建和部署的 SHBuild 的可执行文件名总是 SHBuild.exe 。除非有同名的目录(在部署中不会出现),在 Windows 的命令行运行这个可执行文件不需要后缀。
      • 在其它运行环境中,被 Sysroot 部署的 SHBuild 的可执行文件通常是 SHBuild 。但在此之前,为避免和同名的目录冲突,使用 SHBuild 构建时直接得到的可执行文件总是带有 .exe 扩展名
  • 这些环境使用 NPLA1 脚本而不是 stage 1 的 shell 脚本提供可用的构建功能。

  由于多平台构建的自然要求,这些环境需要相同(本机构建),或至少保持兼容性。当前工具脚本没有另行显示指定使用不同平台的接口,因此只支持本机构建。

运行

  通过以下方式调用 SHBuild 命令输出帮助消息并退出:

  • 没有命令行参数。
  • 使用 -h--help 作为命令行参数。

  通过以下方式调用 SHBuild 命令输出版本信息并退出:

  • 使用 -V--version 作为命令行参数。

  其它情形调用 SHBuild ,使用参数执行命令,支持不同的运行模式:

  • 构建模式:调用递归扫描指定的目录以调用构建后端工具。
  • 命令模式:执行内建的功能。

  命令模式以 -xcmd, 起始的选项指定。其它情形的运行使用构建模式。

  命令行参数 -- 钱的参数中,以 -x 起始的特定选项(详见帮助消息)被作为 SHBuild 选项。命令行参数 -- 后的参数不被识别为 SHBuild 选项,而被传递给后端或作为命令模式的参数。

  以下仅列出部分选项。关于环境、选项和退出状态等的详细说明参见帮助消息。

构建模式

  构建模式递归扫描指定的源代码目录,以其中符合内建规则要求的文件作为输入,调用相应的后端命令行构建。构建包括对符合内建规则的输入的编译,以及对得到的目标文件进行链接。除 SHBuild 选项的命令行参数直接传除递给后端编译器。若需要构建复杂项目,可以使用其它的脚本支持。

  调用的构建后端工具的名称以及链接器命令行选项可使用环境变量指定。此外,若环境变量 SHBuild_CFLAGSSHBuild_CXXFLAGS 被定义为非空值,调用 C 和 C++ 编译器命令行时,变量的值会先于生成的命令选项以及上述命令行选项被传递。关于支持的环境变量,详见运行 SHBuild 的说明。

  调用的后端命令行的不同的命令行选项之间应确保以空白符间隔。环境变量确定的选项不被检查;由 SHBuild 生成的命令行选项之间以一个空格分隔。

  使用 SHBuild 构建若得到的库文件,则按宿主平台确定添加的文件扩展名;而可执行文件总是带有 .exe 后缀,以避免递归扫描生成的输出文件目录和可执行文件重名导致无法生成。

  构建模式支持以 -xdef, 起始的选项指定变量配置,可覆盖环境的值。

  通过开发脚本等方式部署 SHBuild 输出的文件时,可以调整安装的文件名。

内建规则

  遍历扫描目录时,不需要使用领域特定语言的外部脚本,SHBuild 识别名称符合特定模式串的文件。

  当前支持后缀名区分源文件。

  文件名符合以下通配符模式的文件视为 C 源文件:

  • *.c

  文件名符合以下通配符模式的文件视为 C++ 源文件:

  • *.cpp
  • *.cc
  • *.cxx

  对以上文件,对应的内建 C 和 C++ 编译器规则分别被调用。其它文件不被视为源文件。

  和 make 类似,SHBuild 的内建规则依赖文件修改时间(mtime) 判断一个目标是否最新。

  内建规则使用的编译器和环境变量参见帮助消息。

命令模式

  参见帮助消息。

构建应用程序

  使用 SHBuild 构建应用程序所需的环境和多阶段构建的最后一个阶段的相同。当前和自举时相同,即 stage 2 环境。

其它平台

  除构建 stage 1 SHBuild 外,当前未正式支持 Linux 。

  因为 SHBuild 本身和直接依赖的代码已经保证了可移植性,所以静态链接可以成功。得到的可执行文件除了没有扩展名,用法和前述 MinGW 下相同。

  使用进一步编译 YFramework 可能会出错,因为 YFramework 中宿主 GUI 支持未在 Linux 上实现。这不影响已经构建的 SHBuild 的可用性。

已知限制 若系统时间不正确,可能导致冗余的重复构建或无法构建。若文件时间戳无法被正确更新(如编译器或者文件系统实现问题导致无法在命令执行后正确地更新被修改的文件时间,或者不恰当的缓存配置导致修改时间没有立即更新),可能导致冗余的重复构建。

  当前不支持上述以外的其它平台。

NPL 支持

  SHBuild 运行 -xcmd,RunNPL-xcmd,RunNPLFile 命令支持解释 NPLA1 翻译单元。

  调用方式详见帮助文本。

  后者的翻译单元为文本文件。当前支持文件头可选的 UTF BOM 。**若找到 BOM ,直接跳过继续读取文件内容。在 SHBuild 中不假设文件编码,直接以窄字符流透明地处理。后续编码内容格式按 YFramework 提供的当前实现的方式支持。

  因此,一般应使用 UTF-8 + BOM ,或不带 BOM 的 UTF-8 作为编码。

应用

  当前 stage 1 SHBuild 构建 YSLib 库使用脚本已以此方式实现。Shell 脚本调用 stage 1 SHBuild 解释这些脚本,其中进一步调用 stage 1 SHBuild 执行其它构建命令。