libsilk(7) — C99 ABI for the Silk Compiler
NOTE: This is the Markdown source for a man 7 page describing the C99 embedding ABI exposed by
libsilk.a. The roff-formatted manpage should be generated from this content.
Name#
libsilk — C99-compatible embedding ABI for the Silk compiler.
Synopsis#
#include <silk/silk.h>
/* Core types */
typedef struct SilkString SilkString;
typedef struct SilkRange SilkRange;
typedef struct SilkBytes SilkBytes;
typedef struct SilkCompiler SilkCompiler;
typedef struct SilkModule SilkModule;
typedef struct SilkError SilkError;
typedef enum SilkOutputKind SilkOutputKind;
typedef enum SilkAmdGpuAqlFenceScope SilkAmdGpuAqlFenceScope;
typedef struct SilkAmdGpuAqlDispatchPacketConfig SilkAmdGpuAqlDispatchPacketConfig;
/* Version */
void silk_abi_get_version(int *out_major,
int *out_minor,
int *out_patch);
/* Lifecycle */
SilkCompiler *silk_compiler_create(void);
void silk_compiler_destroy(SilkCompiler *compiler);
/* Configuration */
bool silk_compiler_set_stdlib(SilkCompiler *compiler,
SilkString stdlib_name);
bool silk_compiler_set_std_root(SilkCompiler *compiler,
SilkString std_root);
bool silk_compiler_set_nostd(SilkCompiler *compiler,
bool nostd);
bool silk_compiler_set_debug(SilkCompiler *compiler,
bool debug);
bool silk_compiler_set_noheap(SilkCompiler *compiler,
bool noheap);
bool silk_compiler_set_target(SilkCompiler *compiler,
SilkString target_triple);
bool silk_compiler_set_z3_lib(SilkCompiler *compiler,
SilkString path);
bool silk_compiler_set_std_archive(SilkCompiler *compiler,
SilkString path);
bool silk_compiler_add_needed_library(SilkCompiler *compiler,
SilkString soname);
bool silk_compiler_add_runpath(SilkCompiler *compiler,
SilkString path);
bool silk_compiler_set_soname(SilkCompiler *compiler,
SilkString soname);
bool silk_compiler_set_optimization_level(SilkCompiler *compiler,
int level);
bool silk_compiler_set_c_header(SilkCompiler *compiler,
SilkString path);
/* Sources */
SilkModule *silk_compiler_add_source_buffer(SilkCompiler *compiler,
SilkString name,
SilkString contents);
/* Build */
bool silk_compiler_build(SilkCompiler *compiler,
SilkOutputKind kind,
SilkString output_path);
bool silk_compiler_build_to_bytes(SilkCompiler *compiler,
SilkOutputKind kind,
SilkBytes *out_bytes);
void silk_bytes_free(SilkBytes *bytes);
/* AMDGPU AQL */
#define SILK_AMDGPU_AQL_DISPATCH_PACKET_SIZE 64
bool silk_amdgpu_aql_dispatch_packet_build(
const SilkAmdGpuAqlDispatchPacketConfig *config,
uint8_t *out_packet);
/* Errors */
SilkError *silk_compiler_last_error(SilkCompiler *compiler);
size_t silk_error_format(const SilkError *error,
char *buffer,
size_t buffer_len);
Link with (on linux/x86_64, libsilk.a includes built-in Z3, which is built as C++):
cc -std=c99 -Wall -Wextra \
-I/path/to/include \
your_app.c \
-L/path/to/lib -lsilk \
-lstdc++ -lpthread -lm
Description#
libsilk.a exposes a stable C99 ABI for embedding the Silk compiler inside C (or C++) applications. The ABI is designed to be:
- simple and explicit,
- versioned independently of the compiler implementation,
- usable from plain C99 without extensions.
Embedders are expected to:
- include the public header
silk/silk.h, - link against
libsilk.a, - drive compilation by creating a
SilkCompilerhandle, adding source buffers, and invokingsilk_compiler_build, - inspect error details via
silk_compiler_last_errorandsilk_error_format.
The canonical include form is #include <silk/silk.h>. A flat
include/silk.h wrapper is still shipped for compatibility.
This manpage summarizes the ABI; the normative specification lives at abi libsilk.
For terminal-driven discovery:
- use
man 7 libsilkfor the embedding overview, - use
man 3 silk_compiler,man 3 silk_error,man 3 silk_bytes, andman 3 silk_abi_get_versionfor the core section 3 ABI entrypoints, - use
man 3 silk_amdgpu_aql_dispatch_packet_buildfor the AMDGPU AQL packet serializer, - use
silk envandsilk ccwhen you need the toolchain’s embedder-facing environment and default compiler/linker flags, - and use the hosted ABI specification at abi libsilk when you need the full normative contract.
Types#
SilkString#
typedef struct SilkString {
char *ptr;
int64_t len;
} SilkString;
- Represents a UTF‑8 string as a pointer plus a length.
ptrmay beNULLwhenlen == 0.- Unless explicitly documented otherwise for a given API:
- functions taking
SilkStringdo not take ownership ofptr, - the caller is responsible for the lifetime of the underlying storage.
SilkBytes#
typedef struct SilkBytes {
uint8_t *ptr;
int64_t len;
} SilkBytes;
- Represents an owned byte buffer as a pointer plus a length.
ptrmay beNULLwhenlen == 0.- Buffers returned by
silk_compiler_build_to_bytesmust be freed withsilk_bytes_free.
Package export helpers#
Named Silk packages mangle exported symbols so package exports do not collide. C and Objective-C bridge headers should use the public helper macros instead of spelling the reserved mangled prefix directly:
SILK_C_ABI_EXPORT_FN(lumen_trail, silk_ios_daily_score)
SILK_PACKAGE_EXPORT_FN(lumen_trail, silk_ios_daily_score)
SILK_PACKAGE_EXPORT_DATA(my_pkg, answer)
The macro arguments are C identifier tokens. The C ABI function helper expands
to lumen_trail_silk_ios_daily_score; use it for Silk functions declared
as export attr(abi=c) fn ... or attr(abi=c) export fn .... For nested Silk
packages, pass the clean C package spelling with namespace separators collapsed
to _, for example ui_model for package ui::model. The default package
function helper expands to
__silk_export_fn__lumen_trail__silk_ios_daily_score.
SilkRange#
typedef struct SilkRange {
int64_t start;
int64_t end;
uint64_t flags;
} SilkRange;
- Represents the Silk
rangeprimitive as three scalar slots. flagsis a bitfield:- bit 0:
has_end(when unset,endis ignored), - bit 1:
inclusive(only valid whenhas_endis set).
Opaque handles#
typedef struct SilkCompiler SilkCompiler;
typedef struct SilkModule SilkModule;
typedef struct SilkError SilkError;
SilkCompilerrepresents a compiler instance and owns configuration, modules, and internal error state.SilkModuleis an opaque handle returned when a source buffer is registered; its layout is not exposed.SilkErrorrepresents a diagnostic object owned by aSilkCompiler.
Callers must never allocate, free, or dereference these types directly. They are managed exclusively through the ABI functions.
SilkOutputKind#
typedef enum SilkOutputKind {
SILK_OUTPUT_EXECUTABLE = 0,
SILK_OUTPUT_STATIC_LIBRARY = 1,
SILK_OUTPUT_SHARED_LIBRARY = 2,
SILK_OUTPUT_OBJECT = 3,
} SilkOutputKind;
Selects the kind of build artifact requested by silk_compiler_build. At the current stage of implementation, all kinds perform full front‑end validation; code generation is implemented only for a small, constant‑expression subset of executable builds on linux/x86_64 (see Build behavior).
Versioning#
The header defines:
#define SILK_ABI_VERSION_MAJOR 0
#define SILK_ABI_VERSION_MINOR 1
#define SILK_ABI_VERSION_PATCH 1
and the function:
void silk_abi_get_version(int *out_major,
int *out_minor,
int *out_patch);
Callers should:
- compare the runtime version returned by
silk_abi_get_versionwith the compile‑time macros, - reject or warn on mismatches as appropriate for their integration.
The ABI is versioned so that future incompatible changes can be detected at runtime.
AMDGPU AQL Packets#
typedef enum SilkAmdGpuAqlFenceScope {
SILK_AMDGPU_AQL_FENCE_SCOPE_NONE = 0,
SILK_AMDGPU_AQL_FENCE_SCOPE_AGENT = 1,
SILK_AMDGPU_AQL_FENCE_SCOPE_SYSTEM = 2,
} SilkAmdGpuAqlFenceScope;
typedef struct SilkAmdGpuAqlDispatchPacketConfig {
uint16_t dimensions;
uint16_t workgroup_size_x;
uint16_t workgroup_size_y;
uint16_t workgroup_size_z;
uint32_t grid_size_x;
uint32_t grid_size_y;
uint32_t grid_size_z;
uint32_t private_segment_size;
uint32_t group_segment_size;
uint32_t max_flat_workgroup_size;
uint64_t kernel_object;
uint64_t kernarg_address;
uint64_t completion_signal;
uint8_t barrier;
int32_t acquire_fence_scope;
int32_t release_fence_scope;
} SilkAmdGpuAqlDispatchPacketConfig;
bool silk_amdgpu_aql_dispatch_packet_build(
const SilkAmdGpuAqlDispatchPacketConfig *config,
uint8_t *out_packet);
silk_amdgpu_aql_dispatch_packet_build writes one 64-byte HSA AQL
kernel-dispatch packet. It validates dimensions, workgroup/grid sizes, unused
dimensions, flat work-group size, and fence-scope values. Set
max_flat_workgroup_size to zero to use the conservative 1024 work-item
default. The fence-scope fields are fixed-width int32_t values containing one
of the SilkAmdGpuAqlFenceScope constants. The function returns false for
invalid inputs or null pointers; when out_packet is non-null, it is zeroed
before validation. The helper is independent of SilkCompiler and does not
update compiler last-error state.
The helper only serializes the packet. ROCR executable loading, HSA queue creation, signal allocation, and doorbell submission remain the caller's runtime responsibility.
Lifecycle#
silk_compiler_create / silk_compiler_destroy#
SilkCompiler *silk_compiler_create(void);
void silk_compiler_destroy(SilkCompiler *compiler);
silk_compiler_create:- returns a new compiler handle on success,
- returns
NULLon allocation error. silk_compiler_destroy:- may be called with
NULL(it is a no‑op), - must be called exactly once for each non‑
NULLhandle fromsilk_compiler_create, - releases all modules and errors owned by the compiler.
A single SilkCompiler instance is not currently specified as thread-safe; callers should either confine it to one thread or synchronize access.
Examples#
# Read the embedding overview and then the compiler handle API.
man 7 libsilk
man 3 silk_compiler
# Ask Silk for the environment variables used by the CLI/toolchain.
silk env
# Compile a simple embedder against the staged install.
silk cc c-tests/basic_abi.c -o basic_abi
Configuration#
Standard library selection#
bool silk_compiler_set_stdlib(SilkCompiler *compiler,
SilkString stdlib_name);
- Sets the name of the standard library package (for example
"std"). - The function:
- copies the name internally,
- returns
trueon success, - returns
falseon error and records an error in the compiler.
Standard library root#
bool silk_compiler_set_std_root(SilkCompiler *compiler,
SilkString std_root);
- Sets the filesystem stdlib root directory used to resolve
import std::...;declarations. - This overrides
SILK_STD_ROOT(environment variable) and thestd/working-directory default. - The function:
- validates that the directory exists,
- copies the path internally,
- returns
trueon success, - returns
falseon error and records an error in the compiler.
Disable stdlib auto-loading (nostd)#
bool silk_compiler_set_nostd(SilkCompiler *compiler,
bool nostd);
- When
nostdistrue, the compiler disables filesystem-based stdlib auto-loading forimport std::...;. - In this mode, any
std::...packages must be provided explicitly by adding the corresponding sources as modules (for example viasilk_compiler_add_source_buffer).
Debug build mode (debug)#
bool silk_compiler_set_debug(SilkCompiler *compiler,
bool debug);
- Enables the same debug build mode as the CLI (
silk --debug/-g) for the supported subset: - debug-mode lowering for supported native outputs (e.g. stack traces on
failed
assertforlinux/x86_64), - additional Z3 debug output and
.smt2dump emission on failing Formal Silk verification (see formal verification). --debugis currently incompatible with--noheap.
No-heap build mode (noheap)#
bool silk_compiler_set_noheap(SilkCompiler *compiler,
bool noheap);
- Enables the same no-heap build mode as the CLI (
silk --noheap), disabling heap-backed allocation for the supported subset. --noheapis currently incompatible with--debug.
Target triple#
bool silk_compiler_set_target(SilkCompiler *compiler,
SilkString target_triple);
- Sets the code generation target triple (for example
"x86_64-linux-gnu"). - The triple is copied; errors are recorded in the compiler’s last‑error state.
- Supported targets (implementation):
linux-x86_64(default), plus commonx86_64-*-linux-*triples such asx86_64-linux-gnuandx86_64-unknown-linux-gnu,linux-aarch64,android-aarch64,macos-x86_64,macos-aarch64,ios-aarch64,ios-simulator-aarch64,ios-simulator-x86_64,windows-x86_64,windows-aarch64,wasm32-unknown-unknown(IR-backed wasm32 mode; emits a final.wasmmodule exportingmemoryand exported functions, includingmainwhen present;extdeclarations become imports underenv.<name>; also supports export-only modules with nomainfor JS/Node-style embedding),wasm32-wasi(IR-backed wasm32 WASI mode; emitsmemoryand_start () -> void, importswasi_snapshot_preview1.proc_exit, and calls Silkfn main () -> int; also supports export-only modules for embedding, which do not include_start),amdgcn-amd-amdhsa-gfx942,amdgcn-amd-amdhsa-gfx1100, andamdgcn-amd-amdhsa-gfx1151(AMDHSA object output for source-intrinsic kernels).- Note: for
wasm32targets, onlySILK_OUTPUT_EXECUTABLEis supported.wasm32-wasicurrently supports onlyfn main () -> int(no argv). - Note: for AMDGPU targets,
SILK_OUTPUT_OBJECTemits a.hsacoonly when the input contains exactly one exported root-package void source kernel with up to 32 immutableu64parameters whose body is empty or contains only supported compiler-backed GPU calls, including semantic global-X fill and threshold-classification operations. Dependency-package exports do not count as kernels. The canonical source-intrinsic declarations and diagnostics are documented insilk-build(1)and the AMDGPU backend guide. - The provider-neutral mixed CPU/GPU executable option remains a
silk build --gpu-targetCLI surface. This release adds no correspondinglibsilkcompiler setting and does not change the C99 ABI.
Z3 dynamic library override (z3_lib)#
bool silk_compiler_set_z3_lib(SilkCompiler *compiler,
SilkString path);
- Configures a Z3 dynamic library override for Formal Silk verification
(equivalent to
silk --z3-lib <path>). - Passing an empty string clears the override and returns to normal Z3
resolution (including honoring
SILK_Z3_LIB).
Stdlib archive override (std_archive)#
bool silk_compiler_set_std_archive(SilkCompiler *compiler,
SilkString path);
- Configures a stdlib archive override for native builds (equivalent to
silk --std-lib <path>). - Passing an empty string clears the override and returns to normal stdlib
archive resolution (including honoring
SILK_STD_LIB).
Dynamic linker metadata#
These configuration functions affect dynamic metadata emitted for executable and
shared library outputs on platforms/backends that support dynamic linking (the
current target: linux/x86_64).
silk_compiler_add_needed_library#
bool silk_compiler_add_needed_library(SilkCompiler *compiler,
SilkString soname);
- Adds a dynamic loader dependency for executable and shared outputs by emitting
a
DT_NEEDEDentry. - The
sonamestring is copied; the function may be called multiple times (duplicates are ignored). - Ignored for static library and object outputs.
- On
linux/x86_64, when an executable or shared library imports any external symbols, the compiler automatically adds the selected libc as aDT_NEEDEDdependency (libc.so.6for glibc,libc.sofor musl), so hostedstd::modules likestd::ioandstd::fsdo not require manually adding libc. Additional non-libc dependencies still require explicitDT_NEEDEDentries via this API. DT_NEEDEDentries starting withlibsilk_rtare rejected: bundled runtime helpers are linked statically fromlibsilk_rt.a/libsilk_rt_noheap.aand must not become runtime loader dependencies.
silk_compiler_add_runpath#
bool silk_compiler_add_runpath(SilkCompiler *compiler,
SilkString path);
- Adds a runtime search path element for executable and shared outputs by
emitting a
DT_RUNPATHentry. - The
pathstring is copied; the function may be called multiple times (duplicates are ignored) and the finalDT_RUNPATHstring is formed by joining entries with:. - Ignored for static library and object outputs.
silk_compiler_set_soname#
bool silk_compiler_set_soname(SilkCompiler *compiler,
SilkString soname);
- Sets the shared library soname recorded as
DT_SONAMEfor shared outputs. - The
sonamestring is copied; passing an empty string clears the configured soname (noDT_SONAMEentry). - Ignored for executable, static library, and object outputs.
Optimization level#
bool silk_compiler_set_optimization_level(SilkCompiler *compiler,
int level);
levelmust be in the range[0, 3]:0— no optimization (fastest compile),1— light optimization,2— balanced optimization,3— aggressive optimization.- The default optimization level is
0unless overridden. level >= 1enables lowering-time pruning of unused extern symbols before code generation. This typically reduces output size and over-linking when using the prebuilt stdlib archive (libsilk_std.a) to satisfy auto-loadedimport std::...;modules.- The CLI also exposes
silk build --strip-unusedto force analogous reachability-based pruning at-O0for executable/static/shared outputs; the current C ABI does not yet expose a separate setter for that flag. - Returns:
trueon success,falseand records an error (e.g."invalid optimization level (expected 0-3)") when the value is invalid.
C header generation (c_header)#
bool silk_compiler_set_c_header(SilkCompiler *compiler,
SilkString path);
- Configures C header generation for non-executable outputs (equivalent to the
CLI
--c-header <path>). - Passing an empty string clears the configured header output path.
- The header is written when
silk_compiler_buildsucceeds for: SILK_OUTPUT_OBJECT,SILK_OUTPUT_STATIC_LIBRARY,SILK_OUTPUT_SHARED_LIBRARY.- C header generation is not supported for
silk_compiler_build_to_bytes.
Source buffers#
silk_compiler_add_source_buffer#
SilkModule *silk_compiler_add_source_buffer(SilkCompiler *compiler,
SilkString name,
SilkString contents);
- Registers a source buffer with the compiler:
nameis a logical module name used in diagnostics (e.g."main.slk"or"<memory>"),contentsis the UTF‑8 Silk source.- On success:
- returns a non‑
NULLSilkModule *, - copies both
nameandcontentsinto memory owned by the compiler. - On error:
- returns
NULL, - records an error describing the cause.
The returned SilkModule * must not be freed by the caller and remains valid until the compiler is destroyed.
Build behavior#
silk_compiler_build#
bool silk_compiler_build(SilkCompiler *compiler,
SilkOutputKind kind,
SilkString output_path);
- Performs a build for all modules added to the compiler:
- lexes and parses each module,
- type‑checks statements and expressions according to the language spec,
- enforces additional front‑end constraints (see below),
- stops on the first error.
output_path:- is the requested output location for the artifact,
- for executable outputs (
SILK_OUTPUT_EXECUTABLE) in the supported subset (see below), it is used as the path of the native executable that is produced, - for other output kinds, it is used as the output file path in supported backend subsets; for unsupported programs/targets, no output is written.
Return value:
- On any front‑end error, returns
falseand records a descriptive error string. Examples include: "unexpected token while parsing module","type mismatch","invalid break statement","invalid continue statement","invalid return statement".- On success of front‑end validation:
- for non‑executable outputs (
SILK_OUTPUT_STATIC_LIBRARY,SILK_OUTPUT_SHARED_LIBRARY,SILK_OUTPUT_OBJECT): - on supported targets/backends (currently
linux/x86_64, plus Apple Silicon host-backedmacos-aarch64and iOS device/simulator object/static/shared outputs, plus AMDGPU.hsacosource-intrinsic object output), the compiler attempts code generation for the documented backend subset and returnstrueafter writing the requested artifact on success, - for front‑end valid programs outside that subset (or on unsupported
targets), the call returns
falseand records either anE4001/E4002formatted diagnostic (unsupported construct / backend failure) or a more direct descriptive error string (for example invalid arguments), and does not write output. - when lowering cannot isolate a narrower statement / expression span, the
recorded
E4001diagnostic falls back to the offending function declaration and names that function directly. - for executable outputs (
SILK_OUTPUT_EXECUTABLE): - if the program satisfies the executable entrypoint rule (below) and
mainreturns a constant integer expression in the supported subset: - the body of
mainmust be one of the following: - zero or more
letstatements with constant integer initializers followed by exactly onereturnof a constant expression built from integer literals,+,-,*,/,%, and references to immutableletbindings whose initializers are themselves constant integer expressions, or - a final
ifstatement whose condition is a compile‑time boolean literal (trueorfalse) and whose branches each satisfy the same “constant lets +returnconstant expression” rule, or - one or more trivial constant
whileloops that appear before the finalreturn, each of which has: - a condition that is a compile‑time boolean literal (
trueorfalse), - for
while false { ... }, a body that is ignored by the constant backend, and - for
while true { ... }, a body consisting of zero or more constantletstatements followed by abreak;, with no other control flow; loop invariants (#invariant), variants (#variant), and monovariants (#monovariant) may be present but are treated as metadata and do not affect constant evaluation, - then
silk_compiler_build: - evaluates the constant integer expression determined by
main, - emits a tiny native executable image directly using an Silk‑owned backend (no C stub, no external C compiler):
- currently this backend writes a minimal target-specific executable
that terminates the process with the evaluated
mainvalue: - ELF64 for
linux-x86_64,linux-aarch64, andandroid-aarch64, - Mach-O 64-bit for
macos-x86_64,macos-aarch64,ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64, - PE32+ for
windows-x86_64andwindows-aarch64, - returns
trueon success and leaves the last error unset, - on Apple Silicon macOS hosts, the current temporary host-backed non-const executable and Apple Mach-O library-output subset used by the CLI is also available through the C ABI:
- this path emits target-specific arm64 or x86_64 assembly, assembles
it with host
clang -c, links executables and dylibs with hostld, builds static archives with Applelibtool -static, ad hoc-signs macOS Mach-O executables when needed, and currently covers the implemented scalar IR subset, - for
macos-aarch64and the three iOS device/simulator targets, the same subset is available throughsilk_compiler_build(...)because that ABI entrypoint writes a filesystem artifact at the requestedoutput_path, - the CLI / driver also supports
ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64for the same pure-Silk scalar subset on Apple Silicon macOS hosts, including reachable float-to-int lowering and the portable bundled runtime helper families for number / regex / unicode / filesystem / dns / process / signal / term / pty / readline / task-pool / async support, - the C ABI entrypoints now support that same non-const iOS host-backed executable/object/static/shared subset as well,
- the remaining explicit
E4001iOS limitation is only for lowered programs that still need narrower unsupported bundled runtime-internal helper families, - if the program is front‑end valid but outside this subset (for example,
maincontains non‑constant expressions, references to non‑constant values, function calls, or unsupported control flow), or if the backend cannot produce an executable for the current platform or output path, the call returnsfalseand typically records either"code generation is not implemented yet"or"failed to build executable output"as the last error.
Executable entrypoint rule#
For executable builds (kind == SILK_OUTPUT_EXECUTABLE), the ABI currently enforces a simple entrypoint rule:
-
there MUST be exactly one top‑level function with one of the signatures:
fn main() -> int { ... } fn main(argc: int, argv: u64) -> int { ... } -
name:
main, -
either zero parameters, or exactly two parameters whose types are
intandu64, -
result type:
int.
If this condition is not met:
silk_compiler_buildreturnsfalse,- records an error message such as:
"no valid main function for executable output", or"multiple main functions for executable output".
This rule is enforced before code generation exists so that embedders and tests can rely on a stable definition of an “executable module”.
For other SilkOutputKind values (static/shared libraries, object files), no main entrypoint is required by the current front‑end.
silk_compiler_build_to_bytes#
bool silk_compiler_build_to_bytes(SilkCompiler *compiler,
SilkOutputKind kind,
SilkBytes *out_bytes);
Builds the requested artifact as an owned in-memory byte buffer instead of writing to a filesystem path.
- Behavior and supported subsets match
silk_compiler_buildfor the samekind: - this now includes the Apple Silicon macOS
macos-aarch64and iOS device/simulator host-backed executable/object/static/shared subset as well;silk_compiler_build_to_bytes(...)bridges that path through a temporary filesystem artifact (signed for executables) and then returns the produced Mach-O/archive bytes to the caller, - for
ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64, that same non-const pure-Silk scalar executable subset and library-output subset, including reachable float-to-int lowering and the same portable bundled runtime helper families, is now available throughsilk_compiler_build_to_bytes(...)on Apple Silicon macOS hosts as well, - the remaining explicit
E4001iOS limitation applies only when the lowered program actually needs narrower unsupported bundled runtime-internal helper families. - On success:
- returns
true, - fills
*out_byteswith(ptr, len)describing the produced artifact, - leaves the last error unset.
- On error:
- returns
false, - records an error message retrievable via
silk_compiler_last_error, - and sets
out_bytesto{ NULL, 0 }.
The returned buffer must be freed with:
void silk_bytes_free(SilkBytes *bytes);
When bytes->ptr is NULL, silk_bytes_free is a no-op. After freeing, it
clears the struct to { NULL, 0 }.
Error handling#
silk_compiler_last_error#
SilkError *silk_compiler_last_error(SilkCompiler *compiler);
- Returns a pointer to the last error object produced by operations on
compiler, orNULLif no error is recorded. - Ownership and lifetime:
- the pointer is owned by the compiler,
- it remains valid until:
- the compiler is destroyed, or
- a subsequent operation overwrites the last‑error state.
- callers must not attempt to free it.
silk_error_format#
size_t silk_error_format(const SilkError *error,
char *buffer,
size_t buffer_len);
- Formats a human‑readable error message into the caller‑provided
buffer. - Behavior:
- writes up to
buffer_len - 1bytes of UTF‑8 intobuffer, - always NUL‑terminates if
buffer_len > 0, - returns the number of bytes that would be required to format the full message, excluding the terminating NUL.
- If the return value is greater than or equal to
buffer_len, the message was truncated. - The formatted message is intended for end-user display and follows the standard compiler diagnostic format (error code + optional file/line/column + caret snippet) as specified at diagnostics.
Callers can use a two‑step pattern:
- Call with
buffer = NULL,buffer_len = 0to discover the required size. - Allocate a buffer of that size plus one and call again to retrieve the full message.
Build and link integration#
Typical integration in a C99 project:
- Install or vendor:
include/silk/silk.h,- optionally
include/silk.has the legacy compatibility wrapper, libsilk.a.
-
Include the header from your C source:
#include <silk/silk.h>
3. Link against the static library:
```sh
cc -std=c99 -Wall -Wextra \
-I/path/to/include \
your_app.c \
-L/path/to/lib -lsilk \
-lstdc++ -lpthread -lm
-
Create and drive a compiler instance:
SilkCompiler *compiler = silk_compiler_create(); if (!compiler) { /* handle allocation error */ } silk_compiler_set_stdlib(compiler, make_string("std")); silk_compiler_set_target(compiler, make_string("x86_64-linux-gnu")); silk_compiler_set_optimization_level(compiler, 2); silk_compiler_add_source_buffer( compiler, make_string("main.slk"), make_string("fn main() -> int { return 0; }")); if (!silk_compiler_build(compiler, SILK_OUTPUT_EXECUTABLE, make_string("out.exe"))) { SilkError *err = silk_compiler_last_error(compiler); char buf[256]; size_t n = silk_error_format(err, buf, sizeof buf); /* handle error message in buf */ } silk_compiler_destroy(compiler);
At this stage, successful builds are limited to the backends implemented by the compiler:
- On
linux/x86_64, the compiler can emit native ELF64 executables, objects, static libraries, and shared libraries for the current IR subset documented in abi libsilk (structured control flow, helper calls, limitedstring/struct/optional support, and a limited FFI subset). - On
wasm32-unknown-unknownandwasm32-wasi, executable builds emit.wasmmodules for the current IR-backed wasm32 subset documented in abi libsilk (including multi-module builds, export-only modules, andextimports underenv.<name>). - On
amdgcn-amd-amdhsa-gfx942,amdgcn-amd-amdhsa-gfx1100, andamdgcn-amd-amdhsa-gfx1151, object builds emit AMDHSA.hsacocode objects for the current source-intrinsic subset; seesilk-build(1)and the AMDGPU backend guide for the canonical declaration sets. - On other targets, no code generation backend is available yet.
- For well‑typed programs outside these subsets,
silk_compiler_buildfails withE4001/E4002diagnostics (or a more specific build error) until the back‑end is extended.
When Formal Silk verification syntax is present (for example #require,
#assure, #assert, #invariant, #variant, #monovariant, #const), libsilk runs the Z3-backed
Formal Silk verifier and fails the build if verification conditions cannot be
proven. The verifier is currently skipped for std::... modules until it
covers the full std surface.
Environment#
SILK_STD_ROOT— path to the stdlib root directory used to resolveimport std::...;declarations when the embedder has not calledsilk_compiler_set_std_root.SILK_STD_LIB— path to a target-specific stdlib static archive (libsilk_std.a). When present, supported executable builds treat auto-loadedstd::...modules as external and resolve their exported functions from this archive.SILK_Z3_LIB— path to a dynamic Z3 library used by the Formal Silk verifier. When set, it overrides the default built-in Z3 linkage for verification.SILK_VERIFY_JOBS— override the number of worker threads used for Formal Silk verification (default: auto; capped at 8).
See Also#
silk(1)— Silk language compiler CLI.silk_abi_get_version(3),silk_compiler(3),silk_error(3),silk_bytes(3),silk_amdgpu_aql_dispatch_packet_build(3)silk(7)- abi libsilk — normative ABI spec.
silk/silk.h— canonical C99 ABI header in the source tree.
Source repository · Edit this page · View Markdown