Coding

Fun With Apple Multi-Arch Binaries

Apple macOS has for many years supported the ability to have binaries for multiple platforms in one executable. Upon execution the correct binary data is loaded into RAM. This has multiple names such as “Universal”, “fat binary” or “Multi-Architecture Binaries”. These were really useful when Apple was transition from PowerPC to Intel CPUs, a single binary would execute on both platforms. It could be useful in the future if, as many predict, Apple move from Intel to ARM CPUs.

In this post I’ll talk about the m4 script I wrote at HP to use this feature for combined 32bit and 64bit Intel binaries (back when that was relevant).

I was working on a high-performance asynchronous C API to connect to MySQL servers around 2014 which was to be used by HP. As part of this I wanted to make it work on as many platforms as possible. Quite a few people in my division used Apple hardware so I wanted to make it work on that. At the time I had access to both 32bit and 64bit Apple hardware and wanted my binaries to work on both. Hence building this solution.

I was using autotools back then as it is my preferred build system, so after figuring out how to do it I created a script which would build a single library that simultaneously worked for x86 and x86_64 platforms. The script is as follows:

# SYNOPSIS
#
#   AX_UNIVERSAL_BINARY()
#
# DESCRIPTION
#
#   --enable-universal-binary
#
# LICENSE
#
#  Copyright 2014 Hewlett-Packard Development Company, L.P.
#  All rights reserved.
#
# [CUT BSD 3-Clause license, see SPDX-License-Identifier: BSD-3-Clause]

#serial 2

AC_DEFUN([AX_UNIVERSAL_BINARY],
    [AC_ARG_ENABLE([universal-binary],
                   [AC_HELP_STRING([--enable-universal-binary=auto],
                                   [Apple combined x86 & x86_64 binary support])],,
                   [enable_universal_binary=auto])
    have_universal_binary=no
    if test x"enable_universal_binary" != x"no"; then
        AC_CANONICAL_HOST
        AC_MSG_CHECKING([for universal binary support])
        case $host in *-apple-darwin*)
            save_CFLAGS="$CFLAGS"
            save_CXXFLAGS="$CXXFLAGS"
            save_LDFLAGS="$LDFLAGS"
            CFLAGS="$CFLAGS -arch x86_64 -arch i386"
            CXXFLAGS="$CXXFLAGS -arch x86_64 -arch i386"
            LDFLAGS="$LDFLAGS -arch x86_64 -arch i386"
            AC_LINK_IFELSE([AC_LANG_SOURCE([int main() {return 0;}])],
                          [have_universal_binary=yes])
            if test x"$have_universal_binary" = x"no"; then
                CFLAGS="$save_CFLAGS"
                CXXFLAGS="$save_CXXFLAGS"
                LDFLAGS="$save_LDFLAGS"
            fi
            ;;
        esac
        AC_MSG_RESULT($have_universal_binary)
    fi
    case "$have_universal_binary:$enable_universal_binary" in
        no:yes) AC_MSG_ERROR([no universal binary support on this host]) ;;
        yes:*)  AC_MSG_WARN([disabling dependency tracking])
                AM_CONDITIONAL([AMDEP],[false])
                AM_CONDITIONAL([am__fastdepCC],[false])
                AMDEPBACKSLASH=
                ;;
    esac])

You can see here that it first looks “Apple Darwin” which is the macOS kernel and the advertised platform. If we don’t have this then we error saying that we cannot do this.

In the compiler we specify multiple archs, in this case x86_64 and i386. The compiler knows what to do with this and we have a very simple test to build to make sure it works.

If we get this far the script disables dependency tracking. I honestly can’t remember why now (it has been 6 years) but I know dependency tracking didn’t work.

Summary

There have been attempts to do this in Linux too using a project called “FatELF“. This doesn’t appear to have taken off but I think it would be very interesting if more work was put into this. Especially with ARM and Intel both becoming major Linux platforms.

LinuxJedi

Share
Published by
LinuxJedi

Recent Posts

Diagnosing an Amiga 1200 Data Path Fault

I recently acquired an Amiga 1200 motherboard in a spares/repairs condition for about £100 recently.…

2 days ago

Bare Metal “Hello World” on an STM32MP135F-DK

Whilst I do like working with STM32 development boards, some basic information I need can…

3 days ago

Two special Amiga 4000s: Diagnosing Jops

When I last left this blog series, the first of Stoo Cambridge's A4000s had gone…

6 days ago

Joining wolfSSL

At the beginning of November, I started working for wolfSSL. Now that I'm a week…

1 week ago

Two special Amiga 4000s: Rebuilding Jools

In my previous post, I had the Amiga 4000 known as Jools mostly repaired, there…

4 weeks ago

Two special Amiga 4000s: Repairing Jools

In my last post, I created a list of things I needed to repair on…

4 weeks ago