Quickest way to start would be to use the template.
For more involved examples, see a dedicated repository
The bindgen's binary is dynamically linked against Clang 14.
Therefore you must have it installed on the system that generates the code, you can follow Scala Native's instructions.
Code generated by bindgen has no runtime dependencies on bindgen, LLVM, or Clang.
OS | Architecture | Tested on CI | Binary published | Comments |
---|---|---|---|---|
Linux | x64 | ✅ | ✅ | |
Mac OS X | x64 | ✅ | ✅ | |
Windows | x64 | ✅ | ✅ | |
Mac OS X | M1 (arm64) | ❌ | ❌ | Works well, M1 is where I develop this project |
Linux | arm64 | ❌ | ❌ | Anecdotal evidence that it works, I run tests in an arm64 VM sometimes |
Windows | arm64 | ❌ | ❌ | Anecdotal evidence that it works, I run tests in an arm64 VM sometimes |
project/plugins.sbt
// only add this line if you're living on the edge and using
// a version that has "SNAPSHOT" in it
resolvers += Resolver.sonatypeRepo("snapshots")
addSbtPlugin("com.indoorvivants" % "bindgen-sbt-plugin" % "0.0.14+8-94a9e9fb-SNAPSHOT")
build.sbt
// only add this line if you're living on the edge and using
// a version that has "SNAPSHOT" in it
resolvers += Resolver.sonatypeRepo("snapshots")
scalaVersion := "3.1.1"
enablePlugins(ScalaNativePlugin, BindgenPlugin)
import bindgen.interface.Binding
bindgenBindings := Seq(
Binding(
/* 1 */ baseDirectory.value / "src" / "main" / "resources" / "scala-native" / "header.h",
/* 2 */ "libtest",
/* 3 */ cImports = List("header.h")
)
)
There are more settings available, see Configuration page for details.
Now all that is left to do is put some definitions into the header file:
typedef enum { X = 1, Y = 2} bla;
void sum(bla one, bla two);
package libtest
import scala.scalanative.unsafe.*
import scala.scalanative.unsigned.*
import scalanative.libc.*
import scalanative.*
object predef:
trait CEnumU[T](using eq: T =:= UInt):
given Tag[T] = Tag.UInt.asInstanceOf[Tag[T]]
extension (t: T)
def int: CInt = eq.apply(t).toInt
def uint: CUnsignedInt = eq.apply(t)
def value: CUnsignedInt = eq.apply(t)
object types:
import predef.*
opaque type bla = CUnsignedInt
object bla extends CEnumU[bla]:
given _tag: Tag[bla] = Tag.UInt
inline def define(inline a: Long): bla = a.toUInt
val X = define(1)
val Y = define(2)
inline def getName(inline value: bla): Option[String] =
value match
case X => Some("X")
case Y => Some("Y")
case _ => None
extension (a: bla)
inline def &(b: bla): bla = a & b
inline def |(b: bla): bla = a | b
inline def is(b: bla): Boolean = (a & b) == b
@extern
private[libtest] object extern_functions:
import types.*
def sum(one : bla, two : bla): Unit = extern
object functions:
import types.*
import extern_functions.*
export extern_functions.*
After that in your Scala sources you can use libtest
package to access the
generated bindings.