silk CLI
This document describes the command-line interface of the silk compiler from the downstream user’s perspective.
Binary#
- Name:
silk. - Alias entrypoints:
slc— behaves likesilk build ...(convenience wrapper),slcc— behaves likesilk cc ...(convenience wrapper).
Core Responsibilities#
At maturity, the silk CLI should:
- Compile Silk source files into:
- executables,
- static libraries (
.a), - shared libraries (
.so/.dylib/.dllas appropriate). - Provide options to:
- select target triple and optimization level,
- choose build mode (debug / release),
- control linkage to the default
std::implementation or an alternative, - enable/disable or tune Formal Silk verification checks,
- configure external and ABI-related behaviors where appropriate (e.g. visibility of
libsilk.asymbols, header emission). - Emit clear diagnostics with stable error codes and machine‑readable output when requested.
The implementation is intentionally smaller and focuses on:
-
global options:
-
--help/-h— print global usage and exit, -
help— print global usage and exit, -
help <command>— print command-specific usage and exit, -
live help surfaces group options and notes by purpose instead of emitting a flat option dump; for example
build,check,test,doc,man,package, and the utility commands use grouped terminal help sections, -
--version— print the Silk toolchain version, ABI version, and git commit and exit, -
silk repl— start an interactive “compile-and-run” REPL: -
currently supported on:
-
linux/x86_64via the native ELF executable backend, -
macos/aarch64on Apple Silicon hosts for session startup and non-printing declaration/state lines via the current host-backedmacos-aarch64executable path, -
current Apple Silicon note:
-
the REPL command itself now starts on
macos/aarch64, -
REPL value auto-printing and
std::ioformatting-driven runtime lines use the current host-backedmacos-aarch64executable path, so unsupported backend shapes still report normal compile diagnostics, -
intended as a node-like default when
silkis launched with no arguments and stdin is a TTY, -
stateful by replay of state-building lines:
-
import lines are persisted after syntax and import-target validation without building a temporary executable,
-
top-level declaration lines are persisted and validated by compilation only (not executed),
-
in the REPL only, import lines may omit the trailing semicolon; the session stores the semicolon-terminated form, and ordinary source files still require semicolon-terminated imports,
-
runtime lines that build state (for example
let/varbindings and assignments) are persisted and replayed from the start on each new runtime line, -
simple committed runtime bindings cache their rendered value when the existing validation run can capture it, and repeated bare value queries such as
nreuse that cache until committed state changes, -
lines that fail parsing, type checking, compilation, or execution are not committed and leave the previous completion/introspection state intact,
-
other runtime lines (for example
hello();orprintln("...");) are executed once and are not replayed, -
runtime snippets may use top-level
await; the REPL emits an async synthetic entrypoint for snippets or replayed state lines that need one, -
bare auto-printed
async fncalls are awaited before formatting the resulting value, while non-promise await operands still report the normal await operand diagnostic, -
supports:
-
.help— show help, -
.man <query>— render inline documentation for current-session symbols, imported symbols, andstd::...modules/symbols, with highlighted Silk synopsis/examples and comment-colored prose descriptions when ANSI colors are available, -
.clear— reset session state, -
.cls— clear the screen, -
.undo— undo the last committed line, -
.exit— exit the REPL, -
interactive TTY input is syntax-highlighted as the user types; when ANSI colors are available, shared completion prefixes also appear as a dim inline completion hint and
Tabaccepts or cycles the active completion, using the same ordered candidate set as the hint, -
Ctrl-Rstarts reverse incremental history search in TTY mode; type to filter, pressCtrl-Ragain to move to older matches,Enterto accept the selected line, orEscape/Ctrl-Gto cancel back to the original edited line, -
completion candidates include REPL commands, language keywords, std namespace paths, quoted
from "std/..."import specifier paths, current-session declarations and bindings, imported symbols, functions, static impl functions afterType., and struct fields or receiver methods after typed values and receiver expressions such as call results, indexed values, chained field accesses, imported type aliases, and result/optional receiver chains, -
the live highlighting/hint surface uses the same Silk lexer-backed ANSI colors as REPL
.mansource snippets and is disabled for non-TTY input,NO_COLOR, and dumb/unsupported terminals, -
supports multi-line input: when delimiters are unbalanced (for example
{without}), the REPL prompts with...and keeps reading until the statement is complete, -
continuation lines are pre-indented from the current unmatched delimiter depth so nested
{},(), and[]constructs carry indentation forward, -
when a complete pasted chunk contains multiple top-level entries, the REPL splits and executes them in order while keeping multiline blocks/declarations together,
-
multiline expressions still use the normal expression/auto-print path when they are not declaration or statement forms, including multiline raw backtick strings,
-
Ctrl-C cancels a pending multi-line statement,
-
symbol queries: when a line is a bare identifier or qualified name (for example
User,User.method,std::fs,std::io::println, or an imported namespace alias such asfsorfs::FileResultafterimport fs from "std/fs";), the REPL prints the matching declaration or module overview from the current session or imported modules instead of executing it, -
.manis intentionally narrower thansilk man: -
it is for inline REPL browsing of module/symbol docs,
-
use
silk man ...outside the REPL for sectioned/shipped pages, search, and list modes (for examplesilk man 7 silkorsilk man --search io), -
history is loaded/saved to:
-
$SILK_REPL_HISTORYwhen set, otherwise -
$SILK_WORK_DIR/repl_history(default:.silk/repl_historyunder the nearest package root or current directory), -
Ctrl-Rsearches that in-memory history during interactive editing, -
silk check [--json] [--verify|--no-verify] [--nostd] [--std-root <path>] [--z3-lib <path>] [--debug] [--feature <spec> ...] [--arch <arch>] [--target <triple>] [--security-provider <auto|platform|builtin>] [--package <dir|manifest>] <file> [<file> ...]— parse and type-check one or more Silk source files as a unit, exiting with: -
code
0on success, -
non-zero on error, printing a human-readable diagnostic (format specified in diagnostics).
-
--jsonwrites a newline-terminated, schema-versioned JSON result packet to stdout instead of the human success line, and compiler diagnostics emitted through the standard diagnostic path are written as JSON diagnostic packets. -
when
<file> ...inputs are omitted and--package/--pkgis also omitted, but./silk.tomlexists,silk checkbehaves as if--package .was provided. -
when
--packageis provided and the root manifest enables a build module via[build].build_module = true, the compiler runs that build module and type-checks the emitted manifest/module set instead of the rawsilk.toml; for compatibility, the build module currently receives the action stringbuild. -
silk targets [--json]— inspect target triples and architecture aliases: -
human output matches the target/architecture lists used by
silk build --list-targetsandsilk build --list-archs; target lines show current-host output kinds and call out Apple Silicon macOS host-backed support when it is not available on the current host; AMDGPU targets are listed for metadata and backend-encoder discovery, but are not yet generalsilk buildGPU lowering targets, -
--jsonemits a packet withschemaVersion,command,host,targets,architectures, and per-target capability facts including baseline output kinds, current-host output kinds, native-input support, POSIX/Unix/WASM shape, and current async-runtime availability. -
silk devices <subcommand> [options]— discover and manage platform devices: -
listanddoctorreport the local desktop backend plus platform device backends discovered from installed tools, -
--jsonemitsschemaVersion,command: "devices", host metadata, normalized device records, backend/tool availability, and, forlist, raw platform listing command output for editor, CI, and agent workflows, -
setupdelegates to setup/listing commands for the selected platform backend (xcrun simctl,xcrun devicectl, oradb), -
install,uninstall,boot,shutdown,launch/run, andlogscover the app lifecycle for supported simulators, physical devices, emulators, and local desktop launch/log surfaces, -
--kind <desktop|ios-simulator|ios-device|android>selects a backend; when omitted, install/launch actions infer from--app,--bundle-id, or--packagewhere the artifact shape is unambiguous, -
--passes remaining arguments to the underlying platform tool so users can reach SDK-specific flags without leaving the Silk CLI. -
silk codesign <subcommand> [options]— sign and verify platform artifacts: -
doctorandlist-toolsreport installed signing tools, includingcodesign,apksigner,jarsigner,keytool,dpkg-sig,rpmsign,rpmkeys,appimagetool, andgpg, -
--jsonemitsschemaVersion,command: "codesign", host metadata, and tool availability, -
signandverifyselect a platform with--platform <auto|macos|ios|android|linux>or infer one from the input extension when possible, -
macOS/iOS signing delegates to
codesign; Android APK signing delegates toapksignerby default, Android App Bundle/JAR-compatible signing delegates tojarsigner, and Android keystore creation delegates tokeytool; Linux signing selectsdpkg-sig,rpmsign/rpmkeys,appimagetool, orgpgby artifact format, -
--toolcan override Android and Linux tool selection, and--passes remaining arguments through to the selected signing tool. -
silk graph [--json] [--nostd] [--std-root <path>] [--feature <spec> ...] [--arch <arch>] [--target <triple>] [--package <dir|manifest>] <file> [<file> ...]— inspect the module/package/import graph loaded by the CLI: -
accepts the same stdlib, feature, package, and target selectors as
silk check, -
when inputs are omitted and
./silk.tomlexists, behaves as if--package .was provided, -
loads the module set but does not type-check, lower, or emit code,
-
--jsonemitsschemaVersion,command,target, module counts, package roots, and module entries with origin (user,package, orstd) plus parsed import declarations. -
silk size [--json] <artifact>— inspect an output artifact: -
human output prints file size and available section sizes,
-
--jsonemitsschemaVersion,command,path,fileSize,format, andsections, -
ELF64 little-endian artifacts report section names, offsets, sizes, and allocation/write/execute flags; other artifact formats currently report
format: "unknown"with an empty section list, -
very large artifacts still report
fileSizefrom filesystem metadata even when section parsing is skipped. -
silk test [--nostd] [--std-root <path>] [--std-lib <path>] [--z3-lib <path>] [--debug] [--feature <spec> ...] [--security-provider <auto|platform|builtin>] [-O <0-3>] [--noheap] [--jobs <n>] [--filter <pattern>] [--package <dir|manifest>] <file> [<file> ...]— compile and run language-leveltestdeclarations found in the module set, emitting TAP output: -
uses TAP version 13 formatting (
TAP version 13,1..N,ok/not oklines), -
each test runs in its own process, so a failing
assert(panic/abort) does not stop the whole suite, -
top-level test bodies that contain
awaitare run through async test wrappers and awaited by the generated runner, -
executable test runners use the native host target when Silk has a host-backed executable backend for it, and otherwise fall back to the
linux/x86_64executable backend. Formal Silk target metadata insilk testreflects that selected execution target. -
the supported code generation subset matches
silk buildfor the selected execution target. -
--filter <pattern>runs only tests whose test path contains<pattern>(substring match). The test path is the nestedtest "..." { ... }stack joined with/(for examplesuite/case). -
when nested tests are present, the runner prints subtest progress lines to stderr as they complete:
-
ok - suite/case -
not ok - suite/case -
execution controls:
-
--jobs <n>runs up to<n>test processes in parallel (default:1;0means auto; capped at8). -
SILK_TEST_JOBSoverrides--jobswhen--jobsis not provided (default:1;0means auto; capped at8). -
SILK_TEST_TIMEOUT_MSoverrides the per-top-level-test process timeout (default:30000), -
SILK_TEST_MAX_OUTPUT_BYTEScaps captured stdout/stderr per test process for diagnostics (default:1048576; output beyond this limit is truncated). -
when
<file> ...inputs are omitted and--packageis also omitted, but./silk.tomlexists,silk testbehaves as if--package .was provided. -
when
--packageis provided: -
input files must be omitted (the compiler loads the package module set from the manifest),
-
the manifest file is
silk.toml(when a directory is provided, it is discovered in that directory), -
when the root manifest enables a build module via
[build].build_module = true, the compiler runs that build module and uses the emitted manifest for package tests; for compatibility, the build module currently receives the action stringbuild, -
manifest-native link metadata for the test harness (
[[target]].inputs,cflags,ldflags,needed, andrunpath) is taken from: -
[build].default_targetwhen it names a code target, -
otherwise the first declared code target,
-
matching package and dependency
[[native]]entries are merged as package-level native requirements, -
while
kind = "man"targets are ignored for target metadata, -
raw
.c,.h, and supported.msource inputs are compiled to temporary objects before the harness is linked, -
built-in provider native-input auto-linking for libsodium, mbedTLS, and libssh2, plus built-in SQLite auto-linking, follows the same supported-target rules as
silk build --package, -
and when no code target exists, tests run without manifest link metadata,
-
see package manifests for the manifest format and source discovery rules.
-
silk doc— generate documentation from Silkdoc comments (/** ... */and/// ...) attached to declarations: -
Markdown mode:
silk doc [--all] <file> [<file> ...] [-o <output.md>] -
by default, includes:
-
exported
fn/let/ext/type/theorydeclarations and exportedimplmethods, and -
all
struct/enum/error/interfacedeclarations in the input modules, -
--allincludes non-exported functions, bindings, and methods, -
when
-o/--outis provided, writes the Markdown output to that path; otherwise writes to stdout. -
Manpage mode:
silk doc --man [--package <dir|manifest>] [--std-root <path>] <query> [-o <output.man>] -
renders a single roff
man(7)page to stdout (or to-o/--outwhen provided), -
the page kind is derived from the documentation tags (
@cli→ section 1,@misc→ section 7, otherwise section 3 for API pages), -
when
<query>is notstd::..., the module set is loaded from--packagewhen provided; otherwise the compiler searches the current working directory and its parents forsilk.tomland uses the nearest match, -
package-scoped source-doc queries are evaluated against the root package’s own source modules, not dependency docs in the same manifest graph,
-
intended as a non-interactive complement to
silk man <query>. -
silk man <query>— render and view a temporary manpage for a symbol/module/concept derived from source documentation: -
std::...queries are resolved from the configured stdlib root (see “standard library import resolution” below), -
other queries are resolved from
--package <dir|manifest|module>when provided; otherwise the compiler searches the current working directory and its parents forsilk.tomland uses the nearest match, -
when a package root is in scope,
silk manalso discovers package-authored docs/man pages from that root: -
local
package.readmepaths act as the package overview page, -
local
package.documentationpaths act as a package docs landing page, -
local metadata doc paths must stay inside the package root; absolute paths and
..escapes are rejected, -
and package man roots are discovered under
docs/man/,man/,share/man/, and installed sectioned roots such asshare/man/man1/, -
package-scoped source-doc queries are evaluated against the root package’s own source modules, not dependency docs in the same manifest graph,
-
API symbol pages are derived from exported/public declarations; non-exported declarations are intentionally omitted so docs match the public surface,
-
when no manifest is found, the compiler may also resolve the query from the package search path (
SILK_PACKAGE_PATH). -
to select a shipped toolchain page by section, prefer
silk man 7 silkorsilk man silk.7(most shells require quotingsilk(7)). -
discovery helpers:
-
silk man(no arguments) opens the nearest package overview when one is in scope; otherwise it prints a quick-start plus a list of entrypoints, -
silk man --listlists shipped pages, common stdlib entrypoints, and package-local pages when a package root is in scope, -
silk man --search <pattern>searches: -
shipped section 1/3/7 pages,
-
stdlib module names,
-
public stdlib API symbol paths,
-
package-local overview/docs/man pages when a package root is in scope,
-
and public root-package symbol paths when a package root is in scope.
-
use
silk man <query>when you want to open docs immediately, andsilk doc --man <query> -o <path>when you want the generated roff page as a file. -
when stdout is not a TTY,
silk man <query>writes the resolved roff page to stdout instead of invoking the interactivemanviewer. -
when the host
mancommand cannot open the generated local page directly,silk manfalls back to the configured pager (MANPAGER/PAGER). -
shorthands:
-
silk man buildopenssilk-build(1)(same forrepl,package,cache,devices,codesign,check,targets,graph,size,test,doc,man,guide,error,proto,help,lsp,cc,env, andformat/fmt), -
when no package is selected/resolvable,
silk man fsis treated assilk man std::fs(and similarly for other top-level std modules). -
when no package is selected/resolvable,
silk man io println(orsilk man 3 io println) is treated assilk man std::io::println. -
when a package root is selected/resolved,
silk man readme,silk man overview,silk man <package-name>, and qualified aliases such assilk man <package-name> readmeprefer the package overview page when a localpackage.readmeexists. -
when a package root is selected/resolved,
silk man docs,silk man documentation, and qualified aliases such assilk man <package-name> documentationopen the localpackage.documentationpage when present. -
when a query cannot be resolved,
silk manprints actionable next steps (try--search,--list, or qualify withstd::.../pkg::...). -
silk guide [options] <query>— search a curated installed example corpus: -
the source-of-truth catalog lives in
examples/guide/catalog.json, -
install/build staging generates
share/silk/guide.db, -
the seeded corpus target is at least
1000entries and is guarded by repo tests, -
the corpus combines runnable examples with documentation-backed reference guides covering every canonical page under
docs/language/anddocs/std/, -
generated public-symbol metadata lets
silk guideroute shipped stdexportdeclarations and public methods (public fnandpublic async fn) to the matchingstd/*-apiguide, -
fixture-backed seeded guides are promoted to
verified_buildwhen they compile cleanly, -
silk guide --listlists seeded guide ids and titles, -
silk guide --show <id>renders one guide entry with an action-first summary plus the stored Silk source, -
silk guide --show <prefix>expands guide-id prefixes such asfsortaskand may render multiple matching guides; when generated variants share the same source body, show output keeps one entry and prefers the canonical overview variant, -
silk guide --json ...emits machine-readable search/show payloads with list-valued metadata rendered as JSON arrays, -
silk guide tags:<name>queries normalized tag metadata, -
silk guide module:std::taskqueries normalized std-module metadata, and direct module names such assilk guide std::taskstill resolve as module lookups when they are not exact public-symbol matches, -
silk guide std::http::request,silk guide std::mime::content_type_with,silk guide std::atomic::AtomicU64.fetch_add,silk guide std::dylib::open_self,silk guide ByteSlice.find_bytes, andsilk guide GL_TEXTURE_2Dquery generated public std symbol metadata before free-text FTS search, -
silk guide diag:E2034(orsilk guide E2034) queries normalized diagnostic-code metadata, -
exact alias matches are resolved before free-text FTS search,
-
free-text guide search first applies deterministic intent routing plus filler-word normalization for common natural-language queries such as
how to read a file,how can i open a file and read it,read from stdin, andhow do i make a http request, -
free-text queries search a bundled SQLite FTS5 index over guide titles, summaries, stored source, aliases, keywords, tags, modules, requirements, docs, and diagnostics,
-
non-empty guide queries that still miss after alias/FTS routing return no matches instead of falling back to the alphabetical
--listoutput, -
documentation-backed reference guides are tagged with
reference-guideand link directly to canonical language/std docs, -
reference queries such as
silk guide language atomicsandsilk guide std io overviewroute to documentation-backed entries, -
text search results include an explicit
matched:reason, -
--showprioritizesWhat,Why, and other action-oriented metadata before secondary search metadata, does not printRun:,Source:, orVerified:summary fields, and rendersDocs:as canonical docs links URLs, -
the stored Silk source is printed directly through the configured printer path instead of fenced code blocks,
-
guide
Docs:references are rendered as canonical docs URLs rather than repo-relative markdown paths, -
guide source output is printed through the configured printer path (or direct plain source fallback), not wrapped in fenced code blocks,
-
high-traffic diagnostics may point directly at guide lookups such as
silk guide E2030andsilk guide E2034, -
--db <path>overrides the database path for testing/staging, -
--printer <cmd>chooses the source printer for--show; if omitted,SILK_GUIDE_PRINTERis used, thenbat, thencat, -
SILK_GUIDE_DBoverrides the installed database path when--dbis not provided, -
SILK_GUIDE_PRINTERoverrides the--showsource printer when--printeris not provided. -
silk error [--json] <code>— look up a stable compiler diagnostic code: -
prints the canonical code, category, short description, documentation references, any bundled example, and a guide lookup hint only when the installed guide catalog links that diagnostic code,
-
--jsonemitsschemaVersion,command,mode, and a structureddiagnosticobject for lookup, or adiagnosticsarray for--list, -
examples are syntax-highlighted when stdout is a color-capable TTY; piped output,
NO_COLOR, andTERM=dumbstay plain, -
accepted code forms include
E2028,2028,diag:E2028, anderror[E2028], -
silk error --listandsilk error -llist all stable compiler error codes and their short descriptions in deterministic order. -
silk proto [options] <schema.proto> [<schema.proto> ...]— compile Protocol Buffers v3 schemas to Silk modules without invokingprotoc: -
-I <dir>,-I<dir>,--proto-path <dir>, and--include <dir>add schema import roots, -
-o <dir>/--out-dir <dir>selects the output root (default:.), -
--module <name>overrides the generated module name for a single input, -
--include-importsis accepted for explicit import-closure output; imported schema dependencies are emitted automatically so generated Silk imports resolve, -
--descriptor-out <path>writes a deterministicversion: 1JSON schema summary for tooling, including files, imports, options, messages, fields, oneofs, enums, services, RPCs, reserved declarations, map metadata, packed field status, and resolved type names, -
each file must declare
syntax = "proto3";, -
schema parsing accepts adjacent protobuf string literals in string-valued positions and supports normal imports, public import re-exports, and unused missing weak imports,
-
schema integer parsing accepts protobuf decimal, hexadecimal, octal, and signed integer literal forms where the grammar permits signed integers,
-
validation rejects cyclic imports, invalid or reversed reserved ranges, enum values outside the protobuf int32 range, labelled map fields, helper-name collisions, and unsupported
extend/extensions/groupforms, -
output paths mirror generated module names (
acme::chat::personbecomes<out-dir>/acme/chat/person.slk), -
generated modules use
std::protobuffor protobuf binary wire helpers, -
enum fields use generated raw-value wrappers so unknown proto3 enum numbers are preserved,
-
repeated scalar and enum fields encode with proto3 packed records by default unless
[packed = false]is present, while generated decoders accept both packed and unpacked wire forms, -
singular message fields and explicit
optionalfields useT?storage for proto3 presence, and singular message wire repeats merge into existing payloads, -
generated service metadata includes RPC descriptor structs and lookup helpers,
-
generated modules type-check, build as object code, and can be imported by Silk programs that construct, encode, decode, and inspect messages.
-
silk package inspect|lint [--json] [--package <dir|manifest>]: -
inspectprints package metadata, public definitions, dependency constraints, declared artifacts, the current package hash, and any installed Formal Silk bundle paths discovered undershare/silk/formal/<artifact-relative-path>/..., -
inspect --jsonemitsschemaVersion,command,mode,root,sha256, and a structuredmanifestobject with definitions, dist patterns, dependencies, artifacts, native requirements, and Formal Silk bundles, -
lintvalidates that[package].definitions,[dist], and[[artifact]]describe a coherent distributable package root, -
lint --jsonemitsok,issueCount, and anissuesarray while keeping the same exit-code behavior as human output, -
when
--packageis omitted and./silk.tomlexists, the current directory is used. -
silk cache [subcommand] [--json] [--package <dir|manifest>] [--cache-dir <path>]: -
the managed cache root is
<work_root>/cachewhere<work_root>defaults to.silkand can be overridden viaSILK_WORK_DIR, -
current recognized managed entry types include:
-
CLI build-cache artifact entries under
cache/build/<sha256-key>/, -
and
std::buildgenerated-file blobs undercache/build/<fnv1a64>.blob, -
the default
silk cacheform prints a cache-root summary (same assilk cache inspect), -
--jsonemitsschemaVersion,command,mode,cacheRoot, and subcommand-specific fields: -
path: the resolved cache root, -
list:summaryplus sortedentries, -
inspect: rootsummary/policyor a singleentry, -
prune/compact/clear:dryRun,healedEntries,removedEntries, andreclaimedBytes, -
subcommands:
-
path— print the effective cache root path, -
list— list recognized managed cache entries with type/size/health, -
inspect [<entry>]— inspect the cache root or one entry in detail, -
prune— prune recognized managed entries by the active/default age/size policy, -
compact— auto-heal recognized entries, remove stale broken managed residue, and then apply pruning policy, -
clear— remove recognized managed entries under the selected cache root, -
cleanup commands are conservative:
-
unknown/unmanaged files under the cache root are preserved,
-
and
--dry-runpreviews removals without deleting anything, -
policy defaults:
-
auto-heal enabled,
-
auto-prune enabled,
-
maximum size
2 GiB, -
maximum age
30d, -
keep at least
64recent recognized managed entries, -
policy overrides:
-
SILK_CACHE_AUTO_HEAL -
SILK_CACHE_AUTO_PRUNE -
SILK_CACHE_MAX_BYTES -
SILK_CACHE_MAX_AGE -
SILK_CACHE_KEEP_RECENT -
silk env [--json]— print key environment variables consulted by thesilkCLI (stdlib resolution, Formal Silk verification, paging, build scratch dirs, C compiler selection). -
--jsonemitsschemaVersion,command, andvars, where each entry recordsname,state(unset,empty, orset), andvalue. -
includes
SILK_GUIDE_DB, which overrides the installedshare/silk/guide.dbpath used bysilk guide. -
includes the cache-maintenance environment variables that control the managed cache policy (
SILK_CACHE_*). -
silk format [--json] [--check] <path> [<path> ...](alias:silk fmt) — format Silk source files (.slk/.silk) using project configuration from.silk/format.toml(discovered by walking upward from each formatted file’s directory). -
--jsonemitsschemaVersion,command,ok,check,status,changedCount, andchangedFiles; in--checkmode, files that would change still produce a non-zero exit code withok: false, -
recursive directory walks honor
.gitignore, including parent repository ignore files when you format a subdirectory, -
explicitly named file paths still format even when ignored, so targeted one-off formatting remains possible,
-
the formatter is intentionally readability-oriented rather than indentation-only:
-
same-line statement runs are split so each statement or block body starts on its own line,
-
semicolons nested inside paren/bracket groups stay inline instead of being treated as statement boundaries (for example
join(T; h)andfor (...; ...; ...)remain single-line unless the source already breaks them), -
newline-based
if/else ifheaders keep the opening{on its own line and indent chained condition lines one level deeper than the control keyword, -
standalone block-closing
}boundaries are given breathing room (for example anif { ... }followed by another statement becomes}\n\nnext;while} else {stays on one line), -
formatter-emitted layout preserves the file’s detected newline style (
\nvs\r\n) instead of introducing mixed line endings, -
ordinary line/block comments are preserved instead of being deleted or reflowed away during formatting,
-
named import lists with more than three imported symbols are rewritten to one symbol per line,
-
and comment-free leading import headers are canonicalized into sections:
-
std::.../ std-root imports first, -
then non-relative package/module imports,
-
then relative file imports, with alphabetical sorting inside each section.
-
the header reordering pass is conservative:
-
when the leading package/module/import region contains ordinary comments or other non-whitespace trivia, the formatter preserves that header region instead of reordering it,
-
but it still normalizes the blank-line boundary between that preserved header region and the first non-header declaration.
-
diagnostics (initial):
-
emits a single primary error diagnostic on error,
-
includes a stable error code for known error kinds,
-
includes a file/line/column location and caret snippet when available,
-
source and module read failures describe common filesystem problems in user-facing terms, such as a directory being provided where a file is expected, rather than exposing implementation error tags,
-
when stderr is a TTY, diagnostics are decorated with ANSI colors unless disabled via
NO_COLORorTERM=dumb, -
silk check --jsonemits schema-versioned JSON packets withok,diagnostics, andsummaryfields; diagnostic entries containseverity,code,message, optionalspan, optionaldetail,notes, andhelps, -
silk error <code>explains a diagnostic code after the fact, andsilk error --listlists the stable catalog, -
the diagnostic format and initial error code set are specified in diagnostics.
-
standard library import resolution (first slice):
-
when a module contains
import std::...;or a module-specifier import such asimport { println } from "std/io";, the CLI automatically loads the referencedstd::...package modules from a configured stdlib root, so downstream users do not need to pass std source files explicitly on the command line, -
when
--nostd(or-nostd) is provided, this auto-loading is disabled andstd::...imports, includingfrom "std/..."module specifiers, must be satisfied by explicitly passing source files (or the build fails), -
the stdlib root is selected via:
-
--std-root <path>(or--std <path>/-std <path>when<path>does not end in.a) when provided, otherwise -
SILK_STD_ROOT(environment variable) when set, otherwise -
a
std/directory in the current working directory (development default), otherwise -
../share/silk/stdrelative to thesilkexecutable (installed default), otherwise -
walk upward from the
silkexecutable’s directory to find astd/directory (developer build fallback). -
package-to-path mapping is deterministic:
std::foo::barresolves to the file<std_root>/foo/bar.slk. -
JS-style module specifiers that start with
std/are std package specifiers, not file imports: -
from "std/foo/bar"normalizes to packagestd::foo::bar, -
a trailing
.slkis accepted for compatibility and is stripped before package normalization, -
named imports bind against the package export surface and can participate in prebuilt std archive linking.
-
package search path import resolution (non-
std::): -
when a module imports an unquoted package path (for example
import api from my_api;), the CLI may load that package from a package search path: -
when
SILK_PACKAGE_PATHis set, it is the primary search path (PATH-like list of roots separated by:on POSIX,;on Windows), -
for package graph work, relative entries are resolved from the importing package root and then from parent package roots up to the graph root, with the historical current-working-directory fallback checked afterward,
-
when
SILK_PACKAGE_PATHis not set, the CLI uses a small default set: -
packages/relative to the importing package and each parent package root up to the graph root, -
./packagesfrom the current working directory, -
../share/silk/packagesrelative to thesilkexecutable (installed layout), -
$HOME/.local/share/silk/packageswhen it exists (user-local installs), -
finally, the CLI appends a system library root at
PREFIX/lib/silk(defaultPREFIX=/usr/local) as the last search path entry when it exists, -
package-to-path mapping is deterministic:
my_api::coreresolves to the candidate directory<root>/my_api/coreand the manifest<candidate>/silk.toml, -
qualified symbol imports resolve the longest package prefix that exists (for example
my_api::core::Thingloadsmy_api::coreif present, otherwisemy_api), -
the same search path is used when loading manifest dependencies that omit a
pathfield; in that case the dependency key, not a quotedfrompackage name, is the search candidate, and dot-separated dependency keys map to slash directories (my.dep.b-><root>/my/dep/b) (see package manifests). -
standard library archive linking (
linux/x86_64, current archive layout): -
make stdlibbuilds a target-specific static archive (libsilk_std.a) containing one ELF object per std module (repo default:build/lib/silk/std/libsilk_std.a), -
for supported
silk build --kind executablebuilds, the compiler can treat auto-loadedstd::...modules as external during code generation and resolve their exported functions from the archive when available (while still type-checking the std sources as part of the module set), -
by default this archive-linking path is only used for
-O0builds (when-Ois omitted, this is usually the case only when--debugis enabled), -
for
-O1+ builds,silk buildprefers compiling std sources into the executable so unreachable std code can be pruned, -
--std-lib/--std <path>.aforces archive linking regardless of-O, -
std modules auto-loaded via
import std::...;and package-shapedfrom "std/..."module specifiers participate in this external/archive path, -
archive discovery (in order):
-
--std-lib <path>(or--std <path>.a/-std <path>.a) when provided, otherwise -
SILK_STD_LIBwhen set, otherwise -
build/lib/silk/std/libsilk_std.awhen using the in-repostd/root, otherwise -
../lib/silk/std/libsilk_std.arelative to thesilkexecutable, otherwise -
../lib/libsilk_std.arelative to thesilkexecutable (legacy installed layout), otherwise -
common installed-layout heuristics derived from the selected stdlib root,
-
walk up from the current working directory to find
libsilk_std.a,lib/libsilk_std.a, orlib/silk/std/libsilk_std.a, -
when no suitable archive is found (or on unsupported targets), the compiler falls back to compiling the reachable std sources into the build,
-
--nostddisables stdlib auto-loading and avoids linking the default std archive (but users may still explicitly provide their ownstd::...inputs as ordinary source files), -
user-provided
package std::...;modules continue to override the default std implementation for the same package names. -
security provider selection:
-
--security-provider <auto|platform|builtin>is accepted bysilk build,silk check, andsilk test. -
Precedence is CLI flag, then
SILK_SECURITY_PROVIDER, then[build] security_provider, thenauto. -
autoselects platform-backed APIs first on Apple targets and falls back to built-in archives for std APIs that do not yet have an Apple platform mapping; it selectsbuiltinelsewhere. -
platformis valid only for Apple targets and is strict. It routes the currently supportedstd::cryptoprimitives (init,memzero,equal, andstd::crypto::random) through the Apple Security runtime helpers and linksSecurity.framework;std::netalso linksNetwork.frameworkfor Apple-provider builds while Network-backed TCP/UDP work continues. It rejectsstd::tls,std::ssh/std::ssh2, native inputs that reference libsodium or mbedTLS symbols, and advancedstd::crypto::*modules until platform mappings exist for those APIs. -
builtinuses the toolchain-built libsodium, mbedTLS, and libssh2 static archives. -
silk build [--nostd] [--std-root <path>] [--std-lib <path>] [--z3-lib <path>] [-Wz <spec> ...] [--feature <spec> ...] [-f <spec> ...] [--security-provider <auto|platform|builtin>] [--debug] [-O <0-3>] [--noheap] [--strip-unused] [--package <dir|manifest>] [--build-module] [--package-target <name> ...] <input> [<input> ...] -o <path> [--kind executable|object|static|shared] [--emit bin|asm] [-S] [--arch <arch>] [--target <triple>] [--gpu-target <gpu-triple>] [--list-targets] [--list-gpu-targets] [--list-archs] [--c-header <path>] [--cflag <arg> ...] [-I <path> ...] [-isystem <path> ...] [-L <path> ...] [-l <name> ...] [-Wl <arg> ...] [--ldflag <arg> ...] [--needed <soname> ...] [--runpath <path> ...] [--soname <soname>] [--elf-interp <path>](or--out <path>) — for now: -
silk build -hgroups the live help into: General; Stdlib and verification; Output and target selection; Link inputs and dynamic linking; Package builds; Install and uninstall. Linux ELF-only flags are shown in terminal help only on Linux compiler hosts, and Apple SDK linking flags are shown only on Apple Silicon macOS compiler hosts. The static docs below remain the full cross-target reference. -
inputs are classified by extension:
-
.slk— Silk source files (compiled as the module set), -
.o— relocatable objects linked into--kind executable|sharedoutputs (and included in--kind staticarchives), -
.a— static archives; their.omembers are treated like object inputs, -
.so— shared libraries treated as dynamic dependencies (equivalent to--needed <soname>using the library’s basename), -
.c— C sources compiled to objects via the native compiler for the active target and then treated like.oinputs, -
.m— Objective-C sources compiled to objects for the supported Apple host-backed Mach-O targets and then treated like.oinputs, -
.h— header build inputs: -
if a sibling
.cexists next to the header, Silk compiles that.cand treats the resulting object like a.oinput, -
otherwise, if a sibling
.mexists next to the header, Silk compiles that Objective-C source and treats the resulting object like a.oinput, -
otherwise Silk falls back to compiling the header itself as a C translation unit (
-x c) and then treats the resulting object like a.oinput, -
note: linking
.o/.a/.c/.hinputs is supported forlinux/x86_64outputs and formacos-aarch64plus iOS device/simulator executable/object/static/shared outputs on Apple Silicon macOS hosts, -
note: compiling Objective-C
.minputs is supported only formacos-aarch64,ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64on Apple Silicon macOS hosts; supported executable/shared outputs that include.minputs are linked against the Objective-C runtime automatically, -
note: Objective-C
.minputs that import Cocoa / AppKit or UIKit also add the corresponding Apple framework (AppKit.frameworkorUIKit.framework) to the host-backed Mach-O executable/shared link; inputs that import Foundation addFoundation.framework, -
note: native C/Objective-C inputs that import Security or Network add
Security.frameworkorNetwork.frameworkrespectively to supported host-backed Apple executable/shared links, -
note: on
macos-aarch64, reachable Silkextcalls whose symbol name starts withsilk_appkit_opt the executable link intoAppKit.framework; this supports examples and applications that ship a native AppKit.mprovider beside Silk code, -
note: when linking non-PIC object inputs that reference external data symbols directly via
R_X86_64_PC32(for examplestdout/stderrfromfprintf), the backend supports the common pointer-load pattern by emitting a writable COPY slot andR_X86_64_COPYrelocation so the dynamic loader initializes it; other external-dataR_X86_64_PC32patterns are rejected, -
--cflag <arg>may be repeated to add additional native compiler arguments when compiling.c,.m, and.hinputs, -
-I <path>/-I<path>and-isystem <path>/-isystem<path>are direct repeatable include-path forms for native.c,.h, and.mcompilation, -
when multiple input files are provided (or when imports load multiple modules), runs module-set front-end checks (package/import resolver + multi-module type checking that accounts for imported exported constants and imported
export fncalls), -
declaration-only exported function prototypes (
export fn name(...) -> T;) are accepted as module exports for type-checking, but do not emit code; calls lower as link-time symbol references that must be satisfied by other Silk sources in the module set and/or non-.slklink inputs (.o/.a/.c/.m), -
when a single input file is provided and no imports load additional modules, the compiler may run the existing single-module front-end checks (a fast path intended for constant-expression programs),
-
when no input files are provided and
--package/--pkgis omitted, but./silk.tomlexists, the compiler behaves as if--package .was provided (package builds from the current directory by default), -
on interactive TTY stderr,
silk buildrenders a single animated progress line while it walks source files, import/package traversal, dependency artifact scans, dependency native requirements, built-in external auto-link passes, and laterresolve/check/codegen/linkphases, -
this line is transient and is cleared before diagnostics or other stderr output so build errors remain readable,
-
non-interactive output (for example CI logs or piped output) stays concise and only prints the final artifact summary lines,
-
successful builds now report final artifacts in the form
build: <kind> -> <path>, -
when
--packageis provided: -
.slkinput files must be omitted (the module set is loaded from the manifest), but non-.slklink inputs (.c,.h,.m,.o,.a,.so) may still be provided, -
--build-moduleruns<package_root>/build.slkand uses the manifest it emits as the package manifest (see build scripts), -
--build-module-path <path>overrides the default build module path (and implies--build-module), -
legacy aliases:
--build-scriptand--build-script-path, -
build modules are opt-in by default; to run one without
--build-module, set[build].build_module = trueinsilk.toml(see package manifests), -
successful compilation or cache restoration of the compiler-generated build-module runner is intentionally silent; final artifact summaries describe only user-requested package targets, while runner diagnostics and build-module stderr are still emitted,
-
--package-target <name>selects one or more manifest[[target]]entries by name (repeatable;--pkg-targetis accepted as an alias), -
when omitted, the compiler builds every manifest
[[target]]entry by default, -
this includes manifest
kind = "man"targets, which emit package-owned manpages from either static sources or source-doc queries, -
source-doc man queries are evaluated against the root package’s own source modules, not dependency docs in the same manifest graph,
-
when building multiple targets (the default when
--package-targetis omitted, or when it is repeated), per-output flags are rejected:-o/--out,--kind,--emit,--arch,--target,--gpu-target,--c-header,--cflag,-I,-isystem,--ldflag,-l,-L,--framework,-F,-Wl,--needed,--runpath,--soname,--elf-interp, -
-o/--outis optional only when building a single target (defaults to the target’soutputor a computed default underbuild/), -
package dependencies are loaded from the manifest’s
[dependencies]table, and matching dependency[[native]]entries are linked when the imported dependency is present in the loaded module set, -
see package manifests,
-
silk build installinstalls package artifacts (package builds only): -
prefix selection:
-
-p <path>,--prefix <path>when provided, otherwise -
$PREFIX(environment variable) when set, otherwise -
/usr/local. -
staging:
-
--destdir <path>stages the install under<destdir><prefix>/...without changing the logical prefix recorded in the package layout. -
installs:
-
package-owned artifacts under
<prefix>/lib/silk/<package>/...(for examplelib/<target>/...orbin/<target>/...inside the package root), -
package-owned manpages under
<prefix>/lib/silk/<package>/share/man/man{1,3,7}/...and mirrored to<prefix>/share/man/man{1,3,7}/..., -
emitted C headers inside the package root and mirrored to
<prefix>/include/silk/<package>/for compatibility, -
executables inside the package root and mirrored to
<prefix>/binfor compatibility, -
and, when
[package].definitionsis set, installs those definition files plus an installedsilk.tomlunder<prefix>/lib/silk/<package>/so the package is importable from the system package search root (PREFIX/lib/silk). -
when a built artifact exposes exported Formal Silk surface, the install also copies the compiler-emitted Formal Silk bundle into
<prefix>/lib/silk/<package>/share/silk/formal/<artifact-relative-path>/asmanifest.jsonplusbundle.smt2, -
when local
[package].readme/[package].documentationlanding pages are present, the install copies them into<prefix>/lib/silk/<package>/share/silk/docs/readme/...or<prefix>/lib/silk/<package>/share/silk/docs/documentation/...and rewrites the installedsilk.tomlto those packaged paths, -
when
[package].documentationpoints at a static man target source, the installedsilk.tomlrewrites it to the installedshare/man/...path so package docs aliases continue to resolve after install, without also installing a redundantshare/silk/docs/documentation/...copy. -
note: installing library targets requires
[package].definitionsto be set and non-empty; executable-only and manpage-only packages do not. -
writes an uninstall receipt at
<prefix>/lib/silk/<package>/.silk_install_receipt. -
silk build uninstallremoves files listed in the uninstall receipt (same prefix selection rules as install). -
when
-o/--outor--c-headerincludes parent directories that do not exist yet, the compiler creates them (likemkdir -p), -
multi-file builds are supported for
--kind executableand for--kind object,--kind static, and--kind shared: -
when multiple packages are present in a module set for a non-executable output, only exports from the root package (the package of the first input module) are emitted as globally-visible symbols; other packages are compiled as dependencies and their
exportdeclarations are treated as internal for that output, -
for
--kind executable: -
when the module set defines a valid Silk entrypoint, enforces the executable entrypoint rule (exactly one
mainof eitherfn main() -> int,fn main() -> void,async fn main() -> int,async fn main() -> void,fn main(argc: int, argv: u64) -> int, orfn main(argc: int, argv: u64) -> void), -
script-style entrypoints: when the first
.slkinput contains top-level statements (after the normalpackage/moduleheader andimportblock) and does not define an explicitmain,silk buildtreats those statements as a script body and synthesizes an implicitfn main() -> voidthat executes them, -
when the module set defines no valid Silk
main, requires an object/archive-providedmain(argc: int, argv: u64) -> intsymbol (for example from a.c/.m/.o/.ainput) and emits an entry stub that forwardsargc/argvto it, -
note: for now,
--std-lib/--std <path>.ais rejected when linking additional.c/.h/.m/.o/.ainputs into an executable (std sources are compiled into the build instead), -
for
linux/x86_64native executables, when theargc/argvform is used, the entry stub passes: -
argc: the process argument count, and -
argv: a raw pointer to the argv pointer list (a C-stylechar**, whereargv[0]is at byte offset0,argv[1]at8, etc.), -
other targets and backends may continue to require the parameterless
fn main() -> intorfn main() -> voidforms until they implement argument passing, -
for
--kind object,--kind static, and--kind shared,mainis optional; the current backend emits supportedexport fnfunctions and supported exported constants (export let/export const; scalar exports require an explicit type annotation, and string exports may omit: stringwhen the initializer is a string literal), plus a valid executablemainwhen present, as globally-visible symbols, -
it is valid for a non-executable output to contain no globally-visible symbols (for example, type-only or interface-only modules); in that case the build still succeeds and produces an “empty” object/archive/shared library,
-
--debug(or-g) enables a debug build mode for the supportedlinux/x86_64back-end subset: -
failed
assertprints a panic header + optional message + stack trace to stderr (via glibcbacktrace_symbols_fd) before aborting, and -
dynamically-linked executables export internal function symbols in
.dynsym(similar to-rdynamic) so stack traces can be symbolized without external tooling, -
when Formal Silk verification fails,
--debugalso emits a Z3 debug block and writes an SMT-LIB2 reproduction script under.silk/z3/(or$SILK_WORK_DIR/z3; see formal verification), -
compiled code can query build metadata at runtime via
std::runtime::build::{is_debug,kind,mode,version}(), -
--noheapdisables heap allocation for the current compiler/runtime subset: -
heap-backed
new(outside awithregion) is rejected withE2027, -
extbindings to libc heap primitives (malloc/calloc/realloc/free/etc) are rejected withE2027in non-stdlib modules, -
std::runtime::mem::{alloc,realloc,free}traps when called without an activewithregion (no implicit heap fallback), -
non-stdlib concurrency usage that declares or forms
Task(...)/Promise(...)handles is rejected withE2027(async fn,task fn,async {},task {},async loop,task loop,await,yield, and calls or type positions that produce awaitable handles), -
imported stdlib async/task declarations alone do not trigger
E2027; the error is raised only once user code uses those awaitable surfaces under--noheap, -
capturing closures are rejected with
E2027, -
region-backed
newinsidewithis still permitted, -
--noheapis currently incompatible with--debug(debug panic traces requiremalloc/free), -
by default, builds an executable (
--kind executable), -
when
--kind object,--kind static, or--kind sharedis provided: -
on
linux/x86_64, attempts to emit an ELF64 relocatable object, static library, or shared library (.so) for the same supported IR subset, -
on Apple Silicon macOS hosts,
--target macos-aarch64,--target ios-aarch64,--target ios-simulator-aarch64, and--target ios-simulator-x86_64attempt to emit Mach-O 64-bit relocatable objects, static library archives (.avia Applelibtool -static), and shared libraries (.dylibvia the Apple linker) for the same supported IR subset, -
and otherwise exits non-zero with
E4001(unsupported construct) orE4002(backend failure) diagnostics that explain the exact limitation, -
when lowering cannot isolate a narrower statement / expression span,
E4001falls back to the offending function declaration and names that function directly, -
attempts to emit an executable using:
-
for
--target linux-x86_64(the default; also accepts commonx86_64-*-linux-gnutriples), an IR→ELF backend forlinux-x86_64outputs (host-agnostic) for a growing scalar subset, and a constant‑expression backend (with a tiny ELF64 stub) for purely constantmainbodies, -
for
--target linux-x86_64-musl(also accepts commonx86_64-*-linux-musltriples), the same x86_64 IR→ELF backend with musl defaults (PT_INTERP/lib/ld-musl-x86_64.so.1, default hosted libc dependencylibc.so, and libc-aware package artifact selection), -
for
--target linux-aarch64,--target linux-aarch64-musl, and--target android-aarch64, a constant‑expression backend (with a tiny ELF64 stub) for purely constantmainbodies (non-constant programs are rejected withE4001), -
for Apple targets, a constant‑expression backend that emits a minimal Mach-O 64-bit
exit(code)executable: -
macos-x86_64 -
macos-aarch64 -
ios-aarch64(iPhoneOS / device) -
ios-simulator-aarch64 -
ios-simulator-x86_64 -
when the build host is macOS and the output target is
macos-x86_64ormacos-aarch64,silk buildalso performs an ad hoccodesign -s -pass on the emitted executable so the result is directly runnable on macOS hosts, including Apple Silicon -
macos-aarch64const-main executables are emitted by the Silk-owned Mach-O backend; the host signing step remains in place so the produced binary is runnable immediately on macOS hosts -
on Apple Silicon macOS hosts, the temporary host-backed Mach-O non-const executable bring-up path now uses host
clang -c/ldfor: -
macos-aarch64, -
ios-aarch64, -
ios-simulator-aarch64, -
and
ios-simulator-x86_64, -
for
macos-aarch64, that path also links bundled runtime-backed executables by expandinglibsilk_rt*.ainto object members for the host linker, -
for
macos-aarch64,ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64,--kind object|static|sharedcan emit Mach-O library artifacts for the supported IR subset, -
for
ios-aarch64,ios-simulator-aarch64, andios-simulator-x86_64, the supported subset is intentionally narrower thanmacos-aarch64, but now includes: -
pure-Silk scalar executables,
-
reachable float-to-int lowering via target-correct helper objects compiled from
src/silk_rt_f128.c, -
and portable bundled runtime helpers compiled on demand for the requested iOS SDK target, including the public number / regex / unicode / filesystem / dns / process / signal / term / pty / readline / task-pool / async helper families,
-
mixed
.slk+ native.c/.h/.m/.o/.aexecutable/static/shared link-input support, -
and native-input-only executables whose
mainis provided by linked objects or archives, -
when a reachable iOS executable module graph includes
std::window,silk buildalso materializes an adjacent<output>.appbundle containing the executable,Info.plist, andPkgInfo; importing/reachingstd::windowis the opt-in signal and no additional CLI flag is required, -
and the same host-supported subset is reflected in target metadata / diagnostics instead of being reported as uniformly const-main-only
-
outside that Apple Silicon host-only subset, non-constant Apple-target programs are still rejected with
E4001 -
on Apple Silicon macOS hosts,
macos-aarch64and the three iOS device/simulator targets now have current-host artifact-kind parity withlinux-x86_64for executable, object, static library, and shared library outputs; this is still host-backed and not yet the portable baseline for every compiler host. -
for Windows targets, a constant‑expression backend that emits a minimal PE32+
ExitProcess(code)executable (non-constant programs are rejected withE4001): -
windows-x86_64 -
windows-aarch64 -
for
--target wasm32-unknown-unknown: -
an IR→WASM backend for the supported subset (multi-module builds, control flow, string/data segments, and
extimports), -
exports
memoryplusmainwhen present (embedder entry), or emits an export-only module (nomain) that exports supportedexport fndeclarations from the root package, -
note: Silk
intcurrently lowers to wasmi64, so wasm exports usingintsurface asi64, -
for
--target wasm32-wasi: -
an IR→WASM backend that emits
memoryplus_start () -> void, importswasi_snapshot_preview1.proc_exit, and calls Silkfn main () -> intorfn main () -> void(themain(argc, argv)entrypoint form is not supported yet for WASI), -
programs that need argv on
wasm32-wasishould read it insidemain()viastd::args::{argc,argv,current}and then build the usualstd::args::Argsview, -
also supports export-only modules for embedding (export-only modules do not include
_start), -
for both wasm targets, a smaller constant-only wasm backend remains as a fallback for programs that fit the constant subset,
-
amdgcn-amd-amdhsa-gfx942,amdgcn-amd-amdhsa-gfx1100, andamdgcn-amd-amdhsa-gfx1151are recognized for target metadata and the standalone AMDHSA code-object/AQL encoder (src/backend_amdgpu.zig);silk build --kind object --target amdgcn-*emits a.hsacofor exactly one exported root-package void source kernel with up to 32 immutableu64parameters whose body is empty or contains only supported compiler-backed GPU call statements. Dependency-package exports do not count as additional kernels. The copy-pasteable intrinsic declarations and current authoring diagnostics are documented in backend amdgpu. The AMDHSA code-object metadata spellings with an empty environment field (amdgcn-amd-amdhsa--gfx942/amdgcn-amd-amdhsa--gfx1100/amdgcn-amd-amdhsa--gfx1151) are accepted as aliases, -
other targets are not implemented yet (see backend wasm),
-
the constant subset (available on
linux-x86_64,linux-x86_64-musl,linux-aarch64,linux-aarch64-musl,android-aarch64,macos-x86_64,macos-aarch64,ios-aarch64,ios-simulator-aarch64,ios-simulator-x86_64,windows-x86_64,windows-aarch64, and the initialwasm32targets) consists of: -
a single
fn main() -> intwhose body is: -
zero or more
letstatements with constant integer initializers, followed by exactly onereturnof a constant integer expression, or -
the same, with a final
ifwhose condition is a compile‑time boolean literal (true/false) and whose branches each satisfy the “constant lets + return constant expression” rule, and -
optionally, one or more trivial constant
whileloops before the finalreturn, with constant boolean conditions and bodies of constantletbindings followed bybreak;, as described in ir overview, -
or a
fn main() -> voidbody in the same supported statement subset, withreturn;or implicit fallthrough producing exit status0, -
on
linux/x86_64, a richer IR‑based backend is used first; for this backend, the currently supported (documented and tested) subset includes: -
fn main() -> int,fn main() -> void, and helper functions that: -
take scalar parameters (defaulting to
intwhen unannotated) drawn fromint,bool,char,f32,f64,Instant,Duration, and the fixed-width integer types (u8/i8…u64/i64); helper functions return a scalar from the same set, orvoid(omitted result type or explicit-> void) when used only as standalone statements (return;and implicit fallthrough returns are supported forvoidhelpers), -
helpers may also accept and return
stringvalues at ABI boundaries (represented as{ ptr: u64, len: i64 }/SilkString; results return viarax/rdx), -
use integer arithmetic (
+,-,*,/,%, including unary-x), bitwise operators (&,|,^,~,<<,>>), integer comparisons (==,!=,<,<=,>,>=), and floating-point arithmetic/comparisons (+,-,*,/,==,!=,<,<=,>,>=, including unary-x) overf32/f64, -
use
charliterals (UTF-8 or escaped) and==/!=comparisons overcharvalues (lowered asu32scalars in IR), -
use
boolas a distinct surface type, with booleans represented as integer values at the IR level, -
use
if/elseandwhilewith conditions drawn from: -
boolean literals,
-
comparisons over integer and floating-point expressions, and
==/!=over boolean expressions, -
calls to
bool-returning helpers of this subset, -
logical operators
!,&&, and||composed over those expressions (&&/||are short‑circuiting), -
and boolean locals (
let flag: bool = <bool expr>; if flag { ... }), -
in addition to conditions, boolean value positions (for example
let flag: bool = a && b;andreturn a || b;inbool-returning helpers) support the same boolean expression subset and preserve short-circuit evaluation, -
use
ifas an expression (let x: T = if cond { a } else { b };) when both branches produce the same supported value typeT(scalars,string, unit-only enums, and supported optionals), -
use
break;andcontinue;insidewhileloops, -
allow call expressions as standalone statements (discarding the returned value),
-
allow assignment and compound assignment to
let mutlocals by name (x = expr;,x += y;); the left-hand side must be an identifier;=is supported for all currently supported value types (includingstring, the supportedstructsubset, and optionals of those); compound assignments are supported only for numeric scalar locals, -
and, for helpers, use direct calls between functions of this shape; scalar parameters follow the System V AMD64 calling convention as documented in ir overview:
-
integer-like scalars (
booland integers) use up to 6 general-purpose registers (rdi,rsi,rdx,rcx,r8,r9), -
f32/f64use up to 8 XMM registers (xmm0..xmm7), -
remaining scalar arguments are spilled to the stack in order,
-
the caller maintains 16-byte stack alignment before
call(padding by one 8-byte slot when needed), and -
results return in registers for 0–2 scalar results (integer-like in
rax/rdx, floats inxmm0/xmm1), and 3+ scalar results return indirectly via a hidden sret pointer passed inrdi(caller-allocated return buffer), -
on
linux/x86_64, the same backend also supports a limitedstringsubset: -
within function bodies, the compiler supports a small
stringexpression subset: string literals,letbindings ofstring,returnof astringvalue,ifexpressions that producestringvalues, direct calls tostring-returning helpers, and==/!=/</<=/>/>=comparisons overstringvalues (producingbool); other string operations (concatenation, indexing, etc.) are not implemented yet, -
string literals are embedded as rodata byte blobs and
.text→rodata fixups are emitted/handled appropriately for each output kind (ELF relocations for object/static outputs; direct RIP-relative displacement patching for shared libraries and executables once the final.text/rodata layout is known), -
for non-executable outputs, exported
stringconstants (export let/export constwith a string literal initializer;: stringis optional) are emitted asSilkStringdata symbols for downstream C consumers, and exported functions of this subset may accept and returnstringvalues using the same{ ptr: u64, len: i64 }ABI. -
on
linux/x86_64, the current backend also supports a limitedstructsubset: -
structdeclarations with 0+ fields of supported value types: -
scalar primitives (
int/fixed-width ints,bool,char,f32,f64,Instant,Duration), -
string(lowered as{ ptr: u64, len: i64 }), -
nested (non-opaque) structs,
-
and optionals (
T?) of supported payload types, -
struct literals (
Type{ field: expr, ... }) and field access (value.field) for those structs; in Silk, struct literals may omit fields and omitted fields are zero-initialized, -
==/!=comparisons over values of those structs (deep/slot-wise equality, including embedded strings, nested structs, and optionals) producingbool, -
passing and returning such structs by value in helper calls by lowering them to their scalar slots in order (“slot flattening”) and using the same System V AMD64 calling convention as scalar arguments/results,
-
at ABI boundaries for exported/FFI functions, structs must be ABI-safe: after slot flattening, all slots must be
i64/u64/f64(for examplestringfields are ABI-safe, butbool,char, andf32fields are not). -
on
linux/x86_64, the current backend also supports a limited optional subset: -
optionals of scalar payload types (
T?whereTisbool,char,f32,f64,int,Instant,Duration, or a fixed-width integer), -
optionals of
stringpayload type (string?), and optionals of the supportedstructsubset (Type?whereTypeis a supported 0+ fieldstruct), -
optionals of unit-only enum payload types (
E?whereEis anenumwith no payload fields), -
nested optionals (
T??) for these payload types, -
constructing optionals via
NoneandSome(<expr>)for those payload types, -
==/!=comparisons over those optionals (tag + payload equality; nested optionals compare recursively);None/Some(...)can be used directly in equality expressions when the other operand provides the optional type context (for exampleopt == Noneandopt == Some(x)), -
accessing fields of optional structs via optional field access (
opt?.field), producing an optional result of the field type (FieldType?), -
calling methods on optional structs via optional chaining (
opt?.method(args...)), producing an optional result of the method result type (ResultType?) and short-circuiting when the receiver isNone, -
matching on optionals via
match <scrutinee> { None => <expr>, Some(<name|_>) => <expr>, }(exactly oneNonearm and oneSome(...)arm; arm bodies are expressions), -
unwrapping optionals via
??with short-circuit evaluation of the fallback expression (including unwrappingT??toT?), -
using the same
??operator on: -
recoverable
Result-style enums, -
and ordinary named enums with exactly two declared variants, where declaration order defines the coalescing shape:
-
if the first variant is unit,
value ?? fallbackyields that enum value, -
if the first variant carries exactly one payload, it yields that payload,
-
and if the value is the second variant, the fallback expression is evaluated,
-
and permitting the narrow terminal control-flow forms on the right-hand side of
??: -
value ?? return expr, -
value ?? break, -
value ?? continue, with the same validity rules as the statement forms, -
and passing/returning optionals between helpers at ABI boundaries as
(bool tag, payload0, payload1, ...), where the payload slots follow the lowering of the underlying non-optional type (for examplestring?is(bool, u64 ptr, i64 len)). -
for non-executable outputs, exported functions may accept and return these optionals; see abi libsilk for the exact C ABI mapping.
-
on
linux/x86_64, the current backend also supports a limited external call subset: -
top-level
extdeclarations of external functions (ext name = fn (T, ...) -> R;) may be called like normal functions from Silk code, -
these calls are supported for all output kinds:
-
--kind objectand--kind staticemit relocations against undefined external symbols for downstream linkers, and -
--kind sharedemits dynamic imports and calls through the shared object’s GOT (symbols must be available at runtime), -
--kind executableemits a dynamically-linked ELF64 executable and calls through the executable’s GOT (symbols must be available at runtime), -
top-level
extdeclarations of external scalar variables (ext name = T;) may be read like normal values from Silk code: -
--kind objectand--kind staticemit relocations against undefined external data symbols, and -
--kind sharedemits dynamic imports and loads through the shared object’s GOT (symbols must be available at runtime), -
--kind executableemits a dynamically-linked ELF64 executable and loads through the executable’s GOT (symbols must be available at runtime), -
writing to
extvariables is not supported, -
for executables and shared libraries,
silk buildsupports declaring dynamic loader dependencies via--needed <soname>(repeatable), which are emitted asDT_NEEDEDentries, -
runtime search paths for those dependencies can be provided via
--runpath <path>(repeatable), which is emitted as a singleDT_RUNPATHentry (joined with ':'), and -
for shared library outputs, the library soname can be set via
--soname <soname>(emitted asDT_SONAME), -
on
linux/x86_64with the glibc dynamic loader (ld-linux), when an executable or shared library imports any external symbols,silkautomatically addslibc.so.6as aDT_NEEDEDdependency (so hostedstd::modules do not require--needed libc.so.6), -
on
linux/x86_64with the musl dynamic loader (ld-musl), the same hosted external-symbol path automatically adds musl's unifiedlibc.sodependency;-lm,-lpthread,-ldl,-lrt,-lutil,-lresolv,-lcrypt, and-lxnetalso map tolibc.sowhen no matching-Llibrary is found, -
on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::cryptoand/orstd::tlsare imported, or when linked native.c/.h/.m/.o/.ainputs reference common libsodium / mbedTLS symbol families,silkauto-links the target-matched built-in static archives (libsodium.aand the mbedTLS archives) fromvendor/lib/<target-layout>/(or an installed prefix) so executables do not depend on systemlibsodium/mbedTLSshared libraries at runtime, -
on
linux/x86_64glibc or musl, whenstd::sqliteis imported, or when linked native.c/.h/.m/.o/.ainputs referencesqlite3_*symbols,silkauto-links the target-matched built-inlibsqlite3.aarchive so executables do not depend on a system SQLite shared library at runtime, -
on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::sshorstd::ssh2is imported, or when linked native.c/.h/.m/.o/.ainputs referencelibssh2_*symbols,silkauto-links the target-matched built-inlibssh2.aarchive (and its built-in crypto dependencies) so executables do not depend on a systemlibssh2shared library at runtime, -
on
linux/x86_64glibc, whenstd::runtime::z3is imported or linked native inputs referenceZ3_*symbols,silkauto-links the built-in glibclibz3.a; onlinux/x86_64musl the same use is accepted only when the build explicitly supplies a musl-builtlibz3.ainput or alibz3dynamic dependency such as--needed libz3.so.0, -
on
linux/x86_64, whenstd::dyliborstd::gpuis imported, or when linked native.o/.ainputs reference bundledsilk_rt_dylib_*/silk_rt_gpu_*runtime symbols,silkautomatically adds the libc component that providesdlopen(libdl.so.2on glibc,libc.soon musl), -
on Linux x86_64 executable builds,
--gpu-target <gpu-target>compiles root-packageattr(device=gpu)functions into AMDHSA code objects or NVIDIA PTX and embeds them in a provider-tagged bundle.std::gpudynamically loads HIP or the CUDA Driver API, so the application has no link-time GPU-provider dependency, -
on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::ggmlis imported (or when linked.o/.ainputs referencesilk_ggml_init) and the built-in ggml static archives are present,silklinks them automatically; on Linux it also addslibstdc++.so.6,libgcc_s.so.1, and the target libc math/dynamic-loader providers, while on Apple Silicon macOS hosts it adds-lc++to the native link (see ggml and builtin deps), -
on
linux/x86_64glibc or musl, whenstd::image::png/std::image::jpegare imported (or when linked.o/.ainputs reference the shim symbols) and the built-in archives are present,silklinks them automatically and addslibz.so.1and/or the target libc math provider asDT_NEEDEDdependencies (see image and builtin deps), -
on
linux/x86_64glibc or musl, whenstd::xmlis imported (or when linked.o/.ainputs referencesilk_xml_node_name_ptr) and the built-in libxml2 archives are present,silklinks them automatically and adds the target libc math provider as aDT_NEEDEDdependency (see xml and builtin deps), -
on
linux/x86_64, whenstd::windowis imported and reaches the bundled runtime,silklinks the bundled runtime archive and adds the dynamic-loader API provider used by the runtime-loaded GTK provider (libdl.so.2on glibc targets,libc.soon musl targets); GTK itself is loaded at runtime, so GTK libraries are not recorded asDT_NEEDEDdependencies, -
when the active security provider is
autoon Apple targets, platform-backedstd::cryptocore/random helpers useSecurity.framework, and fallback-only TLS/SSH/advanced-crypto APIs auto-link the built-in archives, -
when the active security provider is
builtin, the crypto/TLS/SSH fallback paths above use the same target-matched built-in archive directories (vendor/lib/<target-layout>/or an installed prefix), -
when bundled runtime support symbols are imported (for example via
import std::regex;,import std::unicode;, orimport std::number;),silkstatically links the bundled runtime support archive into the output (libsilk_rt.a, orlibsilk_rt_noheap.awhen building with--noheap); the produced executable/shared library does not depend onlibsilk_rt*.soat runtime, -
additional non-libc dependencies still must be declared via
--needed <soname>(or otherwise be available in the process global scope at load time, for example viaLD_PRELOAD), -
bundled runtime archive discovery:
-
the compiler locates
libsilk_rt.a/libsilk_rt_noheap.avia (in order): -
SILK_RT_LIBDIR(environment variable; a directory containing the runtime archives), -
build/libin the current working directory (repo default), -
zig-out/libin the current working directory (legacy zig build layout), -
../librelative to thesilkexecutable (installed default). -
fn main()itself may be: -
a single function with structured control flow as above, or
-
a small program that calls one or more helpers (with the same scalar subset), all lowered into IR and compiled together into a single executable,
-
when multiple input files are provided, this executable build path operates on the entire module set and supports:
-
same-package helper calls across modules (functions in one module calling functions defined in another module of the same package), and
-
imported exported calls (
export fn) across packages for the current scalar subset (bothfoo()andpkg::foo()call forms are accepted initially afterimport pkg;), -
examples that are known to be supported and tested include:
-
straight‑line integer programs such as
fn main() -> int { return 1 + 2 * 3; }, -
programs with local and top‑level integer
letbindings used in the finalreturn, -
programs that branch on comparison conditions at runtime, for example:
```silk fn main () -> int { if 1 < 2 { return 10; } else { return 20; } } ``` -
small loops expressed in terms of
whileandbreak;/continue;, -
helper‑call programs such as:
```silk fn helper (x, y) -> int { if x < y { let one: int = 1; return x + one; } else { let two: int = 2; return y + two; } } fn main () -> int { return helper(1, 3); } ``` -
helpers that take many integer parameters (exercising both register and stack‑passed arguments) and are called from
main, -
programs that use boolean locals and conditions, for example:
```silk fn main () -> int { let x: int = 1; let y: int = 2; let flag: bool = x < y; if flag { return 3; } else { return 4; } } ``` -
value-producing
ifexpressions whose branch bodies are single expressions (Supported forms restriction), including optionals: -
tests/silk/pass_if_expr_optional_call.slk(let m: i64? = if flag { f() } else { g() };) -
and small helper programs with boolean locals and
if/else, such as:```silk fn helper (x) -> int { let flag: bool = x < 0; if flag { return 1; } else { return 2; } } fn main () -> int { return helper(1); } ``` -
for programs that type‑check but fall outside both the constant subset and the current IR‑based backend subset,
silk buildexits non‑zero withE4001diagnostics that point at the rejected construct (orE4002when the backend fails unexpectedly).
High-Level Command Model#
The initial CLI implementation supports a small, well-defined subset of the eventual UX.
Top-level commands:
silk help [<command>]:- Prints global usage when
<command>is omitted. - Prints command-specific usage when
<command>is provided. - Subcommands also accept
--help/-hto print command-specific usage. - For
check/test/build/doc,--ends option parsing (all remaining args are treated as file paths, even if they begin with-). silk devices list|doctor|setup|install|uninstall|boot|shutdown|launch|run|logs— manage platform device and app lifecycle plumbing:- supported backend kinds are
desktop,ios-simulator,ios-device, andandroid, - backend availability is detected from the current host and installed SDK
tools:
xcrun simctlfor iOS simulators,xcrun devicectlfor iPhone/iPad devices,adb/emulatorfor Android devices and emulators, and host tools for desktop launch/log actions, listanddoctorare discovery commands and support--json; JSON output includes host metadata, normalized device records, backend records, tool paths when found, setup hints when tools are missing, and raw platform listing output forlist,- app lifecycle actions accept
--device,--booted,--name,--app,--bundle-id,--package, and--activityas applicable, launch/run --app <path>launches desktop executables directly, launches macOS.appbundles directly when--kind desktopis selected, and derives Apple bundle identifiers from iOS.appbundleInfo.plistfiles;.apppaths inferios-simulatorby default, while.ipaarchives and Android.apklaunches require explicit--bundle-idor--packagevalues,- Android install delegates to
adb installfor APK inputs; Android App Bundles (.aab) are rejected until a bundletool-backed install path exists, --passes remaining arguments to the platform tool after Silk has chosen the backend and assembled the canonical command shape.silk codesign doctor|list-tools|setup-keystore|sign|verify— manage platform signing and verification:- discovery commands report availability of
codesign,xcrun,apksigner,jarsigner,keytool,dpkg-sig,rpmsign,rpmkeys,appimagetool, andgpg, signandverifyaccept--input <path>and--platform <auto|macos|ios|android|linux>;autoinfers Android from.apk/.aab, Linux from.deb/.rpm/.AppImage, iOS from.ipa, and Apple signing for.app/.dylib/.frameworkon macOS hosts,- Apple signing uses
codesign --force --sign <identity>with ad-hoc-as the default identity, - Android
.apksigning usesapksignerby default; Android.aabsigning usesjarsignerby default.--tool apksignerand--tool jarsignerselect either Android backend explicitly.setup-keystoreuseskeytoolto create Java keystores, - Linux signing selects the package/app tool appropriate for the input, and
generic detached signatures use
gpg, --tooloverrides Android or Linux tool selection and--passes remaining flags to the chosen signing tool.silk check [--json] [--verify|--no-verify] [--nostd] [--std-root <path>] [--z3-lib <path>] [--debug] [--feature <spec> ...] [--arch <arch>] [--target <triple>] [--security-provider <auto|platform|builtin>] [--package <dir|manifest>] <file> [<file> ...]:- Reads one or more input files, runs lexing, parsing, package/import resolution, and type checking.
- Formal Silk verification is opt-in:
--verifyenables verification for modules that contain Formal Silk directives.--no-verifydisables verification (default).--z3-liband--debugare meaningful only when--verifyis enabled.--arch <arch>and--target <triple>are mutually exclusive; omit both to use the default target (linux-x86_64).- The selected target controls
OS_PLATFORM/OS_ARCHandattr(...)conditional compilation during checking. --feature <spec>(repeatable) enables build features forattr(feature="...")queries and declaration gating.- Feature specs are of the form
NAMEorNAME=VALUE(see attributes). - Feature names start with a letter or
_and may contain letters, digits,_, and-. - For package builds (
--package), you may target a specific package withPKG/NAMEorPKG/NAME=VALUE(for exampleui/tui). - When
--packageis provided, input files must be omitted and the module set is loaded from the package manifest (see package manifests). - when the root manifest enables a build module via
[build].build_module = true,silk check --packageruns that build module and uses the emitted manifest/module set instead of the rawsilk.toml, - for compatibility, package checks currently invoke the build module with the action string
build, - When
<file> ...inputs are omitted and--package/--pkgis also omitted, but./silk.tomlexists,silk checkbehaves as if--package .was provided. - Prints a success message on stdout for valid programs.
- Prints a human-readable error on stderr and exits non-zero for invalid programs.
silk test [--nostd] [--std-root <path>] [--std-lib <path>] [--z3-lib <path>] [--debug] [--feature <spec> ...] [--security-provider <auto|platform|builtin>] [-O <0-3>] [--noheap] [--jobs <n>] [--filter <pattern>] [--package <dir|manifest>] <file> [<file> ...]:- Discovers language-level
testdeclarations (see testing) in the loaded module set. - Compiles and runs each test, emitting TAP version 13 output.
- Each test runs in its own process, so a failing
assert(panic/abort) does not stop the whole suite. - Top-level test bodies that contain
awaitare run through async test wrappers and awaited by the generated runner. - Test executables use the native host target when Silk has a host-backed executable backend for it, and otherwise fall back to
linux-x86_64(orlinux-x86_64-muslon musl x86_64 Linux hosts). Formal Silk target metadata insilk testreflects that selected execution target. - Optimization:
-O <0-3>selects the optimization level (default:-O2; when--debugis set and-Ois omitted, defaults to-O0).-O1+ prunes unused extern symbols before code generation (typically reducing output size and stdlib linkage).- IR-backed native executable builds lower and emit only functions reachable
from the executable entrypoint at every optimization level.
-O1+ also prunes unused extern symbols before code generation. - When
--filter <pattern>is provided, only tests whose test path contains<pattern>are executed. The test path is the nested test name stack joined with/(for examplesuite/case). - When nested tests are present, the runner prints subtest progress lines to stderr as they complete (in
--jobs 1mode): ok - suite/casenot ok - suite/case- When
--jobsis greater than1, child stderr is captured (not streamed) to avoid interleaving output across tests. - Environment:
SILK_TEST_TIMEOUT_MSoverrides the per-top-level-test process timeout in milliseconds (default:30000).SILK_TEST_JOBSoverrides the number of test processes run in parallel (default:1;0means auto; capped at8). Overridden by--jobs.SILK_TEST_MAX_OUTPUT_BYTEScaps captured stdout/stderr per test process for diagnostics (default:1048576; output beyond this limit is truncated).- When
<file> ...inputs are omitted and--packageis also omitted, but./silk.tomlexists,silk testbehaves as if--package .was provided. - When
--packageis provided and the root manifest enables a build module via[build].build_module = true,silk test --packageruns that build module and uses the emitted manifest for the test harness/module set. - for compatibility, package tests currently invoke the build module with the action string
build. - Manifest-native test-harness metadata comes from the selected code target:
.c,.h, and supported.mentries in[[target]].inputsare compiled to temporary objects and linked with the generated test harness, using that target’scflags,- matching package and dependency
[[native]]entries are also compiled and linked when their target gate matches the test execution target, .o,.a, shared-library inputs,needed,runpath, and supportedldflagsare linked as they are for package builds.silk build [--nostd] [--std-root <path>] [--std-lib <path>] [--z3-lib <path>] [-Wz <spec> ...] [--debug] [--feature <spec> ...] [-f <spec> ...] [--security-provider <auto|platform|builtin>] [-O <0-3>] [--noheap] [--strip-unused] [--package <dir|manifest>] [--build-module] [--package-target <name> ...] <file> [<file> ...] -o <path> [--kind executable|object|static|shared] [--emit bin|asm] [--arch <arch>] [--target <triple>] [--gpu-target <gpu-triple>] [--list-gpu-targets] [--c-header <path>] [--cflag <arg> ...] [-I <path> ...] [-isystem <path> ...] [-L <path> ...] [-l <name> ...] [-Wl <arg> ...] [--ldflag <arg> ...] [--needed <soname> ...] [--runpath <path> ...] [--soname <soname>] [--elf-interp <path>](or--out <path>):- Reads one or more input files, runs the same front-end pipeline as
check. --feature <spec>and-f <spec>are repeatable build-feature specs forattr(feature="...")queries;-Fis reserved for Apple framework search paths insilk build. Feature names start with a letter or_and may contain letters, digits,_, and-.- Optimization:
-O <0-3>selects the optimization level (default:-O2; when--debugis set and-Ois omitted, defaults to-O0).-O1+ prunes unused extern symbols before code generation.- For
--kind executablebuilds, only functions reachable from the executable entrypoint are lowered and emitted at every optimization level.-O1+ additionally prunes unused extern symbols. --strip-unusedforces reachability-based pruning even at-O0:- for
--kind executable, it prunes unused extern symbols at-O0; unreachable functions are already excluded at every optimization level, - for
--kind staticand--kind shared, it prunes unreachable non-exported helper functions from the root exported surface before emission, - for
--kind object, unreachable non-exported helper functions are already pruned; the flag is accepted for consistency, - when executable builds auto-load std modules,
--strip-unusedis incompatible with--std-lib/--std <path>.abecause whole-archive std linking defeats fine-grained std reachability pruning. - When
--packageis provided: - explicit
.slkinputs must be omitted (the module set is loaded from the package manifest), - native build inputs (
.c,.h,.m,.o,.a,.so) may still be provided: - per-target via
[[target]].inputsinsilk.toml, - package-wide via target-gated
[[native]]entries in the root package and imported dependencies, - and, when building a single target, on the command line (merged with the manifest inputs),
.hfollows the same safer rule as direct CLI builds:- sibling
.cwins when present, - sibling
.mis used when no sibling.cexists, - otherwise the header itself is compiled as a C translation unit,
--build-moduleruns<package_root>/build.slkand uses the manifest it emits as the package manifest (see build scripts),--build-module-path <path>overrides the default build module path (and implies--build-module),- legacy aliases:
--build-scriptand--build-script-path, - build modules are opt-in by default; to run one without
--build-module, set[build].build_module = trueinsilk.toml(see package manifests), --package-target <name>selects one or more manifest[[target]]entries by name (repeatable;--pkg-targetis accepted as an alias),- when omitted, the compiler builds every manifest
[[target]]entry by default, - source-doc
kind = "man"targets query only the root package’s own source modules, - executable iOS targets may set
ios_app_bundle = truein the manifest sosilk build --packagealso creates<output>.app, copies the executable and either the targetios_info_plistor a generatedInfo.plist, writesPkgInfo, and ad-hoc signs the bundle by default on macOS, - when building multiple targets (the default when
--package-targetis omitted, or when it is repeated), per-output flags are rejected:-o/--out,--kind,--emit,--arch,--target,--gpu-target,--c-header,--cflag,-I,-isystem,--ldflag,-l,-L,--framework,-F,-Wl,--needed,--runpath,--soname,--elf-interp, - when building a single target,
-o/--outis optional (defaults to that target’soutputor a computed default underbuild/). - Target selection:
--arch <arch>and--target <triple>are mutually exclusive; omit both to use the default target.--gpu-target <gpu-target>independently selects the device processor forattr(device=gpu)functions while--targetcontinues to select the host. The GPU-v1 path is Linux x86_64 executable-only, accepts AMDgfx942,gfx1100, andgfx1151plus NVIDIAsm80, and embeds a provider-tagged version-3 bundle forstd::gpu. It is rejected for other output kinds/host targets and for sources without a launchable root-package GPU entry; executable sources with GPU functions require it.--list-gpu-targetsprints canonical GPU target spellings, providers, and embedded artifact forms, then exits.--list-targetsprints the recognized--targettriples, current-host output kinds, current-host const-main-only notes, and Apple Silicon macOS host-backed notes for targets with that extra support, then exits. AMDGPU triples are included for metadata and source-intrinsic.hsacoobject output, not as general Silk IR-to-GPU lowering targets; see backend amdgpu for the source shape.--list-archsprints the recognized--archvalues and exits.- Entrypoint rules:
- for
--kind executable(the default), there must be exactly onemain, using eitherfn main() -> int,fn main() -> void,async fn main() -> int,async fn main() -> void,fn main(argc: int, argv: u64) -> int, orfn main(argc: int, argv: u64) -> void, - for
--kind object,--kind static, and--kind shared,mainis not required; at least one supportedexport fn, supportedexport letconstant, or a valid executablemainmust be present so the output contains one or more globally-visible symbols. - Multi-file builds are supported for
--kind executableand for--kind object/--kind static/--kind shared: - for non-executable outputs, when multiple packages are present in a module set, only exports from the root package (the package of the first input module) are emitted as globally-visible symbols; other packages are compiled as dependencies and their
exportdeclarations are treated as internal for that output. - Output selection:
- default: build an executable (
--kind executable), --kind object: build a relocatable object (.o):- ELF64 on
linux/x86_64, - Mach-O 64-bit relocatable for
--target macos-aarch64and the iOS device/simulator targets on Apple Silicon macOS hosts, - AMDHSA
.hsacofor--target amdgcn-amd-amdhsa-gfx942,--target amdgcn-amd-amdhsa-gfx1100, and--target amdgcn-amd-amdhsa-gfx1151when the source contains exactly one exported source kernel in the AMDGPU intrinsic-call subset, --kind static: build a static library (.a) onlinux/x86_64and on host-backed Apple targets when running on Apple Silicon macOS,--kind shared: build a shared library (.soon Linux,.dylibon macOS/iOS) onlinux/x86_64and on host-backed Apple targets when running on Apple Silicon macOS.- Emission:
--emit bin(default) emits the selected binary artifact at<path>,--emit asmwrites anobjdump-style disassembly (Intel syntax) of the selected output onlinux/x86_64and writes it to<path>,-Sis accepted as an alias of--emit asmand defaults to--kind objectwhen--kindis not set.- Dynamic dependencies:
--cflag <arg>adds an additional native compiler argument used when compiling.c,.h, and.minputs; it may be repeated,-I <path>/-I<path>and-isystem <path>/-isystem<path>add native include and system include search paths; they may be repeated,--ldflag <arg>adds a backend linker argument; prefer the dedicated-land-Wlflags for command-line builds. Recognized arguments follow the same backend rules as those dedicated flags, including the internal ELF translations for-Wl,-rpath,-Wl,-soname, and-Wl,--dynamic-linker(see package manifests),-L <path>/-L<path>adds a library search path; host-backed Apple Mach-O executable/shared links pass it told, whilelinux/x86_64uses it to resolve-l/-l:names to dynamic dependencies or static archives,-l <name>/-lnamelinks with a library name; host-backed Apple Mach-O executable/shared links pass it told, whilelinux/x86_64searches-Lpaths first and otherwise translates it to aDT_NEEDEDsoname,-Wl <arg>/-Wl,<arg>passes backend linker arguments; platform-linker backends receive comma-split payloads directly, whilelinux/x86_64supports translated-rpath,-soname, and--dynamic-linkerpayloads,- Apple SDK linking flags are shown in
silk build --helponly on Apple Silicon macOS compiler hosts and are supported for host-backedmacos-aarch64plus iOS executable/shared outputs: --framework <name>links an Apple framework by name,-F <path>/-F<path>adds an Apple framework search path;silk buildno longer uses-Ffor build features,- package iOS executable targets can request app bundle materialization
with
ios_app_bundle = true; the generated or copied bundle is named<output>.appand is ad-hoc signed by default for simulator use, --needed <soname>adds aDT_NEEDEDentry for executable and shared outputs; it may be repeated,--runpath <path>(or--rpath <path>) adds a runpath element for executable and shared outputs; it may be repeated (joined with ':' intoDT_RUNPATH),--soname <soname>sets the shared library soname recorded asDT_SONAMEfor shared outputs (an empty string clears it),--elf-interp <path>overrides thePT_INTERPdynamic loader path used forlinux/x86_64executable outputs (this also influences glibc/musl linkage defaults for-l...mapping).- This option is rejected for non-
linux/x86_64targets. - For
linux-x86_64-musl, the default is/lib/ld-musl-x86_64.so.1; explicit glibc loader paths are rejected for that target. - For generic
linux-x86_64, when omitted,silkprobes common loader paths when running onlinux/x86_64, and otherwise falls back to/lib64/ld-linux-x86-64.so.2for cross-compilation. - Override sources (highest priority first):
--elf-interp, manifest[[target]].elf_interp,SILK_ELF_INTERP. - for object and static library outputs,
--ldflag,--needed,--runpath,--soname, and--elf-interpare ignored. - on
linux/x86_64with the glibc dynamic loader (ld-linux),silkautomatically adds: libc.so.6as aDT_NEEDEDdependency when external symbols are present (so hostedstd::modules do not require--needed libc.so.6), andlibpthread.so.0whenpthread_*symbols are imported.- on
linux/x86_64with the musl dynamic loader (ld-musl),silkautomatically adds musl's unifiedlibc.sodependency when external symbols are present; common libc component link names such as-lm,-lpthread, and-ldlalso map tolibc.so. - on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::cryptoand/orstd::tlsare imported, or when linked native.c/.h/.m/.o/.ainputs reference common libsodium / mbedTLS symbol families,silkauto-links the target-matched built-in static archives (libsodium.aand the mbedTLS archives) fromvendor/lib/<target-layout>/(or an installed prefix) so executables do not depend on systemlibsodium/mbedTLSshared libraries at runtime. - on
linux/x86_64glibc or musl, whenstd::sqliteis imported, or when linked native.c/.h/.m/.o/.ainputs referencesqlite3_*symbols,silkauto-links the target-matched built-inlibsqlite3.aarchive so executables do not depend on a system SQLite shared library at runtime. - on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::sshorstd::ssh2is imported, or when linked native.c/.h/.m/.o/.ainputs referencelibssh2_*symbols,silkauto-links the target-matched built-inlibssh2.aarchive (and its built-in crypto dependencies) so executables do not depend on a systemlibssh2shared library at runtime. - on
linux/x86_64glibc, whenstd::runtime::z3is imported or linked native inputs referenceZ3_*symbols,silkauto-links the built-in glibclibz3.a; onlinux/x86_64musl the same use is accepted only when the build explicitly supplies a musl-builtlibz3.ainput or alibz3dynamic dependency such as--needed libz3.so.0. - on
linux/x86_64, whenstd::dyliborstd::gpuis imported, or when linked native.o/.ainputs reference bundledsilk_rt_dylib_*/silk_rt_gpu_*runtime symbols,silkautomatically adds the libc component that providesdlopen(libdl.so.2on glibc,libc.soon musl). - on Linux x86_64 executable builds,
--gpu-target <gpu-target>compiles root-packageattr(device=gpu)functions into AMDHSA code objects or NVIDIA PTX and embeds them in a provider-tagged bundle.std::gpudynamically loads HIP or the CUDA Driver API, so the application has no link-time GPU-provider dependency. - on supported hosted target layouts (
linux/x86_64glibc,linux/x86_64musl, andmacos/aarch64), whenstd::ggmlis imported, or when linked native.o/.ainputs referencesilk_ggml_init,silkauto-links the built-in ggml archives; on Linux it also addslibstdc++.so.6,libgcc_s.so.1, and the target libc math/dynamic-loader providers, while on Apple Silicon macOS hosts it adds-lc++for the native link. - on
linux/x86_64glibc or musl, whenstd::image::png/std::image::jpegare imported, or when linked native.o/.ainputs reference the shim symbols,silkauto-links the target-matched built-in image archives and addslibz.so.1and/or the target libc math provider as needed. - on
linux/x86_64glibc or musl, whenstd::xmlis imported, or when linked native.o/.ainputs referencesilk_xml_node_name_ptr,silkauto-links the target-matched built-in libxml2 archives and adds the target libc math provider as needed. - on
linux/x86_64, whenstd::windowreaches the bundled runtime,silkadds the dynamic-loader API provider used by the runtime-loaded GTK provider (libdl.so.2on glibc targets,libc.soon musl targets); GTK remains runtime-loaded rather than a requiredDT_NEEDEDentry. - when the active security provider is
autoon an Apple target,std::cryptocore/random helpers linkSecurity.framework, andstd::netlinksNetwork.framework;std::tls,std::ssh/std::ssh2, native libsodium/mbedTLS symbol references, and advancedstd::crypto::*modules fall back to built-in archives. - when the active security provider is explicit
platformon an Apple target, fallback-only std and native security APIs are rejected until platform mappings are implemented. - when the active security provider is
builtin, the crypto/TLS/SSH fallback paths above use the same target-matched built-in archive directories (vendor/lib/<target-layout>/or an installed prefix). - when bundled runtime support symbols are imported (for example via
import std::regex;),silkstatically linkslibsilk_rt.a(orlibsilk_rt_noheap.awhen building with--noheap) into the output; no runtimeDT_NEEDEDentry is emitted forlibsilk_rt*. --neededentries starting withlibsilk_rtare rejected; the bundled runtime support layer is always linked from the static archives.- Debug builds:
--debug(or-g) enables runtime stack traces for failedassertstatements onlinux/x86_64by printing a stack trace to stderr before aborting, and preserves internal function symbols in.dynsymfor better symbolization.- when Formal Silk verification fails,
--debugalso emits Z3 debugging output and writes an SMT-LIB2 reproduction script under.silk/z3/(or$SILK_WORK_DIR/z3). - Heap control (Supported forms):
--noheapdisables heap allocation for the Supported forms:- heap-backed
new(outside awithregion) is rejected withE2027, extbindings to libc heap primitives (malloc/calloc/realloc/free/etc) are rejected withE2027in non-stdlib modules,std::runtime::mem::{alloc,realloc,free}traps when called without an activewithregion (no implicit heap fallback),- non-stdlib concurrency usage that declares or forms
Task(...)/Promise(...)handles is rejected withE2027(async fn,task fn,async {},task {},async loop,task loop,await,yield, and calls or type positions that produce awaitable handles), - imported stdlib async/task declarations alone do not trigger
E2027; the error is raised only once user code uses those awaitable surfaces under--noheap, - capturing closures are rejected with
E2027, - region-backed
newinsidewithis still permitted. --noheapis currently incompatible with--debug(debug panic traces requiremalloc/free).- For the supported subset, emits the selected artifact (or an assembly listing when
--emit asmis selected) at<path>. - C99 header emission (for downstream consumers of exported symbols):
--c-header <path>writes a generated C header at<path>that declares the root package’s exported symbols (export fnprototypes andexport letextern declarations) for consumption from C/C++,- this option is only meaningful for non-executable outputs (
--kind object|static|shared) and is rejected for--kind executable, - to keep the C ABI surface obvious and stable,
--c-headerrequires the root package (the package of the first input module) to be the global package (i.e. omitpackage ...;in the exported library’s sources), - when a package build must compile native C/Objective-C code against
named-package exports in the same package target, the package may keep a
small bridge header and use
SILK_C_ABI_EXPORT_FN(pkg, name)forexport attr(abi=c) fnfunctions,SILK_PACKAGE_EXPORT_FN(pkg, name)for default package exports, orSILK_PACKAGE_EXPORT_DATA(pkg, name)for exported data fromsilk/silk.hto spell package-qualified symbols without hardcoding generated names, - unnamed C-facing root-package
export fnsignatures may not use ordinary borrowed references or slices; the checker rejects those withE2119before object/header emission, - the generated header encodes the current ABI rules described in abi libsilk, including:
stringvalues useSilkString { ptr, len }(fromsilk/silk.h),- optionals and 3+ slot structs are lowered at call boundaries as multiple scalar parameters (so C prototypes for such parameters use flattened arguments rather than by-value C struct parameters).
- For programs outside the supported subset that nonetheless type-check, exits non-zero with a clear
E4001/E4002diagnostic (instead of a generic “code generation is not implemented yet” message). - Formal Silk verification:
- when Formal Silk syntax is present (for example
#require,#assure,#assert,#invariant,#variant,#monovariant,#const),check/test/buildrequire proofs and fail the build when verification fails, - when
--debugis set, failing proof obligations also emit Z3 debugging output and write an SMT-LIB2 reproduction script under.silk/z3/(or$SILK_WORK_DIR/z3), - when a successful
buildoutput exposes exported theories or exported/public contract-bearing functions/methods, the compiler also writes a success-path export bundle under.silk/formal/<output-identity>/(or$SILK_WORK_DIR/formal/<output-identity>/) asmanifest.jsonplusbundle.smt2, --z3-lib <path>overrides the Z3 dynamic library used by the verifier (it also honorsSILK_Z3_LIB).silk buildaccepts repeatable-Wz <spec>/-Wz,<spec>Z3 parameter specs:NAME=VALUEandconfig:NAME=VALUEare applied to every verifierZ3_configwithZ3_set_param_value,global:NAME=VALUEis applied once before context creation withZ3_global_param_set,NAMEandVALUEmust be non-empty, and Silk intentionally does not whitelist Z3 parameter names because valid parameters are Z3-version-specific.- verification runs on multiple worker threads when there are enough proof obligations; set
SILK_VERIFY_JOBS=1to force single-threaded verification. silk doc:- Markdown mode:
silk doc [--all] <file> [<file> ...] [-o <output.md>] - Generates Markdown documentation from Silkdoc comments (
/** ... */and/// ...) attached to declarations. - By default, includes:
- exported
fn/let/ext/type/theorydeclarations and exportedimplmethods, and - all
struct/enum/error/interfacedeclarations in the input modules. --allincludes non-exported functions, bindings, and methods.- When
-o/--outis provided, writes the Markdown output to that path; otherwise writes to stdout. - Manpage mode:
silk doc --man [--package <dir|manifest>] [--std-root <path>] <query> [-o <output.man>] - Renders a roff
man(7)page derived from source docs (@cli/@misc/API docs) and writes it to stdout (or to-o/--out). silk cc <cc args...>:- Runs a host C compiler to build C99 (or C++) programs that embed or link against
libsilk.a. - Selects the compiler executable via
SILK_CC(when set), otherwise falls back toCC, thencc. - Automatically adds the include and library search paths adjacent to the installed
silkbinary (for example../include,../include/silk, and../lib), plus-lsilk. - On
linux/x86_64, also adds-lstdc++ -lpthread -lm(built-in Z3 is built as C++). - Passes through additional arguments verbatim to the underlying compiler (files, flags,
-o,-I,-L, etc.). - Wrapper usage can be displayed via
silk help cc(sincesilk cc --helpis passed through to the underlying compiler;slcc --helpprints wrapper usage). silk cache [subcommand] [--package <dir|manifest>] [--cache-dir <path>]:- current command model:
silk cacheprints a cache-root summary,silk cache pathprints the effective cache root,silk cache listlists recognized managed cache entries,silk cache inspect [<entry>]inspects the root or one entry,silk cache pruneprunes recognized managed cache entries by policy,silk cache compactheals recognized managed entries and reclaims stale managed space and drops now-empty managed directories such asbuild/,silk cache clearremoves recognized managed entries while preserving unknown files under the cache root,- cache mutation commands coordinate through an internal managed-cache lock:
- normal
silk buildcache hits/fills use the same lock, silk cache prune|compact|clearwait for in-flight managed cache work,- automatic maintenance skips itself when the lock is already held,
- root selection:
--cache-dir <path>selects an explicit cache root,- otherwise the command uses
<work_root>/cache, - and the work root comes from
SILK_WORK_DIRor the default.silkresolution rules, - current recognized managed entry types:
- CLI build-cache artifact entries under
build/<sha256-key>/, std::buildgenerated-file blobs underbuild/<fnv1a64>.blob,- common options:
--dry-runpreviews cleanup,--max-age <age>overrides the prune age limit forpruneandcompact,--max-size <bytes>overrides the prune size cap forpruneandcompact,--keep-recent <n>preserves at least<n>recent managed entries during pruning,- default maintenance policy:
- auto-heal enabled,
- auto-prune enabled,
- max size
2 GiB, - max age
30d, - keep recent
64, - environment overrides:
SILK_CACHE_AUTO_HEALSILK_CACHE_AUTO_PRUNESILK_CACHE_MAX_BYTESSILK_CACHE_MAX_AGESILK_CACHE_KEEP_RECENT
Future commands (not yet implemented, but documented for roadmap clarity):
silk abi header— emitsilk/silk.hand ABI descriptions for embedders.
Documentation & Manpages#
- CLI behavior must be mirrored in silk.1.
- Examples of typical build invocations and workflows should also be documented under cli examples.
Source repository · Edit this page · View Markdown