├── .gitignore ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── library ├── src │ ├── nativeInterop │ │ └── cinterop │ │ │ ├── Windows.def │ │ │ └── Windows │ │ │ └── windows.h │ ├── iosMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.ios.kt │ │ │ └── KotlinBackend.ios.kt │ ├── macosMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.macos.kt │ │ │ └── KotlinBackend.macos.kt │ ├── tvosMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.tvos.kt │ │ │ └── KotlinBackend.tvos.kt │ ├── androidMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.android.kt │ │ │ ├── KotlinBackend.android.kt │ │ │ ├── HostArch.android.kt │ │ │ └── HostOSVersion.android.kt │ ├── linuxMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.linux.kt │ │ │ ├── KotlinBackend.linux.kt │ │ │ └── HostOSVersion.linux.kt │ ├── mingwMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.mingw.kt │ │ │ ├── KotlinBackend.mingw.kt │ │ │ └── HostOSVersion.mingw.kt │ ├── watchosMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.watchos.kt │ │ │ └── KotlinBackend.watchos.kt │ ├── iosX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.iosX64.kt │ ├── jsMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostArch.js.kt │ │ │ ├── HostOSVersion.js.kt │ │ │ ├── KotlinBackend.js.kt │ │ │ └── HostOS.js.kt │ ├── linuxX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.linuxX64.kt │ ├── tvosX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.tvosX64.kt │ ├── wasmJsMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostArch.wasmJs.kt │ │ │ ├── HostOSVersion.wasmJs.kt │ │ │ ├── KotlinBackend.wasmJs.kt │ │ │ └── HostOS.wasmJs.kt │ ├── androidNativeMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── HostOS.androidNative.kt │ │ │ ├── KotlinBackend.androidNative.kt │ │ │ └── HostOSVersion.androidNative.kt │ ├── iosArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.iosArm64.kt │ ├── linuxArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.linuxArm64.kt │ ├── macosArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.macosArm64.kt │ ├── tvosArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.tvosArm64.kt │ ├── watchosX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.watchosX64.kt │ ├── jvmMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── KotlinBackend.jvm.kt │ │ │ ├── HostArch.jvm.kt │ │ │ ├── HostOS.jvm.kt │ │ │ └── HostOSVersion.jvm.kt │ ├── watchosArm32Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.watchosArm32.kt │ ├── watchosArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.watchosArm64.kt │ ├── androidNativeX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.androidNativeX64.kt │ ├── androidNativeX86Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.androidNativeX86.kt │ ├── iosSimulatorArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.iosSimulatorArm64.kt │ ├── androidNativeArm32Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.androidNativeArm32.kt │ ├── androidNativeArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.androidNativeArm64.kt │ ├── tvosSimulatorArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.tvosSimulatorArm64.kt │ ├── watchosDeviceArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.watchosDeviceArm64.kt │ ├── watchosSimulatorArm64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.watchosSimulatorArm64.kt │ ├── commonMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ ├── KotlinBackend.kt │ │ │ ├── HostOSVersion.kt │ │ │ ├── HostOS.kt │ │ │ └── HostArch.kt │ ├── macosX64Main │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostArch.macosX64.kt │ ├── darwinMain │ │ └── kotlin │ │ │ └── dev │ │ │ └── zwander │ │ │ └── kmp │ │ │ └── platform │ │ │ └── HostOSVersion.darwin.kt │ └── mingwX64Main │ │ └── kotlin │ │ └── dev │ │ └── zwander │ │ └── kmp │ │ └── platform │ │ └── HostArch.mingwX64.kt └── build.gradle.kts ├── .idea ├── vcs.xml ├── .gitignore └── modules.xml ├── settings.gradle.kts ├── README.md ├── .github └── workflows │ └── publish.yaml ├── LICENSE ├── gradle.properties ├── gradlew.bat └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /.gradle/ 3 | /build/ 4 | /local.properties 5 | /.kotlin/ 6 | **/build/ 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zacharee/KMPPlatform/main/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /library/src/nativeInterop/cinterop/Windows.def: -------------------------------------------------------------------------------- 1 | language = C++ 2 | package = dev.zwander.kmp.platform.cinterop 3 | headers = windows.h 4 | -------------------------------------------------------------------------------- /library/src/iosMain/kotlin/dev/zwander/kmp/platform/HostOS.ios.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.IOS 4 | -------------------------------------------------------------------------------- /library/src/macosMain/kotlin/dev/zwander/kmp/platform/HostOS.macos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.MacOS -------------------------------------------------------------------------------- /library/src/tvosMain/kotlin/dev/zwander/kmp/platform/HostOS.tvos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.TvOS 4 | -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/dev/zwander/kmp/platform/HostOS.android.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.Android -------------------------------------------------------------------------------- /library/src/linuxMain/kotlin/dev/zwander/kmp/platform/HostOS.linux.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.Linux 4 | -------------------------------------------------------------------------------- /library/src/mingwMain/kotlin/dev/zwander/kmp/platform/HostOS.mingw.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.Windows 4 | -------------------------------------------------------------------------------- /library/src/watchosMain/kotlin/dev/zwander/kmp/platform/HostOS.watchos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.WatchOS -------------------------------------------------------------------------------- /library/src/iosX64Main/kotlin/dev/zwander/kmp/platform/HostArch.iosX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X64 4 | -------------------------------------------------------------------------------- /library/src/jsMain/kotlin/dev/zwander/kmp/platform/HostArch.js.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Unknown 4 | -------------------------------------------------------------------------------- /library/src/linuxX64Main/kotlin/dev/zwander/kmp/platform/HostArch.linuxX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X64 4 | -------------------------------------------------------------------------------- /library/src/tvosX64Main/kotlin/dev/zwander/kmp/platform/HostArch.tvosX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X64 4 | -------------------------------------------------------------------------------- /library/src/wasmJsMain/kotlin/dev/zwander/kmp/platform/HostArch.wasmJs.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Unknown 4 | -------------------------------------------------------------------------------- /library/src/androidNativeMain/kotlin/dev/zwander/kmp/platform/HostOS.androidNative.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS = HostOS.Android 4 | -------------------------------------------------------------------------------- /library/src/iosArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.iosArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/jsMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.js.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOSVersion: OSVersion = OSVersion.Unknown 4 | -------------------------------------------------------------------------------- /library/src/jsMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.js.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.JS 4 | -------------------------------------------------------------------------------- /library/src/linuxArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.linuxArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/macosArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.macosArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/tvosArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.tvosArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/watchosX64Main/kotlin/dev/zwander/kmp/platform/HostArch.watchosX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X64 4 | -------------------------------------------------------------------------------- /library/src/iosMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.ios.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.jvm.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.JVM 4 | -------------------------------------------------------------------------------- /library/src/watchosArm32Main/kotlin/dev/zwander/kmp/platform/HostArch.watchosArm32.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm32 4 | -------------------------------------------------------------------------------- /library/src/watchosArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.watchosArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.android.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.JVM 4 | -------------------------------------------------------------------------------- /library/src/androidNativeX64Main/kotlin/dev/zwander/kmp/platform/HostArch.androidNativeX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X64 4 | -------------------------------------------------------------------------------- /library/src/androidNativeX86Main/kotlin/dev/zwander/kmp/platform/HostArch.androidNativeX86.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.X86 4 | -------------------------------------------------------------------------------- /library/src/linuxMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.linux.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/macosMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.macos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/mingwMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.mingw.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/tvosMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.tvos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/wasmJsMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.wasmJs.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOSVersion: OSVersion = OSVersion.Unknown 4 | -------------------------------------------------------------------------------- /library/src/wasmJsMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.wasmJs.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Wasm 4 | -------------------------------------------------------------------------------- /library/src/iosSimulatorArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.iosSimulatorArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/watchosMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.watchos.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/androidNativeArm32Main/kotlin/dev/zwander/kmp/platform/HostArch.androidNativeArm32.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm32 4 | -------------------------------------------------------------------------------- /library/src/androidNativeArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.androidNativeArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/tvosSimulatorArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.tvosSimulatorArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/watchosDeviceArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.watchosDeviceArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/androidNativeMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.androidNative.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostBackend: KotlinBackend = KotlinBackend.Native 4 | -------------------------------------------------------------------------------- /library/src/watchosSimulatorArm64Main/kotlin/dev/zwander/kmp/platform/HostArch.watchosSimulatorArm64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch = HostArch.Arm64 4 | -------------------------------------------------------------------------------- /library/src/nativeInterop/cinterop/Windows/windows.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BOOL IsWow64Process2( 4 | HANDLE hProcess, 5 | USHORT *pProcessMachine, 6 | USHORT *pNativeMachine 7 | ); 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | /artifacts/ 5 | /caches/ 6 | /inspectionProfiles/ 7 | /modules/ 8 | /appInsightsSettings.xml 9 | /compiler.xml 10 | /deploymentTargetSelector.xml 11 | /gradle.xml 12 | /migrations.xml 13 | /misc.xml 14 | /runConfigurations.xml 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jan 19 19:53:47 EST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/dev/zwander/kmp/platform/HostArch.jvm.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch 4 | get() { 5 | return when (val osArch = System.getProperty("os.arch")) { 6 | "x86_64", "amd64" -> HostArch.X64 7 | "aarch64" -> HostArch.Arm64 8 | else -> throw Error("Unknown arch $osArch") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/dev/zwander/kmp/platform/HostArch.android.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostArch: HostArch 4 | get() { 5 | return when (val osArch = System.getProperty("os.arch")) { 6 | "x86_64", "amd64" -> HostArch.X64 7 | "aarch64" -> HostArch.Arm64 8 | else -> throw Error("Unknown arch $osArch") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/dev/zwander/kmp/platform/KotlinBackend.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | enum class KotlinBackend(val id: String) { 4 | JVM("jvm"), 5 | JS("js"), 6 | Native("native"), 7 | Wasm("wasm"), 8 | ; 9 | 10 | companion object { 11 | val current: KotlinBackend 12 | get() = hostBackend 13 | } 14 | } 15 | 16 | internal expect val hostBackend: KotlinBackend 17 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | mavenCentral() 7 | google() 8 | } 9 | } 10 | 11 | dependencyResolutionManagement { 12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 13 | repositories { 14 | mavenCentral() 15 | google() 16 | } 17 | } 18 | 19 | rootProject.name = "KMPPlatform" 20 | include(":library") 21 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | data class OSVersion( 4 | val major: Int?, 5 | val minor: Int?, 6 | val patch: Int?, 7 | val build: Long?, 8 | ) { 9 | companion object { 10 | val Unknown = OSVersion(null, null, null, null) 11 | 12 | val current: OSVersion 13 | get() = hostOSVersion 14 | } 15 | } 16 | 17 | internal expect val hostOSVersion: OSVersion 18 | -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/dev/zwander/kmp/platform/HostOS.jvm.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOS: HostOS 4 | get() { 5 | val osName = System.getProperty("os.name") 6 | return when { 7 | osName == "Mac OS X" -> HostOS.MacOS 8 | osName.startsWith("Win") -> HostOS.Windows 9 | "The Android Project" == System.getProperty("java.specification.vendor") -> HostOS.Android 10 | osName == "Linux" -> HostOS.Linux 11 | else -> HostOS.Unknown 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/androidMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.android.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import android.os.Build 4 | 5 | internal actual val hostOSVersion: OSVersion 6 | get() { 7 | val release = Build.VERSION.RELEASE 8 | val split = release.split(".") 9 | 10 | return OSVersion( 11 | major = split.getOrNull(0)?.toIntOrNull(), 12 | minor = split.getOrNull(1)?.toIntOrNull(), 13 | patch = split.getOrNull(2)?.toIntOrNull(), 14 | build = Build.VERSION.SDK_INT.toLong(), 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/dev/zwander/kmp/platform/HostOS.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | /** 4 | * The operating system the application is currently running on. 5 | */ 6 | enum class HostOS(val id: String) { 7 | Android("android"), 8 | Linux("linux"), 9 | Windows("windows"), 10 | MacOS("macos"), 11 | IOS("ios"), 12 | TvOS("tvos"), 13 | WatchOS("watchos"), 14 | Unknown("unknown"), 15 | ; 16 | 17 | companion object { 18 | val current: HostOS 19 | get() = hostOS 20 | } 21 | } 22 | 23 | internal expect val hostOS: HostOS 24 | -------------------------------------------------------------------------------- /library/src/jvmMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.jvm.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | internal actual val hostOSVersion: OSVersion 4 | get() { 5 | val versionInfo = oshi.SystemInfo().operatingSystem.versionInfo 6 | val version = versionInfo.version 7 | val build = versionInfo.buildNumber 8 | val split = version.split(".") 9 | 10 | return OSVersion( 11 | major = split.getOrNull(0)?.toIntOrNull(), 12 | minor = split.getOrNull(1)?.toIntOrNull(), 13 | patch = split.getOrNull(2)?.toIntOrNull(), 14 | build = build?.toLongOrNull(), 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | android-gradle = "8.8.0" 3 | kotlin = "2.1.0" 4 | mavenPublish = "0.29.0" 5 | oshi = "6.6.5" 6 | 7 | [libraries] 8 | kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } 9 | oshi-core = { module = "com.github.oshi:oshi-core", version.ref = "oshi" } 10 | 11 | [plugins] 12 | android-application = { id = "com.android.application", version.ref = "android-gradle" } 13 | android-library = { id = "com.android.library", version.ref = "android-gradle" } 14 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } 15 | maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" } 16 | -------------------------------------------------------------------------------- /library/src/macosX64Main/kotlin/dev/zwander/kmp/platform/HostArch.macosX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import kotlinx.cinterop.ExperimentalForeignApi 4 | import kotlinx.cinterop.IntVar 5 | import kotlinx.cinterop.cValue 6 | import kotlinx.cinterop.memScoped 7 | import kotlinx.cinterop.sizeOf 8 | import kotlinx.cinterop.toCPointer 9 | import platform.darwin.sysctlbyname 10 | 11 | @OptIn(ExperimentalForeignApi::class) 12 | internal actual val hostArch: HostArch 13 | get() = memScoped { 14 | val ret = cValue() 15 | 16 | return if (sysctlbyname("sysctl.proc_translated", ret, sizeOf().toCPointer(), null, 0U) != -1) { 17 | HostArch.EmulatedX64 18 | } else { 19 | HostArch.X64 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KMPPlatform 2 | Various platform utilities for Kotlin Multiplatform, such as for retrieving the current host OS and architecture. 3 | 4 | Supported platforms: 5 | - Android 6 | - Android Native (x86, x64, ARM32, ARM64) 7 | - JVM 8 | - iOS (x64, ARM64) 9 | - macOS native (x64, ARM64) 10 | - tvOS (x64, ARM64) 11 | - watchOS (x64, ARM32, ARM64) 12 | - JS (Browser) 13 | - Web Assembly (Browser) 14 | - MinGW (x64) 15 | - Linux (x64, ARM64) 16 | 17 | ## Installation 18 | ![Maven Central Version](https://img.shields.io/maven-central/v/dev.zwander/kmpplatform) 19 | 20 | Add the dependency to your `commonMain` source set: 21 | 22 | ```kotlin 23 | sourceSets { 24 | val commonMain by getting { 25 | dependencies { 26 | implementation("dev.zwander:kmpplatform:VERSION") 27 | } 28 | } 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /library/src/darwinMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.darwin.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import kotlinx.cinterop.ExperimentalForeignApi 4 | import kotlinx.cinterop.UnsafeNumber 5 | import kotlinx.cinterop.memScoped 6 | import kotlinx.cinterop.pointed 7 | import platform.Foundation.NSProcessInfo 8 | 9 | @Suppress("RemoveRedundantCallsOfConversionMethods") 10 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) 11 | internal actual val hostOSVersion: OSVersion 12 | get() = memScoped { 13 | val osVersion = NSProcessInfo.processInfo.operatingSystemVersion.ptr.pointed 14 | 15 | return OSVersion( 16 | major = osVersion.majorVersion.toInt(), 17 | minor = osVersion.minorVersion.toInt(), 18 | patch = osVersion.patchVersion.toInt(), 19 | build = null, 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /library/src/commonMain/kotlin/dev/zwander/kmp/platform/HostArch.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | /** 4 | * The CPU architecture of the host system. 5 | */ 6 | enum class HostArch(val id: String) { 7 | /** 8 | * Intel x86. 9 | */ 10 | X86("x86"), 11 | 12 | /** 13 | * AMD64 14 | * x86_64 15 | */ 16 | X64("x64"), 17 | 18 | /** 19 | * 32-bit ARM. 20 | */ 21 | Arm32("arm32"), 22 | 23 | /** 24 | * 64-bit ARM. 25 | */ 26 | Arm64("arm64"), 27 | 28 | /** 29 | * x64 app running on an ARM64 host. 30 | */ 31 | EmulatedX64("emulated_x64"), 32 | 33 | /** 34 | * x86 app running on an ARM64 host. 35 | */ 36 | EmulatedX86("emulated_x86"), 37 | 38 | /** 39 | * Unknown architecture. 40 | */ 41 | Unknown("Unknown"), 42 | ; 43 | 44 | companion object { 45 | val current: HostArch 46 | get() = hostArch 47 | } 48 | } 49 | 50 | internal expect val hostArch: HostArch 51 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | publish: 8 | name: Publish to Sonatype 9 | runs-on: macos-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | 14 | - name: Configure JDK 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'corretto' 18 | java-version: '21' 19 | 20 | - name: Setup Gradle 21 | uses: gradle/actions/setup-gradle@v3 22 | 23 | - name: Upload Artifacts 24 | run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache 25 | env: 26 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 27 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 28 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY_KEY }} 29 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_IN_MEMORY_KEY_ID }} 30 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_IN_MEMORY_KEY_PASSWORD }} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Zachary Wander 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /library/src/mingwMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.mingw.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import platform.windows.BYTE 4 | import platform.windows.DWORD 5 | import platform.windows.GetVersion 6 | import platform.windows.WORD 7 | 8 | private fun WORD.loByte(): BYTE = (this and 0xffU).toUByte() 9 | private fun WORD.hiByte(): BYTE = ((this.toInt() shr 8) and 0xff).toUByte() 10 | 11 | private fun DWORD.loWord(): WORD = (this and 0xffffU).toUShort() 12 | private fun DWORD.hiWord(): WORD = ((this.toInt() shr 16) and 0xffff).toUShort() 13 | 14 | internal actual val hostOSVersion: OSVersion 15 | get() { 16 | val version = GetVersion() 17 | 18 | val majorVersion = version.loWord().loByte() 19 | val minorVersion = version.loWord().hiByte() 20 | 21 | val build = if (version < 0x80000000U) { 22 | version.hiWord() 23 | } else { 24 | null 25 | } 26 | 27 | return OSVersion( 28 | major = majorVersion.toInt(), 29 | minor = minorVersion.toInt(), 30 | patch = null, 31 | build = build?.toLong(), 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /library/src/androidNativeMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.androidNative.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import kotlinx.cinterop.ByteVar 4 | import kotlinx.cinterop.ExperimentalForeignApi 5 | import kotlinx.cinterop.allocArray 6 | import kotlinx.cinterop.memScoped 7 | import kotlinx.cinterop.toKStringFromUtf8 8 | import platform.posix.__system_property_get 9 | 10 | @OptIn(ExperimentalForeignApi::class) 11 | internal actual val hostOSVersion: OSVersion 12 | get() = memScoped { 13 | val releaseString = allocArray(92) 14 | val sdkString = allocArray(92) 15 | 16 | __system_property_get("ro.build.version.release", releaseString) 17 | __system_property_get("ro.build.version.sdk", sdkString) 18 | 19 | val releaseSplit = releaseString.toKStringFromUtf8().split(".") 20 | 21 | return OSVersion( 22 | major = releaseSplit.getOrNull(0)?.toIntOrNull(), 23 | minor = releaseSplit.getOrNull(1)?.toIntOrNull(), 24 | patch = releaseSplit.getOrNull(2)?.toIntOrNull(), 25 | build = sdkString.toKStringFromUtf8().toLongOrNull(), 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /library/src/mingwX64Main/kotlin/dev/zwander/kmp/platform/HostArch.mingwX64.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import dev.zwander.kmp.platform.cinterop.IsWow64Process2 4 | import kotlinx.cinterop.ExperimentalForeignApi 5 | import kotlinx.cinterop.UShortVar 6 | import kotlinx.cinterop.cValue 7 | import kotlinx.cinterop.memScoped 8 | import kotlinx.cinterop.pointed 9 | import kotlinx.cinterop.value 10 | import platform.windows.GetCurrentProcess 11 | 12 | @OptIn(ExperimentalForeignApi::class) 13 | internal actual val hostArch: HostArch 14 | get() = memScoped { 15 | val processHandle = GetCurrentProcess() 16 | val processMachine = cValue() 17 | val nativeMachine = cValue() 18 | 19 | IsWow64Process2(processHandle, processMachine, nativeMachine) 20 | 21 | return if (nativeMachine.ptr.pointed.value.toInt() == platform.windows.IMAGE_FILE_MACHINE_ARM64) { 22 | when (processMachine.ptr.pointed.value.toInt()) { 23 | platform.windows.IMAGE_FILE_MACHINE_AMD64 -> HostArch.EmulatedX64 24 | platform.windows.IMAGE_FILE_MACHINE_I386 -> HostArch.EmulatedX86 25 | else -> HostArch.Unknown 26 | } 27 | } else { 28 | HostArch.X64 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /library/src/linuxMain/kotlin/dev/zwander/kmp/platform/HostOSVersion.linux.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import kotlinx.cinterop.ExperimentalForeignApi 4 | import kotlinx.cinterop.alloc 5 | import kotlinx.cinterop.cValue 6 | import kotlinx.cinterop.memScoped 7 | import kotlinx.cinterop.pointed 8 | import kotlinx.cinterop.toKString 9 | import platform.posix.uname 10 | import platform.posix.utsname 11 | 12 | @OptIn(ExperimentalForeignApi::class) 13 | internal actual val hostOSVersion: OSVersion 14 | get() = memScoped { 15 | val unameValue = cValue() 16 | 17 | return if (uname(unameValue) != -1) { 18 | val releaseString = unameValue.ptr.pointed.release.toKString() 19 | val versionAndBuild = releaseString.split("-") 20 | 21 | val majorMinorAndPatch = versionAndBuild.firstOrNull()?.split(".") 22 | val major = majorMinorAndPatch?.getOrNull(0) 23 | val minor = majorMinorAndPatch?.getOrNull(1) 24 | val patch = majorMinorAndPatch?.getOrNull(2) 25 | 26 | val build = versionAndBuild.getOrNull(1) 27 | 28 | OSVersion( 29 | major = major?.toIntOrNull(), 30 | minor = minor?.toIntOrNull(), 31 | patch = patch?.toIntOrNull(), 32 | build = build?.toLongOrNull(), 33 | ) 34 | } else { 35 | OSVersion.Unknown 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /library/src/jsMain/kotlin/dev/zwander/kmp/platform/HostOS.js.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | import kotlinx.browser.window 4 | 5 | /** 6 | * A string identifying the platform on which the user's browser is running; for example: 7 | * "MacIntel", "Win32", "Linux x86_64", "Linux x86_64". 8 | * See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform - deprecated 9 | * 10 | * A string containing the platform brand. For example, "Windows". 11 | * See https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/platform - new API, 12 | * but not supported in all browsers 13 | */ 14 | internal fun getNavigatorInfo(): String = js("navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform") as String 15 | 16 | /** 17 | * In a browser, user platform can be obtained from different places: 18 | * - we attempt to use not-deprecated but experimental option first (not available in all browsers) 19 | * - then we attempt to use a deprecated option 20 | * - if both above return an empty string, we attempt to get `Platform` from `userAgent` 21 | * 22 | * Note: a client can spoof these values, so it's okay only for non-critical use cases. 23 | */ 24 | internal fun detectHostOs(): HostOS { 25 | val platformInfo = getNavigatorInfo().takeIf { 26 | it.isNotEmpty() 27 | } ?: window.navigator.userAgent 28 | 29 | return when { 30 | platformInfo.contains("Android", true) -> HostOS.Android 31 | platformInfo.contains("iPhone", true) -> HostOS.IOS 32 | platformInfo.contains("iOS", true) -> HostOS.IOS 33 | platformInfo.contains("iPad", true) -> HostOS.IOS 34 | platformInfo.contains("Linux", true) -> HostOS.Linux 35 | platformInfo.contains("Mac", true) -> HostOS.MacOS 36 | platformInfo.contains("Win", true) -> HostOS.Windows 37 | else -> HostOS.Unknown 38 | } 39 | } 40 | 41 | internal actual val hostOS: HostOS 42 | get() = detectHostOs() -------------------------------------------------------------------------------- /library/src/wasmJsMain/kotlin/dev/zwander/kmp/platform/HostOS.wasmJs.kt: -------------------------------------------------------------------------------- 1 | package dev.zwander.kmp.platform 2 | 3 | /** 4 | * A string identifying the platform on which the user's browser is running; for example: 5 | * "MacIntel", "Win32", "Linux x86_64", "Linux x86_64". 6 | * See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform - deprecated 7 | * 8 | * A string containing the platform brand. For example, "Windows". 9 | * See https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/platform - new API, 10 | * but not supported in all browsers 11 | */ 12 | internal fun getNavigatorInfo(): String = js("navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform") 13 | 14 | internal fun getUserAgent(): String = js("window.navigator.userAgent") 15 | 16 | /** 17 | * In a browser, user platform can be obtained from different places: 18 | * - we attempt to use not-deprecated but experimental option first (not available in all browsers) 19 | * - then we attempt to use a deprecated option 20 | * - if both above return an empty string, we attempt to get `Platform` from `userAgent` 21 | * 22 | * Note: a client can spoof these values, so it's okay only for non-critical use cases. 23 | */ 24 | internal fun detectHostOs(): HostOS { 25 | val platformInfo = getNavigatorInfo().takeIf { 26 | it.isNotEmpty() 27 | } ?: getUserAgent() 28 | 29 | return when { 30 | platformInfo.contains("Android", true) -> HostOS.Android 31 | platformInfo.contains("iPhone", true) -> HostOS.IOS 32 | platformInfo.contains("iOS", true) -> HostOS.IOS 33 | platformInfo.contains("iPad", true) -> HostOS.IOS 34 | platformInfo.contains("Linux", true) -> HostOS.Linux 35 | platformInfo.contains("Mac", true) -> HostOS.MacOS 36 | platformInfo.contains("Win", true) -> HostOS.Windows 37 | else -> HostOS.Unknown 38 | } 39 | } 40 | 41 | internal actual val hostOS: HostOS 42 | get() = detectHostOs() 43 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. More details, visit 11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 12 | # org.gradle.parallel=true 13 | 14 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" 15 | org.gradle.parallel=true 16 | org.gradle.caching=true 17 | 18 | android.useAndroidX=true 19 | 20 | kotlin.code.style=official 21 | kotlin.mpp.applyDefaultHierarchyTemplate=false 22 | kotlin.mpp.androidGradlePluginCompatibility.nowarn=true 23 | kotlin.mpp.enableResourcesPublication=false 24 | 25 | org.jetbrains.compose.experimental.jscanvas.enabled=true 26 | org.jetbrains.compose.experimental.macos.enabled=true 27 | 28 | SONATYPE_HOST=CENTRAL_PORTAL 29 | RELEASE_SIGNING_ENABLED=true 30 | 31 | GROUP=dev.zwander 32 | POM_ARTIFACT_ID=kmpplatform 33 | VERSION_NAME=0.1.0 34 | 35 | POM_NAME=KMPPlatform 36 | POM_DESCRIPTION=Kotlin Multiplatform platform utilities. 37 | POM_INCEPTION_YEAR=2024 38 | POM_URL=https://github.com/zacharee/KMPPlatform 39 | 40 | POM_LICENSE_NAME=MIT License 41 | POM_LICENSE_URL=https://github.com/zacharee/KMPPlatform/blob/main/LICENSE 42 | POM_LICENSE_DIST=repo 43 | 44 | POM_SCM_URL=https://github.com/zacharee/KMPPlatform 45 | POM_SCM_CONNECTION=scm:git:git://github.com/zacharee/KMPPlatform.git 46 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com:zacharee/KMPPlatform.git 47 | 48 | POM_DEVELOPER_ID=zacharee 49 | POM_DEVELOPER_NAME=Zachary Wander 50 | POM_DEVELOPER_EMAIL=zachary@zwander.dev 51 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /library/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl 3 | 4 | plugins { 5 | alias(libs.plugins.android.library) 6 | alias(libs.plugins.kotlin.multiplatform) 7 | alias(libs.plugins.maven.publish) 8 | } 9 | 10 | group = "dev.zwander.kmp.platform" 11 | 12 | kotlin.sourceSets.all { 13 | languageSettings.optIn("kotlin.RequiresOptIn") 14 | } 15 | 16 | val javaVersionEnum: JavaVersion = JavaVersion.VERSION_21 17 | 18 | kotlin { 19 | jvmToolchain(javaVersionEnum.toString().toInt()) 20 | 21 | androidTarget { 22 | compilations.all { 23 | compileTaskProvider.configure { 24 | compilerOptions { 25 | freeCompilerArgs.addAll("-opt-in=kotlin.RequiresOptIn", "-Xdont-warn-on-error-suppression") 26 | jvmTarget = JvmTarget.fromTarget(javaVersionEnum.toString()) 27 | } 28 | } 29 | } 30 | } 31 | 32 | jvm { 33 | compilations.all { 34 | compileTaskProvider.configure { 35 | compilerOptions { 36 | jvmTarget = JvmTarget.fromTarget(javaVersionEnum.toString()) 37 | } 38 | } 39 | } 40 | } 41 | 42 | listOf( 43 | iosX64(), 44 | iosArm64(), 45 | iosSimulatorArm64(), 46 | macosX64(), 47 | macosArm64(), 48 | tvosX64(), 49 | tvosArm64(), 50 | tvosSimulatorArm64(), 51 | watchosX64(), 52 | watchosArm32(), 53 | watchosArm64(), 54 | watchosDeviceArm64(), 55 | watchosSimulatorArm64(), 56 | ).forEach { 57 | it.binaries.framework { 58 | baseName = "KMPPlatform" 59 | isStatic = true 60 | } 61 | } 62 | 63 | @OptIn(ExperimentalWasmDsl::class) 64 | listOf( 65 | js(IR), 66 | wasmJs(), 67 | ).forEach { 68 | it.moduleName = "KMPPlatform" 69 | it.browser() 70 | } 71 | 72 | androidNativeArm32() 73 | androidNativeArm64() 74 | androidNativeX86() 75 | androidNativeX64() 76 | 77 | mingwX64 { 78 | compilations.getByName("main") { 79 | cinterops.create("Windows") { 80 | includeDirs("$projectDir/src/nativeInterop/cinterop/Windows") 81 | definitionFile.set(file("$projectDir/src/nativeInterop/cinterop/Windows.def")) 82 | } 83 | } 84 | } 85 | 86 | linuxArm64() 87 | linuxX64() 88 | 89 | targets.all { 90 | compilations.all { 91 | compileTaskProvider.configure { 92 | compilerOptions { 93 | freeCompilerArgs.addAll("-Xexpect-actual-classes", "-Xdont-warn-on-error-suppression") 94 | } 95 | } 96 | } 97 | } 98 | 99 | sourceSets { 100 | val commonMain by getting { 101 | dependencies { 102 | implementation(libs.kotlin.stdlib) 103 | } 104 | } 105 | 106 | val jvmMain by getting { 107 | dependsOn(commonMain) 108 | 109 | dependencies { 110 | implementation(libs.oshi.core) 111 | } 112 | } 113 | 114 | val androidMain by getting { 115 | dependsOn(commonMain) 116 | } 117 | 118 | val darwinMain by creating { 119 | dependsOn(commonMain) 120 | } 121 | 122 | val iosMain by creating { 123 | dependsOn(darwinMain) 124 | } 125 | 126 | val iosX64Main by getting { 127 | dependsOn(iosMain) 128 | } 129 | 130 | val iosArm64Main by getting { 131 | dependsOn(iosMain) 132 | } 133 | 134 | val iosSimulatorArm64Main by getting { 135 | dependsOn(iosMain) 136 | } 137 | 138 | val macosMain by creating { 139 | dependsOn(darwinMain) 140 | } 141 | 142 | val macosArm64Main by getting { 143 | dependsOn(macosMain) 144 | } 145 | 146 | val macosX64Main by getting { 147 | dependsOn(macosMain) 148 | } 149 | 150 | val tvosMain by creating { 151 | dependsOn(darwinMain) 152 | } 153 | 154 | val tvosX64Main by getting { 155 | dependsOn(tvosMain) 156 | } 157 | 158 | val tvosArm64Main by getting { 159 | dependsOn(tvosMain) 160 | } 161 | 162 | val tvosSimulatorArm64Main by getting { 163 | dependsOn(tvosMain) 164 | } 165 | 166 | val watchosMain by creating { 167 | dependsOn(darwinMain) 168 | } 169 | 170 | val watchosX64Main by getting { 171 | dependsOn(watchosMain) 172 | } 173 | 174 | val watchosArm32Main by getting { 175 | dependsOn(watchosMain) 176 | } 177 | 178 | val watchosArm64Main by getting { 179 | dependsOn(watchosMain) 180 | } 181 | 182 | val watchosDeviceArm64Main by getting { 183 | dependsOn(watchosMain) 184 | } 185 | 186 | val watchosSimulatorArm64Main by getting { 187 | dependsOn(watchosMain) 188 | } 189 | 190 | val jsMain by getting { 191 | dependsOn(commonMain) 192 | } 193 | 194 | val wasmJsMain by getting { 195 | dependsOn(commonMain) 196 | } 197 | 198 | val androidNativeMain by creating { 199 | dependsOn(commonMain) 200 | } 201 | 202 | val androidNativeArm32Main by getting { 203 | dependsOn(androidNativeMain) 204 | } 205 | 206 | val androidNativeArm64Main by getting { 207 | dependsOn(androidNativeMain) 208 | } 209 | 210 | val androidNativeX86Main by getting { 211 | dependsOn(androidNativeMain) 212 | } 213 | 214 | val androidNativeX64Main by getting { 215 | dependsOn(androidNativeMain) 216 | } 217 | 218 | val mingwMain by creating { 219 | dependsOn(commonMain) 220 | } 221 | 222 | val mingwX64Main by getting { 223 | dependsOn(mingwMain) 224 | } 225 | 226 | val linuxMain by creating { 227 | dependsOn(commonMain) 228 | } 229 | 230 | val linuxArm64Main by getting { 231 | dependsOn(linuxMain) 232 | } 233 | 234 | val linuxX64Main by getting { 235 | dependsOn(linuxMain) 236 | } 237 | } 238 | } 239 | 240 | android { 241 | this.compileSdk = 34 242 | 243 | defaultConfig { 244 | this.minSdk = 21 245 | } 246 | 247 | namespace = "dev.zwander.kmp.platform" 248 | 249 | compileOptions { 250 | sourceCompatibility = javaVersionEnum 251 | targetCompatibility = javaVersionEnum 252 | } 253 | 254 | buildFeatures { 255 | aidl = true 256 | } 257 | 258 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 259 | sourceSets["main"].res.srcDirs("src/androidMain/res") 260 | } 261 | 262 | tasks.withType { 263 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 264 | } 265 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | --------------------------------------------------------------------------------