Docs/Advanced

Building native libraries

Build a library other languages can call.

On this page

Valk can build a shared or static library that C, or any language that calls C, can link against. Mark the functions to expose with export.

Export functions#

Valk
export fn multiply(left: i32, right: i32) i32 {
    return left * right
}

struct Vec2 {
    x: f32
    y: f32
}

export fn vec2_add(a: Vec2, b: Vec2) Vec2 {
    return Vec2 { x: a.x + b.x, y: a.y + b.y }
}

Rules for exported functions:

  • The signature must be concrete: no generics.
  • Arguments and results cannot hold GC-managed data such as String, Array or class objects. Use numbers, structs and raw pointers.
  • Structs are passed by value with the C layout and calling convention.
  • No fn main() is needed.

Build a shared library#

Terminal
valk build src --lib -o libmath
OS Output
Linux libmath.so
macOS libmath.dylib
Windows libmath.dll

Build a static library#

Terminal
valk build src --lib --static-lib -o libmath           # libmath.a or libmath.lib
valk build src --lib --static-lib --static -o libmath  # with dependencies inside

Without --static, the program that links the archive also links its dependencies, such as libc. With --static they are put in the archive.

Call it from C#

Declare the functions in a header with matching types:

C
#include <stdio.h>

typedef struct { float x; float y; } Vec2;

int multiply(int left, int right);
Vec2 vec2_add(Vec2 a, Vec2 b);

int main(void) {
    printf("%d\n", multiply(6, 7));
    Vec2 v = vec2_add((Vec2){1, 2}, (Vec2){3, 4});
    printf("%.1f %.1f\n", v.x, v.y);
}
Terminal
cc main.c -L. -lmath -o main
LD_LIBRARY_PATH=. ./main   # 42, then 4.0 6.0

Pass data across#

To hand over more than numbers and structs, agree on a pointer protocol: for example, the caller passes a buffer and its length, and Valk writes into it with @ptrv or mem. Memory allocated on one side should be freed by the same side.