`-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>
117 lines
3.6 KiB
Rust
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 }
|
|
}
|