For those types, we generate getters, setters, Tag
definition, and two apply
methods:
typedef struct {
long long number;
} Small;
typedef struct {
int x;
char* hello;
Small sm;
} Big;
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/8322496521827001485header.h
*/
opaque type Big = CStruct3[CInt, CString, Small]
object Big:
given _tag: Tag[Big] = Tag.materializeCStruct3Tag[CInt, CString, Small]
def apply()(using Zone): Ptr[Big] = scala.scalanative.unsafe.alloc[Big](1)
def apply(x : CInt, hello : CString, sm : Small)(using Zone): Ptr[Big] =
val ____ptr = apply()
(!____ptr).x = x
(!____ptr).hello = hello
(!____ptr).sm = sm
____ptr
extension (struct: Big)
def x : CInt = struct._1
def x_=(value: CInt): Unit = !struct.at1 = value
def hello : CString = struct._2
def hello_=(value: CString): Unit = !struct.at2 = value
def sm : Small = struct._3
def sm_=(value: Small): Unit = !struct.at3 = value
/**
* [bindgen] header: /tmp/8322496521827001485header.h
*/
opaque type Small = CStruct1[CLongLong]
object Small:
given _tag: Tag[Small] = Tag.materializeCStruct1Tag[CLongLong]
def apply()(using Zone): Ptr[Small] = scala.scalanative.unsafe.alloc[Small](1)
def apply(number : CLongLong)(using Zone): Ptr[Small] =
val ____ptr = apply()
(!____ptr).number = number
____ptr
extension (struct: Small)
def number : CLongLong = struct._1
def number_=(value: CLongLong): Unit = !struct.at1 = value
object types:
export _root_.libtest.structs.*
object all:
export _root_.libtest.structs.Big
export _root_.libtest.structs.Small
Some bindings (libnotify, gtk, nuklear) have such deep type hierarchies, that apply methods on some structs trigger an exception during bytecode generation (when compiling the generated code):
java.lang.IllegalArgumentException: UTF8 string too large
To work around it, you can disable constructor generation by passing a comma-separated
list of struct names using the --render.no-constructor
option in CLI, and noConstructor
parameter in the Binding(...)
specification.
typedef struct {
int x;
char* hello;
} Enabled;
typedef struct {
int x;
char* hello;
} Disabled;
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/15505166253105999100header.h
*/
opaque type Disabled = CStruct2[CInt, CString]
object Disabled:
given _tag: Tag[Disabled] = Tag.materializeCStruct2Tag[CInt, CString]
def apply()(using Zone): Ptr[Disabled] = scala.scalanative.unsafe.alloc[Disabled](1)
extension (struct: Disabled)
def x : CInt = struct._1
def x_=(value: CInt): Unit = !struct.at1 = value
def hello : CString = struct._2
def hello_=(value: CString): Unit = !struct.at2 = value
/**
* [bindgen] header: /tmp/15505166253105999100header.h
*/
opaque type Enabled = CStruct2[CInt, CString]
object Enabled:
given _tag: Tag[Enabled] = Tag.materializeCStruct2Tag[CInt, CString]
def apply()(using Zone): Ptr[Enabled] = scala.scalanative.unsafe.alloc[Enabled](1)
def apply(x : CInt, hello : CString)(using Zone): Ptr[Enabled] =
val ____ptr = apply()
(!____ptr).x = x
(!____ptr).hello = hello
____ptr
extension (struct: Enabled)
def x : CInt = struct._1
def x_=(value: CInt): Unit = !struct.at1 = value
def hello : CString = struct._2
def hello_=(value: CString): Unit = !struct.at2 = value
object types:
export _root_.libtest.structs.*
object all:
export _root_.libtest.structs.Disabled
export _root_.libtest.structs.Enabled
For a union with N
members, N
constructors will be generated,
along with getters and setters.
typedef struct {
long long number;
} Small;
typedef union {
int x;
char* hello;
Small sm;
} Big;
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
import _root_.libtest.unions.*
/**
* [bindgen] header: /tmp/8328306435233064532header.h
*/
opaque type Small = CStruct1[CLongLong]
object Small:
given _tag: Tag[Small] = Tag.materializeCStruct1Tag[CLongLong]
def apply()(using Zone): Ptr[Small] = scala.scalanative.unsafe.alloc[Small](1)
def apply(number : CLongLong)(using Zone): Ptr[Small] =
val ____ptr = apply()
(!____ptr).number = number
____ptr
extension (struct: Small)
def number : CLongLong = struct._1
def number_=(value: CLongLong): Unit = !struct.at1 = value
object unions:
import _root_.libtest.structs.*
import _root_.libtest.unions.*
/**
* [bindgen] header: /tmp/8328306435233064532header.h
*/
opaque type Big = CArray[Byte, Nat._8]
object Big:
given _tag: Tag[Big] = Tag.CArray[CChar, Nat._8](Tag.Byte, Tag.Nat8)
def apply()(using Zone): Ptr[Big] =
val ___ptr = alloc[Big](1)
___ptr
@scala.annotation.targetName("apply_x")
def apply(x: CInt)(using Zone): Ptr[Big] =
val ___ptr = alloc[Big](1)
val un = !___ptr
un.at(0).asInstanceOf[Ptr[CInt]].update(0, x)
___ptr
@scala.annotation.targetName("apply_hello")
def apply(hello: CString)(using Zone): Ptr[Big] =
val ___ptr = alloc[Big](1)
val un = !___ptr
un.at(0).asInstanceOf[Ptr[CString]].update(0, hello)
___ptr
@scala.annotation.targetName("apply_sm")
def apply(sm: Small)(using Zone): Ptr[Big] =
val ___ptr = alloc[Big](1)
val un = !___ptr
un.at(0).asInstanceOf[Ptr[Small]].update(0, sm)
___ptr
extension (struct: Big)
def x : CInt = !struct.at(0).asInstanceOf[Ptr[CInt]]
def x_=(value: CInt): Unit = !struct.at(0).asInstanceOf[Ptr[CInt]] = value
def hello : CString = !struct.at(0).asInstanceOf[Ptr[CString]]
def hello_=(value: CString): Unit = !struct.at(0).asInstanceOf[Ptr[CString]] = value
def sm : Small = !struct.at(0).asInstanceOf[Ptr[Small]]
def sm_=(value: Small): Unit = !struct.at(0).asInstanceOf[Ptr[Small]] = value
object types:
export _root_.libtest.structs.*
export _root_.libtest.unions.*
object all:
export _root_.libtest.structs.Small
export _root_.libtest.unions.Big
@extern
functionsWhere "Simple" means "not passing naked structs
", because Scala Native cannot handle that (passing by pointer is okay)
typedef struct {
long long number;
} Small;
long simple(int x, char *y);
Small* with_pointers(Small *x, int y);
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/8717274641385827725header.h
*/
opaque type Small = CStruct1[CLongLong]
object Small:
given _tag: Tag[Small] = Tag.materializeCStruct1Tag[CLongLong]
def apply()(using Zone): Ptr[Small] = scala.scalanative.unsafe.alloc[Small](1)
def apply(number : CLongLong)(using Zone): Ptr[Small] =
val ____ptr = apply()
(!____ptr).number = number
____ptr
extension (struct: Small)
def number : CLongLong = struct._1
def number_=(value: CLongLong): Unit = !struct.at1 = value
@extern
private[libtest] object extern_functions:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/8717274641385827725header.h
*/
def simple(x : CInt, y : CString): CLongInt = extern
/**
* [bindgen] header: /tmp/8717274641385827725header.h
*/
def with_pointers(x : Ptr[Small], y : CInt): Ptr[Small] = extern
object functions:
import _root_.libtest.structs.*
import extern_functions.*
export extern_functions.*
object types:
export _root_.libtest.structs.*
object all:
export _root_.libtest.structs.Small
export _root_.libtest.functions.simple
export _root_.libtest.functions.with_pointers
Where "Problematic" means having a struct as one of its arguments or return type. In this case we generate several variations of public Scala functions, but they all delegate to an external C function which takes its arguments as pointers, and (optionally) returns its value in a provided heap-allocated location.
typedef struct {
long long number;
} Small;
void bad_arguments(Small n, Small n2);
Small bad_return_type();
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/17515658453517750206header.h
*/
opaque type Small = CStruct1[CLongLong]
object Small:
given _tag: Tag[Small] = Tag.materializeCStruct1Tag[CLongLong]
def apply()(using Zone): Ptr[Small] = scala.scalanative.unsafe.alloc[Small](1)
def apply(number : CLongLong)(using Zone): Ptr[Small] =
val ____ptr = apply()
(!____ptr).number = number
____ptr
extension (struct: Small)
def number : CLongLong = struct._1
def number_=(value: CLongLong): Unit = !struct.at1 = value
@extern
private[libtest] object extern_functions:
import _root_.libtest.structs.*
private[libtest] def __sn_wrap_libtest_bad_arguments(n : Ptr[Small], n2 : Ptr[Small]): Unit = extern
private[libtest] def __sn_wrap_libtest_bad_return_type(__return : Ptr[Small]): Unit = extern
object functions:
import _root_.libtest.structs.*
import extern_functions.*
export extern_functions.*
/**
* [bindgen] header: /tmp/17515658453517750206header.h
*/
def bad_arguments(n : Small, n2 : Small)(using Zone): Unit =
val __ptr_0: Ptr[Small] = alloc[Small](2)
!(__ptr_0 + 0) = n
!(__ptr_0 + 1) = n2
__sn_wrap_libtest_bad_arguments((__ptr_0 + 0), (__ptr_0 + 1))
/**
* [bindgen] header: /tmp/17515658453517750206header.h
*/
def bad_arguments(n : Ptr[Small], n2 : Ptr[Small]): Unit =
__sn_wrap_libtest_bad_arguments(n, n2)
/**
* [bindgen] header: /tmp/17515658453517750206header.h
*/
def bad_return_type()(__return : Ptr[Small]): Unit =
__sn_wrap_libtest_bad_return_type(__return)
/**
* [bindgen] header: /tmp/17515658453517750206header.h
*/
def bad_return_type()(using Zone): Small =
val __ptr_0: Ptr[Small] = alloc[Small](1)
__sn_wrap_libtest_bad_return_type((__ptr_0 + 0))
!(__ptr_0 + 0)
object types:
export _root_.libtest.structs.*
object all:
export _root_.libtest.structs.Small
export _root_.libtest.functions.bad_arguments
export _root_.libtest.functions.bad_return_type
#include <string.h>
void __sn_wrap_libtest_bad_arguments(Small *n, Small *n2) {
bad_arguments(*n, *n2);
};
void __sn_wrap_libtest_bad_return_type(Small *____return) {
Small ____ret = bad_return_type();
memcpy(____return, &____ret, sizeof(Small));
}
Whatever type clang reports for a particular enum - that's the type that will be used for the enum.
This is important, as on Windows enums are int
by default, whereas on Linux and OS X they are unsigned int
(if there's no negative elements).
This documentation is built on Linux.
typedef enum {
U_X = 1,
U_Y = 4,
U_Z = 228
} MyUnsigned;
typedef enum {
X = -1,
Y = 4,
Z = 228
} MySigned;
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object predef:
private[libtest] trait CEnum[T](using eq: T =:= Int):
given Tag[T] = Tag.Int.asInstanceOf[Tag[T]]
extension (inline t: T)
inline def int: CInt = eq.apply(t)
inline def value: CInt = eq.apply(t)
private[libtest] trait CEnumU[T](using eq: T =:= UInt):
given Tag[T] = Tag.UInt.asInstanceOf[Tag[T]]
extension (inline t: T)
inline def int: CInt = eq.apply(t).toInt
inline def uint: CUnsignedInt = eq.apply(t)
inline def value: CUnsignedInt = eq.apply(t)
object enumerations:
import predef.*
/**
* [bindgen] header: /tmp/14523910063063702636header.h
*/
opaque type MySigned = CInt
object MySigned extends CEnum[MySigned]:
given _tag: Tag[MySigned] = Tag.Int
inline def define(inline a: CInt): MySigned = a
val X = define(-1)
val Y = define(4)
val Z = define(228)
inline def getName(inline value: MySigned): Option[String] =
inline value match
case X => Some("X")
case Y => Some("Y")
case Z => Some("Z")
case _ => None
extension (a: MySigned)
inline def &(b: MySigned): MySigned = a & b
inline def |(b: MySigned): MySigned = a | b
inline def is(b: MySigned): Boolean = (a & b) == b
/**
* [bindgen] header: /tmp/14523910063063702636header.h
*/
opaque type MyUnsigned = CUnsignedInt
object MyUnsigned extends CEnumU[MyUnsigned]:
given _tag: Tag[MyUnsigned] = Tag.UInt
inline def define(inline a: Long): MyUnsigned = a.toUInt
val U_X = define(1)
val U_Y = define(4)
val U_Z = define(228)
inline def getName(inline value: MyUnsigned): Option[String] =
inline value match
case U_X => Some("U_X")
case U_Y => Some("U_Y")
case U_Z => Some("U_Z")
case _ => None
extension (a: MyUnsigned)
inline def &(b: MyUnsigned): MyUnsigned = a & b
inline def |(b: MyUnsigned): MyUnsigned = a | b
inline def is(b: MyUnsigned): Boolean = (a & b) == b
object types:
export _root_.libtest.enumerations.*
object all:
export _root_.libtest.enumerations.MySigned
export _root_.libtest.enumerations.MyUnsigned
The inlining in apply
method is important - it's a restricting of Scala Native
that the function must be statically known.
typedef void* Cursor;
typedef int (*Visitor)(Cursor*);
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object aliases:
import _root_.libtest.aliases.*
/**
* [bindgen] header: /tmp/16238251360031781788header.h
*/
opaque type Cursor = Ptr[Byte]
object Cursor:
given _tag: Tag[Cursor] = Tag.Ptr(Tag.Byte)
inline def apply(inline o: Ptr[Byte]): Cursor = o
extension (v: Cursor)
inline def value: Ptr[Byte] = v
/**
* [bindgen] header: /tmp/16238251360031781788header.h
*/
opaque type Visitor = CFuncPtr1[Ptr[Cursor], CInt]
object Visitor:
given _tag: Tag[Visitor] = Tag.materializeCFuncPtr1[Ptr[Cursor], CInt]
inline def apply(inline o: CFuncPtr1[Ptr[Cursor], CInt]): Visitor = o
extension (v: Visitor)
inline def value: CFuncPtr1[Ptr[Cursor], CInt] = v
object types:
export _root_.libtest.aliases.*
object all:
export _root_.libtest.aliases.Cursor
export _root_.libtest.aliases.Visitor
This is invisible to the user, so doesn't impact the experience, but can complicate reading the code.
Scala cannot have recursive type aliases.
typedef struct Arr;
typedef struct {
struct Arr* nested;
} Arr;
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object structs:
import _root_.libtest.structs.*
/**
* [bindgen] header: /tmp/463041355205791274header.h
*/
opaque type Arr = CStruct1[Ptr[Byte]]
object Arr:
given _tag: Tag[Arr] = Tag.materializeCStruct1Tag[Ptr[Byte]]
def apply()(using Zone): Ptr[Arr] = scala.scalanative.unsafe.alloc[Arr](1)
def apply(nested : Ptr[Arr])(using Zone): Ptr[Arr] =
val ____ptr = apply()
(!____ptr).nested = nested
____ptr
extension (struct: Arr)
def nested : Ptr[Arr] = struct._1.asInstanceOf[Ptr[Arr]]
def nested_=(value: Ptr[Arr]): Unit = !struct.at1 = value.asInstanceOf[Ptr[Byte]]
object types:
export _root_.libtest.structs.*
object all:
export _root_.libtest.structs.Arr
enum {
HELLO = 25,
BYEBYE = 11
};
enum {
HOW=-1,
DOESTHIS=-2,
WORK=0
};
package libtest
import _root_.scala.scalanative.unsafe.*
import _root_.scala.scalanative.unsigned.*
import _root_.scala.scalanative.libc.*
import _root_.scala.scalanative.*
object constants:
val HELLO: CUnsignedInt = 25.toUInt
val BYEBYE: CUnsignedInt = 11.toUInt
val HOW: CInt = -1
val DOESTHIS: CInt = -2
val WORK: CInt = 0