构建原生运行在Apple silicon上的应用程序、库、框架、插件和其他可执行代码。当您在Apple框架和技术之上构建可执行文件时,您可能需要采取的唯一重要步骤是为arm64架构重新编译代码。如果您依赖于特定硬件的细节,或者假设底层特性,那么根据需要修改您的代码以支持Apple silicon。
要想在Apple silicon上获得最佳性能,有时需要调整使用硬件资源的方式。尽可能使用高级技术来减少对硬件的依赖。例如,使用Grand Central Dispatch而不是自己创建和管理线程。在Apple silicon上测试您的更改,以验证您的代码的行为是否最佳。
创建一个macOS应用程序的版本,可以在基于苹果硅和英特尔的Mac电脑上运行。
通过创建通用二进制文件并修改代码以处理架构差异,将现有macOS应用移植到Apple silicon。一个通用的二进制文件看起来和一个普通的应用程序没有什么不同,但是它的可执行文件包含编译代码的两个版本。一个版本在苹果芯片上运行,另一个版本在基于英特尔芯片的Mac电脑上运行。在运行时,系统会自动选择在当前平台上运行的版本。
要构建通用二进制文件,您需要Xcode 12或更高版本,该版本将arm64添加到macOS二进制文件的标准构建体系结构列表中。当你打开你的项目并做一个干净的构建时,如果你的项目使用标准架构,Xcode会自动创建一个通用的二进制文件。如果您使用定制的makefile
或构建脚本,请将arm64
体系结构添加到构建系统中。
创建通用二进制文件后,在两个体系结构上测试它,并确定是否需要进行其他更改。macOS
框架保护应用程序不受平台之间架构差异的影响,但有些差异可能仍然需要您更改代码。此外,架构上的差异可能会影响应用程序的性能,需要进行进一步的更改。
Apple silicon上,为x86_64架构构建的应用程序在Rosetta翻译环境下运行。更多信息请参考:About the Rosetta Translation Environment.
要了解如何构建通用二进制文件,请参见构建通用macOS二进制文件。
在移植过程的早期,确定您将用于构建和测试代码的工作流。Xcode
可以在所有的Mac电脑上运行,因此可以在基于苹果硅芯片或英特尔芯片的Mac电脑上构建代码,并在那里进行初始测试。但是,始终在这两种计算机类型上测试、调优和验证您的代码,以发现特定于该体系结构的问题。
除了工作流程计划之外,还要确定在移植过程中需要研究的潜在领域。对于arm64的移植工作取决于您对特定硬件特性的依赖程度。如果您主要依赖Apple框架和技术,那么您的移植工作可能会很小。如果您专门针对x86_64体系结构和硬件功能调整了代码,那么移植到arm64可能需要额外的工作。
要开始调查,请记下任何执行以下操作的代码:
与您不拥有的第三方库交互。
与内核或硬件交互。
依赖于特定的GPU行为。
包含汇编指令。
管理线程或优化你的应用程序的多线程行为。
包含硬件特定的假设或性能优化。
上面的列表并不详尽,但它为您的调查提供了一个起点。硬件和架构上的差异可能会给您的代码带来bug或性能问题。尽早发现潜在的问题领域将为您以后节省时间。
始终拥有一个定义良好的测试计划,理想情况下拥有一组可以在构建时运行的自动化测试套件。除了测试代码的正确性,还可以收集应用程序的性能指标。检查你的应用程序的内存使用情况,并测量它在苹果硅和基于英特尔的Mac电脑上执行特定任务所需的时间。利用这些信息来确定需要调查的其他领域。
如果您的项目依赖于任何第三方库,请联系原始供应商,要求他们为您提供这些库的通用版本。在同一进程中运行的所有代码必须支持相同的体系结构。如果没有所有链接库的通用版本,就无法生成二进制文件的通用版本。如果一个或多个库不是通用的,链接器会报告错误。
要了解如何创建自己的通用二进制文件,请参见构建通用macOS二进制文件。
一个通用插件可以在任何Mac电脑上运行。如果您的应用程序支持插件模型,请创建您管理的插件的通用版本。如果您的公司允许外部开发人员贡献插件,请鼓励这些开发人员创建他们的插件的通用版本。
如果应用程序直接将这些插件加载到进程空间,通用插件是必不可少的。在相同进程中运行的代码必须支持相同的体系结构。如果您的应用程序试图加载一个具有不兼容架构的插件,系统在加载时报告一个错误。
使用XPC服务运行进程外的插件可能使用与应用程序本身不同的架构运行。为了给开发人员更新插件的时间,提供两个非通用的XPC服务—一个运行arm64插件,另一个运行x86_64插件。单个XPC服务可以管理本机插件或转换插件,但不能同时管理两者。在创建服务时,为每个服务提供唯一的bundle标识符,以便它们可以同时运行。
有关如何使用XPC与进程外插件通信的信息,请参见XPC。
除了处理器和图形硬件的大规模变化,苹果硅芯片和基于英特尔的Mac电脑之间存在着微妙的架构差异。在移植过程中,审计您的代码以确定任何潜在架构问题的修复。例如,查找代码依赖于特定硬件特性或配置的位置。
下面的列表列出了苹果硅芯片和基于英特尔芯片的Mac电脑之间几个已知的架构差异。更新代码,依赖于任何以下:
虚拟内存页面大小
高速缓存线路尺寸
可变的函数
同时可写和可执行的内存
即时编译器
实时线程
显式线程优先级
特定于硬件的细节
汇编语言指令或内建函数
单位向量指令
c++ ABI的细节
Apple silicon和基于intel的Mac计算机都使用小端格式的数据,所以您不需要在代码中进行end转换。但是,继续尽量减少在创建的自定义数据格式中进行末端转换的需要。
有关架构差异的其他信息,请参见在macOS代码中处理架构差异。
苹果芯上的Metal支持基于英特尔的Mac电脑和iOS设备的功能。如果您的应用程序采用了只有在基于intel的Mac电脑上才能找到的Metal特性,那么请考虑在您的arm64代码中也采用ios特有的特性。采用这些特性可以提高许多应用程序的性能。
如果您的应用程序使用Metal, OpenGL,或OpenCL,请注意以下差异:
苹果芯片上的GPU
和CPU
共享内存。
OpenGL
是不推荐的,但在苹果芯上是可用的。
OpenCL
是不推荐的,但在针对GPU
时,它是可用的。OpenCL CPU
设备对arm64
应用程序不可用。
有关如何更新图形代码的信息,请参见将Metal代码移植到Apple Silicon。
在将代码移植到macOS 11时,请注意与内核交互的代码的以下要求:
使用DriverKit实现硬件驱动程序。macOS 11要求你使用一个驱动套件扩展,当支持是可用的。大多数驱动程序类型现在都支持DriverKit,只有少数仍然需要创建内核扩展。
内核扩展必须支持本机体系结构。内核扩展在内核中运行,并且内核始终作为本机进程运行。不能使用Rosetta翻译运行内核扩展。
内核扩展的安装和卸载需要重新启动。当您安装内核扩展时,系统直到重新启动后才加载扩展。
有关内核扩展和驱动程序更改的更多信息,请参见实现驱动程序、系统扩展和kext。
macOS包括一些目前不推荐或不鼓励积极开发的技术。如果您的应用程序使用下列技术之一,迁移到适当的替代尽快:
OpenGL
-用Metal来代替。
OpenCL
-用Metal来代替。
addressbook
—使用联系人框架代替。
Carbon api——迁移到AppKit、Foundation和其他现代api。
IOKit内核扩展-迁移到驱动套件在适当的地方用DriverKit框架。
Apple silicon 仍然提供对上述技术的支持,你可以继续在macOS 11中使用它们。但是,这种支持可能会在macOS的未来版本中删除,所以建议迁移到较新的技术。
Apple silicon支持所有在基于intel的Mac电脑上发现的调试和测试工具。使用Xcode IDE来设置和监控断点,以及监控应用程序其他方面的行为。在命令行中使用lldb在Xcode接口之外执行类似的任务。
有关如何调试和测试代码的更多信息,请参见Xcode。
苹果硅可以运行基于英特尔的Mac电脑上的所有性能工具。使用工具和其他性能工具为你的应用收集不同类型的指标,包括内存使用,速度,能源使用等信息。您还可以使用命令行工具(如leaks、heap、top、fs_usage、sc_usage、vm_stat、otool、sample、malloc_history
和vmmap
)来识别潜在的性能问题。
arm64和x86_64之间的架构差异意味着,在一个系统上运行良好的技术可能在另一个系统上运行不好。例如:
不要假设独立GPU意味着更好的性能。苹果处理器的集成GPU为高性能图形任务进行了优化。请参阅将您的Metal代码移植到苹果芯。
不要假设所有的处理器核心都是相同的。Apple silicon上的处理器混合了性能核心(p -core)和效率核心(e -core),它们执行具有不同性能特征的任务。使用**服务质量(QoS)**类来帮助系统在正确的核心类型上调度任务。
在移植过程中,测量你的应用程序在苹果芯和基于英特尔的Mac电脑上的性能,并调查任何差异。在一个平台上运行时间较长的任务可能需要额外的调优。
有关调优通用二进制文件的具体技巧,请参见为Apple Silicon调优您的代码性能。