EnglishFrançais

3 · CLI reference

Synopsis

amc [options] file1.am [file2.am ...] -o <output>     # compile
amc <subcommand> [args...]                            # other commands

The compiler always emits a .c file. To produce a native binary, follow up with gcc:

amc hello.am -o hello                                    # → hello.c
gcc -Iruntime hello.c -lgc -lm -o hello           # → hello (binary)
./hello

The runtime headers live in runtime/ at the project root.

Subcommands

Command Purpose Reference
build [-o <out>] [-g] [-v] <entry.am> Compile + gcc-link a runnable binary in one step (v0.7.9+). -g/--debug swaps -O2 for -O0 -g (DWARF for amc dap) since v0.8.0. amc build --help
run [-o <out>] [-g] [-v] <entry.am> [-- args…] Build, then exec the binary (v0.7.9+) amc run --help
watch [-o <out>] [--run] [-v] <entry.am> Build now, then poll mtime and rebuild on change (v0.7.9+) amc watch --help
fmt [-w] file.am Idempotent formatter (stdout, or -w in-place) amc fmt --help
test [<dir>] Discover *_test.am, compile + run, aggregate amc test --help
lsp Workspace-aware LSP server over stdio JSON-RPC chap. 6
dap DAP proxy over stdio — forwards to lldb-dap/gdb --dap (v0.8.0+) chap. 6
new <name> [--template exe|lib|test|service] [--vscode] Scaffold a new project. --vscode adds .vscode/launch.json + settings.json (v0.8.1+). amc new --help
package <action> (alias pkg) Project package management (see below) amc package --help
migrate <file|dir> LLM-driven source-to-Amalgame translation chap. 8
generate "<prompt>" LLM-driven prose-to-Amalgame chap. 8
explain <file.am> LLM-driven Amalgame-to-prose chap. 8

Each subcommand handles its own flags and exit codes; consult the referenced chapter or --help for the full surface.

amc package <action> (alias amc pkg)

Project-local package operations. All actions read/write amalgame.toml (deps) and amalgame.lock (resolved Git SHAs) in the current working directory.

Action Purpose
add <name|url>[@<tag>] [--no-precompile] Clone + validate + record dep. Accepts <name>@<tag> (shortname resolved via the curated index) or a full <git-url>@<tag>. Since v0.6.0 the @<tag> is optional on indexed shortnames: amc auto-resolves the latest tag whose required-amalgame is satisfied by the running amc. Full git URLs still need an explicit @<tag>. --no-precompile (v0.5.4+) skips the install-time compile of [stdlib].sources even if the manifest declares precompile = true.
remove <name>[@<tag>] [...] Strip dep(s) from amalgame.toml + amalgame.lock. The @<tag> safety suffix (v0.5.5+) refuses to remove unless the installed tag matches — guards against typo'ing the wrong version after an update.
search <keyword> [--refresh] Substring match against indexed packages. Each result lists known tags with compat status (/ vs running amc) and a ← latest compatible marker. Index cache TTL is 30 min since v0.5.6 (auto-refresh); --refresh forces a re-fetch sooner.
versions <name> [--refresh] Shortcut: same output as search filtered to one package.
list Show installed packages with their pinned tag (since v0.5.5) — format: <ClassName> @ <tag> — <slug>.
update <name>@<tag> Bump a pinned tag (delegates to add under the hood).
cache clear [--all] Drop cached index (and packages with --all).

amc test auto-installs any missing deps before running the suite, and links each package's [stdlib].sources vendored C objects into every test binary — backends like SQLite "just work" without manual gcc flags. Since v0.5.3, .cpp / .cc / .cxx sources are compiled with g++ (and the final test link goes through g++ when any package contributes C++), so DuckDB-style packages vendoring a C++ amalgamation work out of the box too.

amalgame.toml manifest reference

A package's amalgame.toml describes both its own metadata ([package]) and the surface it contributes to consumers ([stdlib]). A user project's amalgame.toml typically has just [package] + [dependencies].

[package]
name              = "amalgame-database-duckdb"
version           = "0.1.0"
license           = "Apache-2.0"
required-amalgame = ">=0.5.3"   # refuses install on older amc
schema-version    = 1           # refuses install on amc < this schema

