Skip to content

Commit 91b8136

Browse files
authored
Merge pull request #146 from jonas/sbt-plugin
Use the builder from the tools project in the sbt plugin
2 parents 667ad50 + 4a68435 commit 91b8136

File tree

8 files changed

+196
-233
lines changed

8 files changed

+196
-233
lines changed

docs/src/paradox/obtaining-bindgen/sbt-plugin.md

+10-14
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@ resolvers += Resolver.bintrayRepo("scala-native-bindgen", "maven")
1111
```
1212
@@@
1313

14-
Next configure the plugin using the settings scoped to either `Compile` or `Test`:
15-
16-
|---------------------------|-------------------|
17-
|`nativeBindgenHeader` | The C header file to read.
18-
|`nativeBindgenPackage` | Package of the enclosing object. No package by default.
19-
|`name in nativeBindgen` | Name of the enclosing object.
20-
|`nativeBindgenLink` | Name of library to be linked.
14+
Next configure the plugin using the `nativeBindings` setting scoped to either `Compile` or `Test`. The `NativeBinding` type to configure each binding that should be generated.
2115

2216
@@@ note
2317

@@ -37,15 +31,17 @@ Example settings:
3731
enablePlugins(ScalaNativeBindgenPlugin)
3832
inConfig(Compile)(
3933
Def.settings(
40-
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
41-
nativeBindgenPackage := Some("org.example.mylib"),
42-
nativeBindgenLink := Some("mylib"), // Will pass `-lmylib` to the linker
43-
nativeBindgenExclude := Some("__"),
44-
name in nativeBindgen := "MyLib"
34+
nativeBindings += {
35+
NativeBinding((resourceDirectory in Compile).value / "header.h")
36+
.name("MyLib")
37+
.packageName("org.example.mylib")
38+
.link("mylib"), // Will pass `-lmylib` to the linker
39+
.excludePrefix("__")
40+
}
4541
))
4642
```
4743

48-
Running `nativeBindgen` will generate a file named `target/scala-2.x/src_managed/main/sbt-scala-native-bindgen//ScalaNativeBindgen.scala` containing something along the following lines:
44+
Running `nativeBindgen` will generate a file named `target/scala-2.x/src_managed/main/sbt-scala-native-bindgen/MyLib.scala` containing something along the following lines:
4945

