7

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)
Philip Maybank
  • 413
  • 4
  • 14
  • Last time I checked, the ARM processor had a completely different assembly language and microcode than the Intel processor. Also neither one can execute the other's machine code. This means that an executable targeted for an x86 architecture won't run on an ARM platform without some kind of interpreter. – Thomas Matthews May 04 '21 at 14:44
  • @ThomasMatthews Isn't [Rosetta](https://en.wikipedia.org/wiki/Rosetta_(software)) used to solve that problem? – Zoso May 04 '21 at 15:37

3 Answers3

17

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
Philip Maybank
  • 413
  • 4
  • 14
  • Thanks! That compiles and runs c/c++ codes with `x86_64` isa on `arm64` succesfully but it is worth to mention that may have been appear `linker` related errors if system is using your native(arm64) linker or like when using `-static` flag: https://stackoverflow.com/questions/3801011/ld-library-not-found-for-lcrt0-o-on-osx-10-6-with-gcc-clang-static-flag So, I think, it should be considered by who is looking for. – Celuk Mar 17 '22 at 07:04
  • Wow, installing another brew for x86 solved a year long problem that we had with getting LightGBM to use the correct libomp version. Thank you! – Hans Bambel Jan 30 '23 at 15:16
2

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

Jim Cownie
  • 2,409
  • 1
  • 11
  • 20
0

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).

Jérôme Richard
  • 41,678
  • 6
  • 29
  • 59
  • I can see how this is the best solution in cases where you have the source code of the library and are confident in knowing how to compile it. To cover other cases, do you know whether there is anywhere I could put in a feature request for the brew variant of clang? It would be nice if the brew variant of clang supported the -arch x86_64 argument in the same way that the Apple variant of clang does. – Philip Maybank May 05 '21 at 10:11
  • I think this answers rather if the Q was about cross-compilation, but this OP is about running the code on M1. – Tchakabam Apr 28 '22 at 12:33
  • > is possible thanks to Rosetta but this is experimental and thus does not always works is an arguably useful comment :) the general case is that it works fine, and is prod-ready. btw where does it say that Rosetta is (still) experimental at all itfp? – Tchakabam Apr 28 '22 at 12:35
  • > It would be nice if the brew variant of clang supported the -arch x86_64 argument in the same way that the Apple variant of clang does. --> maybe you are confusing something here? the arch tool is not related to clang. – Tchakabam Apr 28 '22 at 12:38
  • > 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). --> that is a fully opinionated idea. there isnt any performance drawback with running x86 on M1 (also as arch will cache to run it from arm shell directly too, maybe even convert executable binary), and if that is more convenient to build for you for any reason -- then do it :) Especially if it *simpler* - for you. – Tchakabam Apr 28 '22 at 12:42