[stdlib]
class     = "DuckDB"
header    = "runtime/Amalgame_Database_DuckDB.h"
namespace = "Amalgame.Database.DuckDB"
sources   = ["runtime/Amalgame_Database/duckdb/duckdb.cpp"]
cflags    = ""                  # extra flags for .c sources
cxxflags  = "-O3 -DNDEBUG -std=c++17"  # extra flags for .cpp/.cc/.cxx
libs      = ["stdc++"]          # bare names → -l<name> at link time

[stdlib.functions]
Open     = { returns = "AmalgameDuckDB*" }
Close    = { returns = "void" }
# Optional `returns_generic` (v0.8.40+) carries the AM-level
# generic shape so chained `.Get(i).Get(j)…` on the consumer side
# infers typed casts instead of falling through to `(void*)`.
# Example: `QueryAll` returning rows-of-columns of strings.
QueryAll = { returns = "AmalgameList*", returns_generic = "List<List<string>>" }
# …
Key Where Since Purpose
name, version, license [package] v0.5.0 Required identity fields
description, authors [package] v0.5.0 Surfaced in amc package list / search
required-amalgame [package] v0.5.0 Semver constraint on the running amc. Operators (v0.6.0+): >=, >, <=, <, =, ^ (caret — npm-style, 0.x-aware), ~ (tilde — locks major.minor), bare version treated as >=. E.g. ">=0.5.3", "^0.6.0", "~1.2.3".
schema-version [package] v0.5.3 Refuses install when amc supports a lower manifest schema
class, header, namespace [stdlib] v0.5.0 Required wiring for the cgen + resolver
sources [stdlib] v0.5.0 Vendored .c / .cpp paths to compile + link
cflags [stdlib] v0.5.3 Extra gcc flags for the package's .c sources
cxxflags [stdlib] v0.5.3 Extra g++ flags for the package's .cpp / .cc / .cxx sources
libs [stdlib] v0.5.3 Bare lib names → -l<name> appended to every consumer's final link
precompile [stdlib] v0.5.4 When true, amc package add compiles sources at install time into ~/.amalgame/packages/.../build/<platform>/. Subsequent amc test/amc build reuse the cached .o. Override with --no-precompile.
[stdlib.functions] section v0.5.0 <Method> = { returns = "<C-type>" } — populates the cgen's dispatch
returns_generic (per-function) [stdlib.functions] v0.8.40 AM-level generic shape (e.g. "List<List<string>>"). When present, chained .Get(i).Get(j)… on the consumer infers typed casts ((code_string)… instead of (void*)…). Omit for non-collection returns or when one layer of void* is acceptable.

required-amalgame operators (v0.6.0+)

The constraint string follows npm/Cargo conventions. Examples:

Constraint Matches
">=0.5.3" At least 0.5.3 (current behaviour, back-compat)
">0.5.5" Strictly greater than 0.5.5
"<=0.6.0" At most 0.6.0
"<1.0.0" Strictly less than 1.0.0
"=0.5.5" Exact match
"^1.2.3" >=1.2.3, <2.0.0 (major locked when major > 0)
"^0.5.3" >=0.5.3, <0.6.0 (0.x minor locked, pre-stable rule)
"^0.0.5" =0.0.5 (0.0.x → exact patch, even stricter)
"~1.2.3" >=1.2.3, <1.3.0 (always locks major.minor)
"0.5.0" Bare version — treated as >= for back-compat with v0.5 manifests

Unrecognised operators are treated as "no constraint" (returns true) to keep older amc binaries compatible with future syntax extensions.

Auto-resolve amc package add <pkg> (v0.6.0+)

When the @<tag> suffix is omitted on an indexed shortname, amc fetches the index and picks the latest tag whose required-amalgame is satisfied by the running amc:

$ amc package add duckdb
Auto-resolved 'duckdb' → 'duckdb@v0.1.1' (latest compatible with amc 0.6.0)
…

Full git URLs still require an explicit @<tag> — the index is the SoT for "what amc knows about", and unindexed repos opt out of auto-resolve by design.

If no version is compatible (e.g. all indexed tags require a newer amc than you have installed), the command errors with a hint to run amc package versions <pkg> for the full constraint list.

Options

Flag Effect
-o <output> Output basename. The .c file is <output>.c. Defaults to a.out.
--lib Compile as library (no int main() emitted, [Library] in output).
--check Type-check only, do not write the .c file. Useful for editor checks.
--color Force ANSI color output in diagnostics.
--no-color Disable ANSI color output.
--quiet Suppress progress messages (only errors and the final report).
--verbose Print extra build info.
--version Print the version and exit.
--help, -h Print usage and exit.

