内容提要
xclang 是开箱即用的交叉编译 Clang 工具链,约 90MB 的包内含 6 个平台的 sysroot 与运行时,全平台统一 Clang + libc++,支持静态链接,import std 在 CMake、Bazel 中开箱可用。Apple 与微软 SDK 需用户自行下载。Clang 和 lld 经 PGO + ThinLTO 优化,编译速度与官方版持平,Windows 上更快。项目历时两周多完成,代码几乎全由 agent 编写。
延伸解读
模块编译选项必须严格一致
文章指出,如果模块文件(BMI)的语言选项与导入它的代码不一致,Clang 会直接拒绝加载。影响语义的选项如 -std、GNU 扩展、-fno-exceptions、-fno-rtti 必须完全一致,而宏、头文件路径和优化等级可以不同。这意味着预编译的 std 模块很难通用,xclang 因此选择在每次构建时根据当前选项现编一份 std 模块,作为普通库链接。在 CMake 中,xclang::std 会继承 find_package 所在目录的编译设置,所以最好在项目级别统一选项。
构建缓存对模块的支持差异
文章通过实验对比了 ccache 4.13.6 和 4.14.1 在模块场景下的行为。4.13 及之前版本在模块接口修改后仍会命中缓存,导致使用旧目标文件,程序行为错误且无提示;4.14 虽然结果正确,但模块接口完全不进缓存,每次构建都要重新编译所有模块接口,影响编译速度。Bazel 则没有这个问题,因为其 action 的 key 包含所有输入内容,模块文件变化会触发重新编译。此外,xclang 通过 -fmodule-file-home-is-cwd 使模块文件路径相对化,确保跨机器缓存可共享。
全平台统一 Clang + libc++ 的取舍
文章建议不要混用 Clang 和 libstdc++,因为模块特性较新,各编译器实现仍有 bug,而 std 模块会导出整个标准库,混用容易触发未测试的 corner case。Clang 对模块支持最好,配套的 libc++ 对 std 模块支持也最完整,因此 xclang 选择全平台统一使用 Clang + libc++。但静态链接 libc++ 也有代价:每个共享库都会有一份自己的 libc++,在 Linux 和 macOS 上,一个共享库抛出的标准异常在另一个共享库中只能用 catch (...) 捕获,
PGO 训练与跨平台 profile 复用
xclang 使用 PGO + ThinLTO 构建 Clang 和 lld,训练集覆盖真实代码编译、预编译头、模块和链接等场景,约调用 1700 次编译器。文章对比了 IR 插桩和前端插桩:IR 插桩依赖目标平台的代价模型,跨平台 profile 不通用;前端插桩基于 AST 计算哈希,同一源码在不同目标上哈希一致。实验表明,在 Linux x64 上采集的前端 profile 用于其他平台时,函数匹配率极高,加速效果与各平台单独采集 IR profile 相当。xclang 因此选择前端插桩,只需在一台 Lin
Q&A
xclang 是什么?它主要解决什么问题?
xclang 是一个开箱即用、支持交叉编译的 Clang 工具链。它主要解决跨平台 C++ 开发中工具链不统一、import std 难以使用、以及依赖本机安装 Visual Studio 或 Xcode 的问题。一个下载包内含 6 个平台的 sysroot 和运行时,全平台统一使用 Clang + libc++,支持静态链接,import std 在 CMake 和 Bazel 中开箱可用。
如何在 CMake 项目中使用 xclang 并 import std?
在 CMakeLists.txt 中通过 FetchContent 拉取 xclang 仓库,然后 include 其提供的 xclang.cmake,接着 find_package(xclang REQUIRED CONFIG),并将目标链接到 xclang::std。之后在代码中直接写 import std; 即可,无需开启 CMake 实验开关。需要 CMake 3.28+ 和 Ninja。
xclang 如何处理 Apple 和微软的 SDK?
由于许可证不允许再分发,xclang 不打包 Apple 和微软的 SDK,而是提供命令行工具让用户自行从官方下载。用户执行 xclang sdk fetch macos --accept-license 或 xclang sdk fetch windows --accept-license 即可下载对应 SDK,之后便可在任何平台上交叉编译 macOS 和 MSVC 目标。
xclang 的编译器性能如何?与 LLVM 官方版相比有什么优势?
xclang 的 Clang 和 lld 在所有平台上都做了 PGO + ThinLTO 优化。在 Linux 和 macOS 上,编译 C++ 的速度与 LLVM 官方发布版基本持平;在 Windows 上,xclang 编译 C++ 比官方版快 11%~22%(x64)和 5%~11%(arm64)。此外,xclang 在 macOS 上编译 fmt 比 Apple 自己的 Clang 快 17%~29%。
xclang 支持哪些构建系统和包管理器?
xclang 支持多种构建系统和包管理器:pixi/conda(通过 conda.clice.io 安装)、CMake(FetchContent 或 find_package)、Bazel(通过 bazel.clice.io 提供 module)、以及 cargo(作为 Rust 交叉编译时的 C 编译器和链接器)。
xclang 项目是如何开发出来的?用了多少资源?
xclang 几乎全部由 AI agent 编写,从第一个提交到发布历时两周多。共产生 177 个提交、8 个正式版本,1 个 lead agent 启动了 23 个 worker 会话和 294 个 subagent,进行了 9403 次工具调用(其中 7623 次是 shell 命令),278 次 CI 运行,累计约 499 小时 runner 时间,编写了约 1.9 万行脚本和 4.2 万词文档。
xclang 未来的发展路线图包括哪些内容?
xclang 的路线图包括:按需下载更多目标(如 musl、riscv64、WebAssembly 等)、按需构建运行时(支持 MemorySanitizer、hardening 模式等)、MSVC 目标默认使用 libc++、Bazel 支持 MSVC 目标、扩大 PGO 训练集、跟进 LLVM 版本升级,以及研究 Windows 7/XP、iOS 和 BOLT 等。