5046
```scala
5147
package org.example.mylib
@@ -58,4 +54,4 @@ import scala.scalanative.native._
5854
object MyLib {
5955
// ... left out for brevity ...
6056
}
61-
```
57+
```

sbt-scala-native-bindgen/src/main/scala/org/scalanative/bindgen/sbt/ScalaNativeBindgenPlugin.scala

+18-35
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import sbt.Keys._
66
import java.nio.file.Files
77
import java.nio.file.attribute.{PosixFileAttributeView, PosixFilePermission}
88

9-
import org.scalanative.bindgen.Bindgen
9+
import org.scalanative.bindgen.{Bindgen, BindingOptions}
1010

1111
/**
1212
* Generate Scala bindings from C headers.
@@ -37,21 +37,20 @@ import org.scalanative.bindgen.Bindgen
3737
*
3838
* @example
3939
* {{{
40-
* nativeBindgenHeader in Compile := file("/usr/include/ctype.h")
41-
* nativeBindgenPackage in Compile := Some("org.example.app")
42-
* name in (Compile, nativeBindgen) := "ctype"
40+
* nativeBindings += {
41+
* NativeBinding(file("/usr/include/uv.h"))
42+
* .name("uv")
43+
* .packageName("org.example.uv")
44+
* .link("uv"),
45+
* .excludePrefix("__")
46+
* }
4347
* }}}
4448
*/
4549
object ScalaNativeBindgenPlugin extends AutoPlugin {
4650

4751
object autoImport {
48-
case class NativeBinding(
49-
name: String,
50-
header: File,
51-
packageName: Option[String],
52-
link: Option[String],
53-
excludePrefix: Option[String]
54-
)
52+
type NativeBinding = BindingOptions
53+
val NativeBinding = BindingOptions
5554
val ScalaNativeBindgen = config("scala-native-bindgen").hide
5655
val nativeBindgenPath =
5756
taskKey[File]("Path to the scala-native-bindgen executable")
@@ -105,14 +104,6 @@ object ScalaNativeBindgenPlugin extends AutoPlugin {
105104
}
106105
)
107106

108-
private implicit class BindgenOps(val bindgen: Bindgen) extends AnyVal {
109-
def maybe[T](opt: Option[T], f: Bindgen => T => Bindgen): Bindgen =
110-
opt match {
111-
case None => bindgen
112-
case Some(value) => f(bindgen)(value)
113-
}
114-
}
115-
116107
private val artifactName =
117108
Option(System.getProperty("os.name")).collect {
118109
case "Mac OS X" => "scala-native-bindgen-darwin"
@@ -126,34 +117,26 @@ object ScalaNativeBindgenPlugin extends AutoPlugin {
126117
sourceGenerators += Def.task { nativeBindgen.value },
127118
target in nativeBindgen := sourceManaged.value / "sbt-scala-native-bindgen",
128119
nativeBindgen := {
129-
val bindgenPath = nativeBindgenPath.value
130-
val bindings = nativeBindings.value
120+
val bindgen = Bindgen(nativeBindgenPath.value)
121+
val optionsList = nativeBindings.value
131122
val outputDirectory = (target in nativeBindgen).value
132123
val logger = streams.value.log
133124

134-
bindings.map {
135-
binding =>
136-
val output = outputDirectory / s"${binding.name}.scala"
137-
val result = Bindgen()
138-
.bindgenExecutable(bindgenPath)
139-
.header(binding.header)
140-
.name(binding.name)
141-
.maybe(binding.link, _.link)
142-
.maybe(binding.packageName, _.packageName)
143-
.maybe(binding.excludePrefix, _.excludePrefix)
144-
.generate()
125+
// FIXME: Check uniqueness of names.
145126

146-
result match {
127+
optionsList.map {
128+
options =>
129+
bindgen.generate(options) match {
147130
case Right(bindings) =>
131+
val output = outputDirectory / s"${bindings.name}.scala"
148132
bindings.writeToFile(output)
149133
bindings.errors.foreach(error => logger.error(error))
134+
output
150135
case Left(errors) =>
151136
errors.foreach(error => logger.error(error))
152137
sys.error(
153138
"scala-native-bindgen failed with non-zero exit code")
154139
}
155-
156-
output
157140
}
158141
}
159142
))

sbt-scala-native-bindgen/src/sbt-test/bindgen/generate/build.sbt

+12-19
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@ scalaVersion := "2.11.12"
66
inConfig(Compile)(
77
Def.settings(
88
nativeBindgenPath := file(System.getProperty("bindgen.path")),
9-
nativeBindings := Seq(
10-
NativeBinding(
11-
name = "stdlib",
12-
header = (resourceDirectory in Compile).value / "stdlib.h",
13-
packageName = Some("org.example.app.stdlib"),
14-
link = None,
15-
excludePrefix = Some("__")
16-
)
17-
)
9+
nativeBindings += {
10+
NativeBinding((resourceDirectory in Compile).value / "stdlib.h")
11+
.name("stdlib")
12+
.packageName("org.example.app.stdlib")
13+
.excludePrefix("__")
14+
}
1815
))
1916

2017
val nativeBindgenCustomTarget = SettingKey[File]("nativeBindgenCustomTarget")
@@ -23,13 +20,9 @@ nativeBindgenCustomTarget := baseDirectory.value / "src/main/scala/org/example"
2320
val nativeBindgenCoreBinding =
2421
SettingKey[NativeBinding]("nativeBindgenCoreBinding")
2522
nativeBindgenCoreBinding := {
26-
NativeBinding(
27-
name = "core",
28-
header = (resourceDirectory in Compile).value / "core.h",
29-
packageName = Some("org.example.app.core"),
30-
link = Some("core"),
31-
excludePrefix = None
32-
)
23+
NativeBinding((resourceDirectory in Compile).value / "core.h")
24+
.packageName("org.example.app.core")
25+
.link("core")
3326
}
3427

3528
val StdlibOutput =
@@ -47,14 +40,14 @@ val StdlibOutput =
4740
""".stripMargin
4841

4942
def assertFileContent(file: File, expected: String): Unit = {
50-
val actual = IO.read(file).trim
43+
val actual = IO.read(file).trim()
5144
if (actual != expected.trim) {
5245
println(s"== [ actual ${file.getName} ] ========")
5346
println(actual)
5447
println(s"== [ expected ${file.getName} ] ========")
55-
println(expected.trim)
48+
println(expected.trim())
5649
}
57-
assert(actual == expected.trim)
50+
assert(actual == expected.trim())
5851
}
5952

6053
TaskKey[Unit]("checkSingle") := {

tests/src/test/scala/org/scalanative/bindgen/BindgenReportingSpec.scala

+3-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import org.scalatest.FunSpec
77
class BindgenReportingSpec extends FunSpec {
88
describe("Bindgen") {
99

10-
val bindgenPath = System.getProperty("bindgen.path")
10+
val bindgen = Bindgen(new File(System.getProperty("bindgen.path")))
1111

1212
def writeToFile(file: File, input: String): Unit = {
1313
new PrintWriter(file) {
@@ -24,16 +24,13 @@ class BindgenReportingSpec extends FunSpec {
2424
try {
2525
writeToFile(tempFile, input)
2626

27-
val result = Bindgen()
28-
.bindgenExecutable(new File(bindgenPath))
29-
.header(tempFile)
27+
val options = BindingOptions(tempFile)
3028
.name("BindgenTests")
3129
.link("bindgentests")
3230
.packageName("org.scalanative.bindgen.samples")
3331
.excludePrefix("__")
34-
.generate()
3532

36-
result match {
33+
bindgen.generate(options) match {
3734
case Right(binding) =>
3835
assert(binding.errors == errors)
3936
case Left(errors) =>

tests/src/test/scala/org/scalanative/bindgen/BindgenSpec.scala

+15-27
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,15 @@ import scala.io.Source
66

77
class BindgenSpec extends FunSpec {
88
describe("Bindgen") {
9-
val bindgenPath = System.getProperty("bindgen.path")
9+
val bindgen = Bindgen(new File(System.getProperty("bindgen.path")))
1010
val inputDirectory = new File("samples")
1111

1212
val outputDir = new File("target/bindgen-samples")
1313
Option(outputDir.listFiles()).foreach(_.foreach(_.delete()))
1414
outputDir.mkdirs()
1515

16-
it("should exist") {
17-
assert(new File(bindgenPath).exists, s"$bindgenPath does not exist")
18-
}
19-
20-
def bindgen(inputFile: File, name: String, outputFile: File): Unit = {
21-
val result = Bindgen()
22-
.bindgenExecutable(new File(bindgenPath))
23-
.header(inputFile)
24-
.name(name)
25-
.link("bindgentests")
26-
.packageName("org.scalanative.bindgen.samples")
27-
.excludePrefix("__")
28-
.generate()
29-
30-
result match {
31-
case Right(binding) =>
32-
binding.writeToFile(outputFile)
33-
case Left(errors) =>
34-
fail("scala-native-bindgen failed: " + errors.mkString("\n"))
35-
}
16+
it("executable should exist") {
17+
assert(bindgen.executable.exists, s"${bindgen.executable} does not exist")
3618
}
3719

3820
def contentOf(file: File) =
@@ -42,12 +24,18 @@ class BindgenSpec extends FunSpec {
4224
it(s"should generate bindings for ${input.getName}") {
4325
val testName = input.getName.replace(".h", "")
4426
val expected = new File(inputDirectory, testName + ".scala")
45-
val output = new File(outputDir, testName + ".scala")
46-
47-
bindgen(input, testName, output)
48-
49-
assert(output.exists())
50-
assert(contentOf(output) == contentOf(expected))
27+
val options = BindingOptions(input)
28+
.name(testName)
29+
.link("bindgentests")
30+
.packageName("org.scalanative.bindgen.samples")
31+
.excludePrefix("__")
32+
33+
bindgen.generate(options) match {
34+
case Right(binding) =>
35+
assert(binding.source.trim() == contentOf(expected))
36+
case Left(errors) =>
37+
fail("scala-native-bindgen failed: " + errors.mkString("\n"))
38+
}
5139
}
5240
}
5341
}

0 commit comments

Comments
 (0)