• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

创建通用 macOS 二进制文件

武飞扬头像
SkyNullCode
帮助1

概述

原生应用比解析执行的应用程序运行更高效,因为编译器针对目标架构优化了代码。仅支持 x86_64 架构的应用程序必须通过 Rosetta 转换才能在App芯片上运行 。通用二进制文件在 Apple 芯片和 Intel 芯片的 Mac 上运行,因为它包含两种架构的可执行代码。

可以将所有编译的代码转换为通用二进制文件,而不仅仅是应用程序。以下列表包括最常见的可转换为通用二进制文件的可执行文件类型。

  • 应用

  • 应用扩展

  • 插件

  • 自定义框架

  • 静态库

  • 动态库

  • 构建工具

  • 命令行工具

  • 守护进程和启动代理

  • DriverKit 扩展

  • 内核扩展

更新 Xcode 项目中的架构列表

Xcode 12.2 及更高版本会自动将 arm64 架构添加到所有 macOS 二进制文件(包括应用程序和库)的标准架构列表中。在调试和测试过程中,Xcode 默认只针对当前系统架构进行构建。但是,它会自动为代码的发布版本构建通用二进制文件。

学新通

如果在 Xcode 项目中自定义了 Architectures 构建设置,请删除自定义并改用 Standard Architectures 设置。

更新自定义 Makefile 的架构列表

如果使用自定义脚本或 makefile 构建项目,需要将 arm64 架构添加到适当的环境变量中。 Xcode 使用 ARCHS 环境变量来定义当前的构建架构。其他构建系统可能使用不同的环境变量,但目的相似。将变量添加到适当的环境变量后,需要构建代码来验证编译器是否创建了代码的 arm64 变体。为了创建通用二进制文件,需要使用 lipo 工具将生成的可执行文件合并为单个可执行二进制文件。

使用 makefile 来编译代码,需要设置 -target 选项将适当的架构值传递给编译器。下面的示例展示了 makefile 编译单个源文件两次的过程(每个体系结构一次)。然后通过使用 lipo 工具合将生成的可执行文件创建一个通用二进制文件。

```

x86_app: main.c

    $(CC) main.c -o x86app -target x8664-apple-macos10.12

arm_app: main.c

    $(CC) main.c -o arm_app -target arm64-apple-macos11

universalapp: x86app arm_app

    lipo -create -output universalapp x86app arm_app

```

使用条件编译宏包装特定于平台的代码

为特定平台或处理器类型编写代码时,请使用适当的条件编译语句隔离该代码。对于基于 C 的代码,系统定义了一组宏,在 /usr/include/TargetConditionals.h 中。 Swift 语言还支持使用条件编译块的条件编译。

要区分用于特定类型处理器的代码,需要添加针对适当架构的条件编译语句。通用 macOS 应用程序支持 arm64 和 x86_64 架构,以下示例条件编译在 swift 中的使用:

```swift

// Swift example

if arch(arm64)

   // Code meant for the arm64 architecture here.

elseif arch(x86_64)

   // Code meant for the x86_64 architecture here.

endif

```

对应 oc 语言,代码如下:

```ocx

// Objective-C example

include "TargetConditionals.h"

if TARGETCPUARM64

  // Code meant for the arm64 architecture here.

elif TARGETCPUX86_64

  // Code meant for the x86_64 architecture here.

endif 

```

在 iOS 和 macOS 应用程序之间共享代码,请不要假设 arm64 架构的代码仅在 iOS 设备上运行,该代码也可以在 Apple 芯片上的 macOS 应用程序中运行。区分 macOS 或 iOS 相关部分的代码,需要使用以下示例中展示的条件编译语句。此外,还可以结合特定于平台和特定于体系结构的条件编译来进一步优化代码。

```swift

//Swift example

if os(macOS)

   // Put CPU-independent macOS code here.

   #if arch(arm64)

      // Put 64-bit arm64 Mac code here.

   #elseif arch(x86_64)

      // Put 64-bit x86_64 Mac code here.

   #endif

elseif targetEnvironment(macCatalyst)

   // Put Mac Catalyst-specific code here.

elseif os(iOS)

   // Put iOS-specific code here.

endif

```

