diff -r 7544a7d7c819 -r 6a3dc15b78b9 tools/corrosion/generator/src/subcommands/gen_cmake.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/corrosion/generator/src/subcommands/gen_cmake.rs Wed Aug 28 15:31:51 2024 +0200 @@ -0,0 +1,160 @@ +use std::{ + fs::{create_dir_all, File}, + io::{stdout, Write}, + path::Path, + rc::Rc, +}; + +use clap::{App, Arg, ArgMatches, SubCommand}; + +mod target; + +// Command name +pub const GEN_CMAKE: &str = "gen-cmake"; + +// Options +const OUT_FILE: &str = "out-file"; +const CONFIGURATION_ROOT: &str = "configuration-root"; +const CRATES: &str = "crates"; +const IMPORTED_CRATES: &str = "imported-crates"; +const CRATE_TYPE: &str = "crate-type"; +const PASSTHROUGH_ADD_CARGO_BUILD: &str = "passthrough-acb"; + +pub fn subcommand() -> App<'static, 'static> { + SubCommand::with_name(GEN_CMAKE) + .arg( + Arg::with_name(CONFIGURATION_ROOT) + .long("configuration-root") + .value_name("DIRECTORY") + .takes_value(true) + .help( + "Specifies a root directory for configuration folders. E.g. Win32 \ + in VS Generator.", + ), + ) + .arg( + Arg::with_name(CRATES) + .long("crates") + .value_name("crates") + .takes_value(true) + .multiple(true) + .require_delimiter(true) + .help("Specifies which crates of the workspace to import"), + ) + .arg( + Arg::with_name(CRATE_TYPE) + .long(CRATE_TYPE) + .value_name("kind") + .possible_values(&["staticlib", "cdylib", "bin"]) + .multiple(true) + .value_delimiter(";") + .help("Only import the specified crate types") + ) + .arg( + Arg::with_name(OUT_FILE) + .short("o") + .long("out-file") + .value_name("FILE") + .help("Output CMake file name. Defaults to stdout."), + ) + .arg( + Arg::with_name(IMPORTED_CRATES) + .long(IMPORTED_CRATES) + .value_name("variable_name") + .takes_value(true) + .help("Save a list of the imported target names into c CMake variable with the given name"), + ) + .arg( + Arg::with_name(PASSTHROUGH_ADD_CARGO_BUILD) + .long(PASSTHROUGH_ADD_CARGO_BUILD) + .takes_value(true) + .multiple(true) + .value_delimiter(std::char::from_u32(0x1f).unwrap().to_string().as_str()) + .help("Passthrough arguments to the _add_cargo_build invocation(s) in CMake") + ) +} + +pub fn invoke( + args: &crate::GeneratorSharedArgs, + matches: &ArgMatches, +) -> Result<(), Box> { + let mut out_file: Box = if let Some(path) = matches.value_of(OUT_FILE) { + let path = Path::new(path); + if let Some(parent) = path.parent() { + create_dir_all(parent).expect("Failed to create directory!"); + } + let file = File::create(path).expect("Unable to open out-file!"); + Box::new(file) + } else { + Box::new(stdout()) + }; + + writeln!( + out_file, + "\ +cmake_minimum_required(VERSION 3.15) +" + )?; + + let crates = matches + .values_of(CRATES) + .map_or(Vec::new(), |c| c.collect()); + let crate_kinds: Option> = matches.values_of(CRATE_TYPE).map(|c| c.collect()); + let workspace_manifest_path = Rc::new(args.manifest_path.clone()); + let targets: Vec<_> = args + .metadata + .packages + .iter() + .filter(|p| { + args.metadata.workspace_members.contains(&p.id) + && (crates.is_empty() || crates.contains(&p.name.as_str())) + }) + .cloned() + .map(Rc::new) + .flat_map(|package| { + package + .targets + .iter() + .filter_map(|t| { + target::CargoTarget::from_metadata( + package.clone(), + t.clone(), + workspace_manifest_path.clone(), + &crate_kinds, + ) + }) + .collect::>() + }) + .collect(); + + let passthrough_args: Vec = matches + .values_of(PASSTHROUGH_ADD_CARGO_BUILD) + .map(|values| { + // Add quotes around each argument for CMake to preserve which arguments belong together. + values + .filter(|val| !val.is_empty()) + .map(|val| format!("\"{}\"", val)) + .collect() + }) + .unwrap_or_default(); + let passthrough_str = passthrough_args.join(" "); + + for target in &targets { + target + .emit_cmake_target(&mut out_file, &passthrough_str) + .unwrap(); + } + if let Some(imported_crate_list_name) = matches.value_of(IMPORTED_CRATES) { + let imported_targets: Vec<_> = targets.iter().map(|target| target.target_name()).collect(); + let imported_targets_list = imported_targets.join(";"); + writeln!( + out_file, + "set({} \"{}\")", + imported_crate_list_name, imported_targets_list + )?; + } + + writeln!(out_file)?; + + std::process::exit(0); +}