diff --git a/README.md b/README.md index 1ebf088..3609b32 100644 --- a/README.md +++ b/README.md @@ -153,12 +153,18 @@ Since this plugin is basically a command-line wrapper, native build tools must f An initial, compatible build template can be obtained by running `sbt nativeInit `. Once the native build tool initialised, projects are built by calling the `sbt nativeCompile` task. -Source and output directories are configurable +Source and output directories are configurable: ```scala nativeCompile / sourceDirectory := sourceDirectory.value / "native" nativeCompile / target := target.value / "native" / nativePlatform.value ``` +Some JNI projects may produce more than a single output. If that's an intended behavior it's possible to include all of the produced +binaries into the native package: +```scala +nativeMultipleOutputs := true +``` + #### CMake A regular `CMake` native project definition usually looks this following way: diff --git a/plugin/src/main/scala/com/github/sbt/jni/build/BuildTool.scala b/plugin/src/main/scala/com/github/sbt/jni/build/BuildTool.scala index b5941d4..19a3be7 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/build/BuildTool.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/build/BuildTool.scala @@ -77,12 +77,12 @@ trait BuildTool { /** * Get an instance (build configuration) of this tool, in the specified directory. */ - def getInstance(baseDirectory: File, buildDirectory: File, logger: Logger): Instance + def getInstance(baseDirectory: File, buildDirectory: File, logger: Logger, multipleOutputs: Boolean): Instance /** * At least one produced library is expected. */ - def validate(list: List[File], logger: Logger): List[File] = { + def validate(list: List[File], multipleOutputs: Boolean, logger: Logger): List[File] = { list match { case Nil => sys.error( @@ -91,6 +91,15 @@ trait BuildTool { ) case list @ _ :: Nil => list + + case head :: _ if !multipleOutputs => + logger.warn( + "More than one file was created during compilation, " + + s"only the first one (${head.getAbsolutePath}) will be used." + + "Consider setting nativeMultipleOutputs := true." + ) + List(head) + case list => logger.info("More than one file was created during compilation.") list diff --git a/plugin/src/main/scala/com/github/sbt/jni/build/CMake.scala b/plugin/src/main/scala/com/github/sbt/jni/build/CMake.scala index cfa88e6..fb46276 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/build/CMake.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/build/CMake.scala @@ -14,11 +14,12 @@ class CMake(protected val configuration: Seq[String]) extends BuildTool with Con "/com/github/sbt/jni/templates/CMakeLists.txt" -> "CMakeLists.txt" ) - override def getInstance(baseDir: File, buildDir: File, logger: Logger) = new Instance { + override def getInstance(baseDir: File, buildDir: File, logger: Logger, nativeMultipleOutputs: Boolean) = new Instance { override def log = logger override def baseDirectory = baseDir override def buildDirectory = buildDir + override def multipleOutputs = nativeMultipleOutputs def cmakeProcess(args: String*): ProcessBuilder = Process("cmake" +: args, buildDirectory) diff --git a/plugin/src/main/scala/com/github/sbt/jni/build/Cargo.scala b/plugin/src/main/scala/com/github/sbt/jni/build/Cargo.scala index eaa133c..8084646 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/build/Cargo.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/build/Cargo.scala @@ -18,10 +18,10 @@ class Cargo(protected val configuration: Seq[String]) extends BuildTool { def release: Boolean = configuration.exists(_.toLowerCase.contains("release")) - def getInstance(baseDirectory: File, buildDirectory: File, logger: sbt.Logger): Instance = - new Instance(baseDirectory, logger) + def getInstance(baseDirectory: File, buildDirectory: File, logger: sbt.Logger, multipleOutputs: Boolean): Instance = + new Instance(baseDirectory, logger, multipleOutputs) - class Instance(protected val baseDirectory: File, protected val logger: sbt.Logger) extends super.Instance { + class Instance(protected val baseDirectory: File, protected val logger: sbt.Logger, protected val multipleOutputs: Boolean) extends super.Instance { // IntelliJ friendly logger, IntelliJ doesn't start tests if a line is printed as "error", which Cargo does for regular output protected val log: ProcessLogger = new ProcessLogger { def out(s: => String): Unit = logger.info(s) @@ -44,7 +44,7 @@ class Cargo(protected val configuration: Seq[String]) extends BuildTool { val products: List[File] = (targetDirectory / subdir * ("*.so" | "*.dylib")).get.filter(_.isFile).toList - validate(products, logger) + validate(products, multipleOutputs, logger) } } } diff --git a/plugin/src/main/scala/com/github/sbt/jni/build/ConfigureMakeInstall.scala b/plugin/src/main/scala/com/github/sbt/jni/build/ConfigureMakeInstall.scala index 2da3d47..7fa7848 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/build/ConfigureMakeInstall.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/build/ConfigureMakeInstall.scala @@ -13,6 +13,7 @@ trait ConfigureMakeInstall { self: BuildTool => trait Instance extends self.Instance { def log: Logger + def multipleOutputs: Boolean def baseDirectory: File def buildDirectory: File @@ -36,7 +37,7 @@ trait ConfigureMakeInstall { self: BuildTool => val products: List[File] = (targetDirectory ** ("*.so" | "*.dylib")).get.filter(_.isFile).toList - validate(products, log) + validate(products, multipleOutputs, log) } } diff --git a/plugin/src/main/scala/com/github/sbt/jni/build/Meson.scala b/plugin/src/main/scala/com/github/sbt/jni/build/Meson.scala index 017433b..7d67099 100644 --- a/plugin/src/main/scala/com/github/sbt/jni/build/Meson.scala +++ b/plugin/src/main/scala/com/github/sbt/jni/build/Meson.scala @@ -15,11 +15,12 @@ class Meson(protected val configuration: Seq[String]) extends BuildTool with Con "/com/github/sbt/jni/templates/meson.options" -> "meson.options" ) - override def getInstance(baseDir: File, buildDir: File, logger: Logger) = new Instance { + override def getInstance(baseDir: File, buildDir: File, logger: Logger, nativeMultipleOutputs: Boolean) = new Instance { override def log = logger override def baseDirectory = baseDir override def buildDirectory = buildDir + override def multipleOutputs = nativeMultipleOutputs def mesonProcess(args: String*): ProcessBuilder = Process("meson" +: args, buildDirectory) 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 746e546..a9106ef 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 @@ -30,6 +30,10 @@ object JniNative extends AutoPlugin { "Initialize a native build script from a template." ) + val nativeMultipleOutputs = taskKey[Boolean]( + "Enable multiple native outputs support. Disabled by default." + ) + } import autoImport._ @@ -79,8 +83,8 @@ object JniNative extends AutoPlugin { tools.map(_.name).mkString(",") ) ) - }, + nativeMultipleOutputs := false, nativeBuildToolInstance := { val tool = nativeBuildTool.value val srcDir = (nativeCompile / sourceDirectory).value @@ -89,7 +93,8 @@ object JniNative extends AutoPlugin { tool.getInstance( baseDirectory = srcDir, buildDirectory = buildDir, - logger = streams.value.log + logger = streams.value.log, + multipleOutputs = nativeMultipleOutputs.value ) }, nativeCompile / clean := {