aboutsummaryrefslogtreecommitdiff
path: root/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Defaults.scala
blob: 49f4a492f784101ff93a6eb2c1df2f161da05087 (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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package ch.jodersky.sbt.jni

import sbt._
import sbt.Keys._
import Keys._

import build.CMake
import build.BuildTool

import ch.jodersky.jni.Platform
import ch.jodersky.jni.NativeLoader

object Defaults {

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

    baseDirectory in jni := (baseDirectory in ThisBuild).value / "native",

    target in jni := target.value / "native" / (jniPlatform in jni).value.id,

    jniPlatform in jni := Platform.current.getOrElse{
      sLog.value.warn("Warning: cannot determine platform! It will be set to 'unknown'.")
      Platform.Unknown
    },

    jniBuildTool in jni := {
      val tools = Seq(CMake)

      val base = (baseDirectory in jni).value

      val tool = if (base.exists && base.isDirectory) {
        tools.find(t => t detect base)
      } else {
        None
      }
      tool.getOrElse(
        sys.error("No supported native build tool detected. " +
          s"Check that the setting 'baseDirectory in jni' (currently $base) " +
          "points to a valid directory. Supported build tools are: " +
          tools.map(_.name).mkString(",")
        )
      )
    },

    clean := {
      val log = streams.value.log
      val tool = try {
        Some((jniBuildTool in jni).value)
      } catch {
        case _: Exception => None
      }
      tool foreach { t =>
        log.debug("Cleaning native build")
        t.api.clean(
          (baseDirectory in jni).value,
          log
        )
      }
      clean.value
    },

    jni := {
      val tool = (jniBuildTool in jni).value
      val dir = (baseDirectory in jni).value
      val targetDir = (target in jni).value / "lib"
      val log = streams.value.log

      tool.api.library(dir, targetDir, log)
    },

    javahClasses in javah := Seq(),

    javahObjects in javah := Seq(),

    target in javah := (baseDirectory in jni).value,

    fullClasspath in javah := (fullClasspath in Compile).value,

    javah := {
      val out = (target in javah).value
      val jcp: Seq[File] = (fullClasspath in javah).value.map(_.data)
      val cp = jcp.mkString(sys.props("path.separator"))

      val classes = (javahClasses in javah).value ++
        (javahObjects in javah).value.map(_ + "$")

      for (clazz <- classes) {
        val parts = Seq(
          "javah",
          "-d", out.getAbsolutePath,
          "-classpath", cp,
          clazz)
        val cmd = parts.mkString(" ")
        val ev = Process(cmd) ! streams.value.log
        if (ev != 0) sys.error(s"Error occured running javah. Exit code: ${ev}")
      }

      out
    }

  )

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

    jniLibraryPath in jni := {
      "/" + (organization.value + "." + name.value).replaceAll("\\.|-", "/")
    },

    unmanagedResourceDirectories in jni := Seq(
      (baseDirectory).value / "lib_native"
    ),

    unmanagedClasspath ++= (unmanagedResourceDirectories in jni).value.map{ file =>
      Attributed.blank(file)
    },

    resourceManaged in jni := (target in jni).value / "lib_managed",

    managedResourceDirectories in jni := Seq(
      (resourceManaged in jni).value
    ),

    managedClasspath ++= {

      //build native library
      val library = jni.value

      //native library as a managed resource file
      val libraryResource = (resourceManaged in jni).value /
        NativeLoader.fullLibraryPath(
          (jniLibraryPath in jni).value,
          (jniPlatform in jni).value
        )

      //copy native library to a managed resource (so it can also be loaded when not packages as a jar)
      IO.copyFile(library, libraryResource)

      Seq(Attributed.blank((resourceManaged in jni).value))
    },

    packageJni in Global := {

      val unmanagedMappings: Seq[(File, String)] = (unmanagedResourceDirectories in jni).value flatMap { dir =>
        val files = (dir **  "*").filter(_.isFile).get
        files map { file =>
          println(file.getAbsolutePath)
          file -> (file relativeTo dir).get.getPath
        }
      }

      managedClasspath.value //call this to generate files in resourceManaged

      val managedMappings: Seq[(File, String)] = (managedResourceDirectories in jni).value flatMap { dir =>
        val files = (dir **  "*").filter(_.isFile).get
        files map { file =>
          println(file.getAbsolutePath)
          file -> (file relativeTo dir).get.getPath
        }
      }

      val out = target.value / (name.value + "-native.jar")

      val manifest = new java.util.jar.Manifest
      Package.makeJar(
        unmanagedMappings ++ managedMappings,
        out,
        manifest,
        streams.value.log
      )
      out
    }

  )

  lazy val clientSettings: Seq[Setting[_]] = Seq(
    libraryDependencies += "ch.jodersky" %% "jni-library" % "0.1-SNAPSHOT",
    fork in run := true,
    artifact in jni := {
      Artifact(
        name = name.value,
        `type` = "jar",
        extension = "jar",
        classifier = Some("native"),
        configurations = Seq(Runtime),
        url = None
      ) extra (
        "platform" -> "all"
      )
    }
  ) ++ addArtifact(artifact in jni, packageJni)

}