osxcross
大部分人搜索"cross compiling to macos"应该就会找到osxcross.
众所周知, 交叉编译需要:
- 为target平台生成代码的编译器和工具链
- 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.
然后, 需要准备几个工具软件:
- 7z (p7zip或者新版的7zip)
- xar (一般发行版官方都有打包)
- pbzx, 另见我提的修复Linux上编译的PR
接下来解压:
| |
解压完后, 就能在out/Library/Developer/CommandLineTools/SDKs/下面看到SDK的根目录了, 如MacOSX15.4.sdk. (下载的dmg版本不同, 具体位置可能不同). 其中含有头文件和基础库等.
配置Clang
这里就十分简单了. 只要你主机上的Clang/LLVM功能完整, 能够输出macOS的target.
| |
其实就是设置一下target和sysroot. 另外linker需要用lld, 因为我们host上的GNU ld并不支持其它target.
Universal binary
如果要编译Universal binary, 加入-arch arm64 -arch x86_64即可.
当然, 也可以分别编译后, 用lipo合并.
其它工具链软件
我们还需要Apple的其它工具链软件, 也就是cctools-port部分. 事实上, 我们用LLVM的工具链基本能完全替代:
otool->llvm-otoolar->llvm-arstrip->llvm-striplipo->llvm-lipo
LLVM工具链和Clang前端一样, 都原生支持交叉编译, 支持各平台的二进制格式.
CMake
上面的配置足够编译一些简单的程序了. 对于CMake, 设置一些CMake的标准变量即可, 例如
| |
此外, 还有交叉编译应当设置的标准变量, 如:
| |
当然, 也可以把它们放进一个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!