本文记录如何在 Windows 环境下,借助 MacOSX12.3.sdk 和 LLVM/Clang 交叉编译 Boost 的 macOS 静态库。目标架构包括:
- macOS Intel:
x86_64 - macOS Apple Silicon:
arm64
最终会分别得到两套 .a 静态库:
stage/macos/x86_64/lib
stage/macos/arm64/lib
如果后续需要,也可以再用 lipo / llvm-lipo 合并成 macOS universal .a。
1. 环境说明
本文示例环境:
Windows
Boost
MacOSX12.3.sdk
Visual Studio 2019 Enterprise LLVM/Clang
示例 SDK 路径:
D:/Installed_Files/macosx_sdk/MacOSX12.3.sdk
示例 LLVM 路径:
C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm
其中主要会用到:
clang++.exe
llvm-ar.exe
llvm-ranlib.exe
ld64.lld.exe
这里使用 Visual Studio 自带的 LLVM/Clang,并不是因为只能使用 Visual Studio 的 LLVM,而是因为这套工具链安装方便,并且组件相对完整。除了 clang++.exe、llvm-ar.exe、llvm-ranlib.exe 之外,关键还需要支持 Darwin/Mach-O 的 linker,也就是 ld64.lld.exe。很多人口头上会把它叫作 lld64,实际文件名通常是 ld64.lld.exe。
如果你的其他 LLVM 工具链组件也完整,也可以替换成其他 LLVM。例如自定义 LLVM、llvm-mingw、osxcross 相关工具链都可以尝试,前提是至少满足:
clang++.exe 能识别 --target=x86_64-apple-darwin / --target=arm64-apple-darwin
llvm-ar.exe 能生成 Mach-O 静态库 archive
llvm-ranlib.exe 能为 Mach-O 静态库生成索引
ld64.lld.exe 能在需要链接 Mach-O 目标时作为 Darwin linker 使用
llvm-lipo.exe 可选,用于合并 x86_64 + arm64 universal .a
注意:本文主要编译 macOS 静态库 .a。纯静态库归档阶段通常主要依赖 clang++、llvm-ar、llvm-ranlib;但如果构建过程中有链接测试、生成可执行文件、生成 .dylib,或者后续要在 Windows 上继续链接 macOS 目标文件,就需要可用的 ld64.lld.exe。如果工具链缺少 Mach-O linker,即使 .cpp 能编译成 .o,也可能在链接阶段失败。
2. 准备 MacOSX12.3.sdk
准备好 MacOSX12.3.sdk,本文假设路径为:
D:/Installed_Files/macosx_sdk/MacOSX12.3.sdk
确认 SDK 目录中至少能看到类似结构:
MacOSX12.3.sdk/usr/include/lib/System/Library/
后续会通过 clang 参数指定:
--sysroot=D:/Installed_Files/macosx_sdk/MacOSX12.3.sdk
3. 准备 Boost 1.74
下载并解压 Boost 1.74,例如解压到:
D:/workspace/boost_1_74_0
从开始菜单打开 VS20XX 的开发人员命令提示符(x86 或 x64 版本都可以):

