Search code examples
cmacosarmautotoolsapple-silicon

Build Apple Silicon binary on Intel machine


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

Solution

  • 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