diff --git a/README.md b/README.md index 3609b32a..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 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 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 @@ -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..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 @@ -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,39 @@ class nativeLoaderAnnotationMacro(val c: Context) { case _: UnsatisfiedLinkError => loadPackaged() } + def determinePlatform(): (String, String) = { + 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) + } + } + 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..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 @@ -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,39 @@ object NativeLoader { case _: UnsatisfiedLinkError => loadPackaged() } + def determinePlatform(): (String, String) = { + 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) + } + } + 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..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 @@ -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,39 @@ object JniNative extends AutoPlugin { } ) + private def determinePlatform(): (String, String) = { + 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) + } + } + override lazy val projectSettings = settings }