Kotlin Multiplatform bindings for the Rust sysinfo crate (0.39.x), with a snapshot-style common API backed by two implementations:
- JVM: the Rust shim crate
rust/is compiled by cargo into a JNI shared library (libsyskmp) that is shipped as per-OS/archsysinfo-kmp-jni-jvm-*artifacts.NativeLoaderextracts the matching binary at runtime, so consumers need nothing beyond the normal dependencies. - Native (Kotlin/Native): the same shim is compiled by cargo into a static library that is embedded into the published klib, so consumers get a fully self-contained binary (no dynamic syskmp dependency). This includes the Android native targets (
androidNative*), which are pure-Rust archives and therefore cross-compile on any host without the NDK.
| Platform | Targets | Implementation |
|---|---|---|
| JVM | jvm (Linux/macOS/Windows x64 & arm64) |
JNI shared library built by cargo |
| macOS | macosArm64, macosX64 |
cinterop + embedded static libsyskmp |
| Linux | linuxX64, linuxArm64 |
cinterop + embedded static libsyskmp |
| Windows | mingwX64 |
cinterop + embedded static libsyskmp |
| Android | androidNativeArm64, androidNativeArm32, androidNativeX64, androidNativeX86 |
cinterop + embedded static libsyskmp |
Everything the upstream 0.39.6 crate exposes except Process::kill_and_wait / kill_with_and_wait / wait (they return Rust Result/ExitStatus types that do not map to a C ABI):
- System — memory/swap totals, global + per-CPU usage/frequency/vendor/brand, process table with full details (cmd, environ, exe/cwd/root, status, effective user/group, session, accumulated CPU time, disk I/O, open files, tasks/threads, cgroup limits), host/kernel/os versions, distribution ids, load average, boot time/uptime, physical cores, open-files limit
- Disks — mount points, filesystems, capacity, kind, read-only/removable, per-disk I/O usage
- Networks — per-interface byte/packet/error counters (delta + total), MAC, MTU, IP networks, operational state
- Components — temperature sensors with max/critical thresholds
- Users / Groups — accounts with group membership; standalone group list
- Motherboard / Product — vendor/model/serial/UUID/SKU information
All values are returned as Kotlin snapshots (data classes); no native pointers escape the bindings.
build.gradle.kts:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("cn.enaium:sysinfo-kmp:1.0.0")
}
}
}import cn.enaium.sysinfo.*
fun main() {
// Static host info (no handle required).
println("${System.longOsVersion()} (${System.cpuArch()}, ${System.physicalCoreCount()} cores)")
System().use { sys ->
sys.refreshAll()
println("memory used ${sys.usedMemory} / ${sys.totalMemory} B")
for (cpu in sys.cpus) {
println("${cpu.name}: ${cpu.usage}% @ ${cpu.frequencyMHz} MHz")
}
for (p in sys.processes().sortedByDescending { it.memoryBytes }.take(5)) {
println("[${p.pid}] ${p.name} mem=${p.memoryBytes} cpu=${p.cpuUsage}%")
}
}
Disks().use { disks ->
for (d in disks.list) {
println("${d.mountPoint} free=${d.availableSpaceBytes}B / ${d.totalSpaceBytes}B")
}
}
}- JVM native library: the matching
sysinfo-kmp-jni-jvm-{os}-{arch}artifact is a transitive runtime dependency ofsysinfo-kmp;NativeLoaderextracts the bundled binary from the classpath andSystem.load()s it, so nojava.library.pathsetup is needed. - Kotlin version compatibility: the published klibs are built with Kotlin 2.4.10. Consuming them with a different Kotlin/Native version produces an
IrLinkageErrorat the first call. Keep the consumer's Kotlin version in sync. - CPU usage: like upstream, usage is computed from the delta between two refreshes; wait at least
System.minimumCpuUpdateIntervalMs()between refreshes for meaningful numbers. - macOS linking: the embedded Rust code uses the objc2 crates; the required frameworks (
CoreFoundation,IOKit,OpenDirectory) and-lobjcare recorded in the klib'slinkerOptsand applied automatically when the consumer's binary links. - Windows linking: the mingw import libraries (
ws2_32,iphlpapi,advapi32,ole32,oleaut32,ntdll,netapi32,uuid,bcrypt) come from the Kotlin/Native MinGW sysroot — nothing extra to install. - Android: pure-Rust static archives mean
androidNative*targets cross-compile on any host with justrustup target add; the consumer's Kotlin/Native Android toolchain provides bionic at link time.
Two standalone examples live under examples/:
examples/simple— console demo (JVM + every native target) that prints each API section: host info, motherboard/product, memory, CPUs, processes with all fields, disks, networks, components, users with groups.examples/android-compose— Jetpack Compose application for Android (ART) that renders the same sections on-device. It is an isolated Gradle build included as a composite build (includeBuild), using AGP 9's built-in Kotlin + Compose; its plugin classpath stays separate from the root build's Kotlin Multiplatform classpath.
# Publish the library to the local Maven repository first (each platform
# builds what it can: macOS -> metadata/jvm/macos klibs/darwin JNI,
# Linux -> linux/mingw klibs/linux JNI, Windows -> windows JNI).
./gradlew :sysinfo-kmp:publishToMavenLocal :jni-jvm-<os>-<arch>:publishToMavenLocal
# simple — JVM
./gradlew :examples:simple:jvmRun
# simple — Native
./gradlew :examples:simple:runDebugExecutableMacosArm64The sysinfo shared library ships inside the published AAR's jni/<abi>
entries, so nothing beyond the dependency is required:
# Publish the Android AAR locally once (any host with the NDK; the cargo
# cdylibs are linked through the NDK toolchain automatically).
./gradlew :sysinfo-kmp:publishAndroidPublicationToMavenLocal
# Build the APK (composite build — run through -p so Gradle picks up its
# own settings.gradle.kts)
./gradlew -p examples/android-compose assembleDebug
adb install -r examples/android-compose/build/outputs/apk/debug/*.apkThe Rust shim lives in rust/ (cargo build --release produces both the static library and the cdylib). Gradle invokes cargo automatically; the only prerequisite is a rustup toolchain with the desired targets installed:
rustup target add x86_64-apple-darwin # macosX64 / darwin-x86_64
rustup target add aarch64-unknown-linux-gnu # linuxArm64 / linux-aarch64 (cdylib also needs gcc-aarch64-linux-gnu)
rustup target add x86_64-pc-windows-gnu # mingwX64 / windows-x86_64
rustup target add aarch64-linux-android armv7-linux-androideabi \
x86_64-linux-android i686-linux-android # androidNative*
# Tests on the host platform
./gradlew :sysinfo-kmp:jvmTest :sysinfo-kmp:macosArm64Test # macOS
./gradlew :sysinfo-kmp:jvmTest :sysinfo-kmp:linuxX64Test # LinuxTargets whose rust triple is not installed still compile their bindings (the klib publishes without the embedded library), so partial toolchains never break the build.
.github/workflows/test.yml— push/PR/manual: each runner first publishes everything it can build to Maven Local (signed, mirroring the release path), then runs JVM/native tests and the example. macOS covers metadata/JVM/Apple klibs/darwin JNI; Linux covers linux/mingw klibs/linux JNI (aarch64 linked withgcc-aarch64-linux-gnu); Windows builds thewindows-x86_64JNI artifact; Android builds the fourandroidNativeklibs..github/workflows/publish.yml— manual dispatch that publishes every publication from the runner that builds it (same split as above) to Maven Central.
Required secrets: MAVEN_CENTRAL_USERNAME, MAVEN_CENTRAL_PASSWORD, SIGNING_KEY (base64 GPG keyring), SIGNING_KEY_ID, SIGNING_PASSWORD.
MIT. The bound sysinfo crate is MIT licensed.