Skip to content

Commit

Permalink
Implement the build task using reflection to remove javacpp library a…
Browse files Browse the repository at this point in the history
…s a dependency of the plugin
  • Loading branch information
thirstycrow committed Oct 24, 2019
1 parent 384f8f1 commit 1eb0850
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ you can change the target platform for your build straight from your command lin
sbt compile -Dsbt.javacpp.platform="android-arm android-x86"
```

In case you want to select a different javacpp version, add the following line in your `project/plugins.sbt`:
In case you want to select a different javacpp version:

```scala
libraryDependencies += "org.bytedeco" % "javacpp" % "1.5.1"
javaCppVersion := "1.4.3"
```
2 changes: 0 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ publishArtifact in Test := false

pomIncludeRepository := { _ => false }

libraryDependencies += "org.bytedeco" % "javacpp" % "1.4.3"

scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature", "-Xlint", "-Xlog-free-terms")

publishTo := {
Expand Down
70 changes: 53 additions & 17 deletions src/main/scala/org/bytedeco/sbt/javacpp/JavaCppPlugin.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.bytedeco.sbt.javacpp

import org.bytedeco.javacpp.tools.Builder
import java.net.URLClassLoader
import java.util.Properties

import sbt.Keys._
import sbt._

import scala.language.postfixOps
import scala.language.{ postfixOps, reflectiveCalls }
import scala.util.Try

object JavaCppPlugin extends AutoPlugin {
Expand All @@ -14,30 +16,60 @@ object JavaCppPlugin extends AutoPlugin {
Seq(
autoCompilerPlugins := true,
javaCppClasses := Seq.empty,
javaCppCustomization := identity,
javaCppCustomizer := identity,
javaCppPlatform := Platform.current,
javaCppPresetLibs := Seq.empty,
libraryDependencies += {
"org.bytedeco" % "javacpp" % Versions.javaCppVersion jar
"org.bytedeco" % "javacpp" % javaCppVersion.value jar
},
javaCppPresetDependencies,
javaCppBuild := javaCpp.value,
products in Compile := (products in Compile).dependsOn(javaCppBuild).value)
}

object Versions {
val javaCppVersion = {
val javaCppJar = classOf[Builder].getProtectionDomain.getCodeSource.getLocation.getFile
"(?<=javacpp-)(.*)(?=\\.jar)".r.findFirstIn(javaCppJar).get
}
val javaCppVersion = "1.4.3"
}

object autoImport {
val javaCppCustomization = SettingKey[Builder => Builder]("javaCppCustomization", "Customize the Java CPP builder")
type JavaCppBuilder = {
def classPaths(classPath: String): this.type
def classPaths(classPath: Array[String]): this.type
def encoding(encoding: String): this.type
def outputDirectory(outputDirectory: String): this.type
def outputDirectory(outputDirectory: File): this.type
def clean(clean: Boolean): this.type
def generate(generate: Boolean): this.type
def compile(compile: Boolean): this.type
def deleteJniFiles(deleteJniFiles: Boolean): this.type
def header(header: Boolean): this.type
def copyLibs(copyLibs: Boolean): this.type
def copyResources(copyResources: Boolean): this.type
def outputName(outputName: String): this.type
def jarPrefix(jarPrefix: String): this.type
def properties(platform: String): this.type
def properties(properties: Properties): this.type
def propertyFile(propertyFile: String): this.type
def propertyFile(propertyFile: File): this.type
def property(keyValue: String): this.type
def property(key: String, value: String): this.type
def classesOrPackages(classes: Array[String]): this.type
def buildCommand(buildCommand: Array[String]): this.type
def workingDirectory(workingDirectory: String): this.type
def workingDirectory(workingDirectory: File): this.type
def environmentVariables(environmentVariables: java.util.Map[String, String]): this.type
def compilerOptions(options: Array[String]): this.type
def build(): Array[File]
def printHelp(): Unit
def getClass(): Class[_]
}

val javaCppBuild = TaskKey[Seq[File]]("javaCppBuild", "Build Java CPP products")
val javaCppClasses = SettingKey[Seq[String]]("javaCppClasses", "A list of Java CPP classes. Suffix of '.*' ('.**') can be used to match all classes under the specified package (and any subpackages)")
val javaCppCustomizer = SettingKey[JavaCppBuilder => JavaCppBuilder]("javaCppCustomization", "Customize the Java CPP builder")
val javaCppPlatform = SettingKey[Seq[String]]("javaCppPlatform", """The platform that you want to compile for (defaults to the platform of the current computer). You can also set this via the "sbt.javacpp.platform" System Property """)
val javaCppPresetLibs = SettingKey[Seq[(String, String)]]("javaCppPresetLibs", "List of additional JavaCPP presets that you would wish to bind lazily, defaults to an empty list")
val javaCppClasses = SettingKey[Seq[String]]("javaCppClasses", "A list of Java CPP classes. Suffix of '.*' ('.**') can be used to match all classes under the specified package (and any subpackages)")
val javaCppBuild = TaskKey[Seq[File]]("javaCppBuild", "Build Java CPP products")
val javaCppVersion = SettingKey[String]("javaCppVersion", s"Version of Java CPP that you want to use, defaults to ${Versions.javaCppVersion}")
}

override def requires: Plugins = plugins.JvmPlugin
Expand Down Expand Up @@ -83,20 +115,24 @@ object JavaCppPlugin extends AutoPlugin {
private def javaCpp = Def.task {
import autoImport._
val classes = javaCppClasses.value
val customization = javaCppCustomization.value
val customizer = javaCppCustomizer.value
val dependencies = (dependencyClasspath in Compile).value
val output = (classDirectory in Compile).value
val _ = (compile in Compile).value

val cl = new URLClassLoader(dependencies.map(_.data.toURI.toURL).toArray, null)
val builder = cl.loadClass("org.bytedeco.javacpp.tools.Builder").newInstance().asInstanceOf[JavaCppBuilder]

val thread = Thread.currentThread()
val saved = thread.getContextClassLoader
thread.setContextClassLoader(classOf[Builder].getClassLoader)
thread.setContextClassLoader(cl)

try {
customization(
new Builder()
customizer(
builder
.classPaths(output.getAbsolutePath)
.classPaths(dependencies.map(_.data.absolutePath): _*)
.classesOrPackages(classes: _*)).build()
.classPaths(dependencies.map(_.data.absolutePath).toArray)
.classesOrPackages(classes.toArray)).build()
} finally {
thread.setContextClassLoader(saved)
}
Expand Down
30 changes: 24 additions & 6 deletions src/main/scala/org/bytedeco/sbt/javacpp/Platform.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package org.bytedeco.sbt.javacpp

import org.bytedeco.javacpp.Loader

/**
* Created by Lloyd on 2/22/16.
*/

object Platform {

private val platformOverridePropertyKey: String = "sbt.javacpp.platform"
Expand All @@ -20,7 +17,28 @@ object Platform {
*/
val current: Seq[String] = sys.props.get(platformOverridePropertyKey) match {
case Some(platform) if platform.trim().nonEmpty => platform.split(' ')
case _ => Seq(Loader.getPlatform)
case _ =>
val jvmName = System.getProperty("java.vm.name", "").toLowerCase
var osName = System.getProperty("os.name", "").toLowerCase
var osArch = System.getProperty("os.arch", "").toLowerCase
val abiType = System.getProperty("sun.arch.abi", "").toLowerCase
val libPath = System.getProperty("sun.boot.library.path", "").toLowerCase
if (jvmName.startsWith("dalvik") && osName.startsWith("linux")) {
osName = "android"
} else if (jvmName.startsWith("robovm") && osName.startsWith("darwin")) {
osName = "ios"
osArch = "arm"
} else if (osName.startsWith("mac os x") || osName.startsWith("darwin")) {
osName = "macosx"
} else {
val spaceIndex = osName.indexOf(' ')
if (spaceIndex > 0) osName = osName.substring(0, spaceIndex)
}
if (osArch == "i386" || osArch == "i486" || osArch == "i586" || osArch == "i686") osArch = "x86"
else if (osArch == "amd64" || osArch == "x86-64" || osArch == "x64") osArch = "x86_64"
else if (osArch.startsWith("aarch64") || osArch.startsWith("armv8") || osArch.startsWith("arm64")) osArch = "arm64"
else if (osArch.startsWith("arm") && ((abiType == "gnueabihf") || libPath.contains("openjdk-armhf"))) osArch = "armhf"
else if (osArch.startsWith("arm")) osArch = "arm"
Seq(osName + "-" + osArch)
}

}
}
4 changes: 4 additions & 0 deletions src/sbt-test/sbt-javacpp/simple/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ scalaVersion := "2.11.12"

javaCppClasses := Seq("javacpp.*")

javaCppVersion := "1.5.1"

javaCppCustomizer := { builder => builder.compilerOptions(Array("-std=c++11")) }

libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % Test
2 changes: 0 additions & 2 deletions src/sbt-test/sbt-javacpp/simple/project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
else addSbtPlugin("org.bytedeco" % "sbt-javacpp" % pluginVersion)
}

libraryDependencies += "org.bytedeco" % "javacpp" % "1.5.1"

0 comments on commit 1eb0850

Please sign in to comment.