为什么我在 Apple Silicon 上编译的本机应用程序有时构建为 arm64,有时构建为 x86_64?

Why does my native application compiled on Apple Silicon sometimes build as arm64 and sometimes build as x86_64?

我有一个基本的 C 程序:

#include <stdio.h>

int main() {
  printf("Hello, world!\n");
}

当我在 Apple Silicon 设备上使用 cc 直接编译它时,它会生成一个 arm64 可执行文件:

% cc hello.c -o hello

% file hello
hello: Mach-O 64-bit executable arm64

% ./hello
Hello, world!

但是,当我通过 CMake 或 Ninja 等构建系统构建它时,它会生成一个 x86_64 二进制文件:

% ./my-build-system

% file hello
hello: Mach-O 64-bit executable x86_64

我已经验证构建脚本是 运行ning 的命令与我自己 运行 的命令相同。如果我自己复制并粘贴命令 运行,生成的可执行文件又是 arm64.

当您的构建命令不包含要构建的体系结构的特定标志时,Apple 提供的编译器工具,如 cc,会根据 [=36] 的体系结构执行某种自省=]调用进程。这意味着如果您的构建系统尚未针对 arm64 进行本地编译,您可能会看到此行为,因为编译器会假设您要针对 x86_64!

进行构建

您可以通过使用 arch 工具在 x86_64 模式下对 cc 可执行文件 运行 进行演示:

% arch -x86_64 cc hello.c -o hello

% file hello
hello: Mach-O 64-bit executable x86_64

作为变通方法,您可以引入一个始终重置为本机架构的 shim 编译器。将其保存为 force-arm64-cc 并使其可执行:

#!/usr/bin/env bash

# Note we are using arm64e because `cc` does not have an arm64 binary!
exec arch -arm64e cc "$@"

然后您可以使用此 shim 代替 cc:

% CC=$PWD/force-arm64-cc ./my-build-system

% file hello
hello: Mach-O 64-bit executable arm64

正确的长期解决方案是在编译时指定目标架构:

% arch -x86_64 cc -arch arm64 hello.c -o hello

% file hello
hello: Mach-O 64-bit executable arm64

但是,当您 重建 二进制文件时,这当前会生成伪造的可执行文件,这在编辑-编译-运行 循环中很常见:

% ./hello
zsh: killed     ./hello

另请参阅:

  • Why does my native arm64 application built using an x86_64 build system fail to be code signed unless I remove the previous executable?