在 macOS arm64 架构上使用 x86 库和 OpenMP

7
我有一台MacBook M1,已经在我的设备上安装了一个为x86 / Intel架构编译的库。我有一些使用OpenMP的源代码。我想使用clang编译我的代码,并链接到x86库。
我可以按照这里的说明编译没有x86依赖项的源代码,使用brew分发的clang实现。
但是当我尝试使用-arch x86_64参数进行编译并链接到x86库时,我发现clang会尝试将我的可执行文件链接到为arm64架构构建的OpenMP库。
是否可能在MacBook M1上安装一个版本的clang,其中OpenMP库是针对x86架构构建的?
以下是我在当前设置下使用的错误示例,即使不链接到x86库也会出现这个错误。
源代码:
#include <omp.h>
int main()
{
    return 0;
}

编译器调用:

/opt/homebrew/opt/llvm/bin/clang++ -arch x86_64 omp_ex.cpp \ 
    -L/opt/homebrew/opt/llvm/lib -Wl,-rpath,/opt/homebrew/opt/llvm/lib \
    -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include

错误信息:
ld: in '/opt/homebrew/opt/llvm/lib/libunwind.dylib', building for macOS-x86_64 but attempting to link with file built for macOS-arm64
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)

上次我检查时,ARM处理器的汇编语言和微码与英特尔处理器完全不同。此外,两者都无法执行对方的机器代码。这意味着针对x86架构的可执行文件在没有某种解释器的情况下无法在ARM平台上运行。 - Thomas Matthews
@ThomasMatthews,难道不是使用Rosetta来解决这个问题的吗? - Zoso
3个回答

18

使用x86版本的brew安装程序,解决了我的问题。以下是一组最小的命令,用于安装x86版本的brew和clang,并编译我的C/C++代码:

# launch x86_64 shell
arch -x86_64 zsh  
# install x86_64 variant of brew 
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
# install x86_64 variant of clang
arch -x86_64 /usr/local/bin/brew install llvm 
# compile using x86_64 variant of clang
/usr/local/opt/llvm/bin/clang++ -arch x86_64 omp_ex.cpp

现在Brew应用程序已经在我的计算机上安装在两个不同的位置:

# arm64 (default) location
/opt/homebrew/bin/brew
# x86_64 location
/usr/local/bin/brew

而且clang被安装在三个不同的位置:

# Apple arm64 (default) location
/usr/bin/clang
# brew arm64 location
/opt/homebrew/opt/llvm/bin/clang
# brew x86_64 location
/usr/local/opt/llvm/bin/clang

谢谢!这个编译器可以成功地编译和运行使用x86_64指令集的C/C++代码在arm64上,但需要注意的是,如果系统正在使用本机(arm64)链接器或者使用-static标志时可能会出现与链接器相关的错误:https://dev59.com/P2865IYBdhLWcg3wduaH 因此,我认为这应该被考虑到寻找解决方案的人。 - Celuk
哇,为x86安装另一个brew解决了我们一年的问题,使得LightGBM使用正确的libomp版本。谢谢! - Hans Bambel

3
Brew可以在MacOS M1机器上支持并行的x86和Arm安装。因此,您需要使用x86安装集,并确保适当设置了PATH
它将x86_64应用程序安装在/usr/local(例如/usr/local/bin/brew),将aarch64应用程序安装在/opt/homebrew(例如/opt/homebrew/bin/brew)。
请参见https://docs.brew.sh/Installation

1

首先,由于Rosetta的存在,M1 ARM处理器上可以运行x86二进制文件,但这是“实验性的”,因此并不总是有效。

是否有可能在MacBook M1上安装一个clang版本,其中OpenMP库是为x86架构构建的?

这应该通过交叉编译来实现。至少理论上Clang支持这样做(使用选项-target)。 最好的方法是从软件包管理器中检索二进制文件,或者直接从源代码编译libomp(您可以按照这里的指示进行操作)。

请记住,虽然x86_64二进制文件可以在带有Rosetta的M1处理器上运行,但不同体系结构的库不能混合在一起。这意味着您应该编译所有依赖项(包括libomp的依赖项,尽管它不应该有很多依赖项)。

最佳解决方案(推荐、更安全、更快、更简单)是使用本地库,因此需要为M1处理器重新构建库(如果需要,可以从源代码开始)。

我能看出来在你有库的源代码并且自信知道如何编译时,这是最好的解决方案。为了涵盖其他情况,你知道是否有任何地方可以提出brew版本clang的功能请求吗?如果brew版本的clang以与苹果版本的clang相同的方式支持-arch x86_64参数,那将会很好。 - Philip Maybank
我认为这个回答更适用于跨编译的问题,但是这个OP是关于在M1上运行代码的。 - Tchakabam
由于Rosetta的存在,翻译是可能的,但这只是实验性的,并不总是有效。这是一个可以讨论的有用评论 :) 一般情况下它运行良好,可以使用在生产环境中。顺便问一句,ITFP上哪里说Rosetta仍然是实验性的? - Tchakabam
希望brew版本的clang能够像Apple版本的clang一样支持-arch x86_64参数。可能你在这里混淆了什么?arch工具与clang无关。 - Tchakabam
最佳解决方案(推荐,更安全,更快,更简单)是使用本地库,并根据需要为M1处理器重新构建库(可能从源代码开始)。--> 这是一个充满个人观点的想法。在M1上运行x86没有任何性能缺陷(也可以将架构缓存以直接从arm shell运行它,甚至可能转换可执行二进制文件),如果这对于任何原因更方便您构建 - 那就这么做 :) 尤其是如果这更“简单”- 对于您来说. - Tchakabam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接