对应 oc 语言,代码如下:

```oc

// Objective-C example

include "TargetConditionals.h"

if TARGETOSOSX

  // Put CPU-independent macOS code here.

  #if TARGETCPUARM64

    // Put 64-bit Apple silicon macOS code here.

  #elif TARGETCPUX86_64

    // Put 64-bit Intel macOS code here.

  #endif

elif TARGETOSMACCATALYST

   // Put Mac Catalyst-specific code here.

elif TARGETOSIOS

  // Put iOS-specific code here.

endif

```

设置编译目标

当构建可调试版本时,为了节省构建的时间,Xcode 默认仅针对当前架构构建,这样方便调试代码和快速修复。

可以通过更改项目的 Build Active Architecture Only 设置选项,在任何 Mac 上创建带有调试符号的通用二进制文件。尽管可以在基于 Intel 的 Mac 上创建此二进制文件,但无法运行或调试 arm64 部分的代码。只有配备 Apple 芯片的 Mac 才能运行和调试二进制文件的两种架构的代码,能够使用 Rosetta 转换来运行和调试 x86_64 部分的代码。

判断二进制文件是否通用

对于使用者来说,通用二进制文件与为单一架构构建的二进制文件看起来没有什么不同。当构建通用二进制文件时,Xcode 会编译您的源文件两次(每个架构一次)。在链接每个架构的二进制文件后,Xcode 会使用 lipo 工具将相应架构的二进制文件合并到一个可执行文件中。手动构建源文件时,则必须调用 lipo 作为构建脚本的一部分,以将特定于体系结构的二进制文件合并为一个通用二进制文件。

需要使用 lipo 或 file 命令行工具查看构建的可执行文件中存在的架构。运行任一工具时,需要指定实际可执行文件的路径,而不是中间目录,比如应用程序包。例如,macOS 应用程序的可执行文件位于其捆绑包的 Contents/MacOS/ 目录中。运行 lipo 工具时,包含 -archs 参数以查看架构。以下示例展示了如何使用 lipo 查看 macOS 中 Mail 应用程序的架构列表,结果显示 Mail 是通用二进制文件。

```

% lipo -archs /System/Applications/Mail.app/Contents/MacOS/Mail

x86_64 arm64

```

要获取有关每个架构的更多信息,需要在 lipo 中传入 -detailed_info 参数。

指定应用程序的启动行为

对于通用二进制文件,系统更喜欢执行当前平台原生的代码。在基于 Intel 的 Mac 上,系统始终执行二进制文件的 x86_64 那部分代码。在 Apple 芯片上,系统更喜欢执行 arm64 那部分代码。用户可以强制系统来执行通过 Rosetta 转换之后的 App,通过启用 Finder 中适当的选项。

可以通过在 Info.plist 中设置 LSRequiresNativeExecution 来禁止运行 Rosetta 转换之后的 App。

当该值设置为 YES 时,系统会阻止应用程序在翻译状态下运行。此外,系统会从应用程序的“获取信息”窗口中删除 Rosetta 翻译选项。

在验证应用程序在 Apple 芯片和 Intel 芯片的 Mac 上正确运行之前,不要设置这个值。

如果想优先考虑一种架构,而又不阻止用户在翻译状态下运行应用程序,需要将 LSArchitecturePriority 键添加 Info.plist 中。这个键的值是一个有序的字符串数组,它定义了选择架构的优先级顺序。

总结

本文介绍了创建可以运行在 Apple 芯片和 Intel 芯片上得 macOS 应用程序或其他可执行文件的方式。需要通过设置条件编译来区分不同架构的代码,编译时可以选择通过 Xcode 或者 makefile 来实现。

最后需要通过 lipo 命令当两种架构合并成一个文件。

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgcbcch
系列文章
更多 icon
同类精品
更多 icon
继续加载