# 概述   YSLib 项目提供一系列工具脚本。这些脚本主要集中位于 `Tools` 和 `Tools/Scripts` 。其余特定局部用途的脚本可能位于其它目录,这些脚本可能依赖版本库内的工具脚本或 YSLib 安装时部署的工具脚本。   关于脚本的解释环境和其它一般规则,参见[关于脚本的开发说明](../Development.zh-CN.md#脚本)。关于 shell 脚本,同时参见 [shell 语言使用规约](../Development.zh-CN.md#shell-语言使用规约)。   本文档附加约定,除非另行指定: * 公开的 shell 脚本和 NPLA1 脚本被 [`Tools/install-sysroot.sh`](#toolsinstall-sysrootsh) 分别部署到安装路径下的 `bin` 和 `share/NPLA1` 目录下。 * 除[用于构建选项的环境配置](#环境配置)外,提供的 shell 变量可能设置为只读。 * 脚本引入不具有后缀 `_` 的名称若不是被导出的变量,可在脚本之间使用,满足关于名称的约束,但不保证接口稳定性。 **注释** 维护者和开发者需要阅读开发说明,以保持脚本程序符合文档的描述。其中的一些信息(如关于环境变量等运行时环境的描述)也可能提供对脚本的非开发者用户有帮助的说明,作为[运行环境](../Run.zh-CN.md)中说明的补充。 # Tools   未归类的工具目录。这个目录的脚本是可用于整个项目或非特定子项目的工具脚本,如公用的构建脚本。   工具脚本位于版本库目录 `Tools` 及其子目录 `Scripts` 下。   工具主要用于开发,包括构建和版本库维护。   一部分工具脚本也可被部署到 [Sysroot](../Sysroot.zh-CN.md) 。在 [stage 2 SHBuild](SHBuild.zh-CN.md#多阶段构建) 安装后运行的脚本可依赖安装的 Sysroot 实例的文件系统布局。支持维护版本库的开发脚本应保证在此之前(不依赖 Sysroot 的实例或仅依赖构建 [stage 1](SHBuild.zh-CN.md#多阶段构建) 后可用的有限环境)可用。 ## 环境配置   一些环境变量可能被可选地在外部环境或在调用脚本的其它脚本中指定。若没有被指定为非空值,则可被特定上下文按需初始化。初始化后的值可能被断言非空,断言失败则非正常地退出脚本。   这些变量可能指定外部环境的配置。   在[开发文档中的环境变量](../Development.zh-CN.md#环境变量)的基础上,以下各节补充指定适用于多个脚本的变量。在对应的脚本的文档中可能补充描述。   一些环境变量具有特定的命名模式: * [开发文档](../Development.zh-CN.md)中的环境变量具有相同前缀的外部扩展环境变量: * 具有前缀 `SHBuild_` :可能适用于所有构建脚本流程。 * **注释** 具有前缀 `SHBuild_S1_` 和 `SHBuild_S2_` 的名称不指定环境变量,而是函数名称。 * 具有前缀 `YSLib_` :指定和 YSLib 库相关的环境和配置。 * **注释** 这些前缀的变量通常在开发文档中指定。仅在个别脚本中适用或不在 shell 脚本(而仅在 NPLA1 脚本)适用时,在本文档指定扩展。 * 具有前缀 `SS_` :[公共构建配置变量](#公共构建配置变量)。 * **注释** 环境变量名称中的 `SS` 前缀表示 SHBuild Settings 。 * 具有前缀 `S1_` :在 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 构建流程中作用的变量。 * **注释** 环境变量名称中的 `S1` 前缀表示 Stage 1 。 * 具有前缀 `CFLAGS` 、`CXXFLAGS` 和 `LDFLAGS` 等:指定构建工具使用的选项。 * **注释** 在 shell 环境中这主要通过 [`Tools/Scripts/SHBuild-common-options.sh`](#toolsscriptsshbuild-common-optionssh) 配置。 ### 公共构建配置变量   以下配置行为的环境变量可在多个构建脚本中被支持且具有一致的含义: * `SS_DebugEnv` 启用脚本执行时系统环境相关的调试输出。 * `SS_DirectExtract` 启用直接解压缩。 * `SS_NoParallel` 不使用并行命令调用。 * `SS_Offline` 离线模式:不使用互联网。 * `SS_Verbose` 启用详细消息输出。   除非另行指定,这些变量的值当且仅当非空表示启用特性。   具体作用在具体脚本的说明中详细描述。 ### Stage 1 共享变量   以下变量影响 stage 1 的多个构建脚本的行为。 * `S1_BuildConf` 内部配置名称。 * 通常指定不同的值对应不共享的构建配置组合。 * **注释** 可影响默认构建目录。 * `S1_BuildDir` Stage 1 SHBuild 构建和输出文件目录路径。 * `S1_CacheFile` Stage 1 缓存文件名。 * `S1_CacheMode` Stage 1 缓存模式。 * 可选模式是如下子模式的组合: * 读模式:加载缓存时,无条件忽略或不忽略缓存之一。 * 默认写模式:保存缓存且缓存文件不存在时,不写入、写入空文件或写入缓存之一。 * 覆盖写模式:保存缓存且缓存文件存在时,不写入、写入空文件、覆盖写入缓存或清除缓存文件之一。 * 组合模式如下: * 加载缓存时忽略: * 默认不写入: * `disable` 禁用缓存:不覆盖写入。 * `reset` 复位为空文件:覆盖写入空文件。 * `update` 只更新:覆盖写入。 * `clean` 清理:清除缓存文件。 * 默认写入空文件: * `touch` 只创建空文件:不覆盖写入。 * `mark` 标记:覆盖写入空文件。 * 默认写入: * `create` 只创建新文件:不覆盖写入。 * `writeonly` 只写:覆盖写入。 * 加载缓存时不忽略: * 默认不写入: * `readonly` 只读:不覆盖写入。 * `clear` 清除:覆盖写入空文件。 * `writeback` 写回:覆盖写入。 * `purge` 清洗:清除缓存文件。 * 默认写入空文件: * `move` 转移:不覆盖写入。 * `absorb` 吸收:覆盖写入空文件。 * 默认写入: * `keep` 保持:不覆盖写入。 * `force` 强制:覆盖写入。 * 别名: * `disabled` 同 `disable` 。 * `false` 同 `disable` 。 * `ignore` 同 `disable` 。 * `n` 同 `disable` 。 * `no` 同 `disable` 。 * `none` 同 `disable` 。 * `once` 同 `purge` 。 * `overwrite` 同 `force` 。 * `skip` 同 `disable` 。 * `writethrough` 同 `update` 。 * 其它值的含义同未设置此变量,默认启用缓存,同 `keep` :加载和保存缓存,但不覆盖已有缓存。 * 前缀为 `S1_Cached_` 的变量是可在外部指定的缓存项。作为配置项的变量支持以下值: * `disable` 禁用:不使用。 * `disabled` 同 `disable` 。 * `false` 同 `disable` 。 * `n` 同 `disable` 。 * `no` 同 `disable` 。 * `none` 同 `disable` 。 * 其它非空值视为 `true` ,指定启用库:使用库配置参数。 * 空值(未缓存):自动检查可用性并确定配置项的变量值,之后可写入缓存。 * `S1_DistDir` Stage 1 SHBuild 可执行程序目录路径。 * `S1_SHBuild` Stage 1 SHBuild 可执行文件路径。 * **注释** Win32 平台实际的可执行文件可隐含后缀 `.exe` 。   具体作用可在具体脚本的说明中详细描述。 ## Tools/install-sysroot.sh   Sysroot 安装脚本。用于直接构建和部署基础环境。   构建时会调用 `Tools/Scripts` 目录下的脚本,按需构建 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 后间接调用 `SHBuild` 构建 `YBase` 和 `YFramework` 的静态库和动态库,再构建依赖于动态库的 `SHBuild` : * 按需初始化[变量 `SHBuild_ToolDir`](../Development.zh-CN.md#环境变量) 。 * 包含脚本 [`Tools/Scripts/SHBuild-common.sh`](#toolsscriptsshbuild-commonsh) 以按需初始化确定默认构建位置依赖的环境变量。 * 设置[变量 `S1_BuildConf`](#stage-1-共享变量) 的值,并调用[函数 `SHBuild_S1_InitConf`](#函数-shbuild_s1_initconf) 初始化必要的变量,以允许判断是否在预期位置存在 stage 1 SHBuild 。 * 按需构建 stage 1 SHBuild 。 * 间接调用 stage 1 SHBuild 构建 `YBase` 和 `YFramework` 的静态库和动态库。 * 再构建依赖于动态库的 `SHBuild` 。   构建使用[变量 `SHBuild_BuildDir`](../Development.zh-CN.md#环境变量) 指定的路径作为中间输出目录。 **注释** 另见 [`Tools/Scripts/SHBuild-bootstrap.sh`](#toolsscriptsshbuild-bootstrapsh) 。   构建脚本同时可安装文件,完成 Sysroot 所需文件的部署。安装的起始目标位置由称为**安装路径**的目录路径指定,其字符串形式去除结尾分隔符的目录文件名为**安装路径前缀**。安装过程在必要时可创建 Sysroot 根目录、安装路径指定的目录及其子目录。安装路径的确定方式详见以下的使用方式。   部署时使用 stage 1 SHBuild 更新文件和目录,在必要时创建符号链接或硬链接,若失败则改为普通复制。仅当被部署的文件为中间目标启用硬链接,以免后续操作意外覆盖源文件。注意在 Windows 上创建符号链接可能因为权限不足失败,取决于用户和组策略。建议使用系统管理权限运行以避免可能的权限问题。 ### 基本使用   脚本接受在 stage 2 使用的 `SHBuild` 命令行中的选项为命令行参数,如 ```shell Tools/install-sysroot.sh -xj,2 ```   使用 2 个并行线程构建。   脚本也支持变量配置构建使用的路径,默认相当于使用如下 bash 命令配置变量: ```bash : ${SHBuild_SysRoot:="$YSLib_BaseDir/sysroot"} : ${SHBuild_BuildDir:="$YSLib_BaseDir/build/$(SHBuild_GetBuildName)"} ```   其中: * [`SHBuild_PrepareBuild`](#函数-shbuild_preparebuild) 是 `Tools/Scripts/SHBuild-common.sh` 中的函数。 * 各个变量参见[开发文档中的环境变量的说明](../Development.zh-CN.md#环境变量)。   在 stage 1 SHBuild 构建调用 NPLA1 脚本 `Tools/Scripts/SHBuild-YSLib*.txt` ,调用方式和接受的配置(构建目标等)、具体默认设置和注意事项见对应 shell 脚本的文档相关章节。 # Tools/Scripts   这个目录的脚本可用于整个项目或项目核心部分的构建工具使用。   当前有以下脚本忽略重复的 `.` 或 `source` 命令: * SHBuild-common.sh   以前缀 `SHBuild_` 起始的名称保留使用。   其中,前缀 `SHBuild_Env_` 总是表示环境配置的只读变量名。这些变量若未被指定,可在第一次访问时(具体时机未指定)初始化为: * `SHBuild_Env_Arch` :参见函数 `SHBuild_CheckUName` 。 * `SHBuild_Env_OS` :参见函数 `SHBuild_CheckUName` 。 * `SHBuild_Env_TempDir` :缓存函数 `SHBuild_GetTempDir` 的输出。 * `SHBuild_Env_uname` :缓存命令 `uname` 的输出。 * `SHBuild_Env_uname_m` :缓存命令 `uname -m` 的输出。 ## Tools/Scripts/GenerateProjects.sh   调用 [ProjectGenerator](ProjectGenerator.zh-CN.md) 生成项目文件。   当前支持生成所有 `.cbp` 文件。   要求可使用 `hg` 或 `git` 命令取版本库根目录,否则不保证输出到正确的路径。 ### 变量 ProjectGenerator   调用 RevisionPatcher 的命令。默认直接使用 `type -P ProjectGenerator` 的结果,一般要求可执行文件在环境变量 `PATH` 中。 ## Tools/Scripts/PatchRevision.sh   开发过程中使用 [RevisionPatcher](RevisionPatcher.zh-CN.md) 维护源文件中版本号的脚本。   当前只支持 Mercurial 或 Git 版本库的已添加或修改的未提交文件。   使用的版本控制系统会被检查。通过检查的条件、确定使用的版本控制的机制及支持的控制检查的环境变量同 Tools/Scripts/SHBuild-YSLib*.txt 公用的版本控制系统支持,参见以下相关章节的说明。   若检查都失败,则脚本出错,不再继续运行。   脚本利用 `hg` 或 `git` 命令把未提交的这些修改导出为补丁备份到版本库根目录的 `bak.patch` ,然后使用这些内容调用 RevisionPatcher 取得文件和对应的新的版本号列表,最后使用 `sed` 查找对应文件并更新版本号。   脚本依赖 `sed` 命令。使用的 `sed` 应支持 `-b -i` 选项。可使用 Linux 或 MSYS2 的发行版中的 sed 4.8 程序。 **警告** 某些 Win32 版本的 `sed` ,如 MSYS2 MinGW64 sed 4.4 可能损坏文本文件的行尾。有些替代版本可能解决[这一问题](https://stackoverflow.com/questions/4652652)。 **注释** 当前不检查特定版本 `sed` 对选项的支持。   若没有找到 `\version r` 模式的版本号前缀则忽略写入版本号。写入的版本号不影响换行符。 **注释** 这个脚本可用于自动化。例如,在 Mercurial 仓库的 `hgrc` 的 `[hooks]` 节中添加 `precommit.PatchRevision = bash Tools/Scripts/PatchRevision.sh` 可在每次提交前调用这个脚本。在 YSLib 中,仅在主分支版本中启用。 ### 变量 PatchBegin   匹配版本号的起始行,应为一个表示行数的正整数。默认值为 `"1"` 。 ### 变量 PatchEnd   匹配版本号的结束行,应为一个表示行数的正整数。默认值为 `"20"` 。 ### 变量 RevisionPatcher   调用 RevisionPatcher 的命令。默认值为 `type -P RevisionPatcher` 的结果。 **注释** 可执行文件可以在环境变量 `PATH` 中。 ### 变量 PatchHg   指定使用 Mercurial 。参见以上确定使用 Mercurial 或 Git 的说明。 ### 变量 PatchGit   指定使用 Git 。参见以上确定使用 Mercurial 或 Git 的说明。 ## Tools/Scripts/SHBuild-bootstrap.sh   编译 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 时被包含的脚本。   脚本执行构建配置的环境初始化。其中指定静态链接需要依赖的 YSLib 源文件以及头文件路径等的必要变量。   脚本按需设置[变量 `S1_BuildConf`](#stage-1-共享变量) 的值,以确保部分变量之后在包含 [`Tools/Scripts/SHBuild-YSLib.sh`](#toolsscriptsshbuild-yslibsh) 时能被按需初始化。默认值为 `stage1` 。 * **注释** 有的脚本如 [`Tools/install-sysroot.sh`](#toolsinstall-sysrootsh) 在此之前应已初始化部分变量。其它脚本可能依赖这里的初始化。   包含 `Tools/Scripts/SHBuild-YSLib.sh` 后,[被缓存的变量](#toolsscriptsshbuild-yslibsh)的值可首先从持久存储的缓存文件中获取。   以下在这个脚本中可被使用的 stage 1 共享变量属于被缓存的变量: * `S1_Cached_quadmath` 支持使用 quadmath ,作为[配置项](#stage-1-共享变量)。   配置结束后,通过调用[函数 SHBuild_SaveCache](#函数-shbuild_savecache)写入所有被缓存的变量。 ## Tools/Scripts/SHBuild-build.sh   编译 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 的脚本。   以下[公共构建配置变量](#公共构建配置变量)影响脚本的特定行为: * `SS_NoParallel` 的作用当前包括: * 不检查并行命令的可用性。 * 不使用并行命令构建。 * `SS_Verbose` 的作用当前包括: * 调用命令前回显。   使用变量 `SHBuild_Output` 指定输出路径。默认值为 `SHBuild` ,即在当前工作目录下生成名为 `SHBuild` 的可执行文件(视宿主平台不同可能带后缀如 Win32 带 `.exe` )。   调用函数 `SHBuild_CheckPCH` 检查预编译头:若变量 `SHBuild_NoPCH` 非空则跳过预编译头,否则使用预编译头包含标准库头。预编译的头文件目标由 YBase 下的 `stdinc.h` ,之后构建时包含预编译头路径为 `$SHBuild_PCH_stdinc_h` 。后者的默认路径为当前工作目录下的 `stdinc.h` 。   因为升级或更换编译器和/或选项,可导致预编译头文件( `.gch` 文件)不和生成的环境匹配而不被识别。 **注意** 预编译头文件不保证对不同的操作系统版本兼容,参见[先决条件](../Prerequisitions.zh-CN.md)中 PC(Win32) 平台关于操作系统版本的说明。   不被识别的预编译头文件通常: * 可引起编译器警告,并忽略预编译头文件。 * 若仅需避免产生警告,确保编译器命令行使用恰当选项,如添加 `-Wno-invalid-pch` 。 * 可能引起无法构建的错误。   一般仍然需要避免使用不匹配的预编译头文件。若无法保证预编译头文件和使用的工具链和选项匹配: * 可设置变量 `SHBuild_NoPCH` 的值非空以跳过预编译头文件的使用。 * 可以手动删除生成的预编译头文件。在没有设置变量 `SHBuild_NoPCH` 的情形下构建通常会默认自动生成。 * **注释** 具体的支持和生成预编译头文件的位置参见具体构建目标的说明,如 [Sysroot](../Sysroot.zh-CN.md#构建中间文件) 。 **已知缺陷** 构建时不自动更新预编译头。   除非环境变量 `SS_NoParallel` 的值非空,构建前可选地检查可用的并行命令。支持如下: * 支持 [GNU parallel](https://www.gnu.org/software/parallel/) 命令 `parallel` 。 * 不支持 [moreutils `parallel`](https://manpages.debian.org/testing/moreutils/parallel.1.en.html) 且 `parallel` 命令的可用性会忽略。 * 不对并行数指定选项。 * **原理** 默认应已能充分使用宿主环境的计算资源。 ## Tools/Scripts/SHBuild-BuildApp.sh   应用程序构建脚本。这个脚本被保留,不再具有实际功能。   **这个脚本是公开的工具**,被安装脚本部署。 ## Tools/Scripts/SHBuild-BuildPkg.sh   包构建脚本。当前只支持构建应用程序,具体步骤和使用的参数参见 [`Tools/Script/SHBuild-BuildApp.txt`](#toolsscriptsshbuild-buildapptxt) 。   **这个脚本是公开的工具**,被安装脚本部署。 ## Tools/Scripts/SHBuild-common.sh   被应用程序构建脚本包含的脚本,提供公共基础功能。   **这个脚本是公开的工具**,被安装脚本部署。 **注意** 这个脚本包含 `INC_SHBuild_common` 守卫变量检查,默认重复包含只被执行一次。 ### 函数 SHBuild_Popd   同 `bash` 内建 `popd` 但不回显标准输出。 ### 函数 SHBuild_Pushd   同 `bash` 内建 `pushd` 但不回显标准输出。 ### 函数 SHBuild_Put   使用 `printf` 输出非格式字符串。   使用 `$*` 形式传递字符串,此时 `IFS` 是默认值。 ### 函数 SHBuild_Puts   使用 `printf` 输出非格式的换行的字符串。   使用 `$*` 形式传递字符串,此时 `IFS` 是默认值。   换行符由变量 `SHBuild_EOL` 指定。若值为空,则首先初始化为全局只读变量。当前默认值通过检查 `$COMSPEC` 是否定义,以确保 Windows 环境(包括 MSYS )使用 CR+LF ,其它情况使用 LF 。   这个函数在可用时可用于代替 `echo` ,以取得对环境更好的适应性。 **注意** 具体的检查逻辑实现可能在以后改变。 ### 函数 SHBuild_Puts_Err   同[函数 `SHBuild_Puts`](#函数-shbuild_puts),但重定向标准输出到标准错误。 ### 函数 SHBuild_Puts_Exit   第一参数指定错误码,以之后的参数调用[函数 `SHBuild_Puts_Exit`](#函数-shbuild_puts_exit),然后以错误码退出。 ### 函数 SHBuild_Puts_Verbose   当[变量 `SS_Verbose`](#公共构建配置变量) 的值非空时,调用[函数 `SHBuild_Puts`](#函数-shbuild_puts)。 ### 函数 SHBuild_AssertNonempty   断言第一参数为名称的变量非空,否则显示出错并退出。   使用 `eval` 实现。 ### 函数 SHBuild_CheckedCall   检查第一参数为名称的命令存在,否则显示出错并退出。   使用 `hash` 实现以优化性能。 ### 函数 SHBuild_CheckedCallSilent   同 SHBuild_CheckedCall ,但不显示错误外的标准输出。 ### 函数 SHBuild_InitReadonly   断言第一参数为名称的变量非空,若空则使用 `eval` 对后续求值并初始化第一参数指定的只读变量。   初始化时在当前 shell 中求值初值。   若发生初始化且[变量 `SS_Verbose`](#公共构建配置变量) 的值非空,则在标准输出中显示。 **已知限制** 当前实现使用临时文件 `/tmp/InitReadonly` 暂存作为初值的调用结果。需确保这个临时文件所在的目录和这个文件可写。 **原理**   保证当前 shell 中求值允许初值中调用可能修改当前 shell 环境的 shell 函数。这使一个 `SHBuild_InitReadonly` 调用中,间接的嵌套调用可使用先前已通过同一个调用者初始化的变量。 ### 函数 SHBuild_2m   接受 1 个表示路径的参数,调用 `cygpath` 转换路径到 Windows 混合风格路径。   当 `cygpath` 不存在时返回原路径。 ### 函数 SHBuild_2u   接受 1 个表示路径的参数。   调用 `cygpath` 转换 Windows 路径到 UNIX 路径。   当 `cygpath` 不存在时返回原路径。 ### 函数 SHBuild_EchoEscape   当标准输出使用终端时调用 `echo -ne` 输出参数指定的 ANSI 转义序列。 **已知缺陷** 不检查 `$TERM` 支持。 ### 函数 SHBuild_EchoString   接受 2 个参数,输出转义序列指定格式的内容,包含以下步骤: * 使用 `SHBuild_EchoEscape` 输出第二参数指定的转义序列。 * 使用 `SHBuild_Put` 输出第一参数的内容。 * 使用 `SHBuild_EchoEscape` 输出复位格式的转义序列。 ### 函数 SHBuild_EchoVar   接受 2 个参数 `x` 和 `y` ,以特定颜色显示为 `x = "$y"` 的形式,其中 `$y` 是 `y` 的值。   第二参数一般是字符串。 ### 函数 SHBuild_EchoVar_N   接受 1 个参数 `x` ,调用 `SHBuild_EchoVar` 显示为 `x = $x` 的形式。   右侧求值时会替换参数中的 `.` 为 `_` 。   参数一般是字符串。 ### 函数 SHBuild_EchoVarA   接受 2 个参数 `x` 和 `y` ,以特定颜色显示为 `x = ($y)` 的形式,其中 `$y` 是 `y` 的值。   第二参数一般是数组。 ### 函数 SHBuild_EchoVarA_N   接受 1 个参数 `x` ,调用 `SHBuild_EchoVarA` 显示为 `x = $x` 的形式。   右侧求值时会替换参数中的 `.` 为 `_` 。   参数一般是数组。 ### 函数 SHBuild_CheckUName   调用 `SHBuild_CheckedCall` 按需初始化只读变量 `SHBuild_Env_OS` 和 `SHBuild_Env_Arch` 的值。   变量 `SHBuild_Env_OS` 的值通过分类系统的值(一般即 `SHBuild_Env_uname` 的值)标识操作系统: * `OS_X` :输入匹配 `*Darwin*` ,用于标识 OS X 系统。 * `Win32` :输入匹配 `*MINGW*` 或 `*MSYS*` ,用于标识 Windows 系统。 * `Linux` :输入匹配 `*Linux*` ,用于标识 Linux 系统。 * `unknown` :不支持的系统。   变量 `SHBuild_Env_Arch` 的值通过分类输入的处理器体系结构的值(一般即 `SHBuild_Env_uname_m` 的值)标识体系结构: * `x86_64` :输入匹配 `x86_64` 或 `i*86-64` 。 * `i*86` :输入匹配 `i*86` ,使用原值。 * `aarch64` :输入是 `aarch64` 。 * `unknown` :不支持的体系结构。   若同时指定环境变量 `SHBuild_Env_Arch` 和 `SHBuild_Env_OS` ,不进行[自动环境检测](../Prerequisitions.zh-CN.md),不依赖 `uname` 。 ### 函数 SHBuild_GetTempDir   取临时目录的路径。   依次检查以下环境变量的值,若非空则作为结果: * `TMPDIR` * `TEMP` * `TMP`   若这些环境变量都没有非空值,则使用经过 `SHBuild_2m` 转换的 `/tmp`(被 [POSIX.1 要求支持](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap10.html#tag_10_01))作为结果。 **注意** 以上过程在所有平台上都一致。这是自适应环境的基本接口,因此不对环境变量的值的合法性进行判断。若结果不表示一个可访问的目录,在访问以此构造的文件路径时可能引发错误。应用程序一般需自行检查或保证使用的环境中这些路径可访问。 **说明** 以上检查中,支持的环境变量符合[惯例(en-US)](https://en.wikipedia.org/wiki/TMPDIR) 。检查环境变量的顺序(偶然地)和一些类似功能的实现(如 [MySQL 在 Windows 上](https://dev.mysql.com/doc/refman/8.0/en/temporary-files.html))一致,和其它一些特定平台的 API(如 [Win32 API](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw) )及另一些不作为公开行为的实现(如 [libiberty 的 `choose_tmpdir`](https://gcc.gnu.org/onlinedocs/gcc-4.8.5/libiberty/Functions.html#index-choose_005ftmpdir-66) )可能不一致。被支持的环境变量可用性举例: * `TMPDIR` :[POSIX.1 要求的环境变量](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html) 。 * `TEMP` :被 [Win32 文件 API](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw) 等使用。 * `TMP` :被 Win32 文件 API 和 [Microsoft C 运行时 API](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tempnam-wtempnam-tmpnam-wtmpnam?view=msvc-160) 等使用。 * 另见[对 MS-DOS 和 Microsoft Windows 使用的临时目录环境变量解释](https://devblogs.microsoft.com/oldnewthing/20150417-00/?p=44213)。 **已知限制** 不检查路径是否表示实际可写的目录。另见文件访问约定。   当前脚本实现假定临时目录可写,不满足条件时,文件操作可能失败。脚本使用的临时文件前也不保证检查文件可写。若此文件不可写(例如,在之前被 `root` 等高权限用户创建),则依赖文件可写的操作可能失败。对构建脚本,这可能导致依赖临时文件进行检查判断失效,而使错误的选项被使用。   一般地,脚本可使用特定的例程(如 Shell 脚本可选地使用[在许多环境中可用的 `mktemp` 命令](https://stackoverflow.com/questions/2792675))随机化文件名减少冲突。若需要更可靠地避免上述问题,可在运行脚本前清理临时目录,或预先设置 `SHBuild_GetTempDir` 访问的环境变量指定确保可写的空目录,同时避免并发调用脚本导致不安全并发访问此目录中的临时文件。脚本不使用其它方法确定直接使用的临时目录,但脚本间接调用的外部工具仍可能导致不安全的访问,而无法保证可靠。 ### 函数 SHBuild_Platform_Detect   通过参数指定的操作系统和体系结构名,结合环境变量,确定平台名称,检查非空并返回。   第一和第二参数分别指定操作系统名和体系结构名,接受的取值参见[函数 `SHBuild_CheckUName`](#函数-shbuild_checkuname) 。   当前 `Win32` 系统外的结果和 `SHBuild_CheckUName` 初始化 `SHBuild_Env_OS` 的结果一致。处理如下: * 若操作系统名为 `Win32` : * 若环境变量 `MSYSTEM` 设置为 [MSYS2 支持的环境](https://www.msys2.org/docs/environments/),结果对应如下: * `MINGW64`:`MinGW64` 。 * `MINGW32`:`MinGW32` 。 * `CLANG64`:`MinGW_Clang64` 。 * `CLANG32`:`MinGW_UCRT64` 。 * `CLANGARM64`:`MinGW_ClangARM64` 。 * `UCRT64`:`MinGW_UCRT64` 。 * 否则,若体系结构为 `x86_64` ,则结果为 `MinGW64` 。 * 否则,结果为 `MinGW32` 。 * 否则,结果为操作系统名。 ### 函数 SHBuild_PrepareBuild   准备构建环境。按以下方式初始化变量使之具有非空值: * 调用[函数 `SHBuild_GetTempDir`](#函数-shbuild_gettempdir) 初始化 `SHBuild_Env_TempDir` 。 * 调用[函数 `SHBuild_CheckUName`](#函数-shbuild_checkuname) 初始化 `SHBuild_Env_OS` 和 `SHBuild_Env_Arch` 。 * 初始化 `SHBuild_Host_OS` 为 `SHBuild_Env_OS` 的值。 * 当变量 `SHBuild_Host_OS` 的值是 `Win32` 时,且环境变量 `MSYSTEM` 的值是 [MSYS2 支持的环境](https://www.msys2.org/docs/environments/)支持的值,初始化 `SHBuild_Host_Arch` 对应的目标体系结构;否则,初始化 `SHBuild_Host_Arch` 为 `SHBuild_Env_Arch` 的值。 ### 函数 SHBuild_GetBuildName   取用于进一步初始化构建路径的构建名称。   首先调用[函数 `SHBuild_PrepareBuild`](#函数-shbuild_preparebuild) 按需初始化变量 `SHBuild_Env_Arch` 和 `SHBuild_Env_OS` 为非空值。   结果为以变量 `SHBuild_Env_OS` 和 `SHBuild_Env_Arch` 的值作为参数调用[函数 `SHBuild_Platform_Detect`](#函数-shbuild_platform_detect) 的结果。 ### 函数 SHBuild_BuildGCH   构建 GNU 预编译头文件,依次执行: * 以第二参数指定的路径附加 `.gch` 后缀确定输出路径。 * 检查输出路径是否已存在文件,若存在则视为目标已被构建,输出消息并跳过以下步骤。 * 确保输出路径所在的目录被创建。 * 输出开始构建的消息。 * 硬链接第一参数指定输入的头文件路径到第二参数指定的安装路径。 * 按第一参数指定的输入路径和输出路径调用第三个参数指定构建命令。 * 输出构建完成的消息。 **已知限制** 构建命令仅支持 GNU 兼容工具链。 ### 函数 SHBuild_CheckPCH   检查和按需构建 GNU 预编译头文件并设置变量,依次执行: * 检查变量 `SHBuild_NoPCH` 的值,若为空值,则: * 以第一参数、第二参数和 `$CXX -xc++-header $CXXFLAGS` 调用 `SHBuild_BuildGCH` 生成 GNU 风格预编译头文件。 * 设置内部变量 `SHBuild_IncPCH` 为合适的命令行选项的数组(以 `"-include"` 和头文件名作为其元素)用于包含生成的预编译头文件。 * 否则: * 输出跳过消息。 * 设置 `SHBuild_IncPCH` 的值为空数组。 **已知限制** 构建命令仅支持 GNU 兼容工具链。 ### 函数 SHBuild_2w   接受 1 个表示路径的参数,调用 `cygpath` 转换 UNIX 路径到 Windows 路径。   当 `cygpath` 不存在时返回原路径。 ### 函数 SHBuild_Install   接受 2 个表示路径的参数,安装前者指定的文件到后者。   首先调用 `rsync` ,若失败调用 `cp` 。 **注意** 防火墙可能导致 `rsync` 超时失败。 ### 函数 SHBuild_InstallDir   接受 2 个表示路径的参数,安装前者指定的目录到后者。   首先调用 `rsync` ,若失败调用 `cp` 。 **注意** 防火墙可能导致 `rsync` 超时失败。 ### 函数 SHBuild_Install_Exe   接受 2 个表示路径的参数,安装前者指定的可执行文件到后者。   首先调用 `SHBuild_Install` ,然后在目标上设置可执行权限。 ### 函数 SHBuild_Install_HardLink   接受 2 个表示路径的参数,安装前者指定的文件到后者为硬链接。   首先删除目标,其次调用 Windows 命令解释器的 `mklink` ,若失败调用 `ln` 。 ### 函数 SHBuild_Install_HardLink_Exe   接受 2 个表示路径的参数,安装前者指定的可执行文件到后者为硬链接。   首先调用 `SHBuild_Install_HardLink` ,然后在目标上设置可执行权限。 **注意** `mklink` 需要 Windows Vista 后的命令解释器(`cmd`) 的支持。硬链接需要文件系统(如 NTFS )支持。 ### 函数 SHBuild_Install_Link   接受 2 个表示路径的参数,安装前者指定的文件到后者为符号链接。   首先删除目标,其次调用 Windows 命令解释器的 `mklink` ,若失败调用 `ln` 。 **注意** `mklink` 需要 Windows Vista 后的命令解释器(`cmd`) 的支持。符号链接需要文件系统(如 NTFS )支持。权限不足可能导致 `mklink` 创建符号链接失败,可在组策略改变相关默认行为。在一些版本的系统上,可能需要[进一步的配置](https://support.microsoft.com/en-us/kb/2856739/en-us)以通过链接执行文件。 ### 函数 SHBuild_LoadCache   加载环境缓存。   函数接收 2 个参数,分别是缓存文件路径和被缓存的变量名的正则表达式模式的数组。   [变量 `S1_CacheMode`](#stage-1-共享变量) 可配置模式控制缓存行为: * 若配置忽略,则无作用。 * 否则加载缓存。   加载缓存通过解析文件内容验证后包含实现。   文件的内容应为可执行的 shell 赋值代码。当前检查支持的格式如下: * 每行一个条目,忽略首尾空白符。 * 若条目的形式是 `if ... then; ASSIGNMENT; fi` ,简化为 `ASSIGNMENT` 进行下一步检查,忽略其余部分。 * 进一步地,若条目的形式是 `declare -X VAR=...` ,其中 `X` 是匹配正则表达式模式 `(-|[Aagirx]+)` 的属性之一,简化为 `VAR` 进行下一步检查,忽略其余部分。 * **注释** 作为全局变量,`declare` 条目一般应具有 `-g` 属性,否则声明为局部变量,实际没有加载配置。 * 进一步地,`VAR` 应为合法的标识符,匹配正则表达式模式 `[A-Za-z_][A-Za-z_0-9]*` 。   若任意检查失败,则缓存格式无效,内容不会被加载;否则,包含缓存文件,以执行其中的赋值代码。   函数的返回值如下: * `0` :成功。 * `1` :内容无效。 * `2` :指定的缓存文件无法读取。 ### 函数 SHBuild_SaveCache   保存环境缓存。   函数接受的参数及其含义和[函数 `SHBuild_LoadCache`](#函数-shbuild_loadcache) 一致。   [变量 `S1_CacheMode`](#stage-1-共享变量) 可配置缓存模式控制缓存行为: * 若配置忽略,则无作用。 * 若缓存模式配置为清除缓存文件则删除缓存文件。 * 否则保存缓存。   保存缓存操作如下: * 打开并清空缓存文件。 * 若缓存模式配置为清除缓存内容则打开文件成功时直接视为成功。 * 否则,继续解析 `declare -p` 结果,把其中变量名匹配第二参数中任意的正则表达式且内容满足函数 `SHBuild_LoadCache` 格式要求的行写入指定的缓存文件。 * 写入前,替换内容中的 `declare --` 或 `declare -` 为 `declare -g` 以确保声明全局变量。 * **注释** 不要求支持 `declare -p` 结果中的所有变量属性。不支持的属性被忽略。   函数的返回值如下: * `0` :成功。 * `2` :指定的缓存文件无法写入。 ### 函数 SHBuild_GetSystemPrefix   转换参数指定的平台名称字符串为系统前缀字符串。   系统前缀用于在文件系统中安装部署。   通常系统前缀因为之前仍有非空的其它前缀(如 `SHBuild_SysRoot` 指定的值)而不是绝对路径的前缀。因此,系统前缀以 `/` 起始而不需要考虑所在的环境是否符合 FHS 的问题。   当前支持的结果包括: * 参数为 `MinGW64` 时,结果为 `/mingw64` 。 * 参数为 `MinGW32` 时,结果为 `/mingw32` 。 * 否则,结果为 `/usr` 。   本函数的结果符合 [Sysroot](../Sysroot.zh-CN.md) 中关于 Sysroot 的目录布局的约定。 **注释** 参数典型地来自调用[函数 `SHBuild_Platform_Detect`](#函数-shbuild_platform_detect) 的结果。 ### 函数 SHBuild_S1_InitConf   初始化 [stage 1 Sysroot](../Sysroot.zh-CN.md) 构建配置,依次执行: * 断言[变量 `SHBuild_ToolDir`](../Development.zh-CN.md#环境变量) 非空。 * 按需初始化[变量 `YSLib_BaseDir`](../Development.zh-CN.md#环境变量) ,默认值为 `"$SHBuild_ToolDir/../.."` 。 * **注释** Stage 1 环境下总是可通过脚本所在目录推断 YSLib 源代码和存储库中的其它源文件的位置。 * 尝试以切换当前目录的方式访问 `$YSLib_BaseDir` 。 * 按需初始化[变量 `SHBuild_BuildDir`](../Development.zh-CN.md#环境变量) ,默认值为 YSLib 版本库根目录下的 `build/$(SHBuild_GetBuildName)` 。 * 确保变量 `SHBuild_BuildDir` 指定的目录被创建,并尝试以切换当前目录的方式访问。 * 若[变量 `S1_BuildDir`](#stage-1-共享变量) 的值为空,断言[变量 `S1_BuildConf`](#stage-1-共享变量) 的值非空。 * **注释** 这排除以下的初始化默认值使用非预期路径。 * 按需初始化变量 `S1_BuildDir` ,默认值为 `"$SHBuild_BuildDir/.$S1_BuildConf"` 。 * 按需初始化[变量 `S1_DistDir`](#stage-1-共享变量) ,默认值为 `"$S1_BuildDir/.stage1"` 。 * 按需初始化[变量 `S1_SHBuild`](#stage-1-共享变量) ,默认值为 `"$S1_DistDir/SHBuild"` 。 * 确保变量 `S1_BuildDir` 指定的目录被创建,并尝试以切换当前目录的方式访问。 * 确保变量 `S1_DistDir` 指定的目录被创建,并尝试以切换当前目录的方式访问。   以上变量初始化后只读。 ### 函数 SHBuild_S2_Prepare   准备 [stage 2 Sysroot](../Sysroot.zh-CN.md) 环境,依次执行: * 确保变量 `SHBuild_SysRoot` 的初始化。 * 使用第一参数作为这个变量的默认值。若变量这个未被设置,则以默认值赋值。 * 断言这个变量的值非空,以其值作为创建目录,若指定的目录已存在则忽略。 * 初始化变量 `SHBuild_SystemPrefix` 。 * **注释** 参见 [`Tools/Scripts/SHBuild-YSLib-build.txt`](#toolsscriptsshbuild-yslib-buildtxt) 的说明。 * 初始化变量 `SR_Prefix` 的值为 `"$SHBuild_SysRoot$SHBuild_SystemPrefix"` 。 ### 函数 SHBuild_S2_Prepare_Build   准备 stage 2 Sysroot 构建环境,依次执行 * 以第一参数调用 `SHBuild_S2_Prepare` 。 * 导出变量 `SHBuild` 的值为 `"$SR_Prefix/bin/SHBuild"` 。 ## Tools/Scripts/SHBuild-common-options.sh   被应用程序构建脚本包含的基础功能,提供默认的编译器和链接器命令行选项。   若某个变量提供默认值且执行脚本时没有非空值,则设置为脚本提供的默认值。   **这个脚本是公开的工具**,被安装脚本部署。   包含 `Tools/Scripts/SHBuild-common-toolchain.sh` 确定工具链。 **注意** G++ 和 Clang++ 不完全兼容。以下部分变量通过 `Tools/Scripts/SHBuild-common-toolchain.sh` 中的例程判断 G++ 和 Clang ,并自动使用不同的选项默认值。因此直接通过名称和符号链接等方式伪装会失效而可能导致错误。   以下所有变量仅在外部环境设置为空或未设置时提供默认值,按顺序被指定。可在外部设置为非空值以避免被本脚本中的值覆盖。以下仅列出部分相对不容易变动的默认值,其它默认值参见脚本源代码。若不需要默认值,可以提前设置非空值或在 `.` 指令后直接设置其它(可能为空的)值。 ### 变量 SHBuild_Debug   默认值为空。   非空时,指定变量的值: ```shell CXXFLAGS_OPT_DBG='-O0 -g -D_GLIBCXX_DEBUG_PEDANTIC' LDFLAGS_OPT_DBG=' ' ``` ### 变量 C_CXXFLAGS_GC   C/C++ 编译器生成二进制节 GC 选项。   默认值为 `-fdata-sections -ffunction-sections` 。   设置后会被检查是否支持,参见下文。 ### 变量 LDFLAGS_GC   链接器生成二进制节 GC 选项。   默认值为 `-Wl,--gc-sections` 。   设置后会和 `C_CXXFLAGS_GC` 通过 `$CXX` 作为编译器编译链接简单程序测试是否支持。若不支持,此变量和 `C_CXXFLAGS_GC` 都会被置空。 **已知限制** [Windows 上的工具链可能缺乏 `/dev/null` 的必要支持](http://sourceforge.net/p/msys2/discussion/general/thread/2d6adff2/?limit=25),因此此项检查使用的输出路径指定为 `/tmp/null` 。 ### 变量 C_CXXFLAGS_PIC   C 和 C++ 编译器共用的 PIC ( Position Independent Code ,位置无关代码)生成选项。   默认值在 Win32 上为空,其它平台上为 `-fPIC -fno-semantic-interposition` 。   用于保证生成的对象文件可被用于生成动态库。 ### 变量 LDFLAGS_STRIP   链接器剥离符号选项。   默认值为 `-s` 。 ### 变量 C_CXXFLAGS_EXT   指定 C/C++ 语言扩展的选项。   默认值和平台相关:若为 Win32 环境则为空,否则为 `-D_POSIX_C_SOURCE=200809L` 。 **注释** 若实现环境没有提供适当的宏定义,YFramework 中使用 POSIX 平台文件系统 API 的实现要求不被满足而可能构建失败。 ### 变量 C_CXXFLAGS_ARCH   C 和 C++ 编译器共用的体系结构相关选项。   默认值为空。   不限制具体形式,使用 G++ 时可以是 `-march=native` 。 ### 变量 C_CXXFLAGS_COMMON   C 和 C++ 编译器共用的公共选项。   默认值为 `-pipe $C_CXXFLAGS_GC $C_CXXFLAGS_ARCH -pedantic-errors $C_CXXFLAGS_EXT` 。 ### 变量 C_CXXFLAGS_OPT_LV   C 和 C++ 编译器优化等级选项。   默认值为 `-O3` 。 ### 函数 SHBuild_Get_C_CXXFLAGS_WARNING   取 C 和 C++ 编译器共用的警告命令行选项的默认值。   结果包括以下列表中的内容: * `-Wall` * `-Wcast-align` * `-Wdeprecated` * `-Wdeprecated-declarations` * `-Wdouble-promotion` * `-Wextra` * `-Wfloat-equal` * `-Wformat=2` * `-Winvalid-pch` * `-Wlogical-op` * `-Wmissing-declarations` * `-Wmissing-include-dirs` * `-Wmultichar` * `-Wno-format-nonliteral` * `-Wredundant-decls` * `-Wshadow` * `-Wsign-conversion` * `-Wstringop-overflow=0` * `-Wsuggest-attribute=const` * `-Wsuggest-attribute=noreturn` * `-Wsuggest-attribute=pure` * `-Wtrampolines`   通过检查 C++ 编译器和版本已知不支持的选项会被替换为其它功能近似的选项或被排除。 **注释** 当前仅检查 C++ 编译器,假定 C 编译器和 C++ 编译器版本对应一致(即 G++ 蕴含 GCC ,Clang++ 蕴含 Clang )。 ### 变量 C_CXXFLAGS_WARNING   C 和 C++ 编译器共用的警告命令行选项。   默认值是调用[函数 `SHBuild_Get_C_CXXFLAGS_WARNING`](#函数-shbuild_get_c_cxxflags_warning) 得到的值。 ### 变量 C_CXXFLAGS_IMPL_WARNING   和特定实现相关的 C 和 C++ 编译器共用的警告命令行选项。   默认值为空值。 ### 变量 CXXFLAGS_IMPL_WARNING   和特定实现相关的 C++ 编译器警告命令行选项。   默认值为空值。 ### 变量 CXXFLAGS_IMPL_COMMON   和特定实现相关的 C++ 编译器一般命令行选项。   默认值包括若干特定实现的选项。 ### 线程命令行选项   线程命令行选项是一组未指定名称的内部命令行选项,包含编译器选项和链接器选项的默认值。其中,编译器选项被[变量 `CFLAGS`](#变量-cflags) 和[变量 `CXXFLAGS`](#变量-cxxflags) 的默认值使用,链接器选项被[变量 `LDFLAGS`](#变量-ldflags) 的默认值使用。   默认值按以下方式检查和指定线程参数: * 通过 `-dumpspecs` 的内容检查是否匹配 `mthreads:` 。若成功,编译器和链接器选项添加 `-mthreads` 。 * 否则,测试带有 `-mthread` 选项的构建。若(直接调用编译器驱动)构建通过,则链接器选项添加 `-mthreads` ,并检查编译。 * 若编译不通过,则编译器选项添加 `-D_MT` ,否则添加 `-mthreads` 。 * 否则,若通过 `-dumpspecs` 的内容检查匹配 `no-pthread:` 且带有 `-pthread` 时无法构建,则保持编译器和链接器选项不变。 * 否则,编译器和链接器选项添加 `-pthread` 。 **注意** 不论 C 或 C++ ,当前实现在调用编译器测试构建时总是使用[函数 SHBuild_CXX_TestSimple](#函数-shbuild_cxx_testsimple) 。 ### 变量 CXXFLAGS_IMPL_OPT   和特定工具相关的 C++ 编译器优化命令行选项。   默认值包括若干特定实现的选项。 ### 变量 CFLAGS_STD   指定 C 标准的编译器命令行选项。   默认值为 `-std=c11` 。 ### 变量 CFLAGS_WARNING   C 编译器警告命令行选项。   默认值包含以下列表中的内容: * 变量 `C_CXXFLAGS_WARNING` 的内容 * 变量 `C_CXXFLAGS_IMPL_WARNING` 的内容 ### 变量 CXXFLAGS_STD   指定 C++ 标准的编译器命令行选项。   默认值为 `-std=c++11` 。 ### 函数 SHBuild_Get_CXXFLAGS_WARNING   取 C++ 编译器的警告命令行选项的默认值。   结果包括以下列表中的内容: * 变量 `C_CXXFLAGS_WARNING` 的内容 * 变量 `C_CXXFLAGS_IMPL_WARNING` 的内容 * `-Wconditionally-supported` * `-Wctor-dtor-privacy` * `-Wdeprecated`(仅当旧版本 GCC 中这个选项支持 C++ 但不支持 C 时) * `-Wno-deprecated-register` * `-Wno-mismatched-tags` * `-Wno-missing-braces`(仅当 Clang++ < 6.0 ,作为[这个问题](https://bugs.llvm.org/show_bug.cgi?id=21629)的变通) * `-Wnon-virtual-dtor` * `-Woverloaded-virtual` * `-Wsign-promo` * `-Wshorten-64-to-32` * `-Wstrict_null_sentinal` * `-Wsuggest-final-methods` * `-Wsuggest-final-types` * `-Wweak-vtables` * `-Wzero-as-null-pointer-constant` * 变量 `CXXFLAGS_IMPL_WARNING` 的内容   除以上变量中的内容外,通过检查 C++ 编译器和版本已知不支持的选项会被替换为其它功能近似的选项或被排除。 ### 变量 CXXFLAGS_WARNING   C++ 编译器警告命令行选项。   默认值是调用[函数 `SHBuild_Get_CXXFLAGS_WARNING`](#函数-shbuild_get_cxxflags_warning) 得到的值。 ### 变量 CXXFLAGS_OPT_DBG   C++ 编译器优化和调试相关的命令行选项。在未设置非空的 `SHbuild_Debug` 时。   默认值包含以下列表中的内容: * 变量 `C_CXXFLAGS_OPT_LV` 的内容 * 变量 `CXXFLAGS_OPT_UseAssert` 没有被设置非空值时包含 `-NDEBUG` * 变量 `CXXFLAGS_IMPL_OPT` 的内容 * `-fomit-frame-pointer` ### 变量 CFLAGS   C 编译器使用的命令行选项。   默认值为 `$CFLAGS_STD $C_CXXFLAGS_PIC $C_CXXFLAGS_COMMON $CFLAGS_WARNING $C_CXXFLAGS_IMPL_THRD_ $C_CXXFLAGS_COMMON_IMPL_ $CXXFLAGS_OPT_DBG` 。其中,`C_CXXFLAGS_COMMON_IMPL_` 是[编译器线程命令行选项](#线程命令行选项),而 `C_CXXFLAGS_COMMON_IMPL_` 是根据支持的编译器在内部定义的非公开变量。 **注意** 当前和 C++ 编译器选项共用 `CXXFLAGS_OPT_DBG` 。 ### 变量 CXXFLAGS   C++ 编译器使用的命令行选项。   默认值为 `$CXXFLAGS_STD $C_CXXFLAGS_PIC $C_CXXFLAGS_COMMON $CXXFLAGS_WARNING $C_CXXFLAGS_IMPL_THRD_ $CXXFLAGS_IMPL_COMMON $CXXFLAGS_OPT_DBG` 。其中,`C_CXXFLAGS_COMMON_IMPL_` 是[编译器线程命令行选项](#线程命令行选项),而 `CXXFLAGS_IMPL_COMMON` 的默认值包含[变量 `C_CXXFLAGS_COMMON_IMPL_`](#变量-cflags) 的内容。 ### 变量 LDFLAGS_OPT_DBG   链接器优化和调试相关的命令行选项。在未设置非空的 `SHbuild_Debug` 时。   默认值为 `$LDFLAGS_STRIP $LDFLAGS_IMPL_OPT $LDFLAGS_GC` 。 ### 变量 LDFLAGS   链接器使用的命令行选项。   默认值依次包含以下内容: * 变量 `C_CXXFLAGS_PIC` 的内容。 * 变量 `CXXFLAGS_WARNING` 的内容。 * 默认的[线程命令行选项](#线程命令行选项)。 * 变量 `LDFLAGS_OPT_DBG` 的内容。 * 可选的其它选项(参见以下 [`Tools/Scripts/SHBuild-YSLib-common.txt`](#toolsscriptsshbuild-yslib-commontxt) )。   默认使用 `-Wl,` 传递链接器特定的命令行。 ## Tools/Scripts/SHBuild-common-toolchain.sh   被应用程序构建脚本包含的基础功能,提供默认的编译器和链接器等工具的名称。   支持 GCC/G++ 和 Clang/Clang++ 。   支持 `ar` 及与其兼容的工具 `gcc-ar`/`llvm-ar` 的自动检测。对 Clang++ 和 G++ ,分别使用 `llvm-ar` 和 `gcc-ar` 。   以下可在环境外部配置,在值确定后被导出: * `CC` * 若操作系统为 `Win32` 且 `MSYSTEM` 指定为默认使用 llvm 工具链(即 Clang )的环境,默认值为 `clang` ,否则为 `gcc` 。 * `CXX` * 若操作系统为 `Win32` 且 `MSYSTEM` 指定为默认使用 llvm 工具链(即 Clang++ )的环境,默认值为 `clang++` ,否则为 `g++` 。 * `AR` * 默认值为变量 `CXX` 指定的 C++ 编译器确定的自动检测结果;若非 Clang++ 和 G++ ,则使用 `ar` 。 * `ARFLAGS` * 默认值为 `rcs` 。 * `LD` * 默认值为变量 `CXX` 的值。   关于 `MSYSTEM` 指定的环境和使用的工具链的对应关系,参见 [MSYS2 支持的环境](https://www.msys2.org/docs/environments/);关于支持的 `MSYSTEM` 的值和 MSYS2 环境,另见[函数 `SHBuild_Platform_Detect`](#函数-shbuild_platform_detect) 。   以下只读变量在初始化配置时被按需初始化并断言非空: * `SHBuild_CC_Name` :C 编译器名称。 * 在调用函数 `SHBuild_CC_GetVersion` 时被首先初始化。 * 初值是 `$CC` 作为参数调用函数 `SHBuild_CheckCC` 的结果。 * `SHBuild_CC_Version` :C 编译器版本号。 * 当前未使用。 * 初值是调用函数 `SHBuild_CC_GetVersion` 的结果。 * `SHBuild_CXX_Name` :C++ 编译器名称。 * 在调用[函数 `SHBuild_CXX_GetVersion`](#函数-shbuild_cxx_getversion) 时被首先初始化。 * 在脚本 [`Tools/Scripts/SHBuild-common-toolchain.sh`](#toolsscriptsshbuild-common-toolchainsh) 确定 `AR` 的默认值值前初始化。 * 在脚本 [`Tools/Scripts/SHBuild-common-options.sh`](#toolsscriptsshbuild-common-optionssh) 确定 `CXXFLAGS` 等其它配置变量的默认值值前初始化。 * 初值是 `$CXX` 作为参数调用函数 `SHBuild_CheckCXX` 的结果。 * `SHBuild_CXX_Version` :C++ 编译器版本号。 * 在脚本 `Tools/Scripts/SHBuild-common-toolchain.sh` 确定 C++ 版本号前初始化。 * 初值是调用函数 `SHBuild_CXX_GetVersion` 的结果。   上述按需初始化使用[函数 `SHBuild_InitReadonly`](#函数-shbuild_initreadonly)。 **注释** 可通过外部执行环境指定这些变量具有非空值而跳过初始化。   **这个脚本是公开的工具**,被安装脚本部署。 ### 函数 SHBuild_CheckCompiler   尝试以参数指定的编译参数和输入调用参数指定的编译器,并按检查结果选择和输出参数的值。   检查编译器时,首先排除参数指定的编译器不可执行的情形,然后通过尝试编译以参数指定的源程序进行。   前四参数分别指定编译器的路径、尝试编译的源程序、检查成功时输出的结果和检查失败时输出的结果,之后的参数指定编译选项和源文件。选项和源文件参数中,应在语言选项(如 `-xc++` )后出现一次表示输入源程序的 `-` 。 **注释** 这允许自由安排参数中 `-` 的顺序。一般地,`-` 应出现在 `-xc++` 等参数之后,而出现在链接的库选项之前(如有)。若指定链接的其它库选项在 `-` 之前,其中的符号在使用 GNU ld 等对出现顺序敏感的链接器时,无法在源程序中引用而链接失败。   检查前断言前两个参数非空。指定编译选项的参数为空时,第三和第四参数可能不提供或为空。   源程序和换行符通过管道输入编译器。 **注释** 对 ISO C 以及 ISO C++11 前的版本,翻译单元不以空行结尾引起未定义行为。此处指定源程序的参数可以不以换行结尾也可安全处理。   结果是以下之一: * 空值(第一参数指定不可执行的路径)。 * 第三参数(检查成功时的结果)。 * 第四参数(检查失败时的结果)。 **注意** 当前不检查失败原因。编译命令调用依赖可写的临时目录。参见函数 `SHBuild_GetTempDir` 的已知限制。 ### 函数 SHBuild_CheckCC   尝试调用参数指定的编译器以检查 C 编译器风格。   第一参数指定编译器可执行文件路径。   结果是以下之一: * 空值(不支持的编译器)。 * `Clang` 。 * `GCC` 。 ### 函数 SHBuild_CheckCXX   尝试调用参数指定的编译器以检查 C++ 编译器名称。   第一参数指定编译器可执行文件路径。   结果是以下之一: * 空值(不支持的编译器)。 * `Clang++` 。 * `G++` 。 ### 函数 SHBuild_CC_Test   测试 `"$CC"` 指定的编译器 C 编译器命令行是否可成功调用。   第一参数指定源程序,之后的参数指定编译选项。编译选项前隐含 `-pipe -xc` 。   以 `SHBuild_CheckCompiler` 实现编译器调用。 ### 函数 SHBuild_CC_TestSimple   测试 `"$CC"` 指定的编译器 C 编译器命令行编译最小程序是否可成功调用。   参数指定编译选项。   以 `SHBuild_CC_Test` 实现编译器调用。   使用的最小程序是 `int main(void){return 0;}` 。 ### 函数 SHBuild_CXX_Test   测试 `"$CXX"` 指定的编译器 C++ 编译器命令行是否可成功调用。   第一参数指定源程序,之后的参数指定编译选项。编译选项前隐含 `-pipe -xc++` 。   以 `SHBuild_CheckCompiler` 实现编译器调用。 ### 函数 SHBuild_CXX_TestSimple   测试 `"$CXX"` 指定的编译器 C++ 编译器命令行编译最小程序是否可成功调用。   参数指定编译选项。   以 `SHBuild_CXX_Test` 实现编译器调用。   使用的最小程序是 `int main(){}` 。 ### 函数 SHBuild_CC_GetVersion   尝试调用 `"$CC"` 指定的编译器以管道输入的程序取 C 编译器版本号。   结果是以下之一: * 成功时:GCC 或 Clang 版本号的 `X.Y.Z` 转换为 `X * 10000 + Y * 100 + Z` 的数值的字符串。 * 失败时:空。 **已知缺陷** 不支持无法取得 `__GNUC_PATCHLEVEL__` 的旧版本 GCC 。 **已知缺陷** 不支持 Apple Clang 。 ### 函数 SHBuild_CXX_GetVersion   尝试调用 `"$CXX"` 指定的编译器以管道输入的程序取 C++ 编译器版本号。   结果是以下之一: * 成功时:G++ 或 Clang++ 版本号的 `X.Y.Z` 转换为 `X * 10000 + Y * 100 + Z` 的数值的字符串。 * 失败时:空。 **已知缺陷** 不支持无法取得 `__GNUC_PATCHLEVEL__` 的旧版本 GCC 。 **已知缺陷** 不支持 Apple Clang 。 ## Tools/Scripts/SHBuild-self-host.sh   [SHBuild](SHBuild.zh-CN.md) 自举测试用脚本。   使用 SHBuild 编译并静态链接构建 SHBuild 。和 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 类似,直接使用 YSLib 源文件。 ## Tools/Scripts/SHBuild-self-host-DLL.sh   [SHBuild](SHBuild.zh-CN.md) 自举测试用脚本。   使用 SHBuild 编译并动态链接构建 SHBuild 。依赖 `/usr/lib` 中存在的 YFramework 和 YBase 动态库文件。 ## Tools/Scripts/SHBuild-YSLib.sh   作为 [stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 公共配置脚本被不同的 stage 1 构建脚本包含。   包含脚本依次执行: * 按需初始化[变量 `SHBuild_ToolDir`](../Development.zh-CN.md#环境变量) 。 * 包含脚本 [`Tools/Scripts/SHBuild-common.sh`](#toolsscriptsshbuild-commonsh) 以按需初始化确定默认构建位置依赖的环境变量。 * 调用[函数 `SHBuild_S1_InitConf`](#函数-shbuild_s1_initconf) 初始化 stage 1 SHBuild 配置。 * 初始化缓存: * 按需初始化[变量 `S1_CacheFile`](#stage-1-共享变量) ,默认值为 `"$S1_BuildDir/config.cache"` 。 * 初始化缓存相关的内部状态,并调用[函数 `SHBuild_LoadCache`](#函数-shbuild_loadcache) 加载缓存。 * 内部状态决定传递给函数 `SHBuild_LoadCache` 被缓存的变量的名称模式:`(CC CXX LD AR '(C|CXX|LD|AR)FLAGS.*' 'SHBuild_(C|CXX)_.*' 'S1_Cached_.*'`)。 * 初始化 stage 1 公共构建资源和配置: * 按需初始化[变量 `SHBuild_PCH_stdinc_h`](#变量-shbuild_pch_stdinc_h) 。 * 包含脚本 [`Tools/Scripts/SHBuild-common-options.sh`](#toolsscriptsshbuild-common-optionssh) 以按需初始化构建工具使用的选项。 * 初始化变量 `INCLUDE_PCH` 为指定版本库下 `YBase/include/stdinc.h` 的路径字符串。 * 初始化变量 `INCLUDES` 为版本库目录下的适合作为编译器选项使用的头文件目录列表。 * 定义函数(参见以下各节)。 **注意** 这个脚本包含 `INC_SHBuild_YSLib` 守卫变量检查,默认重复包含只被执行一次。 ### 变量 SHBuild_PCH_stdinc_h   预编译头文件名称,默认值为 `"$S1_BuildDir/stdinc.h"` 。 ### 函数 SHBuild_S1_InitializePCH   初始化 stage 1 使用的预编译头文件:即调用: ```shell SHBuild_CheckPCH "$INCLUDE_PCH" "$SHBuild_PCH_stdinc_h" ``` ## Tools/Scripts/SHBuild-YSLib*.txt   构建 YSLib 用的 NPLA1 脚本,包含以下文件: * [`Tools/Scripts/SHBuild-YSLib-common.txt`](#toolsscriptsshbuild-yslib-commontxt) :被 `Tools/Scripts/SHBuild-YSLib-build.txt` 加载的 NPLA1 脚本。 * [`Tools/Scripts/SHBuild-YSLib-build.txt`](#toolsscriptsshbuild-yslib-buildtxt) :使用 SHBuild 构建 debug 或 release 配置的 YBase 和 YFramework 库的 NPLA1 脚本,被 `Tools/install-sysroot.sh` 调用,其中 [SHBuild 默认为 stage 1 SHBuild](SHBuild.zh-CN.md#多阶段构建) 。   调用方式详见 [stage 1 SHBuild 中关于 NPL 支持的说明](SHBuild.zh-CN.md)。   可通过[外部环境变量](#环境配置)配置脚本行为。 ### 版本控制系统支持   脚本以相同的方式检查和识别版本控制系统。   以下环境变量提示使用 Mercurial 或 Git : * 若[环境变量 `SHBuild_VCS_hg`](../Development.zh-CN.md#环境变量) 非空,则检查 `hg` 命令可用。 * 否则,若[环境变量 `SHBuild_VCS_git`](../Development.zh-CN.md#环境变量) 非空,则检查 `git` 命令可用。 * 否则,依次检查 `hg` 和 `git` 命令可用,若 `hg` 可用则不再检查 `git` 。   命令可用需要满足以下条件: * 被检查的命令应在 `$PATH` 中。 * 若在 Windows 中使用 shell ,可能需要提前设置环境以确保继承环境变量。 * **注意** MSYS2 提供的 `mercurial` 包的可执行文件是脚本而不是可执行文件,不被 NPLA1 脚本调用的 Windows 命令行支持。 * **注释** 不使用 `HG` 环境变量,因为可能设置为不被支持的 `hg` 程序路径。事实上,MSYS2 的包 `mercurial` 安装到 `/etc/profile.d/mercurial.sh` 设置 `HG` 为脚本,覆盖从其它位置继承的 `hg.exe` 。 * 且当前工作目录求在对应的版本库中,同时确定仓库的顶层目录路径。 * 对 Git ,要求存在工作区。 ## Tools/Scripts/SHBuild-YSLib-common.txt   这个脚本提供一些公共的库,包括支持类似 [`Tools/Scripts/SHBuild-common-options.sh`](#toolsscriptsshbuild-common-optionssh) 和 [`Tools/Scripts/SHBuild-common-toolchain.sh`](#toolsscriptsshbuild-common-toolchainsh) 的选项以环境变量的方式配置,但 C 编译器相关的选项除外(不使用而被忽略)。   除关于 [shell 脚本](../Development.zh-CN.md#shell-脚本)和 [NPLA1 脚本](../Development.zh-CN.md#npla1-脚本)之间的一般差异外,与 `Tools/Scripts/SHBuild-common-options.sh` 和 `Tools/Scripts/SHBuild-common-toolchain.sh` 的不同为: * 通过调用函数进入**构建环境变量检测**并在之后进入回调函数中构建。 * 按需初始化变量。构建环境变量检测可能延迟访问以避免不必要初始化的值。配置时为确定变量的默认值的检查的调用顺序可能不同。 * 使用 debug 模式时,`CXXFLAGS_OPT_DBG` 设置为 `-O0 -g -D_GLIBCXX_DEBUG_PEDANTIC` ,不再被环境变量覆盖。 * 生成变量默认值的选项之间的空白符可能不同(通常可确保为一个空格)。 * 附加支持构建应用的配置,在导出的变量的默认值中添加扩展的选项(参见以下相关说明)替换 shell 脚本中指定的默认值(可影响其它默认值)。 * 附加检查 [sanitizer](https://github.com/google/sanitizers/wiki) 。参见以下相关章节的说明。 * 支持更多变量和默认值。 * 除非另行指定,这些变量在构建环境变量检测中使用。参见以下各节。 * 在构建动态库或应用程序时,使用空 `C_CXXFLAGS_GC` 值。 * **原理** 这些选项[影响编译时代码生成,不总是优化的](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)。对静态库,因为始终无法预测可能需要排除的定义,启用这些选项是合理的。否则,通常从源代码直接确保排除冗余定义更有效。 * **注释** `LDFLAGS_GC` 的值仍被保持。对使用空的 `C_CXXFLAGS_GC` 值构建的目标文件这没有预期的作用,但对其它情形(典型地,静态库)仍然有效。 * 提供部分和 shell 脚本不同的函数,详见版本库中的 `doc/NPL.txt` 。 * 提供单独的缓存机制。 * 配置缓存的变量的名称具有 `SHBuild_` ,可能具有名称前缀为 `S1_` 的对应的 [stage 1 共享变量](#stage-1-共享变量)。 * 两者功能相同,但指定 [stage 2 和之后阶段而非 stage 1](SHBuild.zh-CN.md#多阶段构建) 的缓存行为。 * 支持以下被缓存的变量: * [Stage 1 被缓存的变量](#toolsscriptsshbuild-yslibsh)的一个子集,名称以 NPLA1 字符串列表定义为:`list "CXX" "LD" "AR" "CFLAGS" "CXXFLAGS" "LDFLAGS" "ARFLAGS" "SHBuild_CXX_Name" "SHBuild_CXX_Version"` 。 * 缓存的配置变量,作为配置项取值同 [stage 1 共享变量](#stage-1-共享变量),且支持 `#f` 同 `"false"` ,`#t` 同 `"true"` 。 * 变量 `SHBuild_Cached_quadmath` :类似变量 [`S1_Cached_quadmath`](#toolsscriptsshbuild-bootstrapsh) 。 * `SHBuild_CacheFile` :类似变量 `S1_CacheFile` 。默认值为构建目录下的 `config.cache` 。 * `SHBuild_CacheMode` :类似变量 `S1_CacheMode` 。   这个脚本被 [`Tools/Scripts/SHBuild-YSLib-build.txt`](#toolsscriptsshbuild-yslib-buildtxt) 加载,并被 [`Tools/install-sysroot.sh`](#toolsinstall-sysrootsh) 间接调用。   以下[公共构建配置变量](#公共构建配置变量)影响脚本的特定行为: * `SS_DebugEnv` 的作用当前包括: * 对环境变量修改时输出修改的变量名和对应的值。 * `SS_Verbose` 的作用当前包括: * 在 `LDFLAGS` 变量中附加 `-mwindows` 时提示。 * 在安装文件时输出安装类型、目标和源。   脚本支持外部调用这个脚本的命令行设置变量的默认值,以覆盖直接指定构建环境变量检测确定的选项,如: ```bash CXX=clang++ CXXFLAGS='-std=c++11 -O2' Tools/install-sysroot.sh ``` **警告** 使用预编译头选项和缺陷同 [`Tools/Scripts/SHBuild-build.sh`](#toolsscriptsshbuild-buildsh) 。其中的特性未指定使用 shell 实现,和后者可能存在 shell 环境中可见的差异。   **这个脚本是公开的工具**,被安装脚本部署。 ### 变量 LDFLAGS_DYN_BASE   指定动态库基础链接选项。   默认值和平台相关:若为 Win32 环境则使用 `-shared -Wl,--dll` ,否则为 `-shared` 。 ### 变量 LDFLAGS_DYN_EXTRA   指定动态库附加链接选项。   默认值等价于 `-Wl,--no-undefined,--dynamic-list-data,--dynamic-list-cpp-new,--dynamic-list-cpp-typeinfo` 。 ### 变量 LDFLAGS_DYN   指定动态库链接选项。   默认值为 `$LDFLAGS_DYN_BASE $LDFLAGS_DYN_EXTRA` 。 ### 变量 LIBS_RPATH   用于指定在运行时 ELF 映像需要的动态库的路径的链接器选项。   在 Win32 默认不设置,其它平台默认值为 `-Wl,-rpath,'\$ORIGIN:\$ORIGIN/../lib'` 。 ### 变量 LIBPFX   库前缀。   在 Win32 默认不设置,其它平台默认值为 `lib` 。 ### 变量 DSOSFX   动态库文件名后缀。   在 Win32 默认值为 `.dll` ,其它平台默认值为 `.so` 。 ### 变量 EXESFX   可执行文件名后缀。   在 Win32 默认值为 `.exe` ,其它平台默认不设置。 ### Sanitizer 检查支持   构建环境变量检测支持 sanitizer :若在变量 `CFLAGS`、`CXXFLAGS`、`LDFLAGS` 或 `SHBuild_CXXFLAGS` 中包含启用被支持的 sanitizer 的选项 (以 `-fsanitizer=address` 起始),配置最终在 `CFLAGS`、`CXXFLAGS` 和 `LDFLAGS` 最后添加自动调整的选项。   构建配置支持 ASan、TSan、MSan、UBSan 和 LSan 。Sanitizer 自身支持的系统和编译器详见 sanitizer 的文档。   ASan 使用的选项要求和建议参见 [FAQ](https://github.com/google/sanitizers/wiki/AddressSanitizer#faq) 。 **注意** [GCC 不支持 MSan](https://gcc.gnu.org/legacy-ml/gcc/2014-10/msg00006.html) 。MSan 要求标准库[使用带 MSan 的选项构建](https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo),否则[会有假阳性结果](https://github.com/google/sanitizers/issues/542)。 **注意** 具体调整的选项参见脚本具体实现,不保持构建版本之间稳定。* **注意** 构建脚本不保证构建的二进制程序的具体可用性。构建的程序可能因为程序及 sanitizer 实现的缺陷运行时出错,可能另需具体排查原因修复。 ### 扩展选项的默认值   变量 `LDFLAGS` 的默认值依次包含: * 和 shell 脚本中相同的默认值。 * 生成可执行程序时且要求按需调整链接器参数时,附加的值: * 当需要生成 Win32 子系统程序时,附加 `-mwindows` 。 * 构建动态可执行程序时,变量 `LIBS_RPATH` 的内容。 * 构建动态库或应用时,变量 `LDFLAGS_DYN` 的内容。 ### SHBuild 附加构建选项环境变量   若回调函数中调用 SHBuild 构建,可在此之前设置**扩展环境变量**并调用函数 `SHBuild_Extend_CallVariables` 以更新被 SHBuild 使用的环境变量 `LDFLAGS` 和 `LIBS` 的值。这些影响 SHBuild 工具调用构建工具的命令行的 **SHBuild 附加构建选项环境变量**,包括: * `SHBuild_CFLAGS` * `SHBuild_CXXFLAGS` * `SHBuild_LDFLAGS` * `SHBuild_LIBS`   除非另行指定,SHBuild 附加构建选项环境变量的默认值为空,不被脚本设置。 ### 其它函数和可在外部设置的其它变量   详见版本库中的 `doc/NPL.txt` 。   其它变量不被构建环境变量检测访问,而通过函数调用生效,如 `SHBuild_Extend_CallVariables` 。 ## Tools/Scripts/SHBuild-YSLib-build.txt   这个脚本当前包括和安装相关的流程,实现 `Tools/install-sysroot.sh` 在 [stage 1 SHBuild 构建后的主要逻辑](SHBuild.zh-CN.md#多阶段构建)。   脚本支持在构建前自动从网络安装[外部依赖项二进制归档文件](../Archives.zh-CN.md#External)以准备从源代码构建安装 YFramework 库。这仅在环境变量 `YSLib_DistDir` 被设置非空值时启用。这需要一些外部工具命令的支持: * 下载归档依次检查以下工具命令: * `wget` * `curl` * **注释** 因为 [PowerShell 不被支持](../Run.zh-CN.md#多任务环境),实现不检查[对 `wget` 和 `curl` 的不兼容别名](https://daniel.haxx.se/blog/2016/08/19/removing-the-powershell-curl-alias/)。 * **注释** 另见以下环境变量 `SS_Offline` 的说明。 * 解压缩归档依次检查以下工具命令: * `bsdtar` * `7za` * **注释** 当前不提供这些工具的自动安装。 * **原理** 这些工具广泛可用,在不同环境中具有不同情形。 * [自 Microsoft Windows 10 Insider Build 17063/1809](https://techcommunity.microsoft.com/t5/containers/tar-and-curl-come-to-windows/bc-p/3272679) 起,[随系统提供 `curl` 的可执行文件](https://curl.se/windows/microsoft.html) 。 * MSYS2 和一些 Linux 发行版等环境通过包管理器提供这些命令行工具。 * **原理** 这些工具通常被全局安装,可能需要系统管理员权限才能执行安装命令。考虑潜在的[安全性](../Run.zh-CN.md#多任务环境)和复杂性问题,本脚本不支持确保提供这个前提。   脚本使用 [`Tools/Scripts/SHBuild-YSLib-common.txt`](#toolsscriptsshbuild-yslib-commontxt) 中提供的一些函数。   脚本支持以下[外部扩展环境变量](#环境配置)指定构建和部署目标: * `SHBuild_UseDebug` 非空时启用构建和安装 debug 配置的库。 * `SHBuild_UseRelease` 非空时启用构建和安装 release 配置的库。 * `SHBuild_NoStatic` 非空时跳过静态库构建。 * `SHBuild_NoDynamic` 非空时跳过动态库构建。 * `SHBuild_No3rd` 非空时跳过第三方库安装。 * 对[外部依赖项](../Development.zh-CN.md#外部依赖项)中的库,只安装启用的配置决定的必要的外部依赖。启用的配置由 `SHBuild_UseDebug` 和 `SHBuild_UseRelease` 指定。 * `SHBuild_NoDev` 非空时跳过可选的开发工具构建和安装。 * `SHBuild_Rebuild_S1` 非空时跳过文件存在性检查,总是重新构建 stage 1 SHBuild 。 * `SHBuild_NoDev` 非空时跳过 stage 2 SHBuild 后的开发工具构建和安装。 * `YSLib_DistDir` 非空时应指定包含一个绝对路径作为储存 YSLib 归档的目录。   以下[公共构建配置变量](#公共构建配置变量)影响脚本的特定行为: * 所有调用 `Tools/Scripts/SHBuild-YSLib-common.txt` 而生效的公共构建配置变量在此作用相同。 * `SS_DirectExtract` 的作用包括: * 安装下载的归档时,直接用工具命令行覆盖对应位置的文件,而不先解压缩释放到临时目录后再更新。 * `SS_Offline` 的作用包括: * 不检查下载工具命令的可用性。 * 不使用网络下载资源。   以下构建时的中间变量可被外部配置,当外部没有配置或为空值时使用默认值: * `SHBuild_SystemPrefix` :系统前缀,在 Sysroot 根路径下决定安装路径。 * 默认值由脚本 `Tools/Scripts/SHBuild-YSLib-common.txt` 中的函数的调用确定:同 `SHBuild_GetSystemPrefix (SHBuild_Platform_Detect SHBuild_Host_OS SHBuild_Host_Arch)` 的结果。 * 脚本 `Tools/Scripts/SHBuild-common.sh` 中提供 shell 脚本的等价调用:`$(SHBuild_GetSystemPrefix (SHBuild_Platform_Detect "$SHBuild_Host_OS" "$SHBuild_Host_Arch"))` 。 * `SHBuild_YF_Libs_freetype` :freetype 库链接参数。 * 默认值为 `-lfreetype` 或 `pkg-config --libs freetype2` 的输出结果。 * 其中存在 Sysroot `libfreetype.a` 时默认值为前者。 * `SHBuild_YF_Libs_FreeImage` :FreeImage 库链接参数。 * 默认值为 `-lFreeImaged` 或 `-lFreeImage` ,对应 debug 和非 debug 配置。   这个脚本也可能使用其它变量用于传递参数给被调用的命令,包括一些 `SHBuild` 预期的变量;后者作为公开接口,但**其具体含义和使用不保证在不同版本间稳定**。   在[自举构建 stage 2 SHBuild](SHBuild.zh-CN.md#多阶段构建) 前构建安装 YFramework 库时,接受以下环境变量: * `INCLUDES_freetype` 指定覆盖包含路径的编译器命令行选项。 * 默认值以 `-I` 起始,使用版本库目录下的 `3rdparty/freetype/include` 目录带有适当引号的完整路径。 * [环境变量 `SHBuild_VCS_hg` 或 `SHBuild_VCS_git`](../Development.zh-CN.md#环境变量) 指定构建时的版本控制系统,作用参见以下说明。   在 stage 2 环境中构建其它目标时接受以下[外部环境变量](#环境配置)(部分被 SHBuild 直接以环境变量的方式接受): * `INCLUDES` :包含路径,和非 SHBuild 中的 `Makefile` 惯用法含义类似。 * `LDFLAGS` :链接命令行选项。 * `LIBS` :作为命令行选项的链接时使用的库路径。 * `LIBS_RPATH` :非 Windows 平台使用的 `rpath` 路径。 * SHBuild 附加构建选项环境变量:参见 `Tools/Scripts/SHBuild-YSLib-common.txt` 。其中变量 `SHBuild_CXXFLAGS` 同时作用在预编译头构建。 ### 版本字符串   在 stage 1 构建 YFramework 前,通过选择的版本控制系统指定确定版本字符串,可在被构建的 YFramework 库中引用。   确定版本字符串时,检查对应的命令,具体方式详见关于[版本控制系统支持](#版本控制系统支持)的描述。若检查都失败,则版本字符串为空串。否则,使用第一个检查成功的命令生成对应的版本字符串。 **已知限制** 若使用 `git` 生成版本字符串,当前同时依赖 `sed` 命令。   若版本字符串非空,则通过宏定义的方式参与之后的构建。当前影响以下源文件所在的翻译单元: * `YFramework/source/YSLib/Core/YCoreUtilities.cpp`   在构建前,若被影响的上述翻译单元已被构建,在生成目录中对应的(以 `.d` 为扩展名的)依赖文件被修改,以添加对版本控制系统中的特定文件的依赖。这能使最新的版本控制系统的修改影响生成的目标代码,而无需手动修改这些翻译单元的源文件。 **已知限制** 当前自动更新依赖的实现同时依赖 `sed -i` 命令。 ## Tools/Scripts/SHBuild-BuildApp.txt   NPLA1 应用程序构建脚本。可利用此工具脚本调用 SHBuild 构建特定*配置(configuration)* 下使用 YSLib 库和基础环境开发的应用程序。   **这个脚本是公开的工具**,被安装脚本部署。 ### 基本原理   **配置**是特定用途的一组程序输出的集合。常见软件配置可以区分目标平台,是否为调试配置等。   脚本通过设置特定的环境变量并调用 SHBuild 递归扫描指定目录完成构建。其中调用命令由环境变量 `SHBuild` 指定。若变量 `SHBuild` 为空,则假定使用脚本程序在 Sysroot 中,由 Sysroot 的布局确定的 SHBuild 的位置作为变量 `SHBuild` 的默认值。   脚本支持区分 debug 和非 debug 配置以及静态和 DLL 配置。详见以下说明。   使用 debug 配置总称 debug 模式。使用其它配置总称 release 模式。 ### 调用方式   无参数调用时,显示帮助文本。以第一参数指定**配置名称**,执行脚本直接一次性配置后构建。之后可选的其它参数被脚本传递给 SHBuild ,详见以下的操作说明。 ### 使用须知   脚本依赖 Sysroot 。   这个脚本被 [`Tools/Scripts/SHBuild-BuildPkg.sh`](#toolsscriptsshbuild-buildpkgsh) 调用。   当前只支持构建,不支持部署。   构建时调用的工具链命令行及配置详见 [`Tools/Scripts/SHBuild-YSLib-common.txt`](#toolsscriptsshbuild-yslib-commontxt) 的说明。   需要先确保源代码可访问。**注意**源代码目录会被递归扫描,建议在目录中只包含所有需要构建的源文件或被包含的文件。 ### 操作说明   一般步骤: * 新建一个 GNU bash 脚本(以下称为*用户构建脚本* ),调用此脚本(若无法在 `PATH` 找到,需要使用完整路径)。 * 以源代码所在目录的路径作为参数,执行通过此脚本包含的 `SHBuild_BuildApp` 函数,等待构建完成。 * 直接包含后的脚本仍可使用无参数调用用户构建脚本查看选项和说明。   简化操作:也可以不创建用户构建脚本,直接在命令行中执行,例子见[入门](../GettingStarted.zh-CN.md)。   若有必要,在调用本脚本之前设置 `SHBuild_BuildDir` 变量为指定输出文件所在的目录的完整路径,如: ```shell export SHBuild_BuildDir=$(dirname "$0"`/../build) ```   上述命令行指定相对于用户构建脚本上一层目录的 `build` 子目录下作为基准输出路径。若不显式设置此变量,工具脚本会指定其默认值为用户构建脚本所在的目录。   调用本脚本。脚本会自动加入必要的参数调用 SHBuild ,传递的参数依次具体如下: * 中间变量 `SHBOPT` 的值,包括根据配置决定的目录设置选项、`-xid,include -xmode,2` 以及用户在脚本命令行指定的剩余选项 `SHBOPT_BASE` 。 * 传递给本脚本的配置名称以外的可选参数。 * `SHBuild_BuildApp` 的值,用于编译器的库配置(包含路径以及使用 DLL 需要的宏定义 `-DYF_DLL -DYB_DLL` ),由脚本根据静态或动态库配置自动确定,无需重复输入类似选项。 **特别注意** 脚本执行**以输出基准路径作为当前工作目录**,需要以此为基准指定源文件路径( `SHBuild` 使用的 `SRCPATH` 参数)。   通过脚本命令行间接传递给 `SHBuild` 的参数 `SHBOPT_BASE` 以及函数 `SHBuild_BuildApp` 的参数都可以进一步对构建过程进行调整,如 `-xj,2` 指定 2 个并行线程构建。 **注意** 以 SHBuild 作为 NPLA1 脚本解释器时,传递的参数可能会被 SHBuild 截获,而不被继续传递给 脚本中调用的 SHBuild 。为避免这种情形,在 `-xcmd,RunNPLFile` 和本的脚本文件名选项后,可加上 `--` 分隔其余命令行参数。 ### 配置设置   传递给 SHBuild 指定使用 `.配置名称` 相对路径(无需另外指定 `-xd,` 参数)。如 `-cdebug` 指定输出路径为 `.debug` 。省略此项默认配置名为 `shbuild` 。   脚本根据以下规则自动检测配置: * 若配置名称以 `debug` 起始,或环境变量的 `SHBuild_Debug` 值非空,则视为使用 debug 配置。 * 若配置名称以 `static` 结束,活环境变量 `SHBuild_Static` 的值非空,则视为使用 static 配置。 ### 环境变量   环境变量 `SHBuild_Debug` 和 `SHBuild_Static` 可按上述自动检测配置过程指定配置类型。   默认情况下,release 配置会在链接器命令行加入 `-mwindows` ,[和 debug 配置编译的程序行为不保证相同](../Prerequisitions.zh-CN.md)。设置非空变量 `SHBuild_NoAdjustSubsystem` 禁用此行为。   脚本使用包含 YSLib 库的编译器命令行。脚本已经导出了用于链接器的包含使用 YSLib 库命令行参数的变量 `LDFLAGS` 和 `LIBS` 。若有必要,可设置 SHBuild 附加构建选项环境变量(参见 Tools/Scripts/SHBuild-YSLib-common.txt )。