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
|
import sbt._
import Keys._
import java.io.File
import scala.collection.mutable.HashSet
case class NativeBuild(
name: String,
cCompiler: String,
cFlags: Seq[String],
linker: String,
linkerFlags: Seq[String],
binary: String)
object NativeKeys {
//build settings
val nativeBuilds = taskKey[Seq[NativeBuild]]("All native build configurations, including cross-compilation.")
val nativeVersion = settingKey[String]("Version of native binary")
//compile settings
val nativeIncludeDirectories = settingKey[Seq[File]]("Directories to include during build (gcc -I option)")
//link settings
val nativeLibraries = settingKey[Seq[String]]("Default names of libraries to use during linking.")
val nativeLibraryDirectories = settingKey[Seq[File]]("Directories to search for libraries (gcc -L option)")
//directories
val nativeSource = settingKey[File]("Lowest level directory containing all native sources.")
val nativeCSources = taskKey[Seq[File]]("All c source files.")
val nativeTargetDirectory = settingKey[File]("Directory containing all compiled and linked files.")
//tasks
val nativeCompile = taskKey[Map[NativeBuild, Seq[File]]]("Compile all native build configurations.")
val nativeLink = taskKey[Map[NativeBuild, File]]("Link all native build configurations.")
}
object NativeDefaults {
import NativeKeys._
private def generate(generators: SettingKey[Seq[Task[Seq[File]]]]) = generators { _.join.map(_.flatten) }
private def compile(logger: Logger, compiler: String, flags: Seq[String], includeDirectories: Seq[File], src: File, out: File): File = {
IO.createDirectory(out.getParentFile)
val parts: Seq[String] =
Seq(compiler) ++
flags ++
includeDirectories.map("-I" + _.getAbsolutePath) ++
Seq("-o", out.getAbsolutePath) ++
Seq("-c", src.getAbsolutePath)
val cmd = parts.mkString(" ")
logger.info(cmd)
val ev = Process(cmd) ! logger
if (ev != 0) throw new RuntimeException(s"Compilation of ${src.getAbsoluteFile()} failed.")
out
}
private def link(logger: Logger, linker: String, flags: Seq[String], libraryDirectories: Seq[File], libraries: Seq[String], in: Seq[File], out: File): File = {
val parts: Seq[String] =
Seq(linker) ++
flags ++
Seq("-o", out.getAbsolutePath) ++
in.map(_.getAbsolutePath) ++
libraryDirectories.map("-L" + _.getAbsolutePath) ++
libraries.map("-l" + _)
val cmd = parts.mkString(" ")
logger.info(cmd)
val ev = Process(cmd) ! logger
if (ev != 0) throw new RuntimeException(s"Linking of ${out.getAbsoluteFile()} failed.")
out
}
def nativeCompileImpl() = Def.task {
val logger = streams.value.log
val builds = nativeBuilds.value
val outDir = nativeTargetDirectory.value
val includeDirs = nativeIncludeDirectories.value
val csrcs = nativeCSources.value
val compilations = for (build <- builds) yield {
logger.info("Compiling configuration " + build.name)
val objects = for (src <- csrcs) yield {
compile(logger, build.cCompiler, build.cFlags, includeDirs, src, outDir / build.name / "objects" / (src.base + ".o"))
}
build -> objects
}
compilations.toMap
}
lazy val nativeLinkImpl = Def.task {
val logger = streams.value.log
val builds = nativeBuilds.value
val outDir = nativeTargetDirectory.value
val libDirs = nativeLibraryDirectories.value
val libs = nativeLibraries.value
val compilations = nativeCompile.value
val version = nativeVersion.value
val linkages = for (build <- builds) yield {
logger.info("Linking configuration " + build.name)
val objects = compilations(build)
val binary = link(logger, build.linker, build.linkerFlags, libDirs, libs, objects, outDir / build.name / build.binary)
build -> binary
}
linkages.toMap
}
def localPlatform = try {
Process("gcc -dumpmachine").lines.headOption
} catch {
case ex: Exception => None
}
val settings: Seq[Setting[_]] = Seq(
//nativeBuilds :=
nativeSource := (sourceDirectory in Compile).value / "native",
includeFilter in nativeCSources := "*.c",
nativeCSources := (nativeSource.value ** (includeFilter in nativeCSources).value).get,
nativeTargetDirectory := target.value / "native",
nativeIncludeDirectories := Seq(nativeSource.value, nativeSource.value / "include"),
nativeLibraries := Seq(),
nativeLibraryDirectories := Seq(),
nativeCompile := nativeCompileImpl.value,
nativeLink := nativeLinkImpl.value
)
}
|