Cross Compiling Erlang for iOS

Hi community!

I want to compile and run Erlang on iOS, following this guide in the repository:

Right now, I’m stuck with statically linking OpenSSL. The latest version of OpenSSL, 3.3.0, is cloned from Github.

I used the following script to configure and install OpenSSL:

./Configure --prefix=/opt/openssl --openssldir=/opt/openssl no-shared
make -j `nproc` && sudo make install_sw

Then, I tried to cross-compile Erlang for iOS:

./otp_build configure \
  --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf \
  --with-ssl=/opt/openssl \
  --without-javac \
  --disable-shared \
  --disable-dynamic-ssl-lib

which led to an error, with the following error message:


checking if we can add -Wdeclaration-after-statement to DED_WARN_FLAGS (via CFLAGS)… yes
checking if we can add -Werror=return-type to DED_WERRORFLAGS (via CFLAGS)… yes
checking if we can add -Werror=implicit to DED_WERRORFLAGS (via CFLAGS)… yes
checking if we can add -Werror=undef to DED_WERRORFLAGS (via CFLAGS)… yes
checking if we can add -fno-common to DED_CFLAGS (via CFLAGS)… yes
checking if we can add -fno-strict-aliasing to DED_CFLAGS (via CFLAGS)… yes
checking for arm64-apple-ios-ld… xcrun -sdk iphoneos ld -arch arm64
checking for static compiler flags… -Werror=undef -Werror=implicit -Werror=return-type -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS -fno-strict-aliasing -fno-common -mios-version-min=7.0.0 -fno-common -Os -D__IOS__=yes -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER
checking for basic compiler flags for loadable drivers… -fno-strict-aliasing -fno-common -mios-version-min=7.0.0 -fno-common -Os -D__IOS__=yes -fPIC
checking for compiler flags for loadable drivers… -Werror=undef -Werror=implicit -Werror=return-type -Wdeclaration-after-statement -Wall -Wstrict-prototypes -Wmissing-prototypes -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS -fno-strict-aliasing -fno-common -mios-version-min=7.0.0 -fno-common -Os -D__IOS__=yes -fPIC
checking for linker for loadable drivers… xcrun -sdk iphoneos ld -arch arm64
checking for linker flags for loadable drivers… -L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.2.sdk/usr/lib/ -r -v
checking for ‘runtime library path’ linker flag… not found
checking for multiarch directory… not found
checking size of void *… 8
checking for static zlib… no
checking how to run the C preprocessor… xcrun -sdk iphoneos cc -arch arm64 -E
checking for grep that handles long lines and -e… /usr/bin/grep
checking for egrep… /usr/bin/grep -E
checking for OpenSSL header in /opt/openssl… yes
checking for OpenSSL in /opt/openssl… configure: error: dynamic linking against crypto library disabled by user, but no static library found in /opt/openssl
ERROR: /Users/qhwa/tools/otp/lib/crypto/configure failed!

At this point, I can skip linking OpenSSL with --without-ssl, which I did with a small patch to remove the default -shared argument to the ld command since seemingly ld on my system doesn’t support it, but I think that would cause more problems running the compiled Erlang without SSL. So I’d rather try to understand and fix the problem. I didn’t find much information after several search attempts and consulting ChatGPT.

I would be very grateful if anyone could help!

Here’s my environment:

  • Machine: Mac Mini with M2 chip
  • OS: MacOS 14.2.1
  • Erlang version: master branch and 26.2.1
  • OpenSSL version: 3.3.0-dev
  • Gcc version:

    gcc -v
    Apple clang version 15.0.0 (clang-1500.1.0.2.5)
    Target: arm64-apple-darwin23.2.0
    Thread model: posix
    InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

  • ld version

    ld -v
    @(#)PROGRAM:ld PROJECT:dyld-1022.1
    BUILD 05:27:37 Dec 7 2023
    configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h
    will use ld-classic for: armv6 armv7 armv7s arm64_32 i386 armv6m armv7k armv7m armv7em
    LTO support using: LLVM version 15.0.0 (static support for 29, runtime is 29)
    TAPI support using: Apple TAPI version 15.0.0 (tapi-1500.0.12.8)
    Library search paths:
    Framework search paths:

1 Like

You can take a look how GitHub - elixir-desktop/runtimes: Erlang / Elixir runtimes for Android and iOS does it.

4 Likes

Thank you @LostKobrakai . Indeed, elixir-desktop has lots of wisdom and knowledge in it. Actually, it was what I started with initially. I switched to a manual approach because the script inside it failed with OTP, at least for 26.2.1 which I tested. Now I know how to fix it, but at that time, I decided to figure out a minimum workout.

After studying the scripts in elixir-desktop I learned that I must also cross-compile OpenSSL. So the script to compile OpenSSL is now:

./Configure ios64-xcrun --prefix=/opt/openssl # <- change: now I cross compile OpenSSL
make -j `nproc` && sudo make install_sw

Now with the same initial ./otp_build configure ... and ./otp_build boot, I can successfully generate libbeam.a!

$ find . -name libbeam.a

./bin/aarch64-apple-ios/libbeam.a
./bin/aarch64-apple-darwin23.2.0/libbeam.a

I haven’t tested them out, but the compilation is successful, and I’m so excited! Appreciate your guidance; you saved my day @LostKobrakai !

4 Likes

I forgot to mention that it’s also crucial to set the LIBS environment variable.

These are my scripts for now:

  1. build-openssl.sh

    #!/bin/bash
    set -xeuo pipefail
    
    ./Configure ios64-xcrun --prefix=/opt/openssl-ios64
    make clean
    make -j `nproc`
    sudo make install_sw
    
  2. build-otp.sh

    #!/bin/bash
    set -xeuo pipefail
    
    (
      OPEN_SSL_DIR=/opt/openssl-ios64
    
      export LIBS=${OPEN_SSL_DIR}/lib/libcrypto.a
    
      ./otp_build configure \
        --prefix=$(pwd)/_build/ios64 \
        --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf \
        --with-ssl=${OPEN_SSL_DIR} \
        --disable-dynamic-ssl-lib
    
      ./otp_build boot
    )
    
1 Like