aboutsummaryrefslogtreecommitdiff
path: root/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniPackager.scala
blob: 56322adfa7298b4fb281a9c43d6244e62070b8ee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package ch.jodersky.sbt.jni

import build._
import ch.jodersky.jni.{NativeLoader, Platform}
import sbt._
import sbt.Keys._

object JniPackager extends AutoPlugin {

  override def requires = Jni
  override def trigger = allRequirements

  object autoImport {

    //Main task, inspect this first
    val packageNative = taskKey[File]("Packages native libraries in a jar.")

    val nativeLibraryPath = settingKey[String](
      "String that is prepended to the path of a native library when packaged.")

    val enableNativeCompilation = settingKey[Boolean](
      "Determines if native compilation is enabled in a scoped key (typically for packaging).")

    val unmanagedNativeDirectories = settingKey[Seq[File]](
      """|Unmanaged directories containing native libraries. The libraries must be regular files
         |contained in a subdirectory corresponding to a platform.""".stripMargin)

    val unmanagedNativeLibraries = taskKey[Map[Platform, File]]("")

  }
  import autoImport._
  import Jni.autoImport._

  lazy val settings: Seq[Setting[_]] = Seq(

    nativeLibraryPath := {
      val orgPath = organization.value.replaceAll("\\.", "/")
      s"/${orgPath}/${name.value}/native"
    },

    //Make NativeLoader available to project
    libraryDependencies += "ch.jodersky" %% "jni-library" % Version.PluginVersion,

    name in packageNative := {
      name.value + "-native-" + version.value + ".jar"
    },

    enableNativeCompilation in packageNative := true,

    unmanagedNativeDirectories := Seq(baseDirectory.value / "lib_native"),

    unmanagedNativeLibraries := {
      val dirs: Seq[File] = unmanagedNativeDirectories.value
      val seq: Seq[(Platform, File)] = for (
        dir <- dirs;
        platformDir <- dir.listFiles();
        if platformDir.isDirectory;
        platform = Platform.fromId(platformDir.name);
        library <- platformDir.listFiles();
        if library.isFile
      ) yield {
        platform -> library.getCanonicalFile()
      }

      seq.toMap
    },

    packageNative := {
      val log = streams.value.log

      val unmanagedMappings: Seq[(File, String)] = {
        unmanagedNativeLibraries.value.toSeq.map{ case (platform, file) =>
          file -> NativeLoader.fullLibraryPath(
            (nativeLibraryPath in Compile).value,
            platform)
        }
      }

      val enableManaged = (enableNativeCompilation in packageNative).value

      val managedMappings: Seq[(File, String)] = if (enableManaged) {
        val library: File = (nativeCompile in Compile).value
        val path: String = NativeLoader.fullLibraryPath(
          (nativeLibraryPath in Compile).value,
          (nativePlatform in Compile).value
        )
        Seq(library -> path)
      } else {
        Seq()
      }

      val mappings = unmanagedMappings ++ managedMappings
      val manifest = new java.util.jar.Manifest
      val jar: File = (target in nativeCompile).value / (name in packageNative).value

      Package.makeJar(mappings, jar, manifest, log)
      jar
    },

    //Add native jar to runtime classpath. Note that it is not added as a resource (this would cause
    //the native library to included in the main jar).
    unmanagedClasspath in Runtime += Attributed.blank(packageNative.value),

    fork in run := true //fork new JVM, since native libraries can only be loaded once

  )
  override lazy val projectSettings = (settings)


}