
Bindings to the Rust sysinfo crate offering a snapshot-style system-info API with embedded native libraries and automatic JNI loader, returning safe data snapshots for memory, CPU, processes and disks.
Kotlin Multiplatform bindings for the Rust sysinfo crate (0.39.x), with a snapshot-style common API backed by two implementations:
rust/ is compiled by cargo into a JNI shared library (libsyskmp) that is shipped as per-OS/arch sysinfo-kmp-jni-jvm-* artifacts. NativeLoader extracts the matching binary at runtime, so consumers need nothing beyond the normal dependencies.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):
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")
}
}
}sysinfo-kmp-jni-jvm-{os}-{arch} artifact is a transitive runtime dependency of sysinfo-kmp; NativeLoader extracts the bundled binary from the classpath and System.load()s it, so no java.library.path setup is needed.IrLinkageError at the first call. Keep the consumer's Kotlin version in sync.System.minimumCpuUpdateIntervalMs() between refreshes for meaningful numbers.CoreFoundation, IOKit, OpenDirectory) and -lobjc are recorded in the klib's linkerOpts and applied automatically when the consumer's binary links.ws2_32, iphlpapi, advapi32, ole32, oleaut32, ntdll, netapi32, uuid, bcrypt) come from the Kotlin/Native MinGW sysroot — nothing extra to install.androidNative* targets cross-compile on any host with just rustup 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 with gcc-aarch64-linux-gnu); Windows builds the windows-x86_64 JNI artifact; Android builds the four androidNative klibs..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.
Kotlin Multiplatform bindings for the Rust sysinfo crate (0.39.x), with a snapshot-style common API backed by two implementations:
rust/ is compiled by cargo into a JNI shared library (libsyskmp) that is shipped as per-OS/arch sysinfo-kmp-jni-jvm-* artifacts. NativeLoader extracts the matching binary at runtime, so consumers need nothing beyond the normal dependencies.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):
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")
}
}
}sysinfo-kmp-jni-jvm-{os}-{arch} artifact is a transitive runtime dependency of sysinfo-kmp; NativeLoader extracts the bundled binary from the classpath and System.load()s it, so no java.library.path setup is needed.IrLinkageError at the first call. Keep the consumer's Kotlin version in sync.System.minimumCpuUpdateIntervalMs() between refreshes for meaningful numbers.CoreFoundation, IOKit, OpenDirectory) and -lobjc are recorded in the klib's linkerOpts and applied automatically when the consumer's binary links.ws2_32, iphlpapi, advapi32, ole32, oleaut32, ntdll, netapi32, uuid, bcrypt) come from the Kotlin/Native MinGW sysroot — nothing extra to install.androidNative* targets cross-compile on any host with just rustup 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 with gcc-aarch64-linux-gnu); Windows builds the windows-x86_64 JNI artifact; Android builds the four androidNative klibs..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.