Menu

Command reference

Every manticore command, its options and exit codes. The text under each command is the declared help (manticore <command> --help); tests/cli/help.txt pins it.

Invocation#

manticore <command> [options...]

Commands#

CommandSummary
compileCompile to a native binary (-o <out>); analyzes by default (--no-analyze skips, --analyze-strict gates on errors)
buildBuild all targets from a manticore.json manifest (libraries + applications)
analyzeStatic type analysis; report diagnostics, no codegen
dump-llvmRead PHP source from stdin, emit LLVM IR on stdout
dump-astParse PHP source and print the resulting AST
dump-mirParse PHP, lower to MIR, print the typed IR
dump-llvm-mirParse PHP, run MIR pipeline + EmitLlvm, print LLVM IR
dump-sigParse PHP, print the module-interface .sig (exported symbol table)
split-irSplit a staged .ll module into N part files (dev tool)
versionPrint compiler version
upgradeUpdate the installed compiler to the latest release (--check only reports)
doctorCheck that this compiler and its toolchain work; exit 1 on a failure
completionsPrint a shell completion script (bash, zsh or fish)

compile#

manticore compile [options] <files…|manifest.json> -o <out>
OptionArgumentMeaning
-o<path>Output path (default a.out)
--memory<mode>Memory mode: rc|arena|hybrid (default: $MANTICORE_MEMORY)
--backend<name>Codegen backend override
-O<level>Optimisation level: 0|1|2|3|s|z (default 2)
--preludedump-*: include the prelude in the dump
--effectsdump-mir: show inferred effects
--emit-libraryEmit a library object instead of an executable
--runtimeWith --emit-library: this library is the bundled stdlib
--allow-undefined-trapsDo not refuse a library that contains undefined-function traps
--keep-irKeep the intermediate .ll files
-j<n>Parallel clang jobs; 0 = one per core
--analyzeRun the analyzer (default)
--no-analyzeSkip the analyzer
--analyze-strictFail with rc 65 on analyzer errors
--progress<mode>Progress output: auto|live|plain|json|off (default auto)
--quietSilence progress and timings (diagnostics stay)
--timingsPrint a per-stage time table at the end
--color<when>Colour: auto|always|never (default auto)

Exit codes:

CodeMeaning
0binary written
64usage error: unknown flag, missing value, bad --progress / --color value
65front end failed (parse / type check / empty IR), or --analyze-strict found errors
66no input read: source missing or the source list is empty
73--emit-library: cannot write the .ll file
75clang failed (object, or library with --emit-library)
76cc link failed
manticore compile hello.php -o hello && ./hello
manticore compile src/ -o app -O2 -j 0

build#

manticore build [options] <manticore.json>

Takes the compile options above (except --analyze, --analyze-strict) plus:

OptionArgumentMeaning
--libs-onlyBuild library targets and stop (cold seed)
--apps-onlyBuild application targets only
--no-analyzeAccepted for compile parity; build does not run the analyzer

--libs-only and --apps-only are mutually exclusive (64). Exit codes: 0 ok; 64 usage; 65 manifest conflict between targets (e.g. a class defined in two libraries); 66 manifest, entry point or target sources cannot be read, or an unknown extension is wanted; 75 clang failed; 76 link failed. Manifest format: modules.md.

manticore build manticore.json --timings

analyze#

manticore analyze [options] [paths…]

Takes the shared options -o, --memory, --backend, -O, --prelude, --effects, --emit-library, --runtime, --allow-undefined-traps, --keep-ir, -j (declared for parity, as in the help) plus:

OptionArgumentMeaning
--deepAlso run the compiler's MIR type passes (heavier)
--jsonMachine-readable output
--baseline<path>Suppress findings listed in this baseline file
--generate-baseline<path>Write a baseline file from current findings
--only<prefixes>Keep only diagnostic codes starting with these prefixes (comma list); gates on any survivor