Any positional argument ending in .am is treated as an input file. Unknown options error out with a usage message.

Exit codes

Code Meaning
0 Success.
1 Resolver and/or type-checker reported an error, or the CLI was misused (no input, unknown flag, etc.).

The compiler tries to make progress past resolver warnings — you'll often see a .c file generated alongside diagnostics. Treat exit status as the source of truth, not the presence of the .c file.

Multi-file compilation

Pass several .am files; the compiler merges them, runs all passes across the union, and emits a single .c file:

amc lexer.am parser.am main.am -o myapp

The first file's namespace directive determines the C symbol prefix for the whole compilation unit, so put the most authoritative file first (or make sure all files share the same namespace).

main.am's Program.Main becomes the binary's entry point. If multiple files declare Program.Main, the C compiler will reject the duplicate symbols at link time — only one entry point per executable.

Library mode

amc --lib mylib.am -o mylib
# → mylib.c (no int main, marked "[Library]")
gcc -Iruntime -c mylib.c -o mylib.o
# Link mylib.o from a host program — see chapter 5 for C interop.

Auto-detection: a file without any Program.Main is treated as a library automatically (no --lib flag needed).

amc build / run / watch (since v0.7.9)

The first-class compile verb. amc build runs amc on the entry file and invokes gcc with the right flags (runtime headers, lib/libamalgame.a, installed package facade archives, vendored package .o files, [stdlib].libs declared by each package). The result is a runnable binary — no separate gcc step.

amc build hello.am             # produces ./hello
amc build -o myapp src/main.am # explicit output
amc build -v hello.am          # verbose: prints the gcc command
amc build -g hello.am          # debug build (-O0 -g for `amc dap`)

The -g / --debug flag (v0.8.0+) swaps -O2 for -O0 -g on both the single-stage gcc link and the C++ two-stage path (DuckDB etc.). The cgen emits #line N "foo.am" directives at every statement, so DWARF carries .am filenames and line numbers — debuggers set breakpoints on .am source directly, no source maps. See amc dap in chapter 6 and the debugger workflow at the end of chapter 6.

amc run chains a build with Process.Run on the resulting binary. Args after the -- sentinel pass through to the user program's argv:

amc run hello.am               # build then run, no user args
amc run server.am -- --port 8080 --verbose

amc watch builds once, then polls the entry's mtime every 500 ms and rebuilds on change. With --run, it also re-execs the binary after each successful rebuild — handy for dev loops:

amc watch --run server.am      # rebuild + restart on save
amc watch hello.am             # rebuild only (manual ./hello to run)

v1 watches only the entry file explicitly named on the command line. Transitive imports are out of scope until the Amalgame.IO.FileWatcher package gains an event-based mode (post-D in the roadmap).

The bare-args form amc foo.am -o foo still works (emits foo.c only — no gcc step) and stays supported for the edge cases where users want to splice their own gcc command (CI cross-compile, custom flags, embedded targets).

Typical workflows

Smoke-test a single file

amc build hello.am && ./hello   # since v0.7.9
# OR the explicit two-step form
amc hello.am -o hello
gcc -Iruntime hello.c -lgc -lm -lz -o hello
./hello

Type-check on save (editor integration)

amc --check --no-color foo.am
echo $?     # 0 = OK, 1 = errors printed on stderr

Build a multi-file project

Since v0.7.9 the single-entry amc build covers most cases — amc resolves import statements transitively from the entry, so you typically only need:

amc build src/main.am          # → ./main

For older v0.7.x (or when you want explicit control over the file list), the two-step form still works:

amc \
    src/util/strings.am \
    src/util/collections.am \
    src/server/router.am \
    src/main.am \
    -o build/app

gcc -O2 -Iruntime build/app.c -lgc -lm -o build/app

Rebuild the compiler itself

./build_amc.sh        # ~5s, full self-host (runs amc on its own sources)

That script's behaviour is described in chapter 6.

Environment

The CLI is hermetic — it doesn't read environment variables. The compile-side runtime headers come from gcc -I<runtime-dir>.

Debugging the compiler

If amc produces invalid C, narrow the input by deleting half until the failure disappears, then file an issue with the minimal repro. Useful flags during triage:

For deeper internals (how the pipeline walks the AST, where to add a new builtin, how the CGen emits a feature), see chapter 7.