切换到 Boost 源码根目录:
cd D:\workspace\boost_1_74_0
选一个对应的msvc版本(这里以vc142为例),生成 b2 构建工具:
.\bootstrap.bat vc142
执行成功后,根目录下会出现 b2.exe。
后续所有编译命令都在 Boost 根目录下执行。
4. 编辑 user-config.jam
在 Boost 根目录新建或编辑:
user-config.jam
写入如下配置:
macosSdk = D:/Installed_Files/macosx_sdk/MacOSX12.3.sdk ;
llvmMingwRoot = "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm" ;
llvmMingwBin = $(llvmMingwRoot)/bin ;# macOS Intel x86_64 static libraries.
using clang : macos_x86_64 :$(llvmMingwBin)/clang++.exe:<compileflags>--target=x86_64-apple-darwin<compileflags>--sysroot=$(macosSdk)<compileflags>-mmacosx-version-min=10.13<compileflags>-stdlib=libc++<cxxflags>-std=c++14<cxxflags>-O2<cxxflags>-g<cxxflags>-DNDEBUG<cxxflags>-Wno-enum-constexpr-conversion<linkflags>--target=x86_64-apple-darwin<linkflags>--sysroot=$(macosSdk)<linkflags>-mmacosx-version-min=10.13<linkflags>-stdlib=libc++<archiver>$(llvmMingwBin)/llvm-ar.exe<ranlib>$(llvmMingwBin)/llvm-ranlib.exe;# macOS Apple Silicon arm64 static libraries.
using clang : macos_arm64 :$(llvmMingwBin)/clang++.exe:<compileflags>--target=arm64-apple-darwin<compileflags>--sysroot=$(macosSdk)<compileflags>-mmacosx-version-min=11.0<compileflags>-stdlib=libc++<cxxflags>-std=c++14<cxxflags>-O2<cxxflags>-g<cxxflags>-DNDEBUG<cxxflags>-Wno-enum-constexpr-conversion<linkflags>--target=arm64-apple-darwin<linkflags>--sysroot=$(macosSdk)<linkflags>-mmacosx-version-min=11.0<linkflags>-stdlib=libc++<archiver>$(llvmMingwBin)/llvm-ar.exe<ranlib>$(llvmMingwBin)/llvm-ranlib.exe;
几个关键点:
--target=x86_64-apple-darwin:生成 macOS Intel 目标文件。--target=arm64-apple-darwin:生成 macOS Apple Silicon 目标文件。--sysroot=$(macosSdk):指定使用MacOSX12.3.sdk。-stdlib=libc++:macOS C++ 标准库使用 libc++。-mmacosx-version-min=10.13:x86_64 的最低系统版本。-mmacosx-version-min=11.0:arm64 的最低系统版本,Apple Silicon 通常要求 macOS 11.0 起。-std=c++14:Boost 老版本和较新 clang/libc++ 组合下,C++14 通常更稳。-Wno-enum-constexpr-conversion:规避部分 Boost 版本在新 clang 下的枚举 constexpr 转换警告/错误。
注意 toolset 名中的版本号使用下划线:
macos_x86_64
macos_arm64
后续 b2 中对应:
toolset=clang-macos_x86_64
toolset=clang-macos_arm64
不要写成 macos-x86_64 这类带额外横线的名字,避免被 Boost.Build 解析成 toolset 子特性。
5. 编译 macOS x86_64 静态库
在 Boost 根目录执行:
.\b2 -q -j8 -a -d+2 --debug-configuration `--user-config=.\user-config.jam `toolset=clang-macos_x86_64 `target-os=darwin binary-format=mach-o `architecture=x86 address-model=64 `threading=multi link=static variant=release cxxstd=14 `--without-python `--stagedir=stage/macos/x86_64 stage `2>&1 | Tee-Object -FilePath .\build-macos-x86_64.log
编译完成后,x86_64 静态库位于:
stage/macos/x86_64/lib
6. 编译 macOS arm64 静态库
在 Boost 根目录执行:
.\b2 -q -j8 -a -d+2 --debug-configuration `--user-config=.\user-config.jam `toolset=clang-macos_arm64 `target-os=darwin binary-format=mach-o `architecture=arm address-model=64 `threading=multi link=static variant=release cxxstd=14 `--without-python `--stagedir=stage/macos/arm64 stage `2>&1 | Tee-Object -FilePath .\build-macos-arm64.log
编译完成后,arm64 静态库位于:
stage/macos/arm64/lib
7. 参数说明
7.1 静态库相关参数
link=static
表示生成 Boost 静态库,也就是 .a 文件。
threading=multi
表示生成多线程版本 Boost 库。
variant=release
表示生成 release 版本。需要 debug 版本时,可以改成:
variant=debug
7.2 macOS 目标相关参数
target-os=darwin binary-format=mach-o
表示目标平台是 Darwin/macOS,二进制格式是 Mach-O。
x86_64 使用:
architecture=x86 address-model=64
arm64 使用:
architecture=arm address-model=64
7.3 调试日志参数
-d+2 --debug-configuration
这两个参数是可选的,用于输出更详细的编译命令和 Boost.Build 配置加载信息。调试 user-config.jam 是否生效、实际调用了哪个 clang++.exe、传入了哪些参数时非常有用。
确认配置稳定后,可以去掉它们以减少日志量。
7.4 保存日志
命令末尾使用:
2>&1 | Tee-Object -FilePath .\build-macos-x86_64.log
这样可以把标准输出和错误输出同时保存到日志文件,避免 PowerShell 控制台滚动太快导致看不到真正错误。
如果日志太多,可以临时把:
-j8
改成:
-j1
单线程构建更容易定位第一个错误。
8. 为什么加 --without-python
本文命令中加了:
--without-python
原因是 Boost 的 bootstrap.bat 可能会自动探测 Windows 主机上的 Python。如果交叉编译 macOS 时误用了 Windows Python 的头文件和库,容易导致主机平台和目标平台不匹配的问题。
除非确实需要 Boost.Python,并且已经准备好 macOS x86_64/arm64 对应的 Python 头文件和库,否则建议直接跳过:
--without-python
9. 可选:只编译需要的 Boost 库
如果不想全量编译 Boost,可以使用 --with-xxx 指定需要的库,例如:
--with-atomic --with-chrono --with-date_time --with-filesystem --with-system --with-thread --with-regex
示例:
.\b2 -q -j8 -a `--user-config=.\user-config.jam `toolset=clang-macos_x86_64 `target-os=darwin binary-format=mach-o `architecture=x86 address-model=64 `threading=multi link=static variant=release cxxstd=14 `--without-python `--with-atomic --with-chrono --with-date_time --with-filesystem --with-system --with-thread --with-regex `--stagedir=stage/macos/x86_64 stage `2>&1 | Tee-Object -FilePath .\build-macos-x86_64.log
这样可以减少编译时间,也能避开一些当前项目不需要的 Boost 库带来的额外平台兼容问题。
10. 可选:合并 universal 静态库
macOS 支持 universal/fat binary,可以把 x86_64 和 arm64 两个架构合并到同一个 .a 文件里。
假设已经有:
stage/macos/x86_64/lib/libboost_system-clang-mt-x64-1_88.a
stage/macos/arm64/lib/libboost_system-clang-mt-a64-1_88.a
可以使用 lipo 或 llvm-lipo 合并:
$lipo = "D:\Installed_Files\android_ndk\android-ndk-r26d\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-lipo.exe"New-Item -ItemType Directory -Force .\stage\macos\universal\lib | Out-Null& $lipo -create `.\stage\macos\x86_64\lib\libboost_system-clang-mt-x64-1_88.a `.\stage\macos\arm64\lib\libboost_system-clang-mt-a64-1_88.a `-output .\stage\macos\universal\lib\libboost_system-clang-mt-1_88.a& $lipo -info .\stage\macos\universal\lib\libboost_system-clang-mt-1_88.a
正常会看到类似输出:
Architectures in the fat file: ... are: x86_64 arm64
注意:合并后的 universal .a 不要再用普通 llvm-ar.exe 或 llvm-ranlib.exe 处理,否则某些 Windows 版 LLVM 工具可能无法识别 fat archive。
11. 验证产物
可以使用 llvm-lipo 查看 universal 库架构:
& $lipo -info .\stage\macos\universal\lib\libboost_system-clang-mt-1_88.a
对于单架构 .a,可以查看 archive 内容:
& "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\bin\llvm-ar.exe" t .\stage\macos\x86_64\lib\libboost_system-clang-mt-x64-1_88.a
也可以抽出一个 .o 后用 llvm-readobj 或 llvm-objdump 查看是否为 Mach-O 对象文件。
12. 常见问题
12.1 找不到标准库头文件
如果出现类似:
fatal error: 'cstddef' file not found
通常说明 --sysroot=$(macosSdk) 没有生效,或者当前 clang 没有正确找到 SDK 中的 libc++ 头文件。优先检查:
macosSdk路径是否正确。MacOSX12.3.sdk/usr/include/c++/v1是否存在。user-config.jam是否被 b2 加载。- b2 命令是否包含
--user-config=.\user-config.jam。
12.2 user-config.jam 没有生效
可以保留:
-d+2 --debug-configuration
查看 Boost.Build 是否加载了你的 user-config.jam,以及实际调用的编译器路径。
12.3 不要把 macOS arm64 和 Android arm64 混淆
macOS arm64 使用:
--target=arm64-apple-darwin
Android arm64-v8a 使用:
--target=aarch64-linux-android21
两者 ABI、系统库、目标格式都不同,不能混用。
12.4 Windows 下生成的 .a 能否直接给 macOS 用
可以,前提是 .a 内部是 Mach-O 目标文件,而不是 Windows COFF 或 Linux ELF。本文通过:
--target=...-apple-darwin
binary-format=mach-o
生成的就是 macOS Mach-O 静态库。
13. 目录整理建议
编译完成后,可以按如下方式整理:
boost_macos/include/boost/lib/x86_64/libboost_*.aarm64/libboost_*.auniversal/libboost_*.a
如果你的 macOS 工程使用 CMake,可以按架构选择对应目录,或者直接使用 universal .a。
14. 小结
整个流程可以概括为:
- 准备
MacOSX12.3.sdk。 - 准备 Windows 下可用的 LLVM/Clang。
- 在 Boost 根目录运行
bootstrap.bat生成b2.exe。 - 在
user-config.jam中配置x86_64-apple-darwin和arm64-apple-darwin。 - 分别运行 b2 生成
x86_64和arm64的 macOS.a。 - 如有需要,再用
lipo/llvm-lipo合并 universal 静态库。