Skip to main content

export

export exposes a function implemented in Wave as an external linker symbol. If extern imports an external function into Wave, export makes a Wave function callable from C, Rust, C++, Zig, or another native language through an object file.


Overview

Wave FFI has two directions.

  • extern(c) declares a function provided by an external library so Wave code can call it.
  • export(c) emits a Wave function body as an external ABI symbol.

The two forms share the same ABI header shape, but their meaning is opposite. With extern, the function body is outside Wave. With export, the function body is inside Wave.

The only supported export ABI for now is c.


Function-level export

The basic form is:

export(c) fun add(a: i32, b: i32) -> i32 {
return a + b;
}

This emits a public symbol named add. The generated object file can be linked with external code that expects the C ABI.


Symbol names

The Wave function name and the exported linker symbol can be different.

export(c, "wave_add_i32") fun add_i32(a: i32, b: i32) -> i32 {
return a + b;
}

Here the Wave name is add_i32, but the object file exposes wave_add_i32. External languages must declare and call the exported symbol name.


Block-level export

Multiple functions using the same ABI can be grouped in a block.

export(c) {
fun wave_inc_i32(a: i32) -> i32 {
return a + 1;
}

fun wave_dec_i32(a: i32) -> i32 {
return a - 1;
}
}

Block export uses each function name as its public symbol. export(c, "symbol") { ... } is not allowed because a single alias for several functions would create linker symbol collisions.


Calling from C

Build the Wave file as an object file.

wavec build math.wave --emit=obj -o math.o

Declare the exported symbol in C.

#include <stdio.h>

extern int wave_add_i32(int a, int b);

int main(void) {
printf("%d\n", wave_add_i32(40, 2));
return 0;
}

Then link the C code and the Wave object file with a normal linker.

cc main.c math.o -o app

extern versus export

extern(c) means Wave uses an external symbol.

extern(c) fun puts(s: ptr<i8>) -> i32;

export(c) means external code can use a Wave symbol.

export(c) fun answer() -> i32 {
return 42;
}

Both belong to FFI, but the direction is different.


Limitations

Current export support has these limits.

  • Only export(c) is supported.
  • Exported functions cannot be generic.
  • A block export cannot use one shared symbol alias.
  • For stable interoperation, prefer integer, floating-point, boolean, and pointer arguments and return values for now.
  • Aggregate types such as structs and arrays need stricter ABI rules and may be stabilized later.
  • export is mainly useful when building objects or libraries. It is usually unnecessary for a plain executable.

Use export when you need to:

  • Provide Wave utility functions as a C ABI library.
  • Call Wave functions from Rust, C, C++, Zig, or another native language.
  • Gradually connect Wave-written front, utils, or runtime-free native modules to an existing build system.
  • Let Vex or another build tool link Wave object files into an external project.