From 2b8d4feff9a342910192218a33fc9880abc1f33d Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Fri, 18 Apr 2014 19:36:21 +0200 Subject: reinstore native jars --- .../jodersky/flow/internal/NativeSerial.java | 2 +- .../jodersky/flow/internal/NativeLoader.scala | 40 +++++++++++ project/Dependencies.scala | 3 + project/FlowBuild.scala | 16 +++-- project/native.scala | 82 ++++++++++++++++++++++ project/nativeFat.scala | 69 ------------------ 6 files changed, 135 insertions(+), 77 deletions(-) create mode 100644 flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala create mode 100644 project/native.scala delete mode 100644 project/nativeFat.scala diff --git a/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java b/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java index 22306e0..c159058 100644 --- a/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java +++ b/flow/src/main/java/com/github/jodersky/flow/internal/NativeSerial.java @@ -25,7 +25,7 @@ import com.github.jodersky.flow.PortInterruptedException; final class NativeSerial { static { - System.loadLibrary("flow3"); + NativeLoader.load("flow3"); } final static int PARITY_NONE = 0; diff --git a/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala b/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala new file mode 100644 index 0000000..8fe1e3b --- /dev/null +++ b/flow/src/main/scala/com/github/jodersky/flow/internal/NativeLoader.scala @@ -0,0 +1,40 @@ +package com.github.jodersky.flow.internal + +import java.io.File +import scalax.file.Path +import scalax.io.Resource +import java.security.CodeSource +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.net.URL + +/** Handles loading of the current platform's native library for flow. */ +object NativeLoader { + + private def os = System.getProperty("os.name").toLowerCase.filter(_ != ' ') + + private def arch = System.getProperty("os.arch").toLowerCase + + private def extractNative(nativeLibrary: String): Option[File] = { + val fqlib = System.mapLibraryName(nativeLibrary) //fully qualified library name + + val in = NativeLoader.getClass().getResourceAsStream(s"/native/${os}-${arch}/${fqlib}") + if (in == null) return None + + val temp = Path.createTempFile(nativeLibrary) + Resource.fromInputStream(in).copyDataTo(temp) + temp.fileOption + } + + private def loadFromJar(nativeLibrary: String) = extractNative(nativeLibrary) match { + case Some(file) => System.load(file.getAbsolutePath) + case None => throw new UnsatisfiedLinkError("Cannot extract flow's native library, the native library may not exist for your specific architecture/OS combination.") + } + + def load(nativeLibrary: String) = try { + System.loadLibrary(nativeLibrary) + } catch { + case ex: UnsatisfiedLinkError => loadFromJar(nativeLibrary) + } + +} \ No newline at end of file diff --git a/project/Dependencies.scala b/project/Dependencies.scala index b9d5cb9..9590394 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -4,4 +4,7 @@ object Dependencies { lazy val akkaActor = "com.typesafe.akka" %% "akka-actor" % "2.2.0" + lazy val ioCore = "com.github.scala-incubator.io" %% "scala-io-file" % "0.4.2" + lazy val ioFile = "com.github.scala-incubator.io" %% "scala-io-file" % "0.4.2" + } diff --git a/project/FlowBuild.scala b/project/FlowBuild.scala index e7a21d7..688743b 100644 --- a/project/FlowBuild.scala +++ b/project/FlowBuild.scala @@ -65,15 +65,15 @@ object FlowBuild extends Build { settings (commonSettings: _*) settings (publishSettings: _*) settings (JniDefaults.settings: _*) + settings(NativeDefaults.settings: _*) settings( - javahHeaderDirectory := (baseDirectory in ThisBuild).value / "flow-native" / "include", + nativeBuildDirectory := (baseDirectory in ThisBuild).value / "flow-native", + javahHeaderDirectory := nativeBuildDirectory.value / "src", javahClasses := Seq("com.github.jodersky.flow.internal.NativeSerial"), compileOrder in Compile := CompileOrder.Mixed, - libraryDependencies += Dependencies.akkaActor - ) - settings(NativeDefaults.settings: _*) - settings( - nativeBuildDirectory := (baseDirectory in ThisBuild).value / "flow-native" + libraryDependencies += Dependencies.akkaActor, + libraryDependencies += Dependencies.ioCore, + libraryDependencies += Dependencies.ioFile ) ) @@ -81,7 +81,9 @@ object FlowBuild extends Build { Project("flow-samples-terminal", file("flow-samples") / "flow-samples-terminal") settings(commonSettings: _*) settings(runSettings: _*) - //dependsOn(flowPack) + settings( + unmanagedJars in Compile += (nativePackage in flow).value + ) dependsOn(flow) ) diff --git a/project/native.scala b/project/native.scala new file mode 100644 index 0000000..84537a3 --- /dev/null +++ b/project/native.scala @@ -0,0 +1,82 @@ +import sbt._ +import Keys._ +import java.io.File +import java.util.jar.Manifest + +object NativeKeys { + + val nativeBuildDirectory = settingKey[File]("Directory containing native build scripts.") + val nativeTargetDirectory = settingKey[File]("Base directory to store native products.") + val nativeOutputDirectory = settingKey[File]("Actual directory where native products are stored.") + val nativePackageUnmanagedDirectory = settingKey[File]("Directory containing external products that will be copied to the native jar.") + val nativePackageArtifact = settingKey[Artifact]("Native artifact.") + + + val nativeBuild = taskKey[File]("Invoke native build.") + val nativePackage = taskKey[File]("Package native products into a jar.") + +} + +object NativeDefaults { + import NativeKeys._ + + val autoLib = Def.task { + val log = streams.value.log + val build = nativeBuildDirectory.value + val out = nativeOutputDirectory.value + + val configure = Process( + "./configure " + + "--prefix=" + out.getAbsolutePath + " " + + "--libdir=" + out.getAbsolutePath + " " + + "--disable-versioned-lib", + build) + + val make = Process("make", build) + + val makeInstall = Process("make install", build) + + val ev = configure #&& make #&& makeInstall ! log + if (ev != 0) + throw new RuntimeException(s"Building native library failed.") + + (out ** ("*.la")).get.foreach(_.delete()) + + out + } + + val nativePackageImpl = Def.task { + val managedDir = nativeTargetDirectory.value + val unmanagedDir = nativePackageUnmanagedDirectory.value + + val managed = (nativeBuild.value ** "*").get + val unmanaged = (unmanagedDir ** "*").get + + val jarFile = nativeTargetDirectory.value / (name.value + "-" + version.value + "-native.jar") + + val managedMappings: Seq[(File, String)] = for (file <- managed; if file.isFile) yield { + file -> ("native/" + (file relativeTo managedDir).get.getPath) + } + + val unmanagedMappings: Seq[(File, String)] = for (file <- unmanaged; if file.isFile) yield { + file -> ("native/" + (file relativeTo unmanagedDir).get.getPath) + } + + IO.jar(managedMappings ++ unmanagedMappings, jarFile, new Manifest()) + jarFile + } + + def os = System.getProperty("os.name").toLowerCase.filter(_ != ' ') + def arch = System.getProperty("os.arch").toLowerCase + + val settings: Seq[Setting[_]] = Seq( + nativeTargetDirectory := target.value / "native", + nativeOutputDirectory := nativeTargetDirectory.value / (os + "-" + arch), + nativeBuild := autoLib.value, + nativePackage := nativePackageImpl.value, + nativePackageArtifact := Artifact(name.value, "native"), + nativePackageUnmanagedDirectory := baseDirectory.value / "lib_native" + ) ++ addArtifact(nativePackageArtifact, nativePackage).settings + +} + diff --git a/project/nativeFat.scala b/project/nativeFat.scala deleted file mode 100644 index 55df06d..0000000 --- a/project/nativeFat.scala +++ /dev/null @@ -1,69 +0,0 @@ -import sbt._ -import Keys._ -import java.io.File - -object NativeKeys { - - val nativeBuildDirectory = settingKey[File]("Directory containing native build scripts.") - val nativeTarget = settingKey[File]("Target directory to store native artifacts.") - - val nativeBuild = taskKey[File]("Invoke native build.") - - val nativePackUnmanaged = settingKey[File]("") -} - -object NativeDefaults { - import NativeKeys._ - - val nativeBuildImpl = Def.task { - val log = streams.value.log - val build = nativeBuildDirectory.value - val target = nativeTarget.value - - val configure = Process( - "./configure " + - "--prefix=" + target.getAbsolutePath + " " + - "--libdir=" + target.getAbsolutePath, - Some(build)) - - val make = Process("make", build) - - val makeInstall = Process("make install", build) - - val ev = configure #&& make #&& makeInstall ! log - if (ev != 0) - throw new RuntimeException(s"Building native library failed.") - - (target ** ("*.la")).get.foreach(_.delete()) - - target - } - - - val mappingsImpl = Def.task { - val files = (nativeBuild.value ** "*").get - val unamanagedDir = nativePackUnmanaged.value - - val managed: Seq[(File, String)] = for (file <- files; if file.isFile) yield { - file -> ("native/" + (file relativeTo nativeTarget.value).get.getPath) - } - - val unmanaged: Seq[(File, String)] = for (file <- (unamanagedDir ** "*").get; if file.isFile) yield { - file -> ("native/" + (file relativeTo unamanagedDir).get.getPath) - } - - managed ++ unmanaged - } - - def os = System.getProperty("os.name").toLowerCase.filter(_ != ' ') - def arch = System.getProperty("os.arch").toLowerCase - - val settings: Seq[Setting[_]] = Seq( - nativeTarget := target.value / "native" / (os + "-" + arch), - nativeBuild := nativeBuildImpl.value, - nativePackUnmanaged := baseDirectory.value / "lib_native", - mappings in (Compile, packageBin) ++= mappingsImpl.value - ) - -} - -- cgit v1.2.3