use std::path::PathBuf;
use clap::{Parser, ValueEnum};
use crate::merge::MergeStrategy;
pub fn verbose_log_level(verbose: u8) -> Option<tracing::Level> {
match verbose {
0 => None,
1 => Some(tracing::Level::WARN),
2 => Some(tracing::Level::INFO),
3 => Some(tracing::Level::DEBUG),
_ => Some(tracing::Level::TRACE),
}
}
#[derive(clap::Args, Debug)]
pub struct WrapperOptions {
#[arg(
long = "rllvm-verbose",
num_args = 0..=1,
require_equals = true,
default_missing_value = "1",
default_value = "0"
)]
pub verbose: u8,
#[arg(long = "rllvm-help", action = clap::ArgAction::Help)]
pub rllvm_help: Option<bool>,
#[arg(long = "rllvm-version", action = clap::ArgAction::Version)]
pub rllvm_version: Option<bool>,
}
#[derive(Parser, Debug)]
#[command(
about = "Execute the wrapped clang compiler",
long_about = None,
author = "Shengtuo Hu <h1994st@gmail.com>",
version,
disable_help_flag = true,
disable_version_flag = true
)]
pub struct ClangWrapperArgs {
#[arg(long = "rllvm-compiler")]
pub compiler: Option<PathBuf>,
#[command(flatten)]
pub common: WrapperOptions,
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
pub clang_args: Vec<String>,
}
#[derive(Parser, Debug)]
#[command(
name = "rllvm-get-bc",
about = "Extract a single bitcode file for the given input",
author = "Shengtuo Hu <h1994st@gmail.com>",
version
)]
pub struct ExtractionArgs {
pub input: PathBuf,
#[arg(short = 'o', long)]
pub output: Option<PathBuf>,
#[arg(short = 'b', long)]
pub build_bitcode_archive: bool,
#[arg(long, value_enum)]
pub merge_strategy: Option<MergeStrategy>,
#[arg(short = 'm', long)]
pub save_manifest: bool,
#[arg(long)]
pub bitcode_root: Option<PathBuf>,
#[arg(short = 'v', long, action = clap::ArgAction::Count)]
pub verbose: u8,
}
#[derive(Parser, Debug)]
#[command(
name = "rllvm-init",
about = "Auto-detect LLVM installation and generate rllvm configuration",
author = "Shengtuo Hu <h1994st@gmail.com>",
version
)]
pub struct InitArgs {
#[arg(short = 'o', long)]
pub output: Option<String>,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub llvm_prefix: Option<PathBuf>,
}
#[derive(Parser, Debug)]
#[command(
name = "rllvm-info",
about = "Display information about LLVM bitcode files",
author = "Shengtuo Hu <h1994st@gmail.com>",
version
)]
pub struct InfoArgs {
pub input: PathBuf,
#[arg(short = 'f', long)]
pub functions: bool,
}
#[derive(Parser, Debug)]
#[command(
name = "rllvm-rustc",
about = "Execute the wrapped rustc compiler",
long_about = None,
author = "Shengtuo Hu <h1994st@gmail.com>",
version,
disable_help_flag = true,
disable_version_flag = true
)]
pub struct RustcWrapperArgs {
#[command(flatten)]
pub common: WrapperOptions,
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
pub rustc_args: Vec<String>,
}
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum BinName {
Cc,
Cxx,
GetBc,
Init,
Info,
Rustc,
Completions,
}
#[derive(Parser, Debug)]
#[command(
name = "rllvm-completions",
about = "Generate shell completions for rllvm tools",
author = "Shengtuo Hu <h1994st@gmail.com>",
version
)]
pub struct CompletionArgs {
#[arg(long, value_enum)]
pub shell: clap_complete::Shell,
#[arg(long, value_enum, default_value = "cc")]
pub bin: BinName,
}
#[cfg(test)]
mod tests {
use super::*;
use clap::CommandFactory;
#[test]
fn every_wrapper_option_is_long_and_rllvm_prefixed() {
for command in [ClangWrapperArgs::command(), RustcWrapperArgs::command()] {
for arg in command.get_arguments() {
assert!(
arg.get_short().is_none(),
"`-{}` would be taken from the compiler: {arg:?}",
arg.get_short().unwrap()
);
if let Some(long) = arg.get_long() {
assert!(
long.starts_with("rllvm-"),
"`--{long}` collides with the compiler's own options"
);
}
}
}
}
#[test]
fn the_wrapper_claims_neither_help_nor_version() {
let command = ClangWrapperArgs::command();
for reserved in ["help", "version"] {
assert!(
command
.get_arguments()
.all(|arg| arg.get_long() != Some(reserved)),
"`--{reserved}` must reach the compiler"
);
}
}
#[test]
fn extraction_exposes_every_documented_option() {
let command = ExtractionArgs::command();
let longs: Vec<_> = command
.get_arguments()
.filter_map(|arg| arg.get_long())
.collect();
for expected in [
"output",
"build-bitcode-archive",
"merge-strategy",
"save-manifest",
"bitcode-root",
"verbose",
] {
assert!(
longs.contains(&expected),
"--{expected} missing from {longs:?}"
);
}
}
}