Files
flux/fluxc/src/cli.rs
Jooris Hadeler f836f279de Feat: add -S flag to emit LLVM IR
`-S` stops the pipeline after IR emission and writes the `.ll` file
directly to the output path (default `<stem>.ll`). It implies `-c`
(no main required). Combined with `-o`, the IR goes to the specified
path.

Pipeline summary:
  (none)  →  emit → opt → llc → cc  →  executable
  -c      →  emit → opt → llc       →  <stem>.o
  -S      →  emit                   →  <stem>.ll

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 20:28:24 +01:00

117 lines
3.6 KiB
Rust

use std::process;
use yansi::Paint as _;
// ── Help ───────────────────────────────────────────────────────────────────────
pub fn print_help() {
println!(
"{} {} — the Flux language compiler\n",
"fluxc".bold(),
env!("CARGO_PKG_VERSION").dim(),
);
println!("{}", "USAGE:".bold().yellow());
println!(" fluxc [OPTIONS] <file> [<file> ...]\n");
println!("{}", "OPTIONS:".bold().yellow());
println!(
" {}, {} Print this help message",
"-h".bold(),
"--help".bold(),
);
println!(
" {}, {} Print version information",
"-V".bold(),
"--version".bold(),
);
println!(
" {} Compile to object file (no `main` required, no linking)",
"-c".bold(),
);
println!(
" {} Emit LLVM IR and stop (implies `-c`)",
"-S".bold(),
);
println!(
" {} {} Write output to <file>",
"-o".bold(),
"<file>".bold(),
);
println!();
println!("{}", "ARGS:".bold().yellow());
println!(
" {} One or more Flux source files to compile",
"<file>".bold(),
);
}
pub fn print_version() {
println!("fluxc {}", env!("CARGO_PKG_VERSION"));
}
// ── Error helpers ─────────────────────────────────────────────────────────────
pub fn fatal(msg: &str) -> ! {
eprintln!("{}: {}", "error".bold().red(), msg.bold());
eprintln!(" {} fluxc --help", "hint:".bold().cyan());
process::exit(1);
}
pub fn io_error(path: &str, err: std::io::Error) -> ! {
eprintln!(
"{}: cannot read {}: {}",
"error".bold().red(),
path.bold(),
err,
);
process::exit(1);
}
// ── Argument parsing ──────────────────────────────────────────────────────────
pub struct Opts {
pub files: Vec<String>,
/// `-c`: compile to object file without requiring a `main` entry point.
pub no_main: bool,
/// `-S`: emit LLVM IR text and stop (implies `-c`).
pub emit_ir: bool,
/// `-o <file>`: write final output to this path.
pub output: Option<String>,
}
pub fn parse_args() -> Opts {
let mut files = Vec::new();
let mut no_main = false;
let mut emit_ir = false;
let mut output: Option<String> = None;
let mut args = std::env::args().skip(1).peekable();
while let Some(arg) = args.next() {
match arg.as_str() {
"-h" | "--help" => {
print_help();
process::exit(0);
}
"-V" | "--version" => {
print_version();
process::exit(0);
}
"-c" => no_main = true,
"-S" => { emit_ir = true; no_main = true; }
"-o" => match args.next() {
Some(path) => output = Some(path),
None => fatal("option `-o` requires an argument"),
},
flag if flag.starts_with('-') => {
fatal(&format!("unknown option `{flag}`"));
}
path => files.push(path.to_owned()),
}
}
if files.is_empty() {
fatal("no input files — at least one source file is required");
}
Opts { files, no_main, emit_ir, output }
}