Exit codes: 0 no error-severity findings (with --only: no surviving finding); 1 an error finding (with --only: any surviving finding); 64 usage; 73 cannot write the --generate-baseline file.

manticore analyze src --only undefined.,parse.error

dump-* and split-ir#

dump-llvm, dump-ast, dump-mir, dump-llvm-mir and dump-sig take [options] [files…] and the same shared options as compile up to -j (--prelude and --effects are the ones that matter here). dump-llvm reads PHP from stdin. They print to stdout.

Exit codes: 0 ok; 64 usage; 66 input cannot be read; 65 the stage failed.

The dump-* commands do not link the stdlib: a call into it resolves as unknown, and a bug in that path can vanish from the dump. Read the final binary when that matters.

manticore dump-mir --effects prog.php | less

split-ir is a dev tool:

manticore split-ir <module.ll> <parts> <outbase>

Exit codes: 0 ok; 64 usage; 66 module unreadable; 65 split failed.

version, upgrade#

manticore version [--check]
manticore upgrade [--check] [--version X]

version prints manticore <X.Y.Z>.

OptionArgumentMeaning
--checkReport installed and latest version; change nothing. Exit 1 if an update exists, 2 on error (version --check is the same as upgrade --check)
--version<X>(upgrade) Install this release instead of the latest

--check prints installed A / latest B followed by update available, up to date or installed is newer. Exit codes of --check: 0 current (or newer), 1 update available, 2 cannot check.

upgrade without --check runs the installed install.sh ($MANTICORE_HOME/share/install.sh) with MANTICORE_STRICT=1:

Foreign installs. upgrade and version --check refuse to touch a compiler that install.sh did not install (no share/install.sh beside bin/). They print which installer owns it (Homebrew, a system package manager, the container image, or "an unknown installer"), say nothing was changed, and exit 2.

install.sh in strict mode (MANTICORE_STRICT=1, which upgrade sets): a miss is fatal and never falls back to a source build. Exit codes:

