Configuration

Bindgen provides several options for configuring what to include and how to output the generated bindings. The options can be provided to the CLI or as part of the sbt bindings declaration.

Excluding Definitions By Prefix

Definitions may be excluded by their prefix. This is useful when private definitions should not be part of the generated binding. This is often the case for definitions starting with __.

sbt
NativeBinding(pathToHeader)
  .excludePrefix("__")
Full source at GitHub
CLI
scala-native-bindgen --binding-config=/path/to/config

To exemplify consider the following header file:

int access(const char *path, int mode);
int read(int fildes, void *buf, int nbyte);
int printf(const char *restrict format, ...);
int __excluded(void);
Full source at GitHub

When the exclude prefix is set to __, then the resulting bindings will be:

package org.example.app.stdlib

import scala.scalanative._
import scala.scalanative.native._

@native.extern
object stdlib {
  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
}
Full source at GitHub

Binding Configuration File

The binding configuration is a JSON file which allows to map the path of a header file to the associated object as well as the names of the C types and symbols to their respective Scala types and definitions. The configuration file can be used when integrating with third party bindings.

sbt
NativeBinding(pathToHeader)
  .bindingConfig(pathToConfig)
Full source at GitHub
CLI
scala-native-bindgen --binding-config=/path/to/config

Using Types From Third Party Bindings

If you need to generate bindings that uses types from bindings that have not been generated with scala-native-bindgen you have to provide the mapping between the header path and the Scala object’s fully qualified name. And in some cases also the Scala name of the C types. Using the vector library example from Using Bindings, let’s assume that the vector library was created so that struct point was named Point:

package com.example.custom.binding

import scala.scalanative._
import scala.scalanative.native._

@native.link("vector")
@native.extern
object Vector {
  type Point       = native.CStruct2[native.CFloat, native.CFloat]
  type LineSegment = native.CStruct2[Point, Point]
  // ...
Full source at GitHub

To use this binding, create a configuration file with the folllowing content, where path is the name of the header file (usually the part of the path inside the /usr/include or /usr/local/include directory), object is the fully qualified name of the Scala object (i.e. package name as well as the Scala object name) and finally names for each of the types:

{
  "vector.h": {
    "object": "com.example.custom.binding.Vector",
    "names": {
      "struct point": "Point",
      "struct lineSegment": "LineSegment"
    }
  }
}
Full source at GitHub

Now in the library you are creating a binding for, any usage of struct point:

struct circle {
    struct point point;
    double radius;
};
Full source at GitHub

will reference the Point type alias inside the Vector object:

type struct_circle = native.CStruct2[com.example.custom.binding.Vector.Point, native.CDouble]
Full source at GitHub

Using Types From the Scala Native Bindings

Similar to the above, the following example shows how you can use types defined in the C standard library and C POSIX library bindings shipped with Scala Native. Let’s assume we have a binding with a method that uses the FILE type from <stdio.h>:

int wordcount(struct wordcount *wordcount, FILE *file);
Full source at GitHub

We can then write a binding configuration that maps the header name to the object defined in Scala Native.

{
  "stdio.h": {
    "object": "scala.scalanative.native.stdio"
  },
  "_stdio.h": {
    "object": "scala.scalanative.native.stdio"
  }
}
Full source at GitHub
Note

In the above binding configuration, we duplicate the mapping to work on both Linux and macOS since on macOS the definition of FILE is found inside /usr/include/_stdio.h.

The generated binding will then use the stdio.h binding provided by Scala Native:

def wordcount(wordcount: native.Ptr[struct_wordcount], file: native.Ptr[scala.scalanative.native.stdio.FILE]): native.CInt = native.extern
Full source at GitHub

And we can use the binding by opening a file using fopen(...):

import org.example.wordcount.WordCount._
import scalanative.native._

Zone { implicit zone =>
  val result = struct_wordcount()
  val file   = stdio.fopen(pathToFile, c"r")
  val code   = wordcount(result, file)
  stdio.fclose(file)
}
Full source at GitHub