Seen interoperates with C through extern function declarations and the runtime C library.
Declare C functions with extern fun:
extern fun printf(format: String) r: Int
extern fun malloc(size: Int) r: Int
extern fun free(ptr: Int)
extern fun strlen(s: String) r: Int
Functions starting with __ and having an empty body are treated as external declarations:
fun __OpenFile(path: String, mode: String) r: Int {}
fun __ReadFile(fd: Int) r: String {}
fun __CloseFile(fd: Int) r: Int {}
extern fun time(t: Int) r: Int
fun main() {
let now = time(0)
println("Unix timestamp: {now}")
}
Pass linker flags via the compiler:
seen build app.seen -o app # automatically links -lm -lpthread
The compiler always links:
-lm (math library)-lpthread (POSIX threads)Additional libraries (e.g., -lvulkan) are added when GPU features are used.
For native shims that live inside your project, declare the library in Seen.toml and add a local search path:
[dependencies]
seen_platform = { system = true, path = "native/lib" }
path is resolved relative to the nearest Seen.toml. Seen adds -L<resolved-path> during linking. On native Linux/macOS builds it also records that directory as a runtime search path, so seen build outputs run without extra LIBRARY_PATH or LD_LIBRARY_PATH wrappers.
Generate Seen bindings from a C header file:
seen import-c <header.h>
This parses the C header and outputs extern fun declarations.
Seen functions can be called from C when compiled as a library. The function name is preserved in the generated object file.
pub fun add(a: Int, b: Int) r: Int {
return a + b
}
From C:
#include <stdint.h>
extern int64_t add(int64_t a, int64_t b);
int main() {
int64_t result = add(3, 4);
printf("%lld\n", result);
}
Use @repr(C) for C-compatible struct layout:
@repr(C)
class NetworkPacket {
var version: Int
var flags: Int
var payload_size: Int
}
| Seen Type | C Type | LLVM IR |
|---|---|---|
Int |
int64_t |
i64 |
Float |
double |
double |
Bool |
bool / int64_t |
i1 / i64 |
String |
SeenString (struct) |
{i64, ptr} |
Array<T> |
SeenArray* |
ptr |
typedef struct {
int64_t len;
const char* data;
} SeenString;
typedef struct {
int64_t len;
int64_t cap;
int64_t element_size;
void* data;
} SeenArray;
The Seen runtime (seen_runtime/seen_runtime.c) provides ~170 C functions that are linked with every Seen program. These handle:
seen_str_concat_ss, seen_str_eq_ss, etc.)seen_arr_push_*, seen_arr_get_*, etc.)__OpenFile, __ReadFile, etc.)__seen_fork, __seen_waitpid, etc.)seen_rwlock_*, seen_barrier_*, etc.)seen_simd_f4_*, seen_simd_f8_*, etc.)The standard library provides helpers in seen_std/src/ffi/:
import ffi
let cstr = toCString("hello") // Seen String → CString
let str = fromCString(cstr) // CString → Seen String
Type mapping helpers:
let seen_type = cTypeToSeen("int64_t") // "Int"
let c_type = seenTypeToC("Int") // "int64_t"
let size = getCTypeSize("int64_t") // 8
let align = getCTypeAlignment("int64_t") // 8
