From 2ed343b115ceee0ad3aad7dd511c96685a015360 Mon Sep 17 00:00:00 2001 From: Martin Jakobsson Date: Wed, 1 Jan 2025 18:01:21 +0100 Subject: [PATCH 1/2] remove dependency on `uname` command --- README.md | 4 +-- .../com/github/sbt/jni/annotations.scala | 30 ++++++++++-------- .../github/sbt/jni/syntax/NativeLoader.scala | 31 ++++++++++--------- .../github/sbt/jni/plugins/JniNative.scala | 30 ++++++++++-------- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 3609b32a..57019c4d 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,7 @@ nativeBuildTool := Meson.make(Nil) |--------------------------------|---------------| | automatic, when JniNative enabled | [JniPackage.scala](plugin/src/main/scala/com/github/sbt/jni/plugins/JniPackage.scala) | -This plugin packages native libraries produced by JniNative in a way that they can be transparently loaded with JniLoad. It uses the notion of a native "platform", defined as the architecture-kernel values returned by `uname -sm`. A native binary of a given platform is assumed to be executable on any machines of the same platform. +This plugin packages native libraries produced by JniNative in a way that they can be transparently loaded with JniLoad. It uses the notion of a native "platform", defined using the `os.name` and `os.arch` properties. A native binary of a given platform is assumed to be executable on any machines of the same platform. ## Canonical Use @@ -325,7 +325,7 @@ Real-world use-cases of sbt-jni include: - projects using `JniLoad` must use Scala versions 2.11, 2.12, 2.13 or 3.2 - projects using `JniLoad` with Scala 3 should use it with the `sbtJniCoreScope := Compile` SBT key set -- only POSIX platforms are supported (actually, any platform that has the `uname` command available) +- only POSIX platforms are supported The goal of sbt-jni is to be the least intrusive possible. No transitive dependencies are added to projects using any plugin (some dependencies are added to the `provided` configuration, however these do not affect any downstream projects). diff --git a/core/src/main/scala-2/com/github/sbt/jni/annotations.scala b/core/src/main/scala-2/com/github/sbt/jni/annotations.scala index dce04c41..310790d9 100644 --- a/core/src/main/scala-2/com/github/sbt/jni/annotations.scala +++ b/core/src/main/scala-2/com/github/sbt/jni/annotations.scala @@ -43,19 +43,8 @@ class nativeLoaderAnnotationMacro(val c: Context) { val tmp: Path = Files.createTempDirectory("jni-") val plat: String = { - val line = try { - scala.sys.process.Process("uname -sm").!!.linesIterator.next() - } catch { - case _: Exception => sys.error("Error running `uname` command") - } - val parts = line.split(" ") - if (parts.length != 2) { - sys.error("Could not determine platform: 'uname -sm' returned unexpected string: " + line) - } else { - val arch = parts(1).toLowerCase.replaceAll("\\s", "") - val kernel = parts(0).toLowerCase.replaceAll("\\s", "") - arch + "-" + kernel - } + val (kernel, arch) = determinePlatform() + arch + "-" + kernel } val resourcePath: String = "/native/" + plat + "/" + lib @@ -83,6 +72,21 @@ class nativeLoaderAnnotationMacro(val c: Context) { case _: UnsatisfiedLinkError => loadPackaged() } + def determinePlatform(): (String, String) = { + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } + + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } + + (os, arch) + } + load() } """ diff --git a/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala b/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala index 51a1f303..430ccb67 100644 --- a/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala +++ b/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala @@ -14,20 +14,8 @@ object NativeLoader { val tmp: Path = Files.createTempDirectory("jni-") val plat: String = { - val line = - try { - scala.io.Source.fromString(scala.sys.process.Process("uname -sm").!!).getLines().next() - } catch { - case _: Exception => sys.error("Error running `uname` command") - } - val parts = line.split(" ") - if (parts.length != 2) { - sys.error("Could not determine platform: 'uname -sm' returned unexpected string: " + line) - } else { - val arch = parts(1).toLowerCase.replaceAll("\\s", "") - val kernel = parts(0).toLowerCase.replaceAll("\\s", "") - arch + "-" + kernel - } + val (kernel, arch) = determinePlatform() + arch + "-" + kernel } val resourcePath: String = "/native/" + plat + "/" + lib @@ -56,6 +44,21 @@ object NativeLoader { case _: UnsatisfiedLinkError => loadPackaged() } + def determinePlatform(): (String, String) = { + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } + + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } + + (os, arch) + } + load() } } diff --git a/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala b/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala index a9106ef3..c5415847 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala @@ -43,19 +43,8 @@ object JniNative extends AutoPlugin { // the value retruned must match that of `com.github.sbt.jni.PlatformMacros#current()` of project `macros` nativePlatform := { try { - val lines = Process("uname -sm").lineStream - if (lines.isEmpty) { - sys.error("Error occured trying to run `uname`") - } - // uname -sm returns " " - val parts = lines.head.split(" ") - if (parts.length != 2) { - sys.error("'uname -sm' returned unexpected string: " + lines.head) - } else { - val arch = parts(1).toLowerCase.replaceAll("\\s", "") - val kernel = parts(0).toLowerCase.replaceAll("\\s", "") - arch + "-" + kernel - } + val (kernel, arch) = determinePlatform() + arch + "-" + kernel } catch { case _: Exception => sLog.value.error("Error trying to determine platform.") @@ -155,6 +144,21 @@ object JniNative extends AutoPlugin { } ) + private def determinePlatform(): (String, String) = { + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } + + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } + + (os, arch) + } + override lazy val projectSettings = settings } From 4a7740f91fe094b580b2ada82edab5f96e8db1d2 Mon Sep 17 00:00:00 2001 From: Martin Jakobsson Date: Tue, 7 Jan 2025 01:31:46 +0100 Subject: [PATCH 2/2] use system properties if `uname` command is not available --- README.md | 2 +- .../com/github/sbt/jni/annotations.scala | 40 ++++++++++++++----- .../github/sbt/jni/syntax/NativeLoader.scala | 38 +++++++++++++----- .../github/sbt/jni/plugins/JniNative.scala | 40 ++++++++++++++----- 4 files changed, 87 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 57019c4d..ce7c45b2 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,7 @@ nativeBuildTool := Meson.make(Nil) |--------------------------------|---------------| | automatic, when JniNative enabled | [JniPackage.scala](plugin/src/main/scala/com/github/sbt/jni/plugins/JniPackage.scala) | -This plugin packages native libraries produced by JniNative in a way that they can be transparently loaded with JniLoad. It uses the notion of a native "platform", defined using the `os.name` and `os.arch` properties. A native binary of a given platform is assumed to be executable on any machines of the same platform. +This plugin packages native libraries produced by JniNative in a way that they can be transparently loaded with JniLoad. It uses the notion of a native "platform", defined as the architecture-kernel values returned by `uname -sm`, or using the `os.name` and `os.arch` properties if the `uname` command is not available. A native binary of a given platform is assumed to be executable on any machines of the same platform. ## Canonical Use diff --git a/core/src/main/scala-2/com/github/sbt/jni/annotations.scala b/core/src/main/scala-2/com/github/sbt/jni/annotations.scala index 310790d9..4978387c 100644 --- a/core/src/main/scala-2/com/github/sbt/jni/annotations.scala +++ b/core/src/main/scala-2/com/github/sbt/jni/annotations.scala @@ -73,18 +73,36 @@ class nativeLoaderAnnotationMacro(val c: Context) { } def determinePlatform(): (String, String) = { - val os = System.getProperty("os.name").toLowerCase match { - case s if s.contains("win") => "windows" - case s if s.contains("mac") => "darwin" - case _ => "linux" - } - - val arch = System.getProperty("os.arch").toLowerCase match { - case "arm64" | "aarch64" => "arm64" - case _ => "x86_64" + try { + val line = + try { + scala.io.Source.fromString(scala.sys.process.Process("uname -sm").!!).getLines().next() + } catch { + case _: Exception => sys.error("Error running `uname` command") + } + val parts = line.split(" ") + if (parts.length != 2) { + sys.error("Could not determine platform: 'uname -sm' returned unexpected string: " + line) + } else { + val arch = parts(1).toLowerCase.replaceAll("\\s", "") + val kernel = parts(0).toLowerCase.replaceAll("\\s", "") + (arch, kernel) + } + } catch { + case _: Exception => + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } + + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } + + (os, arch) } - - (os, arch) } load() diff --git a/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala b/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala index 430ccb67..93ae1bf5 100644 --- a/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala +++ b/core/src/main/scala/com/github/sbt/jni/syntax/NativeLoader.scala @@ -45,18 +45,36 @@ object NativeLoader { } def determinePlatform(): (String, String) = { - val os = System.getProperty("os.name").toLowerCase match { - case s if s.contains("win") => "windows" - case s if s.contains("mac") => "darwin" - case _ => "linux" - } + try { + val line = + try { + scala.io.Source.fromString(scala.sys.process.Process("uname -sm").!!).getLines().next() + } catch { + case _: Exception => sys.error("Error running `uname` command") + } + val parts = line.split(" ") + if (parts.length != 2) { + sys.error("Could not determine platform: 'uname -sm' returned unexpected string: " + line) + } else { + val arch = parts(1).toLowerCase.replaceAll("\\s", "") + val kernel = parts(0).toLowerCase.replaceAll("\\s", "") + (arch, kernel) + } + } catch { + case _: Exception => + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } - val arch = System.getProperty("os.arch").toLowerCase match { - case "arm64" | "aarch64" => "arm64" - case _ => "x86_64" - } + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } - (os, arch) + (os, arch) + } } load() diff --git a/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala b/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala index c5415847..d179e8a8 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/plugins/JniNative.scala @@ -145,18 +145,36 @@ object JniNative extends AutoPlugin { ) private def determinePlatform(): (String, String) = { - val os = System.getProperty("os.name").toLowerCase match { - case s if s.contains("win") => "windows" - case s if s.contains("mac") => "darwin" - case _ => "linux" - } - - val arch = System.getProperty("os.arch").toLowerCase match { - case "arm64" | "aarch64" => "arm64" - case _ => "x86_64" + try { + val line = + try { + scala.io.Source.fromString(scala.sys.process.Process("uname -sm").!!).getLines().next() + } catch { + case _: Exception => sys.error("Error running `uname` command") + } + val parts = line.split(" ") + if (parts.length != 2) { + sys.error("Could not determine platform: 'uname -sm' returned unexpected string: " + line) + } else { + val arch = parts(1).toLowerCase.replaceAll("\\s", "") + val kernel = parts(0).toLowerCase.replaceAll("\\s", "") + (arch, kernel) + } + } catch { + case _: Exception => + val os = System.getProperty("os.name").toLowerCase match { + case s if s.contains("win") => "windows" + case s if s.contains("mac") => "darwin" + case _ => "linux" + } + + val arch = System.getProperty("os.arch").toLowerCase match { + case "arm64" | "aarch64" => "arm64" + case _ => "x86_64" + } + + (os, arch) } - - (os, arch) } override lazy val projectSettings = settings