CodeMeaning
2network / release lookup failed
3no published build for this platform
4checksum mismatch
5failure after the swap (the previous install is rolled back if the swap was this run's)

install.sh --check prints latest=<ver> and platform=<os>-<arch> and installs nothing. Install methods: install.md.

doctor#

manticore doctor [--offline] [--no-smoke]
OptionMeaning
--offlineSkip the update check
--no-smokeSkip compiling and running a hello-world

Prints one line per check, [ OK ], [WARN] or [FAIL], then N ok, N warnings, N failures. A hint line follows every non-OK result that has one. Exit 1 if any check failed, else 0; warnings never fail.

CheckOKWARNFAIL
compileralways: manticore <version> and its directory
installinstalled by install.shnot installed by it (names the owner)
clangfound, version >= 15missing, version unparsable, or < 15
ccfound on PATHmissing
stdlib objectlib/manticore_stdlib.o foundnot found
stdlib signaturelib/manticore_stdlib.o.sig foundnot found
preludeprelude sources foundnot found
pcre2pcre2-config --version answersnot found
pkg-configpresentmissing (openssl / zlib are then not probed)
openssl, zlibpkg-config --modversion answersnot found
smoke testcompiled and ran a hello-worldcompile or run failed (last 3 log lines shown)
updateup to date, or skipped (--offline, or not managed by install.sh)update available, or latest unknown

completions#

manticore completions <bash|zsh|fish>

Prints the script to stdout. Any other argument prints completions: expected one of bash, zsh, fish and exits 64.

manticore completions bash > ~/.local/share/bash-completion/completions/manticore
manticore completions zsh  > ~/.zfunc/_manticore     # ~/.zfunc must be in fpath before compinit
manticore completions fish > ~/.config/fish/completions/manticore.fish

The scripts are generated from the command and option declarations, so they match the installed compiler; regenerate them after an upgrade.

Build progress#

compile and build report progress on stderr only; stdout is never touched.

Mode (--progress)Output
liveone line redrawn in place (● EmitLlvm 1.2s (total 4.0s) · functions 512/1881), ends with ✓ done in 7.1s (✗ failed after …)
plainone line per finished stage, a label n/n line when a counter completes, a final done in … / failed after …
jsonone JSON object per line
offnothing
autothe default, see below

auto: with --quiet, off. Otherwise live when stderr is a terminal; plain when it is not but CI is set to a non-empty value; off otherwise, so piped builds stay silent. --quiet silences progress and timings; diagnostics are still printed. --timings appends the 15 slowest stages, longest first.

Counters: files, functions and, for a split build (MANTICORE_SPLIT_JOBS with -j 0), clang (parts compiled so far / total, cache hits included).

Colour is on only if every rule passes, first match wins: --color=never off; NO_COLOR set and non-empty off; TERM=dumb off; --color=always on; otherwise on exactly when stderr is a terminal. json is never coloured; plain is coloured only with --color=always.

plain (manticore compile h.php -o h --progress=plain, middle of the list elided):

      files 1/1
[ 1] stdlib .sig -> extern decls  0.0s
[ 2] prelude-demand (re-lex)  0.0s
[ 3] parse  0.0s
[ 4] prelude read (all files)  0.0s
[ 5] LowerFromAst  0.0s
…
[33] property scan  0.0s
      functions 1887/1887
[34] emit preamble  0.0s
[35] hoist allocas  0.0s
[36] prune IR  0.0s
[37] EmitLlvm  0.0s
[38] clang -O2 -c whole module  0.2s
[39] link  0.0s
done in 0.7s

json events (--progress=json --timings):

eventFields
stage_startname, t_ms (since start)
stage_endname, ms; fns, classes only when known
counterlabel, done, total
donems, rc
timingname, ms (only with --timings, after done)
{"event":"counter","label":"files","done":1,"total":1}
{"event":"stage_start","name":"stdlib .sig -> extern decls","t_ms":119}
{"event":"stage_end","name":"stdlib .sig -> extern decls","ms":6,"fns":1820}
{"event":"stage_start","name":"prelude-demand (re-lex)","t_ms":126}
{"event":"stage_end","name":"prelude-demand (re-lex)","ms":0}
…
{"event":"timing","name":"InferTypes #3","ms":4}

--timings in plain:

done in 0.7s
timings (longest first):
     298ms  clang -O2 -c whole module
      49ms  link
      28ms  EmitLlvm
…

Environment#

VariableEffect
MANTICORE_HOMEInstall prefix used by install.sh (default ~/.manticore); upgrade passes the running compiler's prefix. Also the base of the default object-cache directory ($MANTICORE_HOME/cache/obj)
MANTICORE_VERSIONinstall.sh: install this release instead of the latest (upgrade --version sets it)
MANTICORE_STRICTinstall.sh: 1 makes a miss fatal with exit 2/3/4/5; upgrade sets it
MANTICORE_MEMORYDefault for --memory (rc|arena|hybrid)
MANTICORE_SPLIT_JOBSForce a split build with this many clang jobs (capped at 64); the README pairs it with -j 0
MANTICORE_OBJ_CACHEContent-addressed object cache: on by default for split builds, off for a single unit unless 1; 0 disables it everywhere
MANTICORE_OBJ_CACHE_DIR, MANTICORE_OBJ_CACHE_MAX_MBCache directory and size bound (default 2048 MB)
MANTICORE_STATSNon-empty and not 0: full compile-time profile on stderr; progress auto then picks plain on a TTY or under CI, else off
MANTICORE_PHASE_TRACENon-empty and not 0: per-phase timeline only
CINon-empty: --progress=auto picks plain when stderr is not a terminal
NO_COLORNon-empty: progress colour off, even with --color=always
TERMdumb: progress colour off

See also#

Edit this page on GitHub