交叉编译到macOS

...其实非常简单!

osxcross

大部分人搜索"cross compiling to macos"应该就会找到osxcross.

众所周知, 交叉编译需要:

  1. 为target平台生成代码的编译器和工具链
  2. target平台的一套SDK, 即头文件和一些基础库.

osxcross这个项目默认干了什么事呢?

  • 编译cctools-port, 这是一个把Apple的ar, ld,, otool, lipo等工具链binary移植到了其他Unices的项目.
  • 帮你获取并解包macOS的SDK. 其中, 会帮你编译xar, pbzx等若干工具.
  • 至于最重要的编译器部分, 默认只是生成了一些wrapper, 调用你host系统上的Clang. 众所周知, Clang自己就自带交叉编译功能, 因此不需要额外编译一个不同target的cc.
    • 你也可以选择从头编译Clang或GCC

很简单吧! 其实弄懂原理后, 可以不需要osxcross

PS: osxcross仍然有一些小bug, 比如编译出的ld还依赖一个内部库, 需要你LD_LIBRARY_PATH一下, 比如一些wrapper脚本里变量设置的有问题.

自己动手

获取macOS SDK

先去Apple Developer官网直接下载Command Line Tools, 得到一个dmg文件, 如Command_Line_Tools_for_Xcode_26.2.dmg.

然后, 需要准备几个工具软件:

接下来解压:

1
2
3
4
5
6
7
8
9
7z e -so Command_Line_Tools_for_Xcode_26.2.dmg "Command Line Developer Tools/Command Line Tools*.pkg" > "Command Line Tools.pkg"

mkdir pkg_data out

xar -xf "Command Line Tools.pkg" -C pkg_data

for PKG in pkg_data/*.pkg; do
    pbzx -n "${PKG}/Payload" | (cd out && cpio -i)
done

解压完后, 就能在out/Library/Developer/CommandLineTools/SDKs/下面看到SDK的根目录了, 如MacOSX15.4.sdk. (下载的dmg版本不同, 具体位置可能不同). 其中含有头文件和基础库等.

配置Clang

这里就十分简单了. 只要你主机上的Clang/LLVM功能完整, 能够输出macOS的target.

1
clang --target=arm64-apple-darwin24.4 --sysroot=/path/to/SDKs/MacOSX15.4.sdk -fuse-ld=lld test.c -o test

其实就是设置一下target和sysroot. 另外linker需要用lld, 因为我们host上的GNU ld并不支持其它target.

Universal binary

如果要编译Universal binary, 加入-arch arm64 -arch x86_64即可. 当然, 也可以分别编译后, 用lipo合并.

其它工具链软件

我们还需要Apple的其它工具链软件, 也就是cctools-port部分. 事实上, 我们用LLVM的工具链基本能完全替代:

  • otool -> llvm-otool
  • ar -> llvm-ar
  • strip -> llvm-strip
  • lipo -> llvm-lipo

LLVM工具链和Clang前端一样, 都原生支持交叉编译, 支持各平台的二进制格式.

CMake

上面的配置足够编译一些简单的程序了. 对于CMake, 设置一些CMake的标准变量即可, 例如

1
2
3
4
5
-D CMAKE_CXX_COMPILER=clang
-D CMAKE_CXX_COMPILER_TARGET=arm64-apple-darwin24.4
-D CMAKE_LINKER_TYPE=LLD
-D CMAKE_SYSROOT=/path/to/SDKs/MacOSX15.4.sdk
-D CMAKE_OSX_DEPLOYMENT_TARGET=15.0 # 最低兼容的macOS版本

此外, 还有交叉编译应当设置的标准变量, 如:

1
2
-D CMAKE_SYSTEM_NAME=Darwin
-D CMAKE_SYSTEM_PROCESSOR=arm64

当然, 也可以把它们放进一个CMake toolchain文件.

Windows主机?

Windows主机上用法也是一样简单, 获取SDK内容后, 去LLVM github直接下载安装Windows安装包. 记得把安装目录(bin)加到PATH里.

然后你就有了Windows上完整可用的Clang前端和LLVM工具链, 支持所有target平台. (其实这就是在Windows上使用Clang编译程序的最简单方法: 去官网直接下载安装LLVM安装包! 不是什么clang-cl或者MinGW Clang)

安装好的Clang默认是编译Windows原生程序, 并链接到MS的C/C++运行库. 与上面相同, 我们只要指定--target--sysroot就能编译macOS程序了.

总结

由于工程中产生了交叉编译到macOS的需求, 花了我半天时间研究, 但最终的方法其实非常简单明晰. 多亏了LLVM!