aboutsummaryrefslogtreecommitdiff
path: root/plugin/src/main/scala/ch/jodersky/sbt/jni/build
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/src/main/scala/ch/jodersky/sbt/jni/build')
-rw-r--r--plugin/src/main/scala/ch/jodersky/sbt/jni/build/Autotools.scala.notyet28
-rw-r--r--plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildTool.scala68
-rw-r--r--plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala33
-rw-r--r--plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala55
4 files changed, 184 insertions, 0 deletions
diff --git a/plugin/src/main/scala/ch/jodersky/sbt/jni/build/Autotools.scala.notyet b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/Autotools.scala.notyet
new file mode 100644
index 0000000..7d81858
--- /dev/null
+++ b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/Autotools.scala.notyet
@@ -0,0 +1,28 @@
+package ch.jodersky.sbt.jni
+package build
+
+import java.io.File
+import sbt._
+
+object Autotools extends BuildTool with ConfigureMakeInstall {
+
+ val name = "Autotools"
+
+ def detect(baseDirectory: File) = baseDirectory.list().contains("configure")
+
+ override def getInstance(baseDir: File, buildDir: File, logger: Logger) = new Instance {
+
+ override def log = logger
+ override def baseDirectory = baseDir
+ override def buildDirectory = buildDir
+
+ override def configure(target: File) = Process(
+ s"${base.getAbsolutePath}/configure " +
+ s"--prefix=${target.getAbsolutePath} " +
+ s"--libdir=${target.getAbsolutePath} " +
+ "--disable-versioned-lib",
+ build
+ )
+ }
+
+} \ No newline at end of file
diff --git a/plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildTool.scala b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildTool.scala
new file mode 100644
index 0000000..3d0deb1
--- /dev/null
+++ b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildTool.scala
@@ -0,0 +1,68 @@
+package ch.jodersky.sbt.jni
+package build
+
+import java.io.{ File, InputStream }
+import java.nio.file.Files
+
+import scala.io.Source
+import sbt.Logger
+
+trait BuildTool {
+
+ /** Name of this build tool. */
+ def name: String
+
+ /** Detect if this build tool is configured in the given directory.
+ * E.g. for the Make build tool, this would return true if a Makefile is present
+ * in the given directory.
+ */
+ def detect(baseDirectory: File): Boolean
+
+ protected def templateMappings: Seq[(String, String)]
+
+ /** Initialize the given directory with a minimal, functioning configuration for
+ * this build tool. E.g. for the Make build tool, this would create a Makefile in
+ * the given directory that is compatible with sbt-jni.
+ * @return all created files
+ */
+ def initTemplate(baseDirectory: File, projectName: String): Seq[File] =
+ for ((resource, name) <- templateMappings) yield {
+ val resourceStream = this.getClass.getResourceAsStream(resource)
+
+ if (resourceStream == null) sys.error(s"Template for $name not found.")
+
+ val raw = Source.fromInputStream(resourceStream).mkString("")
+ val replaced = raw.replaceAll("\\{\\{project\\}\\}", projectName)
+
+ baseDirectory.mkdir()
+ val out = baseDirectory.toPath().resolve(name)
+ Files.write(out, replaced.getBytes)
+ out.toFile()
+ }
+
+ /** Actual tasks that can be perfomed on a specific configuration, such as
+ * configured in a Makefile.
+ */
+ trait Instance {
+
+ /** Invokes the native build tool's clean task */
+ def clean(): Unit
+
+ /** Invokes the native build tool's main task, resulting in a single shared
+ * library file.
+ * @param baseDirectory the directory where the native project is located
+ * @param buildDirectory a directory from where the build is called, it may be used
+ * to store temporary files
+ * @param targetDirectory the directory into which the native library is copied
+ * @return the native library file
+ */
+ def library(
+ targetDirectory: File
+ ): File
+
+ }
+
+ /** Get an instance (build configuration) of this tool, in the specified directory. */
+ def getInstance(baseDirectory: File, buildDirectory: File, logger: Logger): Instance
+
+}
diff --git a/plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala
new file mode 100644
index 0000000..eb7be1e
--- /dev/null
+++ b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala
@@ -0,0 +1,33 @@
+package ch.jodersky.sbt.jni
+package build
+
+import sbt._
+
+object CMake extends BuildTool with ConfigureMakeInstall {
+
+ override val name = "CMake"
+
+ override def detect(baseDirectory: File) = baseDirectory.list().contains("CMakeLists.txt")
+
+ override protected def templateMappings = Seq(
+ "/ch/jodersky/sbt/jni/templates/CMakeLists.txt" -> "CMakeLists.txt"
+ )
+
+ override def getInstance(baseDir: File, buildDir: File, logger: Logger) = new Instance {
+
+ override def log = logger
+ override def baseDirectory = baseDir
+ override def buildDirectory = buildDir
+
+ override def configure(target: File) = Process(
+ // disable producing versioned library files, not needed for fat jars
+ "cmake " +
+ s"-DCMAKE_INSTALL_PREFIX:PATH=${target.getAbsolutePath} " +
+ s"-DLIB_INSTALL_DIR:PATH=${target.getAbsolutePath} " +
+ "-DLIB_ENABLE_MINOR_VERSIONS:BOOLEAN=OFF " +
+ baseDirectory.getAbsolutePath,
+ buildDirectory
+ )
+ }
+
+}
diff --git a/plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala
new file mode 100644
index 0000000..7bfedae
--- /dev/null
+++ b/plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala
@@ -0,0 +1,55 @@
+package ch.jodersky.sbt.jni
+package build
+
+import java.io.File
+import sbt._
+
+trait ConfigureMakeInstall { self: BuildTool =>
+
+ /* API for native build tools that use a standard 'configure && make && make install' process,
+ * where the configure step is left ab
+ stract. */
+ trait Instance extends self.Instance {
+
+ def log: Logger
+ def baseDirectory: File
+ def buildDirectory: File
+
+ def clean() = Process("make clean", buildDirectory) ! log
+
+ def configure(targetDirectory: File): ProcessBuilder
+
+ def make(): ProcessBuilder = Process("make", buildDirectory)
+
+ def install(): ProcessBuilder = Process("make install", buildDirectory)
+
+ def library(
+ targetDirectory: File
+ ): File = {
+
+ val ev: Int = (
+ configure(targetDirectory) #&& make() #&& install()
+ ) ! log
+
+ if (ev != 0) sys.error(s"Building native library failed. Exit code: ${ev}")
+
+ val products: List[File] =
+ (targetDirectory ** ("*.so" | "*.dylib")).get.filter(_.isFile).toList
+
+ // only one produced library is expected
+ products match {
+ case Nil =>
+ sys.error(s"No files were created during compilation, " +
+ "something went wrong with the ${name} configuration.")
+ case head :: Nil =>
+ head
+ case head :: tail =>
+ log.warn("More than one file was created during compilation, " +
+ s"only the first one (${head.getAbsolutePath}) will be used.")
+ head
+ }
+ }
+ }
+
+}
+