Skip to content

Commit

Permalink
Merge pull request #111 from kornilova-l/sbt-plugin
Browse files Browse the repository at this point in the history
Add sbt plugin (#60)
  • Loading branch information
kornilova203 authored Jul 10, 2018
2 parents 7c61f98 + ac28616 commit 67ef777
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 14 deletions.
66 changes: 54 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import scala.scalanative.sbtplugin.ScalaNativePluginInternal.nativeWorkdir
import scala.sys.process._
import java.nio.file.Path

addCommandAlias("verify", "; ^test:compile ; ^test ; ^scripted ; docs/makeSite")

val Versions = new {
val scala210 = "2.10.6"
val scala211 = "2.11.12"
val scala212 = "2.12.6"
val sbt013 = "0.13.17"
val sbt1 = "1.1.6"
}

inThisBuild(
Def.settings(
organization := "org.scalanative.bindgen",
version := "0.2-SNAPSHOT",
scalaVersion := "2.11.12",
scalacOptions ++= Seq(
"-deprecation",
"-unchecked",
Expand All @@ -20,10 +27,18 @@ inThisBuild(
git.remoteRepo := scmInfo.value.get.connection.replace("scm:git:", "")
))

val tests = project
.in(file("tests"))
val root = project("scala-native-bindgen")
.in(file("."))
.aggregate(
tests,
samples,
tools,
sbtPlugin,
docs
)

lazy val tests = project("tests")
.dependsOn(tools)
.aggregate(samples)
.settings(
fork in Test := true,
javaOptions in Test += {
Expand All @@ -38,10 +53,11 @@ val tests = project
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % Test
)

lazy val samples = project
lazy val samples = project("samples")
.in(file("tests/samples"))
.enablePlugins(ScalaNativePlugin)
.settings(
scalaVersion := Versions.scala211,
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.3" % "test",
testFrameworks += new TestFramework("utest.runner.Framework"),
nativeLinkStubs := true,
Expand Down Expand Up @@ -91,19 +107,45 @@ lazy val samples = project
}
)

lazy val tools = project in file("tools")
lazy val tools = project("tools")

lazy val sbtPlugin = project("sbt-scala-native-bindgen", ScriptedPlugin)
.dependsOn(tools)
.settings(
Keys.sbtPlugin := true,
scriptedLaunchOpts += s"-Dplugin.version=${version.value}",
scriptedLaunchOpts += {
val rootDir = (ThisBuild / baseDirectory).value
s"-Dbindgen.path=$rootDir/bindgen/target/scala-native-bindgen"
},
publishLocal := publishLocal.dependsOn(tools / publishLocal).value
)

lazy val docs = project
.in(file("docs"))
lazy val docs = project("docs")
.enablePlugins(GhpagesPlugin, ParadoxSitePlugin, ParadoxMaterialThemePlugin)
.settings(
paradoxProperties in Paradox ++= Map(
"github.base_url" -> scmInfo.value.get.browseUrl.toString
),
ParadoxMaterialThemePlugin.paradoxMaterialThemeSettings(Paradox),
paradoxMaterialTheme in Paradox := {
(paradoxMaterialTheme in Paradox).value
Paradox / paradoxMaterialTheme := {
(Paradox / paradoxMaterialTheme).value
.withRepository(scmInfo.value.get.browseUrl.toURI)
.withColor("indigo", "indigo")
}
)

def project(name: String, plugged: AutoPlugin*) = {
val unplugged = Seq(ScriptedPlugin).filterNot(plugged.toSet)
Project(id = name, base = file(name))
.disablePlugins(unplugged: _*)
.settings(
crossSbtVersions := List(Versions.sbt013, Versions.sbt1),
scalaVersion := {
(pluginCrossBuild / sbtBinaryVersion).value match {
case "0.13" => Versions.scala210
case _ => Versions.scala212
}
}
)
}
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.7")
addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.2")
addSbtPlugin("io.github.jonas" % "sbt-paradox-material-theme" % "0.4.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2")

libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.scalanative.bindgen.sbt

import sbt._
import sbt.Keys._

import org.scalanative.bindgen.Bindgen

/**
* Generate Scala bindings from C headers.
*
* == Usage ==
*
* This plugin must be explicitly enabled. To enable it add the following line
* to your `.sbt` file:
* {{{
* enablePlugins(ScalaNativeBindgenPlugin)
* }}}
*
* By default, the plugin reads the configured header file and generates
* a single Scala source file in the managed source directory.
*
* See the [[https://github.com/kornilova-l/scala-native-bindgen/tree/master/sbt-scala-native-bindgen/src/sbt-test/bindgen/generate example project]].
*
* == Configuration ==
*
* Keys are defined in [[ScalaNativeBindgenPlugin.autoImport]].
*
* - `nativeBindgenHeader`: The C header file to read.
*
* - `nativeBindgenPackage`: Package of the enclosing object.
* No package by default.
*
* - `name in nativeBindgen`: Name of the enclosing object.
*
* @example
* {{{
* nativeBindgenHeader in Compile := file("/usr/include/ctype.h")
* nativeBindgenPackage in Compile := Some("org.example.app")
* name in (Compile, nativeBindgen) := "ctype"
* }}}
*/
object ScalaNativeBindgenPlugin extends AutoPlugin {

object autoImport {
val nativeBindgenPath =
taskKey[Option[File]]("Path to the scala-native-bindgen executable")
val nativeBindgenHeader = taskKey[File]("C header file")
val nativeBindgenPackage =
settingKey[Option[String]]("Package for the generated code")
val nativeBindgenLink =
settingKey[Option[String]]("Name of library to be linked")
val nativeBindgenExclude = settingKey[Option[String]]("Exclude prefix")
val nativeBindgen = taskKey[File]("Generate Scala Native bindings")
}
import autoImport._

override def requires = plugins.JvmPlugin

override def projectSettings: Seq[Setting[_]] =
nativeBindgenScopedSettings(Compile)

private implicit class BindgenOps(val bindgen: Bindgen) extends AnyVal {
def maybe[T](opt: Option[T], f: Bindgen => T => Bindgen): Bindgen =
opt match {
case None => bindgen
case Some(value) => f(bindgen)(value)
}
}

def nativeBindgenScopedSettings(conf: Configuration): Seq[Setting[_]] =
inConfig(conf)(
Seq(
nativeBindgenHeader := {
sys.error("nativeBindgenHeader not configured")
},
nativeBindgenPath := None,
nativeBindgenPackage := None,
nativeBindgenExclude := None,
resourceDirectories in nativeBindgen := resourceDirectories.value,
sourceGenerators += Def.task { Seq(nativeBindgen.value) },
name in nativeBindgen := "ScalaNativeBindgen",
nativeBindgen := {
val output = sourceManaged.value / "sbt-scala-native-bindgen" / "nativeBindgen.scala"

Bindgen()
.bindgenExecutable(nativeBindgenPath.value.get)
.header(nativeBindgenHeader.value)
.name((name in nativeBindgen).value)
.maybe(nativeBindgenLink.value, _.link)
.maybe(nativeBindgenPackage.value, _.packageName)
.maybe(nativeBindgenExclude.value, _.excludePrefix)
.generate()
.writeToFile(output)

output
}
))
}
35 changes: 35 additions & 0 deletions sbt-scala-native-bindgen/src/sbt-test/bindgen/generate/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name := "test"
organization := "org.scalanative.bindgen.sbt.test"
enablePlugins(ScalaNativeBindgenPlugin)
scalaVersion := "2.11.12"

inConfig(Compile)(
Def.settings(
nativeBindgenPath := Option(System.getProperty("bindgen.path")).map(file),
nativeBindgenHeader := (resourceDirectory in Compile).value / "header.h",
nativeBindgenPackage := Some("org.example.app"),
nativeBindgenLink := Some("app"),
nativeBindgenExclude := Some("__"),
name in nativeBindgen := "AppAPI"
))

TaskKey[Unit]("check") := {
val file = (nativeBindgen in Compile).value
val expected =
"""package org.example.app
|
|import scala.scalanative._
|import scala.scalanative.native._
|
|@native.link("app")
|@native.extern
|object AppAPI {
| def access(path: native.CString, mode: native.CInt): native.CInt = native.extern
| def read(fildes: native.CInt, buf: native.Ptr[Byte], nbyte: native.CInt): native.CInt = native.extern
| def printf(format: native.CString, varArgs: native.CVararg*): native.CInt = native.extern
|}
""".stripMargin

assert(file.exists)
assert(IO.read(file).trim == expected.trim)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
addSbtPlugin(
"org.scalanative.bindgen" % "sbt-scala-native-bindgen" % sys.props(
"plugin.version"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int access(const char *path, int mode);
int read(int fildes, void *buf, int nbyte);
int printf(const char *restrict format, ...);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
> check
2 changes: 1 addition & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ if [[ ! -e bindgen/target/.llvm-version ]] || [[ "$(<bindgen/target/.llvm-versio
fi

make -C bindgen/target
sbt "${@:-test}"
sbt "${@:-verify}"
2 changes: 1 addition & 1 deletion tools/src/main/scala/org/scalanative/bindgen/Bindgen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ object Bindgen {
withArgs("--extra-arg-before", extraArgBefore) ++
Seq(header.get.getAbsolutePath, "--")

val output = Process(cmd).lineStream.mkString("\n")
val output = Process(cmd).!!

new Bindings(output)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.io.{File, PrintWriter}

class Bindings(private val bindings: String) {
def writeToFile(file: File): Unit = {
file.getParentFile.mkdirs()
new PrintWriter(file) {
write(bindings)
close()
Expand Down

0 comments on commit 67ef777

Please sign in to comment.