Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 679
Till Avatar asked Dec 18 '20 17:12

Till


People also ask

Can you code on Apple silicon?

Debug and Test Your CodeApple silicon supports all debugging and testing tools found on Intel-based Mac computers. Use the Xcode IDE to set and monitor breakpoints and monitor other aspects of your app's behavior. Use lldb from the command line to perform similar tasks outside of the Xcode interface.

Is Xcode optimized for Apple silicon?

Xcode automatically creates a binary slice optimized for Apple silicon Macs and another for Intel-based Macs, then puts them together as a single app bundle thats ready to distribute or submit to the Mac App Store. Optimize for the new MacBook Pro display.

What is Apple silicon ARM64?

The Mac transition to Apple silicon is the process of changing the central processing units (CPUs) of Apple Inc.'s line of Mac computers from Intel's x86-64 processors to Apple-designed systems on a chip that use the ARM64 architecture.

Do Macs use binary?

A universal binary runs natively on both Apple silicon and Intel-based Mac computers, because it contains executable code for both architectures.


3 Answers

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.

like image 158
selbie Avatar answered Oct 14 '22 04:10

selbie


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.

like image 31
Mr. Curious Avatar answered Oct 14 '22 04:10

Mr. Curious


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
like image 4
Till Avatar answered Oct 14 '22 03:10

Till