224 lines
8.7 KiB
Markdown
224 lines
8.7 KiB
Markdown
# 010 — Driver & CLI
|
|
|
|
- **Status:** Draft
|
|
- **Normative language:** `MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, and `MAY` are to
|
|
be interpreted as described in RFC 2119.
|
|
|
|
## 1. Purpose
|
|
|
|
libVCT splits orchestration across two layers. The driver (`vct.driver`) is the
|
|
library-level orchestrator: it takes emitted C translation units, invokes the system C
|
|
compiler, and collects object files. The CLI (`vct.cli`) is a thin wrapper that parses
|
|
command-line flags into a `Config`, drives the whole pipeline, formats diagnostics, and
|
|
sets exit codes. The CLI holds no optimizer state and adds no compilation logic of its
|
|
own.
|
|
|
|
## 2. Scope
|
|
|
|
This file specifies the driver/CLI role split, the pipeline order, the full flag
|
|
surface, the exact C compiler invocation, compiler discovery and probing, error
|
|
handling, determinism, `-mangled` mode, and object-file emission and merging. The
|
|
compiler-facing backends are specified in [008 — C Backend](008-c-backend.md) and
|
|
[009 — LLVM Backend](009-llvm-backend.md). Diagnostics, remarks, and exit codes are
|
|
specified in [011 — Diagnostics](011-diagnostics.md).
|
|
|
|
## 3. Definitions
|
|
|
|
| Term | Meaning |
|
|
|---|---|
|
|
| `Config` | One struct holding opt level, target, budgets, pass toggles, warning policy, compiler selection, and mode. |
|
|
| TU | Translation unit: one emitted C file. |
|
|
| `cc` | The discovered system C compiler. |
|
|
| APE | Actually Portable Executable, the output of cosmopolitan tooling. |
|
|
| Fat LTO object | An object that carries both native machine code and LTO bitcode. |
|
|
| Response file | A file listing arguments for a linker or compiler, referenced by `@file`. |
|
|
|
|
## 4. Model
|
|
|
|
`vct.cli` is GC-allocated and cold-path only. It converts `argv` into a `Config`, runs
|
|
the pipeline, forwards every diagnostic to the configured consumer, and returns an exit
|
|
code. `vct.driver` owns process invocation. Any embedder that has already constructed a
|
|
`Config` can call the driver directly and skip the CLI entirely.
|
|
|
|
The driver also owns the `-llvm` path, which returns textual LLVM IR and never touches
|
|
`cc`, and the `-mangled` path, which switches to the cosmopolitan toolchain.
|
|
|
|
## 5. Normative requirements
|
|
|
|
### 5.1 Role split
|
|
|
|
**R1.** `vct.cli` MUST be a thin wrapper. It MUST NOT contain optimization, lowering, or
|
|
backend logic, and it MUST NOT hold optimizer state.
|
|
|
|
**R2.** `vct.cli` MUST be a pure function from `argv` to `Config` plus pipeline
|
|
invocation. The library entry point MUST accept a `Config`; programmatic callers MUST be
|
|
able to bypass the CLI.
|
|
|
|
**R3.** `vct.driver` MUST own all invocation of the system C compiler.
|
|
|
|
**R4.** `vct.cli` MUST be GC-allocated and MUST be usable on the cold path only.
|
|
|
|
### 5.2 Pipeline
|
|
|
|
**R5.** The default pipeline order MUST be: read input, then HIR optimization if enabled,
|
|
then lowering, then VIR optimization if enabled, then the C backend, then the driver.
|
|
|
|
```
|
|
read input
|
|
-> (HIR opt if enabled)
|
|
-> lower
|
|
-> (VIR opt if enabled)
|
|
-> backend.c -> driver -> .o
|
|
```
|
|
|
|
**R6.** `-S` MUST stop after C emission and MUST NOT invoke `cc`.
|
|
|
|
**R7.** `-emit-llvm` and `-llvm` MUST stop after LLVM IR emission and MUST NOT invoke
|
|
`cc`.
|
|
|
|
### 5.3 Flag surface
|
|
|
|
**R8.** The CLI MUST accept the flags listed in Table 1.
|
|
|
|
**Table 1. v1 flag surface**
|
|
|
|
| Group | Flags | Meaning |
|
|
|---|---|---|
|
|
| Optimize | `-O0` `-O1` `-O2` `-O3` `-Ofast` `-Oz` | Optimization level. |
|
|
| Target | `-march=<arch>`, `-mcpu=<cpu>`, `-target <triple>` | Target selection; `-march`/`-mcpu` forward to `cc` as cflags. |
|
|
| Modes | `-S`, `-emit-llvm`, `-llvm`, `-mangled` | Stop point or alternate mode. |
|
|
| Toolchain | `-cc=<gcc\|clang>`, `-cflags="..."`, `-j<N>`, `-save-temps` | Compiler selection, extra flags, parallelism, temp retention. |
|
|
| LTO | `-flto[=full\|thin]`, `-ffat-lto-objects` | Link-time optimization control. |
|
|
| Debug | `-g`, `--dump-hir`, `--dump-vir`, `--verify`, `--time-passes`, `--stats` | Debug output and instrumentation. |
|
|
| Output | `-o <path>` | Output path. |
|
|
| Warnings | `-Wall`, `-Werror`, `-Wextra`, `-Wno-error[=<category>]`, `-w` | Warning policy. |
|
|
| Diagnostics | `--remarks`, `--diagnostics=json` | Remark and diagnostic channel selection. |
|
|
| Pass toggles | `-f<pass>`, `-fno-<pass>` | Enable or disable an individual pass. |
|
|
|
|
**R9.** `-Wall`, `-Werror`, and `-Wextra` MUST be on by default. A bare `-Wno-error` MUST
|
|
disable every promotion, `-Wno-error=<category>` MUST disable the promotion of that
|
|
category, and `-w` MUST silence warnings.
|
|
|
|
**R10.** `-Werror` MUST apply to the C source that libVCT generates, not only to
|
|
frontend input.
|
|
|
|
**R11.** Every pass MUST be exposed as both `-f<pass>` and `-fno-<pass>`.
|
|
|
|
### 5.4 C compiler invocation
|
|
|
|
**R12.** For each emitted TU, the driver MUST invoke the compiler as:
|
|
|
|
```
|
|
cc -std=c17 -c <tu.c> -o <tu.o> <cflags> <march> -Wall -Werror -Wextra <g> <flto>
|
|
```
|
|
|
|
where `<g>` is `-g` when debug is enabled, and `<flto>` is the LTO flag when LTO is
|
|
requested.
|
|
|
|
**R13.** The driver MUST run one compiler process per TU, with concurrency bounded by
|
|
`-j`.
|
|
|
|
**R14.** The driver MUST discover the compiler via the `$CC` environment variable first,
|
|
then by searching `PATH`, unless `-cc=<gcc|clang>` forces a selection.
|
|
|
|
**R15.** The driver MUST probe the discovered compiler's version and dialect exactly
|
|
once per run. The probed dialect MUST drive the backend's choice of pragmas and builtins
|
|
(see [008 — C Backend](008-c-backend.md)).
|
|
|
|
**R16.** The driver MUST NOT pass `-march`/`-mcpu` values to `cc` that the probed
|
|
compiler does not accept; it MUST diagnose an unsupported target value.
|
|
|
|
### 5.5 Error handling
|
|
|
|
**R17.** The driver MUST capture the compiler's stderr.
|
|
|
|
**R18.** The driver MUST use the `#line` directives emitted by the C backend (see
|
|
[008 — C Backend](008-c-backend.md)) to map C compiler errors back to VIR and frontend
|
|
source positions, then re-emit them through the diagnostics service (see
|
|
[011 — Diagnostics](011-diagnostics.md)).
|
|
|
|
**R19.** A compiler failure MUST produce a diagnostic and MUST cause a nonzero exit.
|
|
|
|
**R20.** The driver MUST NOT discard compiler diagnostics silently.
|
|
|
|
### 5.6 Determinism
|
|
|
|
**R21.** The driver MUST order TUs and flags deterministically. For a fixed `Config` and
|
|
input, the sequence of compiler invocations and their argument order MUST be identical
|
|
across runs and independent of thread count.
|
|
|
|
**R22.** The driver MUST place temporary files under a GC-managed temporary directory.
|
|
|
|
**R23.** The temporary directory MUST be cleaned up after the run unless `-save-temps`
|
|
is given.
|
|
|
|
### 5.7 `-mangled` mode
|
|
|
|
**R24.** `-mangled` MUST switch the toolchain to `cosmocc` and the cosmopolitan libc.
|
|
|
|
**R25.** `-mangled` MUST produce an Actually Portable Executable.
|
|
|
|
**R26.** `-mangled` is the one mode in which libVCT links. In every other mode libVCT
|
|
produces object files and leaves linking to the caller (see
|
|
[000 — Overview](000-overview.md)).
|
|
|
|
### 5.8 Object emission and merging
|
|
|
|
**R27.** In the default path, the driver MUST produce object files only. It MUST NOT link
|
|
a final executable.
|
|
|
|
**R28.** When a single `-o` path is requested and the module produced multiple
|
|
per-function objects, the driver MUST merge them with a relocatable link
|
|
(`ld -r -o <out> <tu>.o ...`).
|
|
|
|
**R29.** The driver MUST emit, for the caller, a recommended link line or response file
|
|
listing the produced objects and any needed libraries.
|
|
|
|
## 6. Invariants
|
|
|
|
- **I1.** A fixed `Config` and input produce byte-identical outputs and an identical
|
|
sequence of compiler invocations.
|
|
- **I2.** `vct.cli` holds no optimizer state.
|
|
- **I3.** The `-llvm` path never spawns `cc`.
|
|
- **I4.** The temporary directory is removed unless `-save-temps` is set.
|
|
- **I5.** Flag assembly order is stable.
|
|
- **I6.** Every captured compiler error is re-emitted through the diagnostics service.
|
|
- **I7.** `-mangled` is the only mode that links.
|
|
|
|
## 7. Examples
|
|
|
|
Default compile of a single source to an object:
|
|
|
|
```
|
|
vct -O2 -march=native -cc=clang -j8 -o out.o input.vir
|
|
```
|
|
|
|
Stop after emitting C, without invoking `cc`:
|
|
|
|
```
|
|
vct -O2 -S -o out.c input.vir
|
|
```
|
|
|
|
Emit textual LLVM IR instead of C:
|
|
|
|
```
|
|
vct -O3 -emit-llvm -target x86_64-unknown-linux-gnu -o out.ll input.vir
|
|
```
|
|
|
|
Produce a portable executable:
|
|
|
|
```
|
|
vct -O2 -mangled -o app.com input.vir
|
|
```
|
|
|
|
## 8. Cross-references
|
|
|
|
- [000 — Overview](000-overview.md) for determinism and the no-linking rule.
|
|
- [001 — Architecture](001-architecture.md) for module boundaries.
|
|
- [002 — Traits](002-traits.md) for the trait vocabulary.
|
|
- [007 — VIR Optimizer](007-vir-optimizer.md) for pass toggles and the pipeline.
|
|
- [008 — C Backend](008-c-backend.md) for `#line` and compiler dialect use.
|
|
- [009 — LLVM Backend](009-llvm-backend.md) for `-target` and the `-llvm` path.
|
|
- [011 — Diagnostics](011-diagnostics.md) for diagnostics, remarks, and exit codes.
|
|
- [013 — Build & Packaging](013-build-packaging.md) for `Config` and the C API.
|