diff --git a/gen/cmd/src/app.rs b/gen/cmd/src/app.rs index 939bb446..152f11ad 100644 --- a/gen/cmd/src/app.rs +++ b/gen/cmd/src/app.rs @@ -65,18 +65,25 @@ pub(super) fn from_args() -> Opt { .unwrap_or_default() .map(str::to_owned) .collect(); - let output = match matches.value_of_os(OUTPUT) { - None => Output::Stdout, - Some(path) if path == "-" => Output::Stdout, - Some(path) => Output::File(PathBuf::from(path)), - }; + + let mut outputs = Vec::new(); + for path in matches.values_of_os(OUTPUT).unwrap_or_default() { + outputs.push(if path == "-" { + Output::Stdout + } else { + Output::File(PathBuf::from(path)) + }); + } + if outputs.is_empty() { + outputs.push(Output::Stdout); + } Opt { input, cxx_impl_annotations, header, include, - output, + outputs, } } @@ -142,6 +149,7 @@ not specified. .long(OUTPUT) .short("o") .takes_value(true) + .multiple(true) .validator_os(validate_utf8) .help(HELP) } diff --git a/gen/cmd/src/main.rs b/gen/cmd/src/main.rs index 12e173ec..f0fd9b44 100644 --- a/gen/cmd/src/main.rs +++ b/gen/cmd/src/main.rs @@ -25,7 +25,7 @@ struct Opt { header: bool, cxx_impl_annotations: Option, include: Vec, - output: Output, + outputs: Vec, } fn main() { @@ -35,35 +35,54 @@ fn main() { } } +enum Kind { + GeneratedHeader, + GeneratedImplementation, + Header, +} + fn try_main() -> Result<()> { let opt = app::from_args(); - let gen_header = opt.header || opt.output.ends_with(".h"); + let mut outputs = Vec::new(); + let mut gen_header = false; + let mut gen_implementation = false; + for output in opt.outputs { + let kind = if opt.input.is_none() { + Kind::Header + } else if opt.header || output.ends_with(".h") { + gen_header = true; + Kind::GeneratedHeader + } else { + gen_implementation = true; + Kind::GeneratedImplementation + }; + outputs.push((output, kind)); + } let gen = gen::Opt { include: opt.include, cxx_impl_annotations: opt.cxx_impl_annotations, gen_header, - gen_implementation: !gen_header, + gen_implementation, }; - let content; - let content = match (opt.input, gen_header) { - (Some(input), true) => { - content = gen::generate_from_path(&input, &gen).header; - content.as_slice() - } - (Some(input), false) => { - content = gen::generate_from_path(&input, &gen).implementation; - content.as_slice() - } - (None, true) => include::HEADER.as_bytes(), - (None, false) => unreachable!(), // enforced by required_unless + let generated_code = if let Some(input) = opt.input { + gen::generate_from_path(&input, &gen) + } else { + Default::default() }; - match opt.output { - Output::Stdout => drop(io::stdout().write_all(content)), - Output::File(path) => fs::write(path, content)?, + for (output, kind) in outputs { + let content = match kind { + Kind::GeneratedHeader => &generated_code.header, + Kind::GeneratedImplementation => &generated_code.implementation, + Kind::Header => include::HEADER.as_bytes(), + }; + match output { + Output::Stdout => drop(io::stdout().write_all(content)), + Output::File(path) => fs::write(path, content)?, + } } Ok(()) diff --git a/gen/cmd/src/test.rs b/gen/cmd/src/test.rs index 2e85fac9..17023e4d 100644 --- a/gen/cmd/src/test.rs +++ b/gen/cmd/src/test.rs @@ -32,7 +32,7 @@ OPTIONS: parse or even require the given paths to exist; they simply go into the generated C++ code as #include lines. \x20 - -o, --output + -o, --output ... Path of file to write as output. Output goes to stdout if -o is not specified. \x20 diff --git a/gen/src/mod.rs b/gen/src/mod.rs index 9578fe86..85227152 100644 --- a/gen/src/mod.rs +++ b/gen/src/mod.rs @@ -50,6 +50,7 @@ pub struct Opt { } /// Results of code generation. +#[derive(Default)] pub struct GeneratedCode { /// The bytes of a C++ header file. pub header: Vec,