Python实战社群
Java实战社群
长按识别下方二维码,按需求添加
扫码关注添加客服
进Python社群▲
扫码关注添加客服
进Java社群▲
作者:老峰,iOS 开发者,《iOSTips》公众号主
Sessions: https://developer.apple.com/videos/play/wwdc2020/10214/
一直以来 Apple 都勇于创新,Mac 共经历几次大的变革,从最初的的架构到 PowerPC 芯片,再到 OSX、Intel 芯片,到这次放弃 Intel x86 架构,自研 Apple Silicon ARM 芯片。第一款搭载该芯片的产品预计年底面世,在我看来这不管对 Mac 还是 Apple 生态开发者都是具有历史意义的一天。
概述
本文主要讨论如何如何为 Apple Silicon 重新编译 MacOS App,如何构建通用架构 App,以及让这些 App 启动更快,性能更好并支持平台未来发展;另外将演示如何使用 Xcode 12 运行、调试、测试你的 App, 以及处理进程内和进程外 plugins 的一些技巧。本文假设读者已拥有一定的 MacOS 平台开发经验。
CPU 架构
为了更好的理解此文,我们先了解下 Apple Silicon Mac 及 Intel-based Mac 的 CPU 架构如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/88d5f4507d06a2cd4c75f0287b1e06a3.png)
Apple Silicon 本身是 arm64 架构( iOS 开发者对此并不陌生),支持 arm64 架构、x86_64 架构 ;Intel-based Mac 是 x86_64 架构, 只支持 x86_64 架构,特别的 Apple Silicon 是通过 Rosetta translation 运行 x86_64 App,关于 Rosetta 更多的信息可以查看 About the Rosetta Translation Environment[1].
通用 Mach-O
程序可执行文件或者动态库文件等,在应用程序包内都是 Mach-O 文件格式,他们可以编译为单架构或者通用架构,使用 "lipo" 命令可以查看具体信息。特别的,从今年开始新 Mac Apps 必须构建通用 CPU 架构的 App,也就是说要同时支持 arm64 和 x86_64 架构。
![](https://i-blog.csdnimg.cn/blog_migrate/7eff8cd71671468e3765d64d28ae62aa.png)
如果你已经有只支持 Intel 架构的 App 或者由于一些特别的原因还不能支持原生 arm64,Apple Silicon Mac 新硬件将提供 Rosetta traslation 环境来无缝的运行他们。另外 Rosetta traslation 不支持 Kernel extensions(内核扩展), AVX vector 指令集, Virtualization 虚拟机等。Xcode 12 支持 App 运行于 Rosetta 环境,我将在下一节讲解如何使用 Xcode 编译 Rosetta App。
使用 Xcode12 编译 Rosetta App
我们以 NetworkBenchmarking 工程为例演示如何适配 Rosetta 环境,在 Xcode 首先选中 My Mac Rosetta 编译运行,我们发现编译成功了没有任何错误。如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/22982914c3aee628d85472c7af74dbd1.png)
接下来第二步我们选中 My Mac 编译 Apple Silicon 原生架构,不出所料,我们遇到了编译错误如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/c52eaf3c49f2eedf19522027722951af.png)
这里补充一下不同 CPU 架构的条件编译列表,如图所示我们只需在 if 条件 再加一个 TARGET_OS_SIMULATOR 就可以解决这个编译错误。
![](https://i-blog.csdnimg.cn/blog_migrate/ffa412c1b64feaeef17b62afe6b1bb1a.png)
改好后我们继续重新编译,很明显我们又遇到了编译错误,但这个错误发生在编译链接期,第三步解决链接期错误 Sparkle.framework 中存在 "Undefined symbols for architecture arm64",大概意思是我们 App 编译是通用架构,但依赖的三方库 Sparkle.framework 还不支持通用架构,如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/3f82a44e27b301cc3e02b55abe00daa3.png)
所以我们需要对应的三方库支持 arm64 版本,我这里已经下载了已经升级的 Sparkle.framework,所以这里直接替换。特别的,所有 .a、.framework、.xcframework 都需要重新编译支持通用架构。
至此我们的 App 可以成功编译,这里总结一下操作步骤,首先编译 x86_64 Rosetta 版本;第二步编译 arm64 版本,fix 可能的编译错误;第三步 fix 链接期的编译错误,升级所有依赖的三方 framework 支持以通用架构。强调一下,我们可以使用任何装有 Xcode 12 的 Mac 电脑构建通用架构的 App。
Apple Silicon App 运行优化
虽然我们的 App 已经可以成功编译,但可能还有一些运行错误,所以我们需要在 Apple Silicon Mac 运行优化我们的 App。
运行 NetWork Benchmarking APP 点击 HTPP+TLS,会报如下图所示错误, dlopen(libTLSPlugin.dylib,2) no suitable image found,Did find libTLSPlugin.dylib:mach-o,but wrong architecture。
![](https://i-blog.csdnimg.cn/blog_migrate/a36a0aed84fd10769bac0cfd21078a17.png)
如图所示,我们的 .dylib 动态库试运行时通过 dlopen 或者 Bundle.load() 在运行时加载,所以编译时不报错,但运行时动态加载 libTLSPlugin.dylib 这个动态库,不支持 arm64 就会报错。我们升级 libTLSPlugin.dylib 即可解决该问题。
![](https://i-blog.csdnimg.cn/blog_migrate/2a4032a37e336305c50ac75061894d28.png)
除了以上运行时错误,我们可能还需要对一些更底层的特别的处理器指令做优化。一般的,Apple Silicon Mac Native code 比 Rosetta 环境的性能高,但是代码中包含了 SSE,AVX 等特定处理器的向量指令,则需要做对应的更新来支持 Apple Silicon 版本。Aceerlerate.framework 中有大量为 Mac 全平台优化的向量操作库,可以作为针对特定处理器的向量操作替代。Aceerlerate.framework 使用当前系统可用的硬件来实现:
向量和矩阵计算
图像操作
数字信号处理
线性代数计算
压缩
神经网络计算
关于更多 Aceerlerate.framework 信息,可以查看 Accelerate[2]。
除了 进程外 Plugins 架构错误,指令调整,在 Apple Silicon 和 Intel 平台的 Mac 上还有很多细微的架构调整。在迁移过程中,我们需要仔细审查相关架构的错误代码并修复,这里简单列出典型需调整的代码:
Virtual memory-page sizes(虚拟内存页)
Cache line sizes(缓存行)
Variadic functions(变长参数函数)
Just-in-time compilers(即时编译器)
Realtime threads(实时线程)
Hardware-specifiec details(特定硬件内容)
Assembly-language instructions or builtin intrinsics(汇编语言指令和内置 intrinsic 函数)
Vector unit instructions(向量单位指令)
C++ ABI details(C++ ABI内容)
特别的,Apple Silicon 和 Intel 平台 Mac 计算机都使用 little-endian(小字节序、低字节序) 格式数据,所以你在代码中无需做字节序的转换。但是,在自定义数据格式中最好还是尽量减少字节序的转换,如果想要了解更多关于架构上的差异,可以查看 Addressing Architectural Differences in Your macOS Code[3]。
Xcode Organizer Crash 日志
在 Xcode 12 中,Archive 打包默认构架通用架构 App, 并且在 Xcode Organizer 里边查看线上 Crash 日志,会发现包含三种类型的日志:
x86_64 Intel Mac 日志
原生 arm_64 Apple Silicon Macs 日志
Rosetta x86_64 Apple Silicon Macs 日志
总结
以上是整体迁移过程,以及迁移过程中可能遇到的问题,整个迁移过程总结如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/49b16f1ccae7e245352ef7b08ab5567a.png)
首先标记第三方库、内核、硬件、 GPU 、特殊 CPU 指令相关交互的代码
升级相关第三方库支持通用架构
升级 Plugins 支持通用架构,如 .dylib 等(如果插件以进程外 XPC 服务运行可以和 App 不同架构)
针对 GPU 代码更新(参见 Porting Your Metal Code to Apple Silicon[4])
App 性能调优(参见 Tuning Your Code’s Performance for Apple Silicon[5])
参考资料
[1]
About the Rosetta Translation Environment: https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment
[2]Accelerate: https://developer.apple.com/documentation/accelerate
[3]Addressing Architectural Differences in Your macOS Code: https://developer.apple.com/documentation/apple_silicon/addressing_architectural_differences_in_your_macos_code
[4]Porting Your Metal Code to Apple Silicon: https://developer.apple.com/documentation/metal/porting_your_metal_code_to_apple_silicon
[5]Tuning Your Code’s Performance for Apple Silicon: https://developer.apple.com/documentation/os/workgroups/tuning_your_code_s_performance_for_apple_silicon
程序员专栏 扫码关注填加客服 长按识别下方二维码进群
近期精彩内容推荐:
在看点这里好文分享给更多人↓↓