libsilk quickstart
This page is the shortest path to embedding the Silk compiler from C or C++.
Use it when you want to:
- compile Silk source from your own host process,
- build executables, libraries, objects, or wasm modules,
- capture diagnostics programmatically, and
- decide which deeper ABI/manpage document to read next.
For the full ABI contract, see C ABI (libsilk).
1) Smallest working embedder#
This builds one in-memory Silk source buffer to an executable on disk:
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <silk/silk.h>
static SilkString silk_str(const char *ptr) {
SilkString s;
s.ptr = (char *)ptr;
s.len = 0;
while (ptr[s.len] != '\0') s.len++;
return s;
}
static void print_last_error(SilkCompiler *compiler) {
SilkError *err = silk_compiler_last_error(compiler);
if (!err) return;
int64_t needed = silk_error_format(err, NULL, 0);
if (needed <= 0) return;
char *buf = (char *)malloc((size_t)needed);
if (!buf) return;
silk_error_format(err, buf, needed);
fprintf(stderr, "%s\n", buf);
free(buf);
}
int main(void) {
SilkCompiler *compiler = silk_compiler_create();
if (!compiler) return 1;
SilkString name = silk_str("main.slk");
SilkString src = silk_str("fn main () -> int { return 0; }\n");
if (!silk_compiler_add_source_buffer(compiler, name, src)) {
print_last_error(compiler);
silk_compiler_destroy(compiler);
return 1;
}
if (!silk_compiler_build(
compiler,
SILK_OUTPUT_EXECUTABLE,
silk_str("hello"))) {
print_last_error(compiler);
silk_compiler_destroy(compiler);
return 1;
}
silk_compiler_destroy(compiler);
return 0;
}
Minimal workflow:
- create a
SilkCompiler, - add source buffers,
- build an artifact,
- print diagnostics on failure,
- destroy the compiler.
2) Compile real files and use the stdlib#
If your host reads Silk files from disk, keep the source text ownership on the
host side and pass the contents through silk_compiler_add_source_buffer, or
load them yourself before calling the ABI.
For programs that import std::..., point the compiler at the stdlib root:
SilkCompiler *compiler = silk_compiler_create();
if (!compiler) return 1;
silk_compiler_set_stdlib(compiler, silk_str("std"));
silk_compiler_set_std_root(compiler, silk_str("./std"));
silk_compiler_add_source_buffer(
compiler,
silk_str("src/main.slk"),
silk_str(
"import fs from \"std/fs\";\n"
"fn main () -> int { return 0; }\n"));
if (!silk_compiler_build(
compiler,
SILK_OUTPUT_EXECUTABLE,
silk_str("app"))) {
print_last_error(compiler);
}
If you want to disable filesystem stdlib auto-loading entirely, call:
silk_compiler_set_nostd(compiler, true);
3) Build to memory instead of disk#
Use silk_compiler_build_to_bytes when your host needs the output artifact in
memory:
SilkBytes bytes = {0};
silk_compiler_set_target(compiler, silk_str("wasm32-wasi"));
silk_compiler_add_source_buffer(
compiler,
silk_str("main.slk"),
silk_str("fn main () -> int { return 0; }\n"));
if (!silk_compiler_build_to_bytes(
compiler,
SILK_OUTPUT_EXECUTABLE,
&bytes)) {
print_last_error(compiler);
silk_compiler_destroy(compiler);
return 1;
}
/* bytes.ptr / bytes.len now contain the final .wasm module */
silk_bytes_free(&bytes);
This is the common pattern for:
- wasm embedders,
- build systems,
- editor integrations,
- test harnesses that want to inspect output bytes directly.
4) Generate libraries and headers#
For shared-library or object outputs, you can set metadata before building:
silk_compiler_set_c_header(compiler, silk_str("libadd.h"));
silk_compiler_set_soname(compiler, silk_str("libadd.so"));
silk_compiler_add_runpath(compiler, silk_str("$ORIGIN"));
silk_compiler_add_needed_library(compiler, silk_str("libm.so.6"));
silk_compiler_add_source_buffer(
compiler,
silk_str("lib.slk"),
silk_str(
"export fn add (a: int, b: int) -> int {\n"
" return a + b;\n"
"}\n"));
if (!silk_compiler_build(
compiler,
SILK_OUTPUT_SHARED_LIBRARY,
silk_str("libadd.so"))) {
print_last_error(compiler);
}
Read the ABI reference before relying on exported layout rules for string,
optionals, structs, and other public interface shapes.
5) Diagnostics: two-pass formatting#
The error API is intentionally low-level and stable:
SilkError *err = silk_compiler_last_error(compiler);
if (err) {
int64_t needed = silk_error_format(err, NULL, 0);
char *buf = (char *)malloc((size_t)needed);
silk_error_format(err, buf, needed);
fprintf(stderr, "%s\n", buf);
free(buf);
}
Use this pattern whenever an ABI call returns false.
6) What to read next#
- Need the full function-by-function ABI contract: C ABI (
libsilk) - Need the public C manpages:
libsilk(7),silk_compiler(3),silk_error(3) - Need Zig instead of C: Zig embedding API
Source repository · Edit this page · View Markdown