Files
scriptc/docs/content/docs/cli.mdx
T
Chris Tate f69ff780e5 Give a stop command that matches the shared checker server
The server's command line puts --cwd and --callbacks between --api and
--listen, so `pkill -f 'tsc-ts --api --listen'` matched no server that a
build started. The docs now give `pkill -f 'tsc-ts --api .*--listen'`, and
name the flags instead of writing them as one command.
2026-10-27 08:33:04 -05:00

389 lines
32 KiB
Plaintext

---
title: "CLI Reference"
---
The `scriptc` command has six subcommands: `build`, `run`, `coverage`, `types`, `cache warm`, and `merge-profiles`. `scriptc --help` prints this summary and the options below, and `scriptc --version` prints the installed version.
```console
$ scriptc --help
scriptc — TypeScript/JavaScript to native and WebAssembly executables (experimental)
Usage:
scriptc build <file.ts|.js> [options] compile to an executable or source artifact
scriptc run <file.ts|.js> [options] compile and run
scriptc coverage <file.ts|.js> how much compiles statically, and why not
scriptc coverage <file.ts|.js> --external-types <specifier=file.d.ts>
type-resolve an embedder-provided module for analysis
scriptc build --lib --profile <p.json> library mode: compile the profile's entry
module to a linkable static archive
(<name>.lib.a), or a Wasm reactor
(<name>.wasm) on wasm32-wasi,
exporting the profile symbols; a profile
with a sidecar section also gets the
contract sidecar JSON beside the archive
scriptc types patch <package> <selector> <type> [--range <r>] [--dry-run]
fix a wrong declaration of an installed
package: shows what the selector
matches and adds the type patch to
package.json ("| undefined" widens)
scriptc types list the project's type patches and what
they match
scriptc cache warm [runtime|tls…] verify and load precompiled runtime families
for the current compiler/SDK/target
scriptc merge-profiles -o <out.profdata> [--sparse] <profile…>
merge the raw profiles that
--profile-generate runs wrote (or
earlier merged profiles) into one
profile for --profile-use;
--sparse leaves out functions
that never ran (a smaller file)
```
## scriptc build
Compiles a TypeScript or JavaScript entry file. By default it writes a native executable, or a WebAssembly module when the target is <code>wasm32-wasi</code>. The program is type-checked first by the TypeScript compiler, honoring the nearest `tsconfig.json`. Anything that can't compile is an error with an `SC`-prefixed code, a code frame, and usually a rewrite hint.
```console
$ scriptc build fib.ts -o fib >/dev/null
$ ./fib
832040
```
`build` prints the path of the file it writes. Without `-o`, the file goes in `.scriptc/` next to the input. Use `--emit` to stop at an earlier stage of compilation:
```console
$ scriptc build fib.ts --emit=ir >/dev/null
$ ls .scriptc/
fib.ir.json
$ scriptc build fib.ts --emit=llvm >/dev/null
$ ls .scriptc/
fib.ir.json
fib.ll
$ scriptc build fib.ts --emit=asm >/dev/null
$ ls .scriptc/
fib.ir.json
fib.ll
fib.s
$ scriptc build fib.ts --emit=obj >/dev/null
$ ls .scriptc/
fib.ir.json
fib.ll
fib.o
fib.s
```
Different output kinds accumulate in `.scriptc/`; rebuilding a kind updates its file.
<code>--emit=exe</code> is the default. Assembly and object output use the LLVM helper installed with scriptc and need no external compiler, linker, or SDK. An object is a relocatable program object that leaves scriptc's runtime functions undefined; it is not a standalone library. Linking objects yourself is experimental and requires the exact runtime pack reported by <code>--print=native-link-info</code>; see <a href="/docs/native-objects">Native Program Objects</a>.
### Library mode
`scriptc build --lib --profile <profile.json>` compiles the entry module named in a library profile into a static archive (`<name>.lib.a`) that a host application links, or into a Wasm reactor (`<name>.wasm`) on `wasm32-wasi`. The profile declares the exported functions and their symbols. Library builds take no input file and don't accept `--emit`, `--print`, `--optimization`, `--strip`, `--ffi`, or `--npm-static`; the profile controls emission and optimization. See [WebAssembly Modules](/docs/wasm) for a complete profile and [iOS and Android](/docs/platforms#ios-and-android-arm64-library-mode) for mobile targets.
## scriptc run
Builds the program, then runs it with stdio inherited. For <code>wasm32-wasi</code>, it runs the module with Node.js's WASI Preview 1 implementation, makes the current working directory available as <code>/</code>, and maps the host's temporary directory to <code>/tmp</code>.
```console
$ scriptc run fib.ts
832040
```
`run` does not pass extra command-line arguments to the program. To pass arguments, build an executable and run it directly.
## scriptc coverage
Analyzes the program without building it and reports what compiles and what blocks the rest. See [Coverage Reports](/docs/coverage).
## scriptc types
Writes and lists [type patches](/docs/dependencies#fix-a-packages-types), the project's fixes for wrong declarations of npm packages.
<dl>
<dt><code>scriptc types patch &lt;package&gt; &lt;selector&gt; &lt;type&gt;</code></dt>
<dd>Finds the package installed for the working directory, prints every declaration the selector matches in its declaration files, its JSDoc and its <code>@types/</code> package with the type before and after, and adds the patch to the nearest <code>package.json</code>. The patch joins an entry whose range covers the installed version, or gets the range <code>^&lt;installed version&gt;</code>. Nothing is written when the selector matches nothing. <code>--range &lt;range&gt;</code> chooses the range, and <code>--dry-run</code> only prints.</dd>
<dt><code>scriptc types list</code></dt>
<dd>Prints each type patch in the nearest <code>package.json</code>, whether it applies to the installed version, and what it matches.</dd>
</dl>
```console
$ scriptc types list
commander@^15.0.0
HelpContext.helpWidth: | undefined
node_modules/commander/lib/command.js:2481 number -> number | undefined
```
## scriptc cache warm
Verifies and loads the installed precompiled runtime objects and vendored libraries, and prints the cache directory. Pass `runtime`, `tls`, or both to select which to warm. Ordinary builds don't need this step. With `--sanitize`, it builds the instrumented runtime objects using a C toolchain.
## scriptc merge-profiles
Merges the raw profiles that runs of a `--profile-generate` executable wrote, and any earlier merged profiles, into one profile for `--profile-use`. See [Profile-guided optimization](#profile-guided-optimization).
```console
$ scriptc merge-profiles -o app.profdata profiles/*.profraw
```
With `--sparse`, the profile leaves out the functions the runs never reached. The file is smaller, typically by about two thirds, and those functions are optimized as without a profile instead of as cold code.
## Options
<dl>
<dt><code>-o, --out &lt;path&gt;</code></dt>
<dd>Primary artifact path. An explicit path is exact. Defaults are <code>.scriptc/&lt;name&gt;.ir.json</code>, <code>.ll</code>, <code>.s</code>, <code>.o</code>, or the platform executable name.</dd>
<dt><code>--emit &lt;ir|llvm|asm|obj|exe&gt;</code></dt>
<dd>Select the primary artifact: serialized typed IR (<code>ir</code>), textual LLVM IR (<code>llvm</code>), assembly (<code>asm</code>), a relocatable object (<code>obj</code>), or an executable (<code>exe</code>, the default). Every kind except <code>exe</code> is produced without an external compiler, linker, or SDK. Assembly and object output is compiled as one module; only executables are divided into partitions that compile in parallel (see <a href="/docs/how-it-works#build-parallelism">Build parallelism</a>).</dd>
<dt><code>--print &lt;native-link-info|diagnostics&gt;</code></dt>
<dd><code>native-link-info</code>: build an object (equivalent to <code>--emit=obj</code>) and print its machine-readable external link recipe as JSON instead of printing the artifact path. The document names the exact installed precompiled runtime pack and all link inputs, but does not invoke a linker. <code>diagnostics</code>: for <code>build</code> and <code>coverage</code>, print the versioned JSON diagnostics document described in <a href="/docs/coverage#machine-readable-diagnostics">Coverage Reports</a> instead of the human output.</dd>
<dt><code>--fail-on &lt;blockers|divergences|dynamic|dynamic-slots&gt;</code></dt>
<dd>Coverage only. Exit with status 1 when the entry has blockers that would fail a build, with <code>divergences</code>, also when it has Node divergence warnings, with <code>dynamic</code>, also when it has the <code>SC6101</code> warning for untyped code that likely runs often, or with <code>dynamic-slots</code>, also when it has <a href="/docs/coverage#dynamic-slots">dynamic slots</a> (<code>SC6104</code>). See <a href="/docs/coverage#gating-builds-and-ci">Gating builds and CI</a>.</dd>
<dt><code>--ffi &lt;file&gt;</code></dt>
<dd>Bind signature-only TypeScript declarations to native C ABI symbols and link the manifest's archive, object, and system-library inputs. See <a href="/docs/ffi">Native FFI</a>.</dd>
<dt><code>--backend &lt;llvm&gt;</code></dt>
<dd>The code generator. <code>llvm</code> is the only backend and the default.</dd>
<dt><code>--strip</code></dt>
<dd>Remove symbol and debug payload when linking an executable, including cross-compiled targets. This flag preserves code optimization.</dd>
<dt><code>--static</code></dt>
<dd>On Linux, link the C library and the other system libraries into the executable. The executable starts without the dynamic loader, which shortens its startup, and doesn't depend on the run host's glibc version. glibc executables link as static PIE, are about 1 MB larger, and need glibc's static libraries on the build machine (<code>libc6-dev</code> on Debian and Ubuntu, <code>glibc-static</code> on Fedora); they link only for the build machine's own glibc target. A program whose executable includes host, user, or group name lookups, which <code>dns.lookup</code>, <code>net</code> and <code>http</code> connections, <code>fetch</code>, and <code>os.userInfo()</code> use, is refused with <code>SC3002</code>: a static glibc executable loads the NSS modules for those lookups from the run host, which glibc supports only for the glibc version it was linked with. Build such a program without <code>--static</code>, or for an <code>&lt;arch&gt;-linux-musl</code> target. musl executables are always linked statically, and accept the flag. Valid only for executable builds.</dd>
<dt><code>--optimization &lt;release|dev|speed&gt;</code></dt>
<dd>Select native optimization for executable, assembly, or object output. The default is <code>release</code> (<code>-O2</code>), which emits string retains and the retains and releases of dynamic values inline. <code>dev</code> uses <code>-O0</code> and emits source locations for TypeScript and JavaScript breakpoints and stack frames. LLVM builds include source variable names and native storage descriptions; see <a href="/docs/limitations#native-debugging">Native debugging</a> for the supported representations. macOS executable builds also produce an adjacent <code>.dSYM</code> bundle. <code>speed</code> is <code>-O2</code> plus optimizations that trade binary size and build time for run-time speed: it emits the remaining reference counting inline and, on x86-64, starts every runtime function on a cache-line boundary. Expect larger executables and longer cold builds than <code>release</code>; how much faster a program runs depends on how much of its time is spent in the runtime. Where a runtime pack has no speed runtime, <code>speed</code> links the release runtime and keeps inline reference counting. Selecting <code>speed</code> never changes what <code>release</code> builds produce, and the two never share cached artifacts. Library profiles accept <code>"optimization": "speed"</code> for inline reference counting. In executables large enough to be divided into partitions, <code>dev</code> compiles each partition on its own, and <code>release</code> and <code>speed</code> add a step that lets partitions import small functions from each other; see <a href="/docs/how-it-works#build-parallelism">Build parallelism</a>.</dd>
<dt><code>--windows-subsystem &lt;console|gui&gt;</code></dt>
<dd>Select the subsystem of a Windows executable. <code>console</code> is the default; <code>gui</code> prevents Windows from opening a console window for the app. Valid only for executable builds targeting Windows.</dd>
<dt><code>--detached-exit</code></dt>
<dd>On Linux, when the program calls <code>process.exit()</code>, hand the release of its memory to a helper process so the parent sees the exit sooner. The kernel otherwise frees the whole address space before the exit is reported, which takes tens of milliseconds per gigabyte. Opt in only where the trade-offs are acceptable: for up to about 100 ms after the exit, the helper keeps the executable mapped (overwriting the binary in place fails with "text file busy"), its memory stays charged to the cgroup, and the teardown CPU time no longer appears in the parent's resource usage. Valid only for executable builds; it has no effect on other platforms.</dd>
<dt><code>--large-pages</code></dt>
<dd>On Linux, when the program starts, move its code onto 2 MiB transparent huge pages, as Node's <code>--use-largepages=silent</code> does. A large program's code then takes a few instruction TLB entries instead of hundreds, and runs faster. The move applies only when the system grants huge pages to memory that asks for them (<code>/sys/kernel/mm/transparent_hugepage/enabled</code> is <code>always</code> or <code>madvise</code>), and only to the code between the first and the last 2 MiB boundary of the executable, so small programs keep their code as it is. Opt in only where the trade-offs are acceptable: the move takes about 3 ms per 10 MiB of code at every start, all of the moved code stays resident and is not shared with other processes running the same executable, and profilers that read symbols from the executable file report the moved code as anonymous memory. If a step of the move fails, the program runs with its code where it was. Valid only for executable builds; it has no effect on other platforms.</dd>
<dt><code>--target-cpu &lt;baseline|x86-64-v2|x86-64-v3|x86-64-v4|native&gt;</code></dt>
<dd>On x86-64 targets, compile the program's code for an x86-64 microarchitecture level. The default, <code>baseline</code>, runs on any x86-64 CPU. A higher level lets LLVM use more instructions, and the executable then runs only on CPUs that support that level. <code>native</code> uses the highest level the build machine supports. Valid for executable, assembly, and object output on x86-64 targets. See <a href="#target-cpu">Target CPU</a>.</dd>
<dt><code>--cpu-dispatch</code></dt>
<dd>On x86-64 targets, compile the program's code twice, for the baseline and for <code>x86-64-v3</code>, and choose the copy when the program starts. The executable runs on any x86-64 CPU and uses the <code>x86-64-v3</code> code on CPUs that support it. Not used with a <code>--target-cpu</code> level above <code>baseline</code>. Valid only for executable builds. See <a href="#runtime-cpu-dispatch">Runtime CPU dispatch</a>.</dd>
<dt><code>--profile-generate &lt;pattern&gt;</code></dt>
<dd>On Linux, build an instrumented executable for profile-guided optimization. Each run writes a raw profile to the path pattern, where <code>%p</code> expands to the process ID; the <code>LLVM_PROFILE_FILE</code> environment variable overrides the pattern at run time. A relative pattern resolves from the current working directory. Instrumented programs run slower. Valid only for executable builds with <code>--optimization=release</code> or <code>speed</code>.</dd>
<dt><code>--profile-use &lt;file.profdata&gt;</code></dt>
<dd>Optimize the executable with a profile from <code>scriptc merge-profiles</code>: code is laid out, inlined, and split by how the profiled runs used it. Code the profile does not describe, or describes from an older version of the program, is optimized as without a profile, so a stale profile only loses part of its gain. A new or changed profile compiles every partition of the program again. <code>scriptc build</code> prints how the profile matched the program's functions on stderr; see <a href="#profile-guided-optimization">Profile-guided optimization</a>. Valid only for executable builds with <code>--optimization=release</code> or <code>speed</code>.</dd>
<dt><code>--npm-static &lt;pkg[,pkg…]|auto&gt;</code></dt>
<dd>Name npm packages to compile even if they don't ship their own type declarations (repeatable). A trailing <code>...</code>, as in <code>fs-extra...</code>, also names every package that package depends on. <code>auto</code> uses the default automatic selection. Packages that can't compile produce diagnostics. See <a href="/docs/dependencies#explicit-package-selection">npm Dependencies</a>.</dd>
<dt><code>--provenance-sources</code></dt>
<dd>Experimental. Compile npm dependencies from the source at the commit their provenance attestation names. Packages without a usable attestation compile from their installed files.</dd>
<dt><code>--external-types &lt;specifier=file.d.ts&gt;</code></dt>
<dd>Coverage only. Map an exact bare module specifier to a local declaration file supplied by an embedder. Repeat the option for multiple modules. The declaration supplies checker types so application coverage can continue; runtime imports and values remain explicit <code>SC1010</code> blockers. Relative paths resolve from the current working directory. Accepted files end in <code>.d.ts</code>, <code>.d.mts</code>, or <code>.d.cts</code>.</dd>
<dt><code>--tier &lt;auto|static-only&gt;</code></dt>
<dd>The tier policy for code that has no static lowering. <code>auto</code> is the default. <code>static-only</code> guarantees that the program contains no dynamic-tier demotions: every such construct stays a compile error in TypeScript and a deferred runtime error in JavaScript, which is how both modes behave today. Use it in CI to keep a program fully static. Library mode is always static-only. See <a href="/docs/coverage#dynamic-tier">Dynamic tier</a>.</dd>
<dt><code>--explain-dynamic[=&lt;name&gt;]</code></dt>
<dd>Coverage only. After the report, list the functions that already operate on values typed only at runtime and the bindings, fields, functions, classes and modules that unsupported constructs would move to the dynamic tier, each with the diagnostic behind it. With a name such as <code>x</code>, <code>Point</code>, or <code>Point.x</code>, show only the matching units. See <a href="/docs/coverage#dynamic-tier">Dynamic tier</a>.</dd>
<dt><code>--no-dynamic-tier-warning</code></dt>
<dd>Build and coverage. Leave out <code>SC6101</code>, the warning that names functions that likely run often and use untyped values. Not allowed with <code>--fail-on=dynamic</code>. See <a href="/docs/coverage#untyped-code-that-likely-runs-often">Untyped code that likely runs often</a>.</dd>
<dt><code>--wasm &lt;file.wasm&gt;</code></dt>
<dd>Coverage only. Report a WebAssembly module the program loads from a path its sources do not spell out. The report already lists modules whose paths the compiler resolves, modules inlined as base64 literals, and <code>.wasm</code> files shipped by packages that use WebAssembly; a <code>scriptc.wasm</code> array in <code>package.json</code> adds files the same way as this flag. Each module is listed with its size, whether it validates, and the WebAssembly proposals it uses. Builds translate the modules they find to native code; a build reads the <code>scriptc.wasm</code> array but not this flag. Repeatable.</dd>
<dt><code>--sanitize</code></dt>
<dd>Build an executable with AddressSanitizer and a reference-count audit at exit, the same checks scriptc's own test suite uses. Requires a C compiler and is available only for host builds. Not supported with <code>--emit=asm</code> or <code>--emit=obj</code>.</dd>
<dt><code>--emit-ir</code></dt>
<dd>Additive IR side artifact. It is deprecated for executable builds for one release cycle; prefer <code>--emit=ir</code> when IR is the primary output. Library mode retains <code>--emit-ir</code> because <code>--emit</code> does not select library artifacts.</dd>
<dt><code>--keep-llvm</code> / <code>--no-keep-llvm</code></dt>
<dd>Keep (default) or delete the generated <code>.ll</code> file next to the executable.</dd>
<dt><code>--lib</code>, <code>--profile &lt;profile.json&gt;</code></dt>
<dd>Build in <a href="#library-mode">library mode</a> from the given profile. <code>--lib</code> requires <code>--profile</code> and works only with <code>build</code>.</dd>
<dt><code>-h, --help</code></dt>
<dd>Show usage.</dd>
<dt><code>-v, --version</code></dt>
<dd>Print the installed version.</dd>
</dl>
## Environment variables
<dl>
<dt><code>SCRIPTC_CACHE_DIR</code></dt>
<dd>Override the persistent build-cache root. By default it is <code>$XDG_CACHE_HOME/scriptc/build</code> when set, <code>$HOME/Library/Caches/scriptc/build</code> on macOS, <code>%LOCALAPPDATA%\scriptc\cache\build</code> on Windows, and <code>$HOME/.cache/scriptc/build</code> elsewhere. Cached frontend results and LLVM artifacts, including the compiled partitions of large executables, are verified against their source, helper, target, and compilation settings. Native outputs also depend on the selected runtime pack and linker inputs. FFI objects, archives, and system libraries relink against their current dependencies. Sanitizer development builds additionally cache instrumented runtime objects and verify external compiler and header inputs. An existing POSIX override must already be private; otherwise caching is bypassed without changing the directory's permissions.</dd>
<dt><code>SCRIPTC_NO_CACHE</code></dt>
<dd>Set to <code>1</code> to bypass all build-cache reads and writes. An explicitly empty <code>SCRIPTC_CACHE_DIR</code> has the same effect.</dd>
<dt><code>SCRIPTC_CACHE_MAX_MB</code></dt>
<dd>Maximum build-cache size in megabytes. The default is <code>4096</code>; the default cache is swept periodically, while an explicitly configured cap is checked after every successful cache write. Least-recently-used entries are removed when the cache exceeds the cap.</dd>
<dt><code>SCRIPTC_CC</code></dt>
<dd>The C compiler used for <code>--sanitize</code> builds. <code>zigcc</code> selects zig's <code>cc</code> subcommand.</dd>
<dt><code>SCRIPTC_LINKER</code></dt>
<dd>The linker driver for executable builds, in place of the default (clang on macOS and glibc Linux, zig elsewhere). It receives only object files, archives, and system libraries, and locates the platform SDK and C runtime itself.</dd>
<dt><code>SCRIPTC_TARGET</code></dt>
<dd>Target triple for cross-compilation, such as <code>aarch64-linux-gnu.2.36</code>, <code>x86_64-windows-gnu</code>, or <code>wasm32-wasi</code>. WASI builds default to a <code>.wasm</code> output name. See <a href="/docs/platforms">Platform Support</a>.</dd>
<dt><code>SCRIPTC_RUNTIME_PACK</code></dt>
<dd>A runtime pack directory to use instead of an installed <code>@scriptc/runtime-&lt;target&gt;</code> package.</dd>
<dt><code>SCRIPTC_CHECKER</code></dt>
<dd>The TypeScript 7 API server that checks the program: <code>tsc-ts</code> (the default), which scriptc includes, or <code>tsgo</code>, from the <code>typescript</code> package scriptc also includes. Both give the same diagnostics and generated code.</dd>
<dt><code>SCRIPTC_CHECKER_SERVER</code></dt>
<dd>On Linux and macOS, builds check with a tsc-ts server that later builds share. The first build in a working directory starts it: a <code>tsc-ts</code> process, started with <code>--api</code> and <code>--listen</code>, that keeps running in the background with no terminal and keeps the files it parsed, so the next build in that directory loads its program faster. Each user, working directory and scriptc installation gets its own server, and a build connects only to the server of its own scriptc and tsc-ts. The socket is in <code>$XDG_RUNTIME_DIR/scriptc</code>, or <code>/tmp/scriptc-&lt;uid&gt;</code>, a directory only that user can access. A build that finds the server in use by another build, cannot start or reach it, or loses its connection to it, checks with its own tsc-ts process. The server exits after 10 minutes without a build, or after a build when its resident memory is above 2048 MB (<code>TSC_TS_LISTEN_MEMORY</code> sets another limit in megabytes). To stop it sooner, end that process, for example with <code>pkill -f 'tsc-ts --api .*--listen'</code>. Set to <code>0</code> to check with a tsc-ts process of each build's own. When <code>CI</code> is set to a value other than <code>0</code> or <code>false</code>, builds use their own process unless this variable is <code>1</code>. Diagnostics and generated code are the same with and without the server. It applies to the default checker, tsc-ts.</dd>
</dl>
```console
$ SCRIPTC_TARGET=aarch64-linux-gnu.2.36 scriptc build fib.ts -o fib-linux
$ file fib-linux
fib-linux: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped
```
## Profile-guided optimization
A profile records how often each branch and call ran in representative runs of the program. With it, the optimizer inlines the hot calls, keeps hot paths together, and moves cold code out of the way. Profiling takes three steps:
```console
$ scriptc build app.ts --optimization=speed --profile-generate profiles/%p.profraw -o app-instrumented
$ ./app-instrumented typical-input.json
$ scriptc merge-profiles -o app.profdata profiles/*.profraw
$ scriptc build app.ts --optimization=speed --profile-use app.profdata
```
Train on workloads like the ones the program will run: code the training never reached is optimized as without a profile. The profile can be committed and reused as the program changes. Functions whose control flow changed since the profile was collected lose their profile, and the rest keep theirs, so regenerate it when much of the program has changed. [Build parallelism](/docs/how-it-works#build-parallelism) describes what a profile adds to build time.
`scriptc build --profile-use` prints one line on stderr with how the profile matched the program's functions:
```
scriptc: profile app.profdata: 9170 functions annotated, 0 mismatched, 28636 without a record
```
- **annotated:** functions optimized with the profile's counts.
- **mismatched:** functions whose control flow changed since the profile was collected. They are optimized without counts.
- **without a record:** functions the profile does not describe: new functions, and functions the profiled runs never reached.
- When the build reuses cached partitions whose counts were not recorded, the line ends with the number of those partitions.
When more than 10% of the functions the profile describes (annotated and mismatched) are mismatched, the build also prints a warning:
```
scriptc: warning: 3739 of the 8947 functions app.profdata describes (41.8%) changed since it was collected and are optimized without their counts; collect the profile again
```
The build still succeeds. Collecting the profile again with the current program and scriptc version restores the counts.
## Target CPU
By default, x86-64 executables run on any x86-64 CPU, so the compiler uses only the baseline instruction set (SSE2). `--target-cpu` compiles the program's code for a higher x86-64 microarchitecture level. Each level includes the ones below it:
<table>
<thead>
<tr>
<th>Level</th>
<th>Adds</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>x86-64-v2</code></td>
<td>SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT</td>
</tr>
<tr>
<td><code>x86-64-v3</code></td>
<td>AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE</td>
</tr>
<tr>
<td><code>x86-64-v4</code></td>
<td>AVX-512 (F, BW, CD, DQ, VL)</td>
</tr>
</tbody>
</table>
```console
$ scriptc build app.ts --target-cpu=x86-64-v3 -o app
```
Loops over typed arrays and numbers gain the most, because LLVM vectorizes them with wider registers. Some loops run slower at a higher level, so measure the program on the machines it will run on.
An executable built for a level runs only on CPUs that support that level. On an older CPU, it crashes with an illegal-instruction signal (`SIGILL`) when it reaches an instruction the CPU lacks. A named level is portable to every machine of that level. `native` selects the highest level the build machine supports, so use it only for executables that run on the machine that built them or on identical machines.
The level applies to the program's own code. The runtime pack keeps its baseline code. Builds for different levels never share cached artifacts, and `baseline` builds are the same as builds without the option.
### Runtime CPU dispatch
`--cpu-dispatch` keeps the executable portable and still uses the higher level where the CPU has it. The program's functions are compiled for the baseline and for `x86-64-v3`. At startup, the executable checks the CPU and the operating system's register support, and then runs the `x86-64-v3` code on CPUs that support every feature of that level. Calls between the program's functions stay within the chosen copy.
```console
$ scriptc build app.ts --optimization=speed --cpu-dispatch -o app
```
The second copy makes the executable larger and the first build of the program slower, since LLVM compiles the program's code twice. Unchanged rebuilds are not affected. Both copies compute the same results: neither contracts floating-point operations into fused multiply-adds.
The `SCRIPTC_CPU_LEVEL` environment variable caps the level the executable uses, for example to test the baseline code on a newer machine. It takes a level from `0` to `4`, `baseline`, or a level name such as `x86-64-v3`; any other value selects the baseline code.
```console
$ SCRIPTC_CPU_LEVEL=baseline ./app
```
## LLVM backend
scriptc generates LLVM IR and compiles it to native code. Executable builds link the result with the matching precompiled runtime pack. Use <code>--emit=llvm</code> to inspect the generated code.
For source breakpoints in Xcode or LLDB, build with <code>--optimization=dev</code>. In an Xcode custom build rule, list the executable and its <code>.dSYM</code> bundle as outputs. Keep the bundle next to the executable and retain the original source files at their build paths. LLVM preserves source locations across imported modules.
## Tool requirements
<table>
<thead>
<tr>
<th>Operation</th>
<th>Needs</th>
</tr>
</thead>
<tbody>
<tr>
<td>Installing with npm</td>
<td>Node.js 24 or later</td>
</tr>
<tr>
<td><code>coverage</code>, <code>--emit=ir|llvm|asm|obj</code></td>
<td>Only the installed compiler</td>
</tr>
<tr>
<td><code>--emit=exe</code> (the default)</td>
<td>A linker and the platform SDK or sysroot: clang and the Xcode Command Line Tools on macOS, clang on glibc Linux, zig on Windows, musl Linux, and for cross-compiled targets</td>
</tr>
<tr>
<td>Cross-compiling</td>
<td>The target's <code>@scriptc/runtime-&lt;target&gt;</code> pack and zig (see <a href="/docs/platforms">Platform Support</a>)</td>
</tr>
<tr>
<td><code>scriptc run</code> on <code>wasm32-wasi</code></td>
<td>Node.js 24 or later on <code>PATH</code></td>
</tr>
<tr>
<td><code>--static</code> on glibc Linux</td>
<td>glibc's static libraries (<code>libc6-dev</code> on Debian and Ubuntu, <code>glibc-static</code> on Fedora)</td>
</tr>
<tr>
<td><code>--sanitize</code></td>
<td>A C compiler and LLVM toolchain</td>
</tr>
</tbody>
</table>