iroh-ffi exposes a minimal, 1.0-track slice of iroh
to Python, Swift, Kotlin, and JavaScript. Python/Swift/Kotlin use
uniffi-rs; JavaScript uses
napi-rs.
All build / test / bindgen / publish flows live in Makefile.toml. The same
commands run locally and in CI, so they never drift. Install once:
cargo install cargo-makecargo make test-all # rust + python + js + kotlin + swift
cargo make test-rust
cargo make test-python # activate your virtualenv first (see below)
cargo make test-js
cargo make test-kotlin
cargo make test-swift # macOS-arm64 slice (fast)cargo make format # rustfmt (workspace)
cargo make format-check
cargo make clippy
cargo make docs
cargo make ci-rust # everything the Rust CI job runscargo make bindgen-kotlin # generate Kotlin binding + stage the cdylib
cargo make bindgen-swift-macos # generate Swift binding + stage the macOS slice
cargo make swift-xcframework # full 4-target Apple xcframework (release)
cargo make python-wheel # release wheel into target/wheels
cargo make js-build-release # stripped release napi addoncargo make --list-all-steps shows every task with its description.
The FFI mirrors the iroh 1.0 surface: Endpoint, Connection, streams,
datagrams, EndpointId / EndpointAddr / EndpointTicket, SecretKey /
Signature, custom relays (RelayMap / RelayMode), watchers, multipath
snapshots, and the iroh-services client. docs, gossip, and blobs are
intentionally not exposed (they are not 1.0 APIs).
General guidelines when surfacing an iroh API:
PathBuf→String;Bytes/[u8]→Vec<u8>- Anything streaming should read from / write to explicit buffers, or expose a
sizeaccessor so callers can decide how to handle the data. - Methods returning a
Stream(e.g. alist) should return aVec. Add a comment warning that everything is loaded into memory. - Methods that emit progress/events take a callback trait
(
#[uniffi::export(with_foreign)]on the uniffi side,ThreadsafeFunctionon the napi side). See the watcher callbacks insrc/watch.rs. - Fallible methods return
IrohError— follow the pattern insrc/error.rs. - Mirror upstream names. Where a name collides with a host-language builtin
(e.g. Kotlin
AutoCloseable.close()), rename only for that binding viauniffi.toml's[bindings.kotlin.rename], not globally. - Every value type that has a sensible textual form implements
Display(uniffi#[uniffi::export(Display)]) and ato_string()/toString()on the napi side, so it feels native in every language.
When you add a piece of the API, add a test for it in every binding:
src/*.rs (#[cfg(test)]), python/*_test.py, iroh-js/test/*.mjs,
kotlin/lib/src/test/kotlin/computer/iroh/*Test.kt, and
IrohLib/Tests/IrohLibTests/IrohLibTests.swift. The end-to-end connectivity
tests use the loopback pattern from iroh's own suite (Preset::N0 +
RelayMode::disabled(), dial via endpoint.addr()).
Install maturin, create + activate a
virtualenv, then:
pip install pytest pytest-asyncio maturin uniffi-bindgen
cargo make test-pythoncargo make python-develop builds + installs into the active venv;
cargo make python-wheel builds a release wheel. For a portable manylinux
wheel: docker run --rm -v $(pwd):/mnt -w /mnt quay.io/pypa/manylinux_2_28_x86_64 /mnt/build_wheel.sh.
cargo make test-js # yarn install + napi build --platform + node --testRequires Node ≥ 20 and yarn.
Requires java, gradle, and a JDK. cargo make test-kotlin generates the
binding and runs the Gradle suite. Android cross-builds are handled in the
release workflow.
cargo make test-swift builds the macOS-arm64 slice and runs swift test.
cargo make swift-xcframework builds the full iOS + macOS xcframework. iroh's
netwatch needs CoreWLAN on macOS; it is declared in IrohLib/Package.swift.