Using x86 libraries and OpenMP on macOS arm64 architecture

Viewed 4258

I have a MacBook M1 and have installed a library on my machine that was compiled for an x86 / Intel architecture. I have some source code that uses OpenMP. I would like to compile my code and link my executable to the x86 library using a clang compiler.

I am able compile source code with no x86 dependencies by following the instructions here, using an implementation of clang that is distributed with brew.

However when I try to compile with the -arch x86_64 argument and link to the x86 library I find that clang tries to link my executable to an OpenMP library that is built for the arm64 architecture.

Is it possible to install a version of clang on a MacBook M1 where the OpenMP libraries are built for x86 architectures?

Here is an example of an error that I get using my current setup, even when not linking to an x86 library.

Source code:

#include <omp.h>
int main()
{
    return 0;
}

Call to compiler:

/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

Error message:

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)
3 Answers

Using an x86 installation of brew solves the problem for me. Here is a minimal set of commands for installing x86 variants of brew and clang, and then compiling my C/C++ code:

# 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

The brew application is now installed in two separate locations on my machine:

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

and clang is installed in three separate locations:

# 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

Brew can support parallel x86 and Arm installations on the MacOS M1 machines. So what you need to do is use the x86 installation set and ensure that your PATH is appropriately set.

It installs x86_64 applications in /usr/local (e.g. /usr/local/bin/brew) and aarch64 ones in /opt/homebrew (e.g. /opt/homebrew/bin/brew).

See https://docs.brew.sh/Installation

First of all, running x86 binaries on M1 ARM processors is possible thanks to Rosetta but this is experimental and thus does not always works.

Is it possible to install a version of clang on a MacBook M1 where the OpenMP libraries are built for x86 architectures?

This should be possible thanks to cross-compilation. At least, Clang theoretically support that (using the option -target). The best way is to retrieve the binaries from a package manager or compile libomp directly from the source code (you can follow the directives here).

Please keep in mind that while x86_64 binaries could be run on M1 processors with Rosetta, libraries of different architecture cannot be mixed together. This means that you should compile all the dependencies (including the one of libomp although it should not have a lot of dependencies).

The best solution (recommanded, safer, faster and simpler) is to use native libraries and so to rebuild libraries for the M1 processors (possibly from the sources if needed).

Related