# 概述   Sysroot 是具有特定逻辑布局根目录兼容的目录,一般在文件系统中实现。   Sysroot 主要用于本机程序的开发环境构建和部署,以后也可能用于交叉构建(cross building) 。   在利用 Sysroot 开发之前有必要了解开发注意事项: * [构建](Build.zh-CN.md) * [先决条件](Prerequisitions.zh-CN.md)   Sysroot 使用的文件系统路径满足[运行](Run.zh-CN.md)环境对外部文件的路径的约定。   当前 Sysroot 仅支持 MinGW 和 Linux 环境。   关于本文档讨论以外的脚本的其它行为,参见[脚本](Tools/Scripts.zh-CN.md)的有关说明。 # 布局   在满足前述要求的前提下,Sysroot 部署实例使用[局部 FHS 目录布局](Run.zh-CN.md#文件系统布局),具体子目录布局如下: * `.shbuild` :使用 [SHBuild](Tools/SHBuild.zh-CN.md) 构建时的临时目录(可以在部署后手动删除)。 * [系统前缀字符串](Tools/Scripts.zh-CN.md)指定的作为[安装路径前缀](Tools/Scripts.zh-CN.md)的最后一个路径组件的目录文件名(如 `usr` ):被部署的用户空间目录,其中的内容使用 [Linux](http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/usr.html) 等现代 UNIX 变体类似的约定: * `bin` :二进制文件。 * `include` :头文件。 * `lib` :库文件。 * `share` :共享的数据文件。 * `share/NPLA1` :NPLA1 脚本部署位置。 * `var` :程序运行时可修改的数据。   其中,除 `var` 外,这些目录中的内容在安装或维护部署情形外通常应保持只读。   对 MSYS2 支持的宿主和目标平台,系统前缀字符串指定的路径和 MSYS2 构建系统的 `/etc/msystem` 脚本指定的 `MSYSTEM_PREFIX` 的值一致。 * 对 MinGW32 和 MinGW64 ,这也对应 [MSYS2 支持的子系统路径](https://www.msys2.org/wiki/MSYS2-introduction/#subsystems)。 * MSYS2 可能支持其它平台的组合,可能直接可用,但并不保证每个配置都提供支持和被测试。详见[先决条件](Prerequisitions.zh-CN.md)中关于平台的描述。   上述 `bin` 目录可以加入[环境变量 `PATH`](Run.zh-CN.md) 中以便其中的程序被命令行执行。当前若使用 [YDE](YDE.zh-CN.md) 构建脚本,这是必要的。   依赖 Sysroot 的程序可预期以上布局符合约定,且功能允许时可访问这些子目录或其它文件,而不被要求能在不符合预期的环境下正常运行。这些程序可能根据上述子目录中的内容判断需要的不同操作。安装或者维护 Sysroot 布局的程序提供附加的保证,不依赖全部或者部分路径符合预期,而在必要时可创建文件使布局满足这些预期。具体的操作可在不同程序的功能描述中明确。   没有在此约定的 Sysroot 中的子目录和其它文件路径为未来的版本保留:这些路径不被当前版本使用,但可能被之后的版本使用。依赖 Sysroot 的程序和用户应注意避免占用保留路径引起变更版本时引起的兼容问题。 **注意** Sysroot 实例的布局*不是*[版本库文件布局](Features.zh-CN.md)。关于部署文件时有关被部署的文件的要求,参见版本库文件布局中的相关约定。 **原理**   文件系统子目录的约定和 FHS 类似。   对 NPLA1 文件,因为脚本并非二进制文件而对体系结构中立,使用 `share` 子目录。脚本不被视为可能依赖具体体系结构的二进制库文件(位于 `lib` 为前缀的子目录)。若未来需要部署二进制文件或作为库的二进制可执行文件,可部署到 `lib` 和 `libexec` 等子目录。这也类似 [Guile 等语言实现使用的惯例](https://www.gnu.org/software/guile/manual/html_node/Installing-Site-Packages.html);但当前没有指定其中的下级子目录。   在程序中实现局部 FHS 目录布局可能需要特定宿主环境的支持,以定位可执行文件映像路径,例如: * Win32(实际依赖 Windows NT 实现)[加载动态库的搜索默认行为](https://learn.microsoft.com/windows/win32/dlls/dynamic-link-library-search-order)以及运行时的 [`GetModuleFileNameW`](https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew) 调用。 * ELF 映像的依赖路径中的[替换序列 `$ORIGIN`](https://www.sco.com/developers/gabi/latest/ch5.dynamic.html#substitution) 。 * Linux 运行时对[文件系统路径 `/proc/self/exe`](https://man7.org/linux/man-pages/man5/proc.5.html) 的访问(在某些 [chroot](https://man7.org/linux/man-pages/man2/chroot.2.html) 环境中可能不可用)。 * Mac OS X 运行时的 [`_NSGetExecutablePath`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html) 调用。 * FreeBSD 运行时的 [`sysctl`](https://man.freebsd.org/cgi/man.cgi?sysctl(3))(构造参数向量 `CTL_KERN` 、`KERN_PROC` 、`KERN_PROC_PATHNAME` 和 `-1` )调用。 * FreeBSD(仅当启用 [procfs](https://man.freebsd.org/cgi/man.cgi?query=procfs) 时)和 [Dragonfly BSD](https://leaf.dragonflybsd.org/cgi/web-man?command=procfs) 运行时对文件系统路径 `/proc/curproc/file` 的访问。 * NetBSD 运行时对[文件系统路径 `/proc/curproc/exe` 或 `/proc/self/exe`](https://man.netbsd.org/mount_procfs.8) 的访问。 * Solaris(自从 10 )运行时对[文件系统路径 `/proc/self/object/a.out` 或 `/proc/self/path/a.out`](https://docs.oracle.com/cd/E88353_01/html/E37852/proc-5.html) 的访问。 * [SunOS](https://docs.oracle.com/cd/E19253-01/816-5168/6mbb3hrb1/index.html) 和 [Solaris](https://docs.oracle.com/cd/E86824_01/html/E54766/getexecname-3c.html) 运行时(对动态加载的具有 `AT_SUN_EXECNAME` 的映像)的 `getexecname` 调用,或 Solaris(自从 11 )对[文件系统路径 `/proc/self/execname`](https://docs.oracle.com/cd/E88353_01/html/E37852/proc-5.html) 的访问。   若不存在这样的支持,则需在运行时配置中指定。 # 安装脚本   YSLib 项目提供生成可打包的 Sysroot 的安装脚本,位于 `Tools/Scripts/install-sysroot.sh` 。输出的 Sysroot 的默认位置为版本库根目录下的 `sysroot` 目录。安装 Sysroot 时构建和部署多个项目,详见以下各节。 ## 基本安装   使用 [SHBuild](Tools/SHBuild.zh-CN.md) 构建和部署运行环境,包括库和工具。 **建议阅读以下关于选项以及[脚本](Tools/Scripts.zh-CN.md)说明后再运行命令。**   可进入 `bash` 运行以下 GNU bash 脚本: ```shell Tools/install-sysroot.sh ```   直接在默认输出位置构建和部署基础环境。 **注意** 当前构建脚本默认使用 `uname` 判断构建系统的体系结构。对 MSYS2 等环境,结果为基本系统的体系结构而不一定和作为构建目标的宿主系统相同。如使用 64 位基本系统构建 32 位目标,需确保环境变量 `MSYSTEM` 设置为 `MINGW32`(在启动 MSYS2 提供的 shell 入口时应正确设置,但直接调用 `bash` 并不保证),或使用以下命令代替: ```bash SHBuild_Host_Arch=i686 Tools/install-sysroot.sh ```   此处[自动环境检测](Prerequisitions.zh-CN.md)的机制同 shell 脚本 `Tools/Scripts/SHBuild-common.sh` 中的函数 `SHBuild_PrepareBuild` ,详见[脚本](Tools/Scripts.zh-CN.md)的说明。 ## 构建和部署   构建过程包括 `SHBuild` 可用的[多阶段构建](Tools/SHBuild.zh-CN.md)。   构建时在 Sysroot 输出目录种保存中间输出。当前不清理这些中间输出。   通过脚本选项,在 [stage 2 SHBuild](Tools/SHBuild.zh-CN.md) 需要的库时,也可生成其它的 YSLib 库(静态库和调试版本的库)。   YSLib 库和依赖的外部的第三方库的二进制文件和对应的头文件在构建后被部署到 Sysroot ,并在之后用于构建 stage 2 SHBuild 。   完成构建 stage 2 SHBuild 后,脚本部署 stage 2 SHBuild 和脚本(参见以下节)到 Sysroot 。 ### 脚本部署   在 stage 2 SHBuild 构建后,部署 SHBuild 同时安装(复制)版本库中的以下位置的 脚本文件(无视路径前缀)到 Sysroot 的对应安装路径: * NPLA1 脚本安装到 `share/NPLA1` : * `Tools/Script/SHBuild-BuildApp.txt` * `Tools/Script/SHBuild-YSLib-common.txt` * Shell 脚本安装到 `bin` : * `Tools/Script/SHBuild-common.sh` * `Tools/Script/SHBuild-common-options.sh` * `Tools/Script/SHBuild-common-toolchain.sh` * `Tools/Script/SHBuild-BuildApp.sh` * `Tools/Script/SHBuild-BuildPkg.sh` ### 可选工具   通过脚本选项,在部署 stage 2 SHBuild 后,也可安装 `Tools` 下的其它工具: * [RevisionPatcher](Tools/RevisionPatcher.zh-CN.md) * [SXML2XML](Tools/SXML2XML.zh-CN.md) * [ProjectGenerator](Tools/ProjectGenerator.zh-CN.md) ## 构建中间文件   当前工具不对构建的中间文件显式管理。若需清理,可以手动删除对应的文件或所在的生成目录。一般生成的文件和源代码的目录结构对应。   若需要预编译头文件在后续重复构建时的性能提升,或者意图重新生成这些文件,可以手动清理这些文件。预编译头文件一般在对应项目生成其它的文件的顶层目录相同;可手动搜索构建目录中所有 `.gch` 文件并删除后再运行构建脚本。默认生成预编译头文件前硬链接被预编译的头文件并在同一个目录中生成,包括以下位置: * 存储库中的 `Tools/SHBuild`(即源代码目录),用于 [stage 1 SHBuild](Tools/SHBuild.zh-CN.md) 构建。 * 安装 stage 1 SHBuild 后默认在[构建中间输出目录 `$SHBuild_BuildDir`](Development.zh-CN.md#环境变量) 下的 `.shbuild` 等作为 SHbuild 输出目录的子目录。 ## 构建时的诊断   一些构建时的诊断可被安全忽略: * [预编译头文件文件不匹配引起的编译器警告](Tools/Scripts.zh-CN.md#toolsscriptsshbuild-buildsh)。 * 在输出标记为 `(ignored)` 被忽略的链接器错误。 * 这些错误典型地出现在 [MinGW 平台启用 LTO 时](https://bugs.launchpad.net/gcc-arm-embedded/+bug/1853451)。 * 这应不会影响生成的二进制文件。 * 默认以 release 配置构建时,启用 LTO 而可能引起错误。 * 设置启用 LTO 编译器和链接器选项时,[引导 stage 1 SHBuild](Tools/SHBuild.zh-CN.md#引导) 最后的链接器可能引起错误。 * 可[在链接器选项使用 `-save-temps`](https://github.com/official-stockfish/Stockfish/pull/2978)变通。   若不需要使用预编译头文件或仅需要避免警告,可参考[脚本的说明设置变量跳过预编译头文件或添加忽略警告的选项](Tools/Scripts.zh-CN.md#toolsscriptsshbuild-buildsh)。 # Sysroot 开发指令   使用 Sysroot 开发,首先需安装 Sysroot 环境,参见以上[安装脚本的说明](#安装脚本)。 ## 应用程序构建脚本   YSLib 应用程序可使用 SHBuild 构建。为简化构建流程,使用应用程序构建脚本包装对 SHBuild 的调用。   应用程序构建脚本不限制实现使用的语言,但在版本库中提供的脚本应符合[公共的约定](Tools/Scripts.zh-CN.md);此外,具体脚本可能需要指定适当的 `PATH` 以确保外部的工具可被调用。   典型地,应用程序构建脚本是 shell 脚本,可依赖 Sysroot 环境已构建的 Sysroot 环境,并调用 NPLA1 脚本。   [YSTest](ProjectDependencies.zh-CN.md) 支持使用脚本 `/YSTest/SHBuild-YSTest.sh` 构建,可作为例子参考。和其它在安装脚本部署的 stage 2 应用不同,当前默认情况下使用版本库中的 `build` 目录下的平台目录存放生成的文件(中间文件和生成的可执行程序示例)。 ## 部署   除安装脚本外,当前不提供直接部署程序。   参照[运行](Run.zh-CN.md)确定二进制依赖项位置和调整运行时的配置。