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 withdefined(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 inKoins/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.