diff --git a/CHANGELOG.md b/CHANGELOG.md index 76e18d5c1b..6fd62155af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -215,6 +215,7 @@ -------------------------------------------------------------------------------- # Unreleased ## Added +- Add support for a configuration file in the TOML format. ## Changed ## Removed ## Fixed diff --git a/Cargo.lock b/Cargo.lock index 8fea3f5b5e..2d86c44491 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,8 +36,9 @@ dependencies = [ "quote", "regex", "rustc-hash", + "serde", "shlex", - "syn 2.0.18", + "syn 2.0.76", ] [[package]] @@ -49,7 +50,9 @@ dependencies = [ "clap_complete", "env_logger 0.10.0", "log", + "serde", "shlex", + "toml", ] [[package]] @@ -69,10 +72,12 @@ dependencies = [ "clap_complete", "owo-colors", "prettyplease", + "serde", "shlex", "similar", - "syn 2.0.18", + "syn 2.0.76", "tempfile", + "toml", ] [[package]] @@ -86,6 +91,9 @@ name = "bitflags" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" +dependencies = [ + "serde", +] [[package]] name = "block" @@ -200,6 +208,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -247,6 +261,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.4.0" @@ -265,6 +285,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "instant" version = "0.1.12" @@ -401,7 +431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43ded2b5b204571f065ab8540367d738dfe1b3606ab9eb669dcfb5e7a3a07501" dependencies = [ "proc-macro2", - "syn 2.0.18", + "syn 2.0.76", ] [[package]] @@ -430,9 +460,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -459,9 +489,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -530,6 +560,35 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "serde" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.209" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.3.0" @@ -561,9 +620,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -601,6 +660,40 @@ dependencies = [ "objc", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.6" @@ -803,6 +896,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "yansi-term" version = "0.1.2" diff --git a/bindgen-cli/Cargo.toml b/bindgen-cli/Cargo.toml index 6fc02f3a55..21077753a3 100644 --- a/bindgen-cli/Cargo.toml +++ b/bindgen-cli/Cargo.toml @@ -25,7 +25,9 @@ clap = { version = "4", features = ["derive"] } clap_complete = "4" env_logger = { version = "0.10.0", optional = true } log = { version = "0.4", optional = true } +serde = { version = "1.0.209", features = ["derive"] } shlex = "1" +toml = "0.8.19" [features] default = ["logging", "runtime"] diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index cd5e9bb127..7809eb9284 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -5,7 +5,8 @@ use bindgen::{ RegexSet, RustTarget, DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS, }; use clap::error::{Error, ErrorKind}; -use clap::{CommandFactory, Parser}; +use clap::{CommandFactory, FromArgMatches, Parser}; +use serde::{Deserialize, Serialize}; use std::fs::File; use std::io; use std::path::{Path, PathBuf}; @@ -87,15 +88,31 @@ fn parse_custom_derive( Ok((derives, regex.to_owned())) } -#[derive(Parser, Debug)] +#[derive(Parser, Debug, Serialize, Deserialize, Default)] #[clap( about = "Generates Rust bindings from C/C++ headers.", override_usage = "bindgen
-- ...", trailing_var_arg = true )] +#[serde(default)] struct BindgenCommand { /// C or C++ header file. + #[serde(skip)] header: Option, + /// Path for the configuration file. If the path is not provided, the `bindgen.toml` file in + /// the current directory will be used by default. + #[arg(long)] + #[serde(skip)] + config_path: Option, + #[serde(skip)] + #[arg(long)] + /// Dump the passed configuration into stdout in TOML format. + dump_config: bool, + #[serde(skip)] + #[arg(long)] + /// Ignore any configuration file, including the default `bindgen.toml` in the current + /// directory. + ignore_config_file: bool, /// Path to write depfile to. #[arg(long)] depfile: Option, @@ -316,9 +333,11 @@ struct BindgenCommand { allowlist_item: Vec, /// Print verbose error messages. #[arg(long)] + #[serde(skip)] verbose: bool, /// Preprocess and dump the input header files to disk. Useful when debugging bindgen, using C-Reduce, or when filing issues. The resulting file will be named something like `__bindgen.i` or `__bindgen.ii`. #[arg(long)] + #[serde(skip)] dump_preprocessed_input: bool, /// Do not record matching items in the regex sets. This disables reporting of unused items. #[arg(long)] @@ -444,12 +463,14 @@ struct BindgenCommand { emit_diagnostics: bool, /// Generates completions for the specified SHELL, sends them to `stdout` and exits. #[arg(long, value_name = "SHELL")] + #[serde(skip)] generate_shell_completions: Option, /// Enables experimental features. #[arg(long)] experimental: bool, /// Prints the version, and exits #[arg(short = 'V', long)] + #[serde(skip)] version: bool, /// Arguments to be passed straight through to clang. clang_args: Vec, @@ -462,10 +483,56 @@ pub fn builder_from_flags( where I: Iterator, { - let command = BindgenCommand::parse_from(args); + let command = { + let mut matches = BindgenCommand::command().get_matches_from(args); + + let ignore_config_file = matches + .get_one::("ignore_config_file") + .copied() + .unwrap_or_default(); + + let res = if ignore_config_file { + BindgenCommand::from_arg_matches_mut(&mut matches) + } else { + let config_path = match matches.get_one::("config_path") { + Some(path) => path.into(), + None => { + let mut cwd = std::env::current_dir()?; + cwd.push("bindgen.toml"); + cwd + } + }; + + if config_path.try_exists()? { + let contents = std::fs::read_to_string(config_path)?; + let mut command = toml::from_str::(&contents) + .map_err(|err| { + io::Error::new(io::ErrorKind::Other, err) + })?; + + command + .update_from_arg_matches_mut(&mut matches) + .map(|()| command) + } else { + BindgenCommand::from_arg_matches_mut(&mut matches) + } + }; + + res.unwrap_or_else(|err| err.exit()) + }; + + if command.dump_config { + let contents = toml::to_string_pretty(&command) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + println!("{}", contents); + exit(0); + } let BindgenCommand { header, + config_path: _, + ignore_config_file: _, + dump_config: _, depfile, default_enum_style, bitfield_enum, diff --git a/bindgen-tests/Cargo.toml b/bindgen-tests/Cargo.toml index a253b349b9..a2062a9dc7 100644 --- a/bindgen-tests/Cargo.toml +++ b/bindgen-tests/Cargo.toml @@ -23,3 +23,7 @@ runtime = ["bindgen/runtime"] __testing_only_extra_assertions = ["bindgen/__testing_only_extra_assertions"] __testing_only_libclang_9 = ["bindgen/__testing_only_libclang_9"] __testing_only_libclang_16 = ["bindgen/__testing_only_libclang_16"] + +[dependencies] +serde = { version = "1.0.209", features = ["derive"] } +toml = "0.8.19" diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml index 9eddd5157d..bd983a4bf3 100644 --- a/bindgen/Cargo.toml +++ b/bindgen/Cargo.toml @@ -36,6 +36,7 @@ proc-macro2 = { version = "1", default-features = false } quote = { version = "1", default-features = false } regex = { version = "1.5.3", default-features = false, features = ["std", "unicode-perl"] } rustc-hash = "1.0.1" +serde = { version = "1.0.209", features = ["derive"], optional = true } shlex = "1" syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] } @@ -51,7 +52,7 @@ experimental = ["dep:annotate-snippets"] ## The following features are for internal use and they shouldn't be used if ## you're not hacking on bindgen # Features used by `bindgen-cli` -__cli = [] +__cli = ["dep:serde", "bitflags/serde"] # Features used for CI testing __testing_only_extra_assertions = [] __testing_only_libclang_9 = [] diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 741a3fbe43..ec8bf336ce 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -54,6 +54,8 @@ use crate::ir::var::Var; use proc_macro2::{Ident, Span}; use quote::{ToTokens, TokenStreamExt}; +#[cfg(feature = "__cli")] +use serde::{Deserialize, Serialize}; use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; @@ -3013,6 +3015,7 @@ impl Method { /// A helper type that represents different enum variations. #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] +#[cfg_attr(feature = "__cli", derive(Serialize, Deserialize))] pub enum EnumVariation { /// The code for this enum will use a Rust enum. Note that creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not @@ -3755,6 +3758,7 @@ impl CodeGenerator for Enum { /// Enum for the default type of macro constants. #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] +#[cfg_attr(feature = "__cli", derive(Serialize, Deserialize))] pub enum MacroTypeVariation { /// Use i32 or i64 Signed, @@ -3794,6 +3798,7 @@ impl std::str::FromStr for MacroTypeVariation { /// Enum for how aliases should be translated. #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] +#[cfg_attr(feature = "__cli", derive(Serialize, Deserialize))] pub enum AliasVariation { /// Convert to regular Rust alias #[default] @@ -3838,6 +3843,7 @@ impl std::str::FromStr for AliasVariation { /// Enum for how non-`Copy` `union`s should be translated. #[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "__cli", derive(Serialize, Deserialize))] pub enum NonCopyUnionStyle { /// Wrap members in a type generated by `bindgen`. BindgenWrapper, diff --git a/bindgen/features.rs b/bindgen/features.rs index 990e4513cb..78f7f01962 100644 --- a/bindgen/features.rs +++ b/bindgen/features.rs @@ -25,6 +25,7 @@ macro_rules! define_rust_targets { /// This enum will have more variants added as necessary. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[cfg_attr(feature = "__cli", derive(serde::Serialize, serde::Deserialize))] pub enum RustTarget { /// Rust Nightly $(#[doc = concat!( diff --git a/bindgen/ir/annotations.rs b/bindgen/ir/annotations.rs index fc9cc0ffe7..35869df8cf 100644 --- a/bindgen/ir/annotations.rs +++ b/bindgen/ir/annotations.rs @@ -10,6 +10,7 @@ use crate::clang; /// What kind of visibility modifier should be used for a struct or field? #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Default)] +#[cfg_attr(feature = "__cli", derive(serde::Serialize, serde::Deserialize))] pub enum FieldVisibilityKind { /// Fields are marked as private, i.e., struct Foo {bar: bool} Private, diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 1557843d03..b76fdc1c48 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -171,6 +171,7 @@ impl DotAttributes for Function { /// A valid rust ABI. #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +#[cfg_attr(feature = "__cli", derive(serde::Serialize, serde::Deserialize))] pub enum Abi { /// The default C ABI. C, diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 3bf0bc3c1d..33e67dde3f 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -111,6 +111,7 @@ fn args_are_cpp(clang_args: &[Box]) -> bool { bitflags! { /// A type used to indicate which kind of items we have to generate. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[cfg_attr(feature = "__cli", derive(serde::Serialize, serde::Deserialize))] pub struct CodegenConfig: u32 { /// Whether to generate functions. const FUNCTIONS = 1 << 0; @@ -167,6 +168,7 @@ impl Default for CodegenConfig { /// Formatting tools that can be used to format the bindings #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "__cli", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pub enum Formatter { /// Do not format the bindings.