25

How can I compile a C project on macOS 11 (Intel) to work on Silicon?

My current build script is as simple as:

./configure
make
sudo make install

I've tried using the --host and --target flags with aarch64-apple-darwin and arm-apple-darwin without any luck.

The binary always defaults to x86_64:

> file foobar.so
foobar.so: Mach-O 64-bit bundle x86_64

UPDATE: It seems cc and gcc aren't found when --host is specified.

checking for arm-apple-darwin-cc... no
checking for arm-apple-darwin-gcc... no
Till
  • 1,107
  • 12
  • 28

3 Answers3

15

I found a hint on this page to use this:

-target arm64-apple-macos11

When I run this from my mac:

clang++ main.cpp -target arm64-apple-macos11

The resulting a.out binary is listed as:

% file a.out
a.out: Mach-O 64-bit executable arm64

I have XCode 12.2 installed.

I don't have an Arm Mac in front of me, so I'm assuming this works.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • How can I specify `clang++` as the compiler when using `./configure`? – Till Dec 21 '20 at 02:49
  • You probably don't have to. Clang is the default compiler and `g++` command line is really just a shim that forwards to clang. – selbie Dec 21 '20 at 02:53
  • Unfortunately we have to use ./configure, since we have several flags. Is there any way to tell `./configure` to use `clang++`? – Till Dec 27 '20 at 19:31
  • 1
    I'm not an expert on autoconf (which is the tool that genrates configure scripts). But you probably just need to have the script set `CC=clang` and `CXX=clang++` – selbie Dec 28 '20 at 02:13
  • We tried that without any luck. Autotools ‍♂️ – Till Mar 26 '21 at 16:03
  • I get `/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h:807:2: error: Unsupported architecture #error Unsupported architecture` type errors when I try this. – Alec Jacobson May 29 '21 at 17:52
  • @AlecJacobson - are you on the latest version of XCode? And have installed all the latest command line tools? – selbie May 29 '21 at 17:53
  • Yes, I have the latest. It's now working if I use `clang++ main.cpp -target arm64-apple-macos11 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk` – Alec Jacobson May 31 '21 at 20:53
6

We ended up solving solving this and being able to compile darwin-arm64 and debian-aarch64 binaries on GitHub Actions' x86-64 machines.

We pre-compiled all our dependencies for arm64 and linked them statically as well as dynamically.

export RELAY_DEPS_PATH=./build-deps/arm64
export PKG_CONFIG_PATH=./build-deps/arm64/lib/pkgconfig

cd ./relay-deps
TARGET=./build-deps make install

cd ./relay
phpize
./configure CFLAGS='-target arm64-apple-macos' \
  --host=aarch64-apple-darwin \
  --enable-relay-jemalloc-prefix
  [snip...]

make

# Dynamically linked binary
cc --target=arm64-apple-darwin \
  ${wl}-flat_namespace ${wl}-undefined ${wl}suppress \
  -o .libs/relay.so -bundle .libs/*.o \
  -L$RELAY_DEPS_PATH/lib -lhiredis -ljemalloc_pic [snip...]

# re-link to standard paths
./relay-deps/utils/macos/relink.sh .libs/relay.so /usr/local/lib
cp .libs/relay.so modules/relay.so

# Build a statically linked shared object
cc --target=arm64-apple-darwin \
  ${wl}-flat_namespace ${wl}-undefined ${wl}suppress \
  -o .libs/relay-static.so -bundle .libs/*.o \
  $RELAY_DEPS_PATH/lib/libhiredis.a \
  $RELAY_DEPS_PATH/lib/libjemalloc_pic.a \
  [snip...]

The relink.sh:

#!/bin/bash
set -e

printUsage() {
    echo "$0 <shared-object> <prefix>"
    exit 1
}

if [[ ! -f "$1" || -z "$2" ]]; then
    printUsage
    exit 1
fi

INFILE=$1
PREFIX=$2

links=(libjemalloc libhiredis [snip...])

if [ -z "$PREFIX" ]; then
    PREFIX=libs
fi

for link in ${links[@]}; do
    FROM=$(otool -L "$INFILE"|grep $link|awk '{print $1}')
    FILE=$(basename -- "$FROM")
    TO="$PREFIX/$FILE"

    echo "$FROM -> $TO"
    install_name_tool -change "$FROM" "$TO" "$1"
done
Till
  • 1,107
  • 12
  • 28
4

Mr. Curious was curious about cross-compilation to M1 as well. One unexpected solution is Zig. It aims to be the best way to cross-compile C, among other things; it easily targets M1 from Linux.

There was a series of streams about cross compiling to M1 a couple of weeks ago: Part 1 shows how to use Zig as a cross-compiler in existing makefiles, and in Part 3 they successfully demonstrate compiling Redis on Linux for M1.

Highly recommended.

Mr. Curious
  • 837
  • 9
  • 14