Solidity 项目 CircleCI 集成指南:buildpack-deps Docker 镜像的构建、推送与本地验证
【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity
本指南基于 Solidity 编译器仓库中 .circleci/README.md 的 CI 集成说明,系统讲解 Solidity 在 CircleCI 中如何依赖自建的buildpack-depsDocker 镜像完成编译与测试:包括镜像在开发者机器上的本地构建与推送流程、CircleCI pipeline 参数(<image-desc>-docker-image-rev类参数)与镜像标签 revision 的对应关系,以及如何在本地挂载源码目录对新镜像进行验证。读完本文,你将掌握 Solidity 团队管理 CI 基础镜像的完整工作流,并能在自己的环境中复现镜像构建、推送和本地冒烟测试的全过程。
一、为什么 Solidity 的 CI 需要自建 Docker 镜像
Solidity 的 CI(CircleCI + GitHub Actions 并存)需要在 Ubuntu、ARM、Clang、OSS-Fuzz、Emscripten 等多种环境下编译并运行庞大的测试套件(单元测试、SMTChecker 形式化验证、EVM 字节码对比、gas 消耗断言等)。为了保证每次构建环境的可复现性,Solidity 不依赖公共镜像上现成的工具链,而是维护一组名为buildpack-deps的自建镜像,把所有依赖固化在镜像内部:
- C++ 编译工具链(GCC/Clang)、CMake、ccache、ninja;
- Boost 库(filesystem / program-options / system / test)与 CLN、Z3 等数学与 SMT 求解器;
- 形式化验证工具 Eldarica 与 CVC5(见 Dockerfile.ubuntu2404);
- evmone 测试执行后端,以及 Python 测试工具链(pylint、requests、tabulate 等)。
从源码结构看,这些镜像的 Dockerfile 统一存放在 scripts/docker/buildpack-deps/,每个变体一个文件(Dockerfile.ubuntu2404、Dockerfile.ubuntu2404.arm、Dockerfile.ubuntu2404.clang、Dockerfile.ubuntu.clang.ossfuzz、Dockerfile.emscripten等)。.circleci/README.md中提到的cd .circleci/docker/是历史路径示意,当前仓库中镜像定义实际位于scripts/docker/buildpack-deps/目录。
二、在开发者机器上构建并推送镜像
.circleci/README.md给出的标准流程是:镜像在开发者本地构建,构建成功后推送到镜像仓库,供 CircleCI 拉取使用。命令如下:
cd .circleci/docker/ docker build -t ethereum/solidity-buildpack-deps:ubuntu2404-<revision> -f Dockerfile.ubuntu2404 . docker push ethereum/solidity-buildpack-deps:ubuntu2404-<revision>关键点解读:
<revision>是镜像版本号,由你在构建时指定。它必须与 CircleCI 配置中 pipeline 参数ubuntu-2404-docker-image的 tag 部分一致(详见下文第三节)。- 在 Solidity 仓库当前的 CI 配置 .circleci/config.yml 中,镜像引用方式已从“用户名:tag”演变为digest 引用:每个镜像参数的值是
ghcr.io/argotorg/solidity-buildpack-deps@sha256:...形式。例如:
parameters: ubuntu-2004-docker-image: type: string # ghcr.io/argotorg/solidity-buildpack-deps:ubuntu2004-26 default: "ghcr.io/argotorg/solidity-buildpack-deps@sha256:1f387a77be889f65a2a25986a5c5eccc88cec23fabe6aeaf351790751145c81e" ubuntu-2404-docker-image: type: string # ghcr.io/argotorg/solidity-buildpack-deps:ubuntu2404-8 default: "ghcr.io/argotorg/solidity-buildpack-deps@sha256:2a8487a3f031000004dda3f16ac82115dd29f91b2dc91ff4f47cd6156ce5786c"配置中的注释行保留了可读的 tag 形式(如ubuntu2404-8),实际使用@sha256:...digest 可以锁定镜像的精确内容,避免同名 tag 被覆盖后导致 CI 环境漂移。
-f Dockerfile.ubuntu2404指定镜像变体。Dockerfile 家族与镜像 tag 的对应关系为:Dockerfile.ubuntu2404→ubuntu2404-<rev>,Dockerfile.ubuntu2404.arm→ubuntu2404.arm-<rev>,Dockerfile.ubuntu2404.clang→ubuntu2404.clang-<rev>,Dockerfile.ubuntu.clang.ossfuzz→ubuntu.clang.ossfuzz-<rev>,Dockerfile.emscripten→emscripten-<rev>。
三、用 CircleCI pipeline 参数管理镜像 revision
.circleci/README.md明确要求:每个镜像当前的 revision 记录在 CircleCI 的pipeline parameters中,参数名为<image-desc>-docker-image-rev风格(如ubuntu-2404-docker-image)。更新镜像时必须同步更新对应参数的值,且要核验参数值与镜像 tag 中的 revision 部分完全一致,否则 CircleCI 实际使用的镜像与推送到镜像仓库的镜像会不一致,造成 CI 结果不可复现。
从 .circleci/config.yml 可以看到当前共定义了 6 个镜像参数:
| 参数名 | 对应镜像 tag(注释中) | 用途 |
|---|---|---|
ubuntu-2004-docker-image | ubuntu2004-26 | Ubuntu 20.04 主构建 |
ubuntu-2404-docker-image | ubuntu2404-8 | Ubuntu 24.04 主构建(默认 EVM 版本环境) |
ubuntu-2404-arm-docker-image | ubuntu2404.arm-4 | ARM 架构构建 |
ubuntu-2404-clang-docker-image | ubuntu2404.clang-9 | Clang 工具链构建 |
ubuntu-clang-ossfuzz-docker-image | ubuntu.clang.ossfuzz-14 | OSS-Fuzz 模糊测试 |
emscripten-docker-image | emscripten-22 | Emscripten(solc-js / WASM)构建 |
这些参数在 CI 中通过<< pipeline.parameters.<name> >>语法注入到各 job 的 executor 里。例如 .circleci/config.yml 中:
- base_ubuntu2404: &base_ubuntu2404 docker: - image: << pipeline.parameters.ubuntu-2404-docker-image >> environment: &base_ubuntu2404_env TERM: xterm MAKEFLAGS: -j 3 CPUs: 3 - base_ubuntu2404_clang: &base_ubuntu2404_clang <<: *base_ubuntu2404 docker: - image: << pipeline.parameters.ubuntu-2404-clang-docker-image >> environment: &base_ubuntu2404_clang_env TERM: xterm CC: clang CXX: clang++ MAKEFLAGS: -j 3 CPUs: 3这些 YAML anchor(&base_*)是整个 CircleCI 配置的基础模板,之后所有 Ubuntu/Clang/ARM/EMS job 均通过<<: *base_*继承镜像选择与环境变量,再按需叠加resource_class(small/large/xlarge/arm.medium 等)调整并发资源。值得注意的是,Emscripten 镜像参数在 .circleci/config.yml 处附有专门注释:每当该镜像的 hash 变化,必须同步更新scripts/build_emscripten.sh,这再次印证了“参数值、镜像内容、脚本引用三者必须保持一致”的管理原则。
四、镜像内容速览:一个 Ubuntu 2404 变体的剖析
以主构建镜像 Dockerfile.ubuntu2404 为例,可以看到镜像分三阶段组装:
base阶段:基于buildpack-deps:noble(Ubuntu 24.04 LTS),通过LABEL version="8"声明镜像版本(见 scripts/docker/buildpack-deps/README.md 的版本管理约定),然后安装编译构建与测试所需的一切依赖,包括固定版本的z3-solver==4.13.3,以及 Eldarica(版本 2.1,用于 CHC 形式化验证)和 CVC5(1.2.0,SMT 求解器),下载后均校验 SHA-256 完整性;libraries阶段:下载并解压evmone-0.22.0-linux-x86_64测试后端;- 最终阶段:从
libraries阶段拷贝/usr/lib、/usr/bin、/usr/include和 Eldarica 目录,并将/opt/eldarica加入PATH。
从源码结构看,其余变体只是在此骨架上的定制:Dockerfile.ubuntu2404.clang侧重 Clang 工具链,Dockerfile.ubuntu2404.arm面向 ARM 架构,Dockerfile.ubuntu.clang.ossfuzz面向模糊测试,Dockerfile.emscripten则携带 Emscripten SDK(见scripts/docker/buildpack-deps/emscripten.jam)。
五、在本地用新镜像测试 Solidity 构建
镜像推送到仓库之前,.circleci/README.md建议先在本地做冒烟验证:把当前 Solidity 源码目录挂载进容器,在容器内执行构建测试命令。原文档给出的流程如下:
cd solidity # Mounts your local solidity directory in docker container for testing docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu2404-<revision> /bin/bash cd /src/solidity <commands_to_test_build_with_new_docker_image><commands_to_test_build_with_new_docker_image>即容器内需要执行的构建/测试命令。结合仓库中的实际脚本,典型的验证内容是:
# 在容器内 /src/solidity 下执行 scripts/ci/buildpack-deps_test_ubuntu2404.sh该脚本(见 scripts/ci/buildpack-deps_test_ubuntu2404.sh)会:进入源码根目录生成prerelease.txt、创建build/目录、通过 ccache 包装 CMake 编译(CMAKE_C_COMPILER_LAUNCHER=ccache、CMAKE_CXX_COMPILER_LAUNCHER=ccache),并在构建前后统计 ccache 命中情况。之后可再运行 .circleci/soltest_all.sh 执行跨 EVM 版本的全量测试矩阵——该脚本会按homestead、constantinople、istanbul、berlin、london、paris、shanghai、cancun、osaka、amsterdam、@future等 EVM 版本与OPTIMIZE=0/1的组合循环调用 .circleci/soltest.sh,默认 EVM 为osaka,并仅在默认 EVM 下附加--enforce-gas-cost参数做 gas 消耗断言。
六、镜像更新的完整链路:从 GitHub Actions 到 CircleCI
虽然.circleci/README.md描述的是镜像的“本地构建”路径,但仓库中还并行维护着一条自动化更新链路(见 scripts/docker/buildpack-deps/README.md),两者互为补充:
- 触发:PR 中修改任一
scripts/docker/buildpack-deps/Dockerfile.*即触发 GitHub Actions workflow(scripts/ci/docker_upgrade.sh负责判断每个变体是否需要真正执行); - 版本检查:以 Dockerfile 中的
LABEL version为准,只有当新版本号比develop分支对应文件递增 1 时才构建新镜像,未变更的变体直接跳过; - 构建与测试:镜像构建后分别由
scripts/ci/buildpack-deps_test_*系列脚本验证——大部分变体符号链接到scripts/ci/build.sh,而ubuntu.clang.ossfuzz变体使用scripts/ci/build_ossfuzz.sh、emscripten变体使用scripts/ci/build_emscripten.sh(这两个脚本同样被 CircleCI 复用); - 回写:测试通过后镜像被打上版本 tag,并在 PR 中评论新镜像的完整仓库、版本与 digest;随后需要人工把新 digest 回填到 .circleci/config.yml 的对应 pipeline 参数(以及 Emscripten 场景下的
scripts/build_emscripten.sh)。
这条链路恰好闭环了.circleci/README.md强调的规则:参数值与镜像 tag revision 必须严格对应,否则 CI 拉取的镜像与仓库中实际存在的镜像会出现偏差。
七、实践要点与注意事项
- revision 是版本契约:构建、推送、配置参数三处的 revision 必须保持一致。README 原文明确警告:若参数值匹配不上镜像 tag 中的 revision 部分,“circle ci 使用的镜像”与“真正推送到 Docker Hub 的镜像”将不一致。
- digest 引用更安全:当前 .circleci/config.yml 已采用
@sha256:...方式锁定镜像,升级镜像时务必连同 digest 一起更新,同时核对注释中的 tag 便于人工审阅。 - 先本地验证再推送:
docker run -v \pwd`:/src/solidity` 的挂载方式让开发者无需把未验证的镜像推上仓库即可完成构建冒烟,是 README 推荐的最小验证闭环。 - 多变体协同更新:修改一个 Dockerfile 会触发整条 workflow,但只有真正变更的变体会被重新构建;更新
.circleci/config.yml参数时注意同时处理关联脚本(如scripts/build_emscripten.sh)。 - 以当前仓库为准:README 中
ethereum/solidity-buildpack-deps的镜像地址与.circleci/docker/路径为历史写法,当前仓库的镜像定义位于 scripts/docker/buildpack-deps/,实际 CI 引用地址为ghcr.io/argotorg/solidity-buildpack-deps,阅读时注意区分。
八、扩展阅读
- .circleci/README.md:本指南对应的原始 CI 集成说明;
- .circleci/config.yml:pipeline 镜像参数定义与 executor 模板;
- scripts/docker/buildpack-deps/README.md:镜像的 GitHub Actions 自动构建、版本管理与回写流程;
- scripts/docker/buildpack-deps/Dockerfile.ubuntu2404:主构建镜像的依赖清单与分层结构;
- .circleci/soltest_all.sh 与 scripts/ci/buildpack-deps_test_ubuntu2404.sh:镜像测试与全量测试矩阵的实际执行入口。
【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考