Bitcoin Core 的 Guix 引导式构建指南可审计、可复现的多平台二进制构建与签名验证全流程【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin本文以 Bitcoin Core 仓库中 contrib/guix/README.md 文档为核心系统讲解如何借助 Guix 函数式包管理器完成引导式构建Bootstrappable Build从磁盘与安装要求、macOS SDK 准备、guix-build全流程构建到guix-codesign代码签名、guix-clean清理、SHA256SUMS 收集再到guix-attest/guix-verify的 GPG 认证与交叉验证并结合仓库内脚本与清单源码剖析其确定性实现细节与三种安全模型选择。读完本文你将能够独立完成一次可复现的 Bitcoin Core 多平台构建理解HOSTS、JOBS、SOURCE_DATE_EPOCH等环境变量的实际作用并掌握替代包substitutes的信任模型配置方法。一、什么是引导式构建Bootstrappabilitycontrib/guix/README.md 开宗明义该目录包含执行引导式 Bitcoin Core 构建所需的全部文件。引导式构建通过审计并复现工具链而非盲目信任二进制下载来强化二进制的安全保证。Bitcoin Core 的实现方式是采用Guix 作为函数式包管理器——所有构建依赖编译器、交叉工具链、glibc 等都由 Guix 从源码清单定义出发构建其输入源码 清单完全可审计从而让最终二进制可追溯到可审计的源头。这一设计在仓库中有清晰的源码体现构建环境清单 manifest_build.scm 中定义了完整的交叉工具链生成流程make-cross-toolchain按交叉 binutils → 不带 libc 的交叉 GCC → 交叉内核头linux-libre-headers-6.1→ 交叉 glibc2.31→ 最终交叉 GCC四步逐级构建并默认使用打了补丁的gcc-14作为基础编译器GUI 依赖由 manifest_gui.scm 按目标平台条件注入mingw 目标追加zip、nsis-x86_64linux 目标追加bison、gawk、pkg-configdarwin 目标追加zip签名环境清单 manifest_codesign.scm 则引入osslsigncodeWindows 签名、python-oscrypto/python-asn1cryptomacOS 签名等专用工具。二、环境需求与安装准备磁盘空间需求文档给出的保守估计如下需求项说明/gnu/store所在分区至少 16GB 可用空间Guix 包存储每个平台三元组HOST每个计划构建的目标平台各需 8GB 可用空间源码层面还有更精细的校验。guix-build 在构建前会按目标平台累加估算所需空间并与df -Pk实测可用空间比对darwin 目标约 440000 KiBmingw 目标约 7600000 KiB约 7.2GiB其余 Linux 目标各约 6400000 KiB约 6.1GiB空间不足时直接中止并提示见 contrib/guix/guix-build#L148-L164。安装 Guix若尚未安装并配置 Guix请先按同目录的 INSTALL.md 操作支持源码安装、发行版包、Shell 安装脚本等多种途径各途径对替代包签名键的授权行为略有差异后文安全模型一节会用到。此外所有脚本必须从仓库顶层目录调用——prelude.bash 在开头就会校验PWD与git_root是否一致否则报错退出并且guix-build/guix-codesign会检查guix-daemon可达性guix gc --list-failures、系统服务数据库getent services http https ftp等前置条件。三、为 macOS 交叉编译准备 Xcode SDKmacOS 目标x86_64-apple-darwin、arm64-apple-darwin包含在默认构建目标集合中因此需要准备 macOS SDK 包。解包工具位于 macdeploy 目录其中 SDK Extraction 一节说明了如何从Xcode.app生成 SDK tarball。SDK 有两种放置方式方式一用SDK_PATH指向已解包的 SDK 所在父目录# 将 SDK tarball 解包到 Xcode-foo-bar-extracted-SDK-with-libcxx-headers 目录 tar -C /path/to/parent/dir/of/extracted/SDK -xaf /path/to/Xcode-foo-bar-extracted-SDK-with-libcxx-headers.tar # 指明 SDK 位置注意指向解包目录的“父”目录而非 SDK 目录本身 export SDK_PATH/path/to/parent/dir/of/extracted/SDK方式二解包进depends/SDKsmkdir -p depends/SDKs tar -C depends/SDKs -xaf /path/to/SDK/tarballguix-build对 darwin 目标会执行make -C depends HOSThost print-OSX_SDK探测 SDK 位置找不到即报错退出。注意SDK_PATH必须指向实际 SDK 目录的父目录例如应为$HOME/Downloads/macOS-SDKs而非.../macOS-SDKs/Xcode-26.1.1-17B100-extracted-SDK-with-libcxx-headers且该路径必须是真实目录而不能是指向目录的符号链接——guix-build会对所有珍贵目录precious dirs执行mkdir -p/ 符号链接 / 目录类型三重校验。四、执行构建guix-build全流程在开始之前强烈建议先通读下文常见调用模式与示例和识别的环境变量两节。在干净仓库的顶层执行./contrib/guix/guix-build构建前的强制检查源码佐证guix-build 在真正构建前执行一系列防御性检查理解它们能避免大部分诡异失败禁止脏工作区git diff-index --quiet HEAD不干净则中止可用FORCE_DIRTY_WORKTREE强制覆盖拒绝意外设置的SOURCE_DATE_EPOCHprelude.bash 中的check_source_date_epoch发现该变量已设置且未指定FORCE_SOURCE_DATE_EPOCH时会直接退出——因为误设会破坏可复现性拒绝残留构建目录若distsrc-*已存在说明该 commit 之前构建过中止并提示使用guix-clean拒绝GUIX_BUILD_OPTIONS非空该变量会覆盖脚本自身的细粒度 flag 机制脚本明确要求改用ADDITIONAL_GUIX_*_FLAGS系列变量。版本目录与确定性锚点prelude.bash 定义了构建目录布局VERSION默认取git_head_version可用FORCE_VERSION覆盖DISTNAME默认为bitcoin-${VERSION}其下依次为guix-build-版本/distsrc-版本-HOST各平台工作目录DISTSRCguix-build-版本/output/HOST/产物输出目录OUTDIRguix-build-版本/var/profiles/HOST/Guix 环境 profile 目录。时间锚点SOURCE_DATE_EPOCH默认取git log --format%at -1当前 HEAD 的最后一次提交时间戳用于 tar 时间戳等确定性控制。容器内 setup.sh 还会导出统一的TAR_OPTIONS--no-same-owner --owner0 --group0 --numeric-owner --mtime${SOURCE_DATE_EPOCH} --sortname并固定TZUTC、umask 0022这些是逐位复现的关键细节。Guix 环境与隔离容器guix-build通过time-machine函数调用固定 commit 的 Guix当前钉在 prelude.bash 中的c5eee3336cc1d10a3cc1c97fde2809c3451624d3保证跨时间的可复现性。对每个 HOST它用guix shell在隔离容器中执行 contrib/guix/libexec/ 下的构建脚本关键 flag 的意图在脚本注释中有详细解释--container --writable-root在隔离容器中运行最小化机器间差异--pure --no-cwd清空继承的环境变量、不共享宿主机当前目录$PWD是复现性污染源--share$PWD/bitcoin把工作区固定映射到容器内/bitcoin路径--share$DISTSRC_BASE/distsrc-base、--share$OUTDIR_BASE/outdir-base共享工作目录与输出目录--expose$(git rev-parse --git-common-dir)让容器内脚本能访问.gitgit archive需要--keep-failed保留失败构建的构建树以便调试--fallback允许构建本机不存在的替代包。每个平台还会运行两轮guix shell第一轮用 manifest_build.scm 构建无 GUI 二进制第二轮用 manifest_gui.scm 构建 GUI 版本分别调用build_linux|macos|win_gui.sh与非 GUI 版本脚本。Linux 目标的构建脚本还会在打包阶段执行 security-check.py二进制安全特性检查与 symbol-check.py动态符号白名单检查——见 package.sh 开头部分。五、构建产物代码签名guix-codesignguix-codesign将签名者产生的分离式代码签名detached codesignatures附加到已构建的、未签名的产物上。更多背景见 release-process.md 的 Codesigning 一节。它尊重guix-build的大多数环境变量但有两个关键差异HOSTS默认值不同只有 Windows 与 macOS 产物需要代码签名因此默认为x86_64-w64-mingw32 x86_64-apple-darwin arm64-apple-darwin见 guix-codesign 中的HOSTS初始化DETACHED_SIGS_REPO为必需变量指向当前版本分离式签名的存放目录即签名者发布的 bitcoin-detached-sigs 仓库克隆。默认选项调用示例env DETACHED_SIGS_REPOpath/to/bitcoin-detached-sigs ./contrib/guix/guix-codesign脚本会先在输出目录中查找各平台的 codesigning tarballbitcoin-版本-win64-codesigning.tar.gz或bitcoin-版本-darwin三元组-codesigning.tar.gz缺失即报错随后在manifest_codesign.scm环境中挂载该签名仓库--share$DETACHED_SIGS_REPO/detached-sigs运行 codesign.sh产物写入带codesigned后缀的独立目录。脚本同样强制签名仓库工作区干净、无残留distsrc-...-codesigned目录、可连接 guix-daemon。六、清理中间工作目录guix-clean默认情况下guix-build会在构建结束后保留全部中间文件depends/work、guix-build-*/distsrc-*等供调试使用但这些目录通常占用大量磁盘。guix-clean 提供一键清理./contrib/guix/guix-clean从源码看它本质是对当前 git 工作区执行git clean -xdff但会先从各版本目录下记录的precious_dirs文件读取珍贵目录SOURCES_PATH、BASE_CACHE、SDK_PATH、OUTDIR_BASE、PROFILES_BASE的实际生效值并逐一加入--exclude白名单从而不误删下载缓存、依赖缓存、SDK 与构建产物。默认先以-ndry-run预览并等待确认传--force可跳过确认直接清理。七、收集构建产物 SHA256构建成功后各架构输出目录中会生成名为SHA256SUMS构建期以SHA256SUMS.part片段形式落盘见 package.sh 的打包逻辑的文件。若要汇总所有摘要输出到控制台例如粘贴到 Guix 依赖的 pull request 评论中可运行文档给出的命令source contrib/shell/git-utils.bash uname -m find guix-build-$(git_head_version)/output/ -type f -print0 | env LC_ALLC sort -z | xargs -r0 sha256sumgit_head_version来自 contrib/shell/git-utils.bash保证在 tag 与 commit 两种场景下都能取到正确的版本标识。八、认证构建产物guix-attest与 Gitian 构建用gitian.sigs仓库做认证一样Guix 构建产物在独立的guix.sigs仓库中认证。克隆该仓库后对当前工作区的 commit/tag 执行认证env GUIX_SIGS_REPOpath/to/guix.sigs SIGNERgpg-key-name ./contrib/guix/guix-attest./contrib/guix/guix-attest --help即缺参时的用法输出展示了更多调用方式均可从 guix-attest 的cmd_usage中确认SIGNERGPG_KEY_NAME[SIGNER_NAME]用可覆盖签名者目录名如SIGNER0x96AB007F1A7ED999dongcarl缺省时签名者名即密钥名NO_SIGN1只生成 SHA256SUMS 清单文件、不做 GPG 签名。从源码可确认其认证逻辑脚本汇总$OUTDIR_BASE/*/SHA256SUMS.part按目录名区分 codesigned 与 noncodesigned 两组去重排序后经basenameify_SHA256SUMSsed把相对文件名替换为 basename写入签名仓库的版本/签名者/noncodesigned.SHA256SUMS及存在 codesigned 产物时的all.SHA256SUMS再用gpg --detach-sign --digest-algo sha256 --armor生成对应.asc。若同名清单已存在但内容不一致比如你之前只认证了部分 HOST 的构建脚本会打印 diff 并提示删除旧认证后重试若 codesigned 产物尚缺分离签名尚未发布只提示 INFO 而非报错。九、验证认证签名guix-verify当至少另一位签名者已向guix.sigs上传签名后git -C path/to/guix.sigs pull env GUIX_SIGS_REPOpath/to/guix.sigs ./contrib/guix/guix-verifyguix-verify 的验证逻辑源码可查以某个签名者的清单为基准可用SIGNERsigner指定基准缺省取找到的第一个对版本/下每个签名者的noncodesigned.SHA256SUMS与all.SHA256SUMS先gpg --verify校验其.asc签名再diff对比清单内容是否逐字节一致额外做完整性自检noncodesigned.SHA256SUMS中不允许存在all.SHA256SUMS中没有的行comm -23检查否则判定出大问题了并退出任一签名或内容校验失败即整体返回非零。配合 release-process.md 的流程签名者将noncodesigned.SHA256SUMS{,.asc}与 codesigned 认证分别提交到guix.sigs待 6 人以上独立构建且结果一致后即可推进发布。十、常见guix-build调用模式与示例1. 把缓存与 SDK 放在工作区之外如果你频繁构建、维护多个 worktree可以把 depends 的下载缓存、构建缓存与 SDK 移出工作区避免重复下载和重复构建。guix-build会识别并透传SOURCES_PATH、BASE_CACHE、SDK_PATH三个变量env SOURCES_PATH$HOME/depends-SOURCES_PATH BASE_CACHE$HOME/depends-BASE_CACHE SDK_PATH$HOME/macOS-SDKs ./contrib/guix/guix-build注意这些路径必须是目录且不能是指向目录的符号链接脚本中elif [ -L $precious_dir_path ]会显式拦截。这三个路径同时会被--share映射进构建容器容器无网络访问depends 源码必须在容器外预下载——guix-build先在容器内执行make -C depends download-linux|osx|win。2. 只构建部分平台三元组用空格分隔的HOSTS覆盖默认列表env HOSTSx86_64-w64-mingw32 x86_64-apple-darwin ./contrib/guix/guix-build3. 控制guix构建命令的线程数./contrib/guix下的脚本默认以--cores$JOBS调用所有guix构建命令$JOBS缺省为容器外$(nproc)。而guix构建命令还接受一个--max-jobs参数未指定时默认为 1两者区别如下把 derivation 理解为 package 即可参数含义--cores控制构建每个 derivation 使用的 CPU 核数即传给make的--jobs值--max-jobs控制同时并行构建多少个 derivation默认为 1因此默认行为是一次构建一个 derivation每个 derivation 使用$JOBS个线程。只设置$JOBS只影响--cores要改--max-jobs需通过$ADDITIONAL_GUIX_COMMON_FLAGS。例如内存充裕时可以export ADDITIONAL_GUIX_COMMON_FLAGS--max-jobs8允许最多 8 个 derivation 并行各自使用$JOBS个线程或者为避免单包内部并行导致的偶发构建失败、但依赖图允许时仍希望多包并行可以export JOBS1 ADDITIONAL_GUIX_COMMON_FLAGS--max-jobs8十一、识别的环境变量完整清单变量作用默认值 / 约束HOSTS覆盖待构建平台三元组的空格分隔列表x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu powerpc64-linux-gnu x86_64-w64-mingw32 x86_64-apple-darwin arm64-apple-darwinSOURCES_PATHdepends 树源码下载缓存目录透传给 depends。跨多次构建共用可消除重复下载必须为目录不可为符号链接BASE_CACHEdepends 树已构建包的缓存目录透传给 depends。共用可消除重复构建必须为目录不可为符号链接SDK_PATH已解包 SDK 的查找路径透传给 depends应设为实际 SDK 的父目录必须为目录不可为符号链接JOBS并行任务数内存有限机器上可调低。会传递给guix--cores、make --jobs、cmake --build -j、xargs -P容器外nproc的值SOURCE_DATE_EPOCH覆盖用于逐位复现的参考 UNIX 时间戳变量名遵循可复现构建社区的标准命名$(git log --format%at -1)注意脚本会拒绝意外设置除非同时设FORCE_SOURCE_DATE_EPOCHV非空即向所有make调用传V1使输出冗长。只看是否为空V空串等同未设置V0与V1效果相同—SUBSTITUTE_URLS空白分隔的预构建包下载 URL 列表仅当对应签名键已授权时生效见安全模型一节ADDITIONAL_GUIX_COMMON_FLAGS传给所有guix命令的附加 flag—ADDITIONAL_GUIX_TIMEMACHINE_FLAGS传给guix time-machine的附加 flag—ADDITIONAL_GUIX_ENVIRONMENT_FLAGS传给guix time-machine内部guix shell调用的附加 flag—另外guix-attest需要GUIX_SIGS_REPO、SIGNER可选NO_SIGNguix-codesign需要DETACHED_SIGS_REPO均见上文对应章节。十二、选择你的安全模型substitutes替代包三方案无论以何种方式安装 Guix构建前都需要决定使用 Guix 构建包的安全模型。Guix 允许用 CPU 时间从零构建一切来获得更强的二进制安全性但用户可以选择是否使用substitutes预构建包。方案 1使用 substitutes 构建第一步授权签名键不同安装途径下你可能已经授权了 Guix 构建农场的键官方 Shell 安装脚本会询问是否安装该键Debian 发行版包在安装时已授权。当前授权列表可查看/etc/guix/acl。仅授权了 Guix 构建农场键时其大致形如(acl (entry (public-key (ecc (curve Ed25519) (q #8D156F295D24B0D9A86FA5741A840FF2D24F60F7B6C4134814AD55625971B394#) ) ) (tag (guix import) ) ) )若官方构建农场键尚未授权且你想授权它以 root 执行guix archive --authorize /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub若该路径不存在尝试guix archive --authorize PREFIX/share/guix/ci.guix.gnu.org.pub其中PREFIX通常是发行版包安装时为/usr从源码安装且未向./configure传入前缀修改参数时为/usr/local。移除已授权键直接编辑/etc/guix/acl删除对应的(entry (public-key ...))条目即可。第二步指定 substitute 服务器键被授权后除非提供--no-substitutes官方 Guix 构建农场将被自动使用。该默认服务器列表可在guix-daemon级别和每次guix命令调用时覆盖修改默认列表以--substitute-urls选项启动guix-daemon通常需要编辑 init 脚本guix-daemon cmd --substitute-urlshttps://bordeaux.guix.gnu.org https://ci.guix.gnu.org覆盖单次guix命令调用的列表guix cmd --substitute-urlshttps://bordeaux.guix.gnu.org https://ci.guix.gnu.org对./contrib/guix下的脚本设置SUBSTITUTE_URLS环境变量脚本会以--substitute-urls$SUBSTITUTE_URLS透传给guix命令见 prelude.bash 与 guix-build 中的${SUBSTITUTE_URLS:--substitute-urls$SUBSTITUTE_URLS}export SUBSTITUTE_URLShttps://bordeaux.guix.gnu.org https://ci.guix.gnu.org方案 2临时禁用 substitutes若不想使用任何 substitute确保提供--no-substitutes。首次构建会比较慢但产出的包会缓存供后续构建使用。直接调用guixguix cmd --no-substitutes对./contrib/guix/下的脚本export ADDITIONAL_GUIX_COMMON_FLAGS--no-substitutes方案 3默认禁用 substitutesguix-daemon接受--no-substitutes参数确保除被命令行显式覆盖外一律不使用 substitutes。若通过 init 脚本启动guix-daemon可直接在脚本中加入该参数。十三、小结目录、脚本与源码地图围绕 contrib/guix/ 的完整工具链可归纳为脚本 / 文件职责guix-build多平台引导式构建入口含全部前置检查与guix shell环境编排guix-codesign将分离式代码签名附加到 win/darwin 产物guix-clean带白名单排除的git clean式工作区清理guix-attest生成并 GPG 签名noncodesigned.SHA256SUMS/all.SHA256SUMSguix-verify交叉验证各签名者清单的签名与内容一致性manifest_build.scm / manifest_gui.scm / manifest_codesign.scm三类 Guix 环境清单核心构建、GUI 依赖、签名工具libexec/prelude.bash / setup.sh公共前置检查、time-machine钉版、确定性环境变量TAR_OPTIONS、TZ、umasklibexec/build_*.sh / codesign.sh / package.sh各平台容器内构建/签名/打包脚本含安全与符号检查security-check.py / symbol-check.py产物二进制的 NX/RELRO 等安全特性与动态符号白名单检查INSTALL.mdGuix 安装步骤整体流程即准备 SDK 与环境 →guix-build在隔离容器中逐平台确定性构建并生成 SHA256SUMS → 签名者guix-codesign附加分离签名 → 所有构建者guix-attest提交认证 → 各方guix-verify交叉验证 → 磁盘紧张时随时用guix-clean回收空间。所有环节均可从上述仓库文件逐行追溯这正是审计工具链而非信任二进制这一安全目标的落地方式。【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考