Files
koins/apps/ios/Monero/toolchain/README.md
T

4.6 KiB

Monero native library for iOS

The wallet runs monero-project wallet2 (plus monero-cpp as the C++ API) on device. Everything is compiled into a single static archive that the app links.

Artifacts

File Architecture Platform
libs/libkoins_monero_merged.a arm64 iOS simulator
libs/libkoins_monero_device.a arm64 iOS device

Both are needed: they are the same CPU architecture but different platforms, so they cannot be merged into one fat archive. project.yml selects the right one per SDK.

Prerequisites

  • Xcode with the iOS device and simulator SDKs
  • CMake 3.2x (monero 0.18 is not tested with CMake 4)
  • GNU make (the builds use the "Unix Makefiles" generator)
  • Roughly 10 GB of disk and a long coffee break

Sources

  • monero-project v0.18.5.1
  • monero-cpp (woodser), which keeps monero-project at external/monero-project

Toolchain customisations

The files under depends/ are the ones modified from upstream, kept here so the archive can be regenerated:

File Change
depends/hosts/ios.mk new host; IOS_PLATFORM=SIMULATOR (default) or DEVICE selects the SDK and the target triple (aarch64-apple-ios[-simulator])
depends/packages/packages.mk ios_packages := boost openssl zeromq expat unbound sodium (no libiconv)
depends/packages/boost.mk boost for the ios toolset: darwin toolset, libtool archiver, c++11, no b2 python
depends/packages/zeromq.mk ios config opts (--host=aarch64-apple-darwin), no libsodium, no curve
depends/packages/unbound.mk drops the autoconf dependency
depends/packages/sodium.mk drops the autoconf dependency
depends/funcs.mk create the prefix lib directory before extracting dependency archives

One source change is also required, in monero-project:

  • src/cryptonote_basic/miner.cpp — wrap the IOKit includes and the related code with defined(TARGET_OS_OSX) && TARGET_OS_OSX; IOKit is unavailable on iOS. Two locations, around lines 51 and 986.

Two more steps are needed when targeting a device:

  • Copy monero's patched boost serialisation headers into the dependency prefix, because monero's build otherwise only finds them for the platform it was installed for:

    cp external/boost/archive/portable_binary_*.hpp \
       contrib/depends/$HOST/include/boost/archive/
    
  • randomx's AArch64 JIT references __clear_cache, which libSystem exports on macOS and the simulator but not on iOS. The app supplies it in Koins/Support/ClearCache.c.

Build

Set PLATFORM to SIMULATOR or DEVICE; the only differences are the depends host flag and the output archive name.

MONERO=/path/to/monero-project
PLATFORM=SIMULATOR          # or DEVICE
HOST=aarch64-apple-ios

# 1. Cross-compiled dependencies (boost, openssl, zeromq, expat, unbound, sodium)
cd "$MONERO/contrib/depends"
make HOST=$HOST IOS_PLATFORM=$PLATFORM -j"$(sysctl -n hw.ncpu)"

# 2. monero-project, static wallet library
cd "$MONERO"
mkdir -p build/ios-$PLATFORM && cd build/ios-$PLATFORM
cmake -G "Unix Makefiles" \
  -DCMAKE_TOOLCHAIN_FILE="$MONERO/contrib/depends/$HOST/share/toolchain.cmake" \
  -DCMAKE_BUILD_TYPE=Release \
  -DSTATIC=ON -DBUILD_SHARED_LIBS=OFF \
  -DBUILD_TESTS=OFF -DBUILD_DOCUMENTATION=OFF -DUSE_DEVICE_TREZOR=OFF \
  ../..
make -j"$(sysctl -n hw.ncpu)" wallet        # produces lib/libwallet.a

# 3. monero-cpp
cd /path/to/monero-cpp
mkdir -p build-ios-$PLATFORM && cd build-ios-$PLATFORM
cmake -G "Unix Makefiles" \
  -DCMAKE_TOOLCHAIN_FILE="$MONERO/contrib/depends/$HOST/share/toolchain.cmake" \
  ../..
make -j"$(sysctl -n hw.ncpu)"               # produces libmonero-cpp.a

# 4. Merge into one archive for the app
libtool -static -o libkoins_monero_merged.a \
  libmonero-cpp.a \
  "$MONERO/build/ios-$PLATFORM/lib/libwallet.a" \
  "$MONERO/build/ios-$PLATFORM"/src/*/lib*.a \
  "$MONERO/build/ios-$PLATFORM"/external/*/lib*.a \
  "$MONERO/build/ios-$PLATFORM"/contrib/epee/src/libepee.a \
  "$MONERO/contrib/depends/$HOST"/lib/lib*.a

Copy the result to libs/, using libkoins_monero_merged.a for the simulator and libkoins_monero_device.a for the device.

Notes

  • Only the simulator archive is needed to run in the simulator; the device archive is needed for a real iPhone, and Xcode requires the matching one at link time.
  • Building the device slice after a simulator build requires moving the simulator depends prefix aside first, since depends installs into contrib/depends/<host> and both platforms share the host name.
  • The app also links the OpenSSL that is embedded in this archive, which is how the XRP wallet gets secp256k1 without an extra dependency.