ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Rust 编译器 CI Docker 测试指南:用 citool 与 run.sh 在本地复现 rustc 构建任务

Rust 编译器 CI Docker 测试指南:用 citool 与 run.sh 在本地复现 rustc 构建任务 Rust 编译器 CI Docker 测试指南用 citool 与 run.sh 在本地复现 rustc 构建任务【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rustrustc 的持续集成CI依托于一组精心构造的 Docker 镜像来完成 Linux 平台的构建与测试本指南以 rustc-dev-guide 的「Testing with Docker」章节为主线系统讲解如何在本地开发机上复现这些 CI 任务先介绍一键式工具citool再深入剖析底层脚本src/ci/docker/run.sh的镜像构建、目录挂载与容器运行机制最后介绍交互模式帮助读者在不同于本机的环境里调试、实验 rustc 的完整构建流程。Docker 在 rustc CI 中的角色rustc 的 CI 需要在大量 Linux 目标平台x86_64、i686、ARM、MIPS、s390x 等上验证编译器的可移植性而这些目标环境在普通开发机上通常并不存在。为此仓库在src/ci/docker目录中为 GitHub Actions 上执行的Linux 作业job准备了完整的 Docker 镜像定义非 Linux 作业如 macOS、Windows则在 Docker 之外直接运行。src/ci/docker目录结构如下host-x86_64/面向 x86_64 主机的镜像定义包含dist-*发行版构建如dist-x86_64-linux与test-*测试如test-x86_64-gnu两大类每类对应一个子目录host-aarch64/面向 aarch64 主机的镜像定义run.sh构建并运行指定镜像的核心脚本scripts/镜像构建过程中被Dockerfile调用的辅助脚本如sccache.sh、cross-apt-packages.sh等static/构建时复制的静态文件。这意味着你可以把这些作业搬到本地开发机上运行用以验证那些与本地系统环境不同的目标平台例如在 x86_64 机器上构建面向 32 位或其它架构的发行产物。你需要在一台 Linux、Windows 或 macOS 机器上安装 Docker——通常情况下 Linux 会快得多因为 Windows 和 macOS 需要借助虚拟机来模拟 Linux 环境。快速上手用 citool 在本地复现 CI 作业CI 中的作业通过一组 bash 脚本配置直接在本地完整复刻它们的行为并不容易。src/ci/citool是一个专门的 Rust 工具即 rustc 团队的 CI tooling详见 src/ci/citool/README.md它负责在 CI 上根据触发场景PR、try 作业、合并尝试计算应执行的作业矩阵同时提供在本地执行部分 CI 作业的能力。若希望以最简方式在本地运行某个 CI 作业可使用其run-local子命令cargo run --manifest-path src/ci/citool/Cargo.toml run-local job-name # 示例运行 dist-x86_64-linux-alt 作业 cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux-alt从 citool 入口 可以看到run-local接受一个必填的作业名参数以及可选的--type默认auto可指定为pr对应合并尝试作业与 PR 作业。其内部执行流程为见 run_workflow_locally 实现从src/ci/github-actions/jobs.yml加载作业数据库并按作业名在 Linux 作业中查找匹配项按作业名推断环境变量作业名以dist-开头且以-alt结尾时设置DEPLOY_ALT1仅以dist-开头则设置DEPLOY1随后合并作业自身定义的环境变量用于尽量复刻src/ci/scripts/setup-environment.sh的效果必要时初始化src/llvm-project/子模块最终以作业的镜像名调用src/ci/docker/run.sh完成构建与测试。如果上述方式在你的环境里不可用或者你希望对 Docker 镜像的执行有更多控制、想弄清 Docker 作业执行期间究竟发生了什么可以继续阅读下文直接使用底层脚本run.sh。核心脚本 run.sh镜像构建、挂载与运行src/ci/docker/run.sh负责完成四件事构建指定的 Docker 镜像、运行容器、在镜像内构建 Rust随后运行测试或准备面向分发的归档文件。目录挂载与产物位置脚本以只读方式挂载你的本地 Rust 源码树以读写方式挂载一个obj目录所有编译器构建产物都会写入obj目录。容器内的 shell 起始工作目录是obj随后执行../src/ci/run.sh由该脚本按镜像定义启动实际的构建。从 run.sh 实现 可以看到非 CI 场景下的挂载细节源码树挂载为/checkout默认追加:ro只读标记obj目录挂载为/checkout/obj本机~/.cargo挂载为/cargo/tmp/toolstate挂载为容器内同名目录用于 toolstate 数据交换容器工作目录设置为/checkout/obj并注入SRC/checkout、CARGO_HOME/cargo等环境变量。关于只读挂载脚本支持通过环境变量READ_ONLY_SRC关闭默认的只读行为当READ_ONLY_SRC0时源码树将以读写方式挂载从而允许在容器内进行实验性工作或调试例如拉取并构建子模块详见 run.sh 中的挂载选项。obj 目录的本地布局镜像构建完成后obj目录在 CI 与非 CI 场景下路径不同见 run.sh 第 41-46 行在 CI 上objdir$root_dir/obj在本地objdir$root_dir/obj/$image即以镜像名隔离避免不同作业的产物互相干扰。此外obj目录下还会创建tmp、cores子目录并生成github-summary.md供 CI 汇总步骤摘要使用。直接运行 run.sh可以这样直接运行src/ci/docker/run.sh image-name关于 run.sh 的几个重要注意事项原文档给出了以下关键提示这里逐条结合源码展开1. 子模块必须齐全。在 CI 上执行时脚本假定所有子模块都已检出。如果作业访问的某个子模块缺失构建会直接报错。因此在本地执行前应确保所需子模块均已检出既可以通过 git 手动检出也可以在bootstrap.toml中设置build.submodules true然后运行类似x build的命令让 bootstrap 下载最重要的子模块——但请注意这未必覆盖某个具体 CI 作业所需的全部子模块。2.image-name与作业名的对应关系。镜像名对应src/ci/docker/host-*目录下的某一个子目录。注意镜像名不一定等于作业名某些作业复用同一个镜像但通过不同的环境变量或 Docker 构建参数区分。这正是本地复现 CI 作业困难的一部分原因——citool的价值就在于替你把这一层映射关系自动化掉。镜像构建基于 Dockerfile 的校验和脚本会将镜像名、Dockerfile 内容、COPY涉及的源文件内容、主机架构以及缓存版本号拼接后计算 SHA-512作为镜像标签的一部分详见 run.sh 的校验和逻辑。3. dist 作业需要DEPLOY1。如果执行的是dist-开头的作业应设置环境变量DEPLOY1。4. alternative dist 作业需要DEPLOY_ALT1。如果执行的是以dist-开头且以-alt结尾的作业应设置DEPLOY_ALT1。这两个变量在src/ci/run.sh中决定了一系列配置差异例如DEPLOY/DEPLOY_ALT生效时启用--enable-llvm-static-stdcpp、设置--debuginfo-level、按CODEGEN_BACKENDS默认llvm配置 codegen 后端-alt作业还会额外启用 debug assertions 与 LLVM assertions见 src/ci/run.sh 第 111-137 行。反之非 dist 的测试作业默认同时测试llvm,cranelift两个 codegen 后端并启用 debug assertions、overflow checks 等见 src/ci/run.sh 第 138-176 行。同时citool的run-local正是依据作业名前缀/后缀自动注入这两个变量的。5. 部分 std 测试需要 IPv6。某些标准库测试依赖 IPv6 支持而 Linux 上的 Docker 默认禁用了它。需要在创建容器前执行src/ci/scripts/enable-docker-ipv6.sh开启 IPv6且只需执行一次。该脚本会向/etc/docker/daemon.json写入{ipv6:true,fixed-cidr-v6:fd9a:8454:6789:13f7::/64}并重启 Docker 服务见 enable-docker-ipv6.sh。镜像构建与缓存策略run.sh在镜像获取上做了分层处理见 run.sh 第 121-192 行本地非 CI 执行优先尝试从ghcr.io的rust-ci镜像仓库docker pull预构建镜像标签为镜像输入校验和拉取成功则直接打上rust-ci标签使用拉取失败才回退到本地docker build。PR CI 作业使用 Buildx 的 registry 缓存后端--cache-from复用缓存但不向仓库写入缓存。auto/try 合并作业先登录镜像仓库若相同校验和的镜像已存在则直接下载否则用--cache-from/--cache-to构建并推送避免镜像内容未变化时重复构建导致缓存抖动。容器运行使用--init正确处理僵尸进程回收与--rm退出即删除并默认以--privileged特权模式运行——原因是 LLVM 5.0 升级后 Leak Sanitizer 需要 ptrace 等系统调用于是对所有构建器统一开启见 run.sh 第 264-269 行。构建加速与容器内用户身份run.sh会为容器注入 sccache 相关配置若设置了SCCACHE_BUCKET等变量则透传 AWS/S3 相关环境PR 构建禁用 S3 认证否则挂载本机~/.cache/sccache到/sccache以复用本地缓存见 run.sh 第 238-254 行。同时通过LOCAL_USER_ID环境变量把宿主机用户 ID 传入容器由src/ci/run.sh在容器内创建同名用户并以该用户身份执行构建从而保证obj目录中产物的属主与本机用户一致在使用 rootless Podman 时会改用--usernskeep-id并设置NO_CHANGE_USER1见 run.sh 第 303-311 行。Docker-in-Docker 场景如果run.sh本身已经在容器内运行通过/.dockerenv文件判断则无法直接使用--volume挂载宿主机目录。此时脚本改用「临时容器 docker cp」的方式创建带/checkout卷的临时容器、把源码目录复制进去、用--volumes-from复用该卷构建结束后再把obj目录从容器拷回宿主机见 run.sh 第 293-312 行。交互模式在容器里自由实验有时我们希望先构建出某个特定的 Docker 镜像再在容器内执行自定义命令以便观察目标系统环境的具体行为。这时可以使用交互模式src/ci/docker/run.sh --dev image-name该模式会在容器内启动一个 bash shell。进入容器后你可以执行单个命令来完成特定任务例如只跑 UI 测试../x test tests/ui从 run.sh 实现 看--dev会追加-it交互 TTY参数且容器命令不再指向src/ci/run.sh而是直接进入 bash若源码树来自 git 检出还会预先执行git config --global --add safe.directory /checkout避免容器内出现 git dubious ownership 保护报错。使用交互模式时有几点补充说明容器退出即删除但产物保留退出 shell 时容器会被自动删除--rm不过构建产物仍保留在obj目录中。如果在不同 Docker 镜像间切换前一个环境留在obj目录里的产物可能干扰构建系统有时需要在容器内构建前删除obj目录的部分或全部内容。容器是精简环境容器只安装了最小化软件包集合缺少编辑器等常用工具时可以自行安装例如apt install less vim。可开多个 shell在容器内可打开多个 shell。首先获取容器名shell 提示符中会显示一个短哈希或在容器外运行docker container ls列出可用容器然后执行docker exec -it CONTAINER /bin/bash其中CONTAINER是类似4ba195e95cef的容器名。实例剖析dist-x86_64-linux 作业以文档示例中的dist-x86_64-linux作业为例其镜像定义位于 src/ci/docker/host-x86_64/dist-x86_64-linuxDockerfile 以 CentOS 7glibc 2.17、kernel 3.2 的最低平台支持基线为基础依次编译 GCC 9.5、cmake、LLVMClang目标架构 X86/AMDGPU/NVPTX、zstd 与 sccache并通过RUST_CONFIGURE_ARGS注入--enable-sanitizers、--enable-profiler、--set llvm.thin-ltotrue、--set rust.ltothin等构建配置dist.sh 定义了容器内实际执行的命令先构建opt-distPGO 优化工具再以x.py dist生成分发产物非 try 构建还会额外使用 GCC 构建gcc-dev/gcc组件并验证retain属性支持。这说明镜像名与作业名之间的映射、构建参数的注入最终都汇聚在run.shsrc/ci/run.sh这一条链路上前者负责「环境」后者负责「构建决策」。小结在本地复现 rustc CI 的 Docker 作业路径可以非常平滑优先使用cargo run --manifest-path src/ci/citool/Cargo.toml run-local job-name一键执行需要精细控制或排查问题时再直接使用src/ci/docker/run.sh image-name或--dev交互模式。理解run.sh的镜像缓存、只读挂载、obj目录布局、DEPLOY/DEPLOY_ALT语义以及 IPv6 与子模块前提是在本地稳定复现 CI 结果的关键而citool与jobs.yml则把作业名到镜像名、环境变量的复杂映射自动化大大降低了本地复刻 CI 的门槛。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表