Linking & FFI
Extern functions (calling native code)
@link("kernel32.dll");
extern fn GetTickCount() -> u32;
extern fn Sleep(ms: u32);extern fn declares a function that lives in a native library. The compiler generates a calling convention trampoline automatically.
Custom symbol names
If the native symbol differs from the tape function name:
@link("user32.dll");
extern("MessageBoxA") fn message_box(hwnd: *u8, text: *u8, caption: *u8, flags: u32) -> i32;The extern("symbol") form specifies the exact linker symbol to resolve.
@link directive
Declares which native library to link against:
@link("user32.dll"); // Windows DLL
@link("opengl32.dll"); // Windows DLL
@link("libSystem.B.dylib"); // macOS system library
@link("libc.so.6"); // Linux shared libraryAll extern fn declarations following a @link are resolved from that library. Multiple @link directives can appear in one file.
Exported functions (callable from native code)
@export
pub fn tape_init(config: *u8) -> i32 {
return 0;
}@export marks a function for inclusion in the output’s export table (DLL exports on Windows, .sto vtable on Uusi).
Custom export symbol:
@export("my_custom_name")
pub fn internal_name() -> i32 {
return 42;
}Link checking
The compiler verifies at build time that @link libraries exist and all extern symbols resolve (on the host platform). Skip with --skip-link-check for cross-compilation.
Cross-module linking
Tape modules link to each other automatically through the import system. The compiler:
- Parses all imported modules recursively
- Injects extern stubs for all
pubdeclarations with qualified names (module.fn_name) - Resolves cross-module calls at link time
Internal symbol naming uses dot-separated qualified names (io.println, str.len) and double-underscore for methods (Button__paint, Vec2__op_add).
Output formats
| Flag | Output | Description |
|---|---|---|
| (default) | .exe / ELF / Mach-O | Standalone executable |
--dll | .dll (PE64) | Windows DLL with export table |
--sto | .sto (ELF64) | Uusi shared object with vtable exports |
DLL output
tape build lib.tape --dll -o mylib.dllOnly functions marked @export appear in the DLL’s export table.
Uusi shared object
tape build lib.tape --sto --target uusi -o mylib.stoOn Uusi, @link externs are resolved at runtime via syscall 23 (library load). The compiler emits thunks that:
- Load the .sto library
- Read the vtable pointer from the library handle
- Jump to the function pointer at the correct vtable slot
Platform-specific linking
| Platform | @link resolves to | Mechanism |
|---|---|---|
| Windows | DLL import (IAT) | PE64 import table |
| Linux | .so symbol | ELF64 dynamic linking |
| macOS | .dylib symbol | Mach-O dynamic linking |
| Uusi | .sto vtable slot | Thunk + syscall 23 |
.so and macOS .dylib shared library is not yet implemented. Currently only Windows --dll and Uusi --sto produce shared libraries with exported symbols. Planned flags: --so (Linux ELF64 shared object) and --dylib (macOS Mach-O dynamic library). @link from .so and .dylib already work on those platforms.Last modified: