diff options
Diffstat (limited to 'plugin/src/main/scala/ch/jodersky/sbt/jni/build')
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 + } + } + } + +} + |