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 !

5 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

Hey! did you tried to compile this with the new Xcode 16.4 / which includes iOS 18.5 sdk to compile?
I currently get the following error, any idea?

CC /Users/michael/Entwicklung/ios_otp26/otp/erts/emulator/zlib/obj/aarch64-apple-ios/opt/zutil.o
In file included from zlib/zutil.c:8:
zlib/zutil.h:170:11: warning: ‘OS_CODE’ macro redefined [-Wmacro-redefined]
170 | # define OS_CODE 19
| ^
zlib/zutil.h:141:11: note: previous definition is here
141 | # define OS_CODE 7
| ^
In file included from zlib/zutil.c:10:
In file included from zlib/gzguts.h:21:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/stdio.h:61:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/_stdio.h:318:7: error: expected identifier or ‘(’
318 | FILE fdopen(int, const char ) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fdopen));
| ^
zlib/zutil.h:147:33: note: expanded from macro ‘fdopen’
147 | # define fdopen(fd,mode) NULL /
No fdopen() /
| ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_null.h:26:16: note: expanded from macro ‘NULL’
26 | #define NULL ((void
)0)
| ^
In file included from zlib/zutil.c:10:
In file included from zlib/gzguts.h:21:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/stdio.h:61:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/_stdio.h:318:7: error: expected ‘)’
zlib/zutil.h:147:33: note: expanded from macro ‘fdopen’
147 | # define fdopen(fd,mode) NULL /
No fdopen() /
| ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_null.h:26:16: note: expanded from macro ‘NULL’
26 | #define NULL ((void
)0)
| ^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/_stdio.h:318:7: note: to match this ‘(’
zlib/zutil.h:147:33: note: expanded from macro ‘fdopen’
147 | # define fdopen(fd,mode) NULL /* No fdopen() /
| ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_null.h:26:15: note: expanded from macro ‘NULL’
26 | #define NULL ((void
)0)
| ^
In file included from zlib/zutil.c:10:
In file included from zlib/gzguts.h:21:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/stdio.h:61:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/_stdio.h:318:7: error: expected ‘)’
318 | FILE fdopen(int, const char ) __DARWIN_ALIAS_STARTING(__MAC_10_6, __IPHONE_2_0, __DARWIN_ALIAS(fdopen));
| ^
zlib/zutil.h:147:33: note: expanded from macro ‘fdopen’
147 | # define fdopen(fd,mode) NULL /
No fdopen() /
| ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_null.h:26:22: note: expanded from macro ‘NULL’
26 | #define NULL ((void
)0)
| ^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.5.sdk/usr/include/_stdio.h:318:7: note: to match this ‘(’
zlib/zutil.h:147:33: note: expanded from macro ‘fdopen’
147 | # define fdopen(fd,mode) NULL /
No fdopen() /
| ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/17/include/__stddef_null.h:26:14: note: expanded from macro ‘NULL’
26 | #define NULL ((void
)0)
| ^
zlib/zutil.c:135:22: warning: a function definition without a prototype is deprecated in all versions of C and is not supported in C23 [-Wdeprecated-non-prototype]
135 | const char * ZEXPORT zError(err)
| ^
zlib/zutil.c:307:22: warning: a function definition without a prototype is deprecated in all versions of C and is not supported in C23 [-Wdeprecated-non-prototype]
307 | voidpf ZLIB_INTERNAL zcalloc(opaque, items, size)
| ^
zlib/zutil.c:317:20: warning: a function definition without a prototype is deprecated in all versions of C and is not supported in C23 [-Wdeprecated-non-prototype]
317 | void ZLIB_INTERNAL zcfree(opaque, ptr)
| ^
4 warnings and 3 errors generated.
make[4]: *** [/Users/michael/Entwicklung/ios_otp26/otp/erts/emulator/zlib/obj/aarch64-apple-ios/opt/zutil.o] Error 1
make[3]: *** [opt] Error 2
make[2]: *** [opt] Error 2
make[1]: *** [emu] Error 2
make: *** [emulator] Error 2