Skip to content

build(openfhe-sys): cross-compile and link for iOS and Android - #2

Open
javruben wants to merge 3 commits into
identikey:mainfrom
javruben:mobile-cross-build
Open

javruben wants to merge 3 commits into
identikey:mainfrom
javruben:mobile-cross-build

Conversation

@javruben

Copy link
Copy Markdown

Makes recrypt-openfhe-sys cross-compile and link for iOS and Android. NAOMS has shipped these build changes on its desktop, iOS and Android builds since June, from a fork. This PR brings them upstream so we can pin your main again.

What changes (crates/recrypt-openfhe-sys/build.rs only)

  • Target-aware, not host-aware. It reads CARGO_CFG_TARGET_OS instead of cfg!(target_os), which reflects the host a build script runs on, not the target.
  • OPENFHE_INSTALL_DIR. An optional absolute path to a target-specific OpenFHE install, such as an iOS device or simulator build or an aarch64-android build. The default stays vendor/openfhe-install. It also adds rerun-if-env-changed.
  • +whole-archive linking for OPENFHEpke/core/binfhe_static, using the propagating rustc-link-lib form.
    • pke, core and binfhe depend on each other in a cycle, and a cdylib tolerates undefined symbols.
    • With plain static=, a downstream Android cdylib ended up missing the CKKS typeinfo and vtables, so dlopen failed on the device ("typeinfo for lbcrypto::CryptoParametersCKKSRNS is missing").
  • C++ runtime per target: c++ on macOS and iOS, c++_shared on Android (the NDK convention for cdylibs), stdc++ on Linux.
  • No OpenMP on iOS or Android. OpenFHE is built with WITH_OPENMP=OFF there.
  • -Wno-error on iOS and Android, where OpenFHE headers trip -Werror under clang.
  • The panic message for missing OpenFHE libraries now explains the cross-build route.

+whole-archive also applies on desktop now. It only force-includes members of OpenFHE's own static libraries.

Verification

  • The branch merges cleanly into main at 0be9ed9 (git merge-tree). build.rs has not changed upstream since 88ec30f.
  • Linux x86_64 (Ubuntu), merged with main:
    • OpenFHE was built from the pinned submodule with BUILD_STATIC=ON, WITH_OPENMP=OFF.
    • Ran cargo test -p recrypt-openfhe-sys -p recrypt-core --lib -- --test-threads=1.
    • Result: recrypt-core 29 passed, recrypt-openfhe-sys 3 passed, 0 failed.
    • That run included the real lattice tests: roundtrips (including 95/96 bytes and the random boundary), keypair generation and the recryption flow.
  • iOS (device and simulator) and Android aarch64: the same build.rs has been used in NAOMS's mobile builds since June, at fork commits d786b42 and 773da1b. These were not re-run against current main for this PR.
  • macOS desktop was not re-run for this PR.

Not included: one Android fix that belongs in OpenFHE

OpenFHE's src/core/lib/utils/get-call-stack.cpp (around line 33) guards the glibc execinfo.h/backtrace() path with #if defined(__linux__) && defined(__GNUC__). Android is __linux__, clang defines __GNUC__, and bionic has no execinfo.h, so the Android build fails. Adding && !defined(__ANDROID__) falls through to the existing no-op #else.

Our fork vendored all of OpenFHE to carry that one line, which isn't right for this repo. It probably belongs upstream in openfheorg, or in a patch step here. Happy to do either, whichever you prefer.

Commits keep their original authorship. The last commit only removes downstream-specific wording from the comments.

🤖 Generated with Claude Code

javruben and others added 3 commits October 21, 2026 05:37
Make recrypt-openfhe-sys cross-compile for iOS and Android (NDK) without a
local [patch] override:

- resolve_openfhe_install(): OPENFHE_INSTALL_DIR env (target-specific prebuilt
  cone) takes priority over the desktop vendor/openfhe-install default.
- target_os() via CARGO_CFG_TARGET_OS (build scripts run on the HOST, so
  cfg!(target_os) is wrong for cross builds).
- C++ stdlib link: macos/ios -> c++, android -> c++_shared (NDK cdylib
  convention; APK bundles libc++_shared.so), linux -> stdc++.
- link_openmp(): no-op on ios/android (OpenFHE built WITH_OPENMP=OFF).
- -Wno-error on ios/android (OpenFHE headers trip -Werror under those clangs).

Lets the NAOMS fork-pin build android directly with OPENFHE_INSTALL_DIR pointing
at the per-ABI OpenFHE cone — no worktree-local clone / committed [patch] to a
gitignored path (1054 cargo-patch-fix).
The mobile (android/iOS) artifact consuming OpenFHE is a cdylib
(libnaoms_core.so). A cdylib tolerates undefined symbols, so the default
rustc-link-lib=static= leaves the OpenFHE CKKS typeinfo/vtable
(_ZTIN8lbcrypto23CryptoParametersCKKSRNSE et al.) UNDEFINED in the .so even
though they are defined (D) in libOPENFHEpke_static.a. On-device dlopen then
fails: "typeinfo for lbcrypto::CryptoParametersCKKSRNS is missing".

rustc-link-arg is NOT forwarded from this -sys crate to naoms-core's final
cdylib link, and --start-group does not help a cdylib that permits UND.
The propagating static:+whole-archive= link-lib form force-includes every
archive member AND propagates transitively to the cdylib link, so the
definitions land in the .so. Desktop/linux link a real executable that
already forces resolution, so keep plain static= there.

Verified aarch64-linux-android: nm -D shows CKKS typeinfo/vtable DEFINED,
0 UND lbcrypto symbols; dlopen(RTLD_NOW) on an arm64-v8a emulator returns
DLOPEN_OK. 1054 android on-device daemon dlopen blocker.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant