From af469996e074b20c196f700e4023dbec38367c5d Mon Sep 17 00:00:00 2001 From: Hitbear Date: Fri, 9 Feb 2024 19:28:23 +0100 Subject: [PATCH] Added support for integrating the package_version information in a comment of the header file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new command line argument for this is --package-version. The TOML config file flag is package_version=true||false. Closes #926 Co-Authored-By: Emilio Cobos Álvarez --- rust-toolchain.toml | 2 +- src/bindgen/bindings.rs | 39 ++++++++++++++++--- src/bindgen/builder.rs | 2 + src/bindgen/config.rs | 3 ++ src/bindgen/ir/constant.rs | 2 +- src/bindgen/library.rs | 4 ++ src/bindgen/parser.rs | 10 +++++ src/main.rs | 10 +++++ tests/expectations/package_version.c | 12 ++++++ tests/expectations/package_version.compat.c | 20 ++++++++++ tests/expectations/package_version.cpp | 17 ++++++++ tests/expectations/package_version.pyx | 14 +++++++ tests/expectations/package_version_both.c | 12 ++++++ .../package_version_both.compat.c | 20 ++++++++++ tests/expectations/package_version_tag.c | 12 ++++++ .../expectations/package_version_tag.compat.c | 20 ++++++++++ tests/expectations/package_version_tag.pyx | 14 +++++++ tests/rust/package_version/Cargo.lock | 5 +++ tests/rust/package_version/Cargo.toml | 7 ++++ tests/rust/package_version/cbindgen.toml | 1 + tests/rust/package_version/src/lib.rs | 7 ++++ tests/tests.rs | 10 +++++ 22 files changed, 236 insertions(+), 7 deletions(-) create mode 100644 tests/expectations/package_version.c create mode 100644 tests/expectations/package_version.compat.c create mode 100644 tests/expectations/package_version.cpp create mode 100644 tests/expectations/package_version.pyx create mode 100644 tests/expectations/package_version_both.c create mode 100644 tests/expectations/package_version_both.compat.c create mode 100644 tests/expectations/package_version_tag.c create mode 100644 tests/expectations/package_version_tag.compat.c create mode 100644 tests/expectations/package_version_tag.pyx create mode 100644 tests/rust/package_version/Cargo.lock create mode 100644 tests/rust/package_version/Cargo.toml create mode 100644 tests/rust/package_version/cbindgen.toml create mode 100644 tests/rust/package_version/src/lib.rs diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf9a..271800cb2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly" +channel = "nightly" \ No newline at end of file diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index 410b11f30..80793db4b 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -33,6 +33,7 @@ pub struct Bindings { /// Bindings are generated by a recursive call to cbindgen /// and shouldn't do anything when written anywhere. noop: bool, + package_version: String, } #[derive(PartialEq, Eq)] @@ -53,6 +54,7 @@ impl Bindings { functions: Vec, source_files: Vec, noop: bool, + package_version: String, ) -> Bindings { Bindings { config, @@ -65,6 +67,7 @@ impl Bindings { functions, source_files, noop, + package_version, } } @@ -209,6 +212,20 @@ impl Bindings { return; } + if self.config.package_version { + out.new_line_if_not_start(); + match self.config.language { + Language::C | Language::Cxx => { + write!(out, "/* Package version: {} */", self.package_version); + } + Language::Cython => { + write!(out, "''' Package version: {} '''", self.package_version); + } + } + + out.new_line(); + } + if let Some(ref f) = self.config.header { out.new_line_if_not_start(); write!(out, "{}", f); @@ -228,11 +245,23 @@ impl Bindings { } if self.config.include_version { out.new_line_if_not_start(); - write!( - out, - "/* Generated with cbindgen:{} */", - crate::bindgen::config::VERSION - ); + match self.config.language { + Language::C | Language::Cxx => { + write!( + out, + "/* Generated with cbindgen:{} */", + crate::bindgen::config::VERSION + ); + } + Language::Cython => { + write!( + out, + "''' Generated with cbindgen:{} '''", + crate::bindgen::config::VERSION + ); + } + } + out.new_line(); } if let Some(ref f) = self.config.autogen_warning { diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 4d2eee12b..d47919b98 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -361,6 +361,7 @@ impl Builder { Default::default(), Default::default(), true, + String::new(), )); } @@ -405,6 +406,7 @@ impl Builder { result.typedefs, result.functions, result.source_files, + result.package_version, ) .generate() } diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 9c1a3ccec..dc5fa4635 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -919,6 +919,8 @@ pub struct Config { /// This option is useful when using cbindgen with tools such as python's cffi which /// doesn't understand include directives pub no_includes: bool, + // Package version: True if the package version should appear as a comment in the .h file + pub package_version: bool, /// Optional text to output at major sections to deter manual editing pub autogen_warning: Option, /// Include a comment with the version of cbindgen used to generate the file @@ -1040,6 +1042,7 @@ impl Default for Config { autogen_warning: None, include_version: false, no_includes: false, + package_version: false, namespace: None, namespaces: None, using_namespaces: None, diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index d3b9bd443..51e59b2d9 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use std::io::Write; use syn::ext::IdentExt; -use syn::{self, UnOp}; +use syn::UnOp; use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index cb4cfbd3a..2fd79fed4 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -27,6 +27,7 @@ pub struct Library { typedefs: ItemMap, functions: Vec, source_files: Vec, + package_version: String, } impl Library { @@ -42,6 +43,7 @@ impl Library { typedefs: ItemMap, functions: Vec, source_files: Vec, + package_version: String, ) -> Library { Library { config, @@ -54,6 +56,7 @@ impl Library { typedefs, functions, source_files, + package_version, } } @@ -141,6 +144,7 @@ impl Library { functions, self.source_files, false, + self.package_version, )) } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index b54c7fbbd..96db4025d 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -81,6 +81,13 @@ pub(crate) fn parse_lib(lib: Cargo, config: &Config) -> ParseResult { let binding_crate = context.lib.as_ref().unwrap().binding_crate_ref(); context.parse_crate(&binding_crate)?; context.out.source_files = context.cache_src.keys().map(|k| k.to_owned()).collect(); + context.out.package_version = context + .lib + .as_ref() + .unwrap() + .binding_crate_ref() + .version + .unwrap(); Ok(context.out) } @@ -409,6 +416,7 @@ pub struct Parse { pub typedefs: ItemMap, pub functions: Vec, pub source_files: Vec, + pub package_version: String, } impl Parse { @@ -423,6 +431,7 @@ impl Parse { typedefs: ItemMap::default(), functions: Vec::new(), source_files: Vec::new(), + package_version: String::new(), } } @@ -471,6 +480,7 @@ impl Parse { self.typedefs.extend_with(&other.typedefs); self.functions.extend_from_slice(&other.functions); self.source_files.extend_from_slice(&other.source_files); + self.package_version = other.package_version.clone(); } fn load_syn_crate_mod<'a>( diff --git a/src/main.rs b/src/main.rs index e9c5ffc35..a6a1852c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,6 +49,10 @@ fn apply_config_overrides(config: &mut Config, matches: &ArgMatches) { config.only_target_dependencies = true; } + if matches.get_flag("package-version") { + config.package_version = true; + } + match matches.try_get_one::("style") { Ok(Some(style)) => { config.style = bindgen::Style::from_str(style).unwrap(); @@ -163,6 +167,12 @@ fn main() { .help("Specify the language to output bindings in") .value_parser(["c++", "C++", "c", "C", "cython", "Cython"]), ) + .arg( + Arg::new("package-version") + .long("package-version") + .action(ArgAction::SetTrue) + .help("Include the package version in the header comment") + ) .arg( Arg::new("cpp-compat") .long("cpp-compat") diff --git a/tests/expectations/package_version.c b/tests/expectations/package_version.c new file mode 100644 index 000000000..dd8e7185d --- /dev/null +++ b/tests/expectations/package_version.c @@ -0,0 +1,12 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +typedef struct { + uint64_t bar; +} Foo; + +void doit(const Foo*); diff --git a/tests/expectations/package_version.compat.c b/tests/expectations/package_version.compat.c new file mode 100644 index 000000000..4bb26e1f0 --- /dev/null +++ b/tests/expectations/package_version.compat.c @@ -0,0 +1,20 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +typedef struct { + uint64_t bar; +} Foo; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void doit(const Foo*); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/package_version.cpp b/tests/expectations/package_version.cpp new file mode 100644 index 000000000..c3091eb18 --- /dev/null +++ b/tests/expectations/package_version.cpp @@ -0,0 +1,17 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include +#include + +struct Foo { + uint64_t bar; +}; + +extern "C" { + +void doit(const Foo*); + +} // extern "C" diff --git a/tests/expectations/package_version.pyx b/tests/expectations/package_version.pyx new file mode 100644 index 000000000..7c92cadcf --- /dev/null +++ b/tests/expectations/package_version.pyx @@ -0,0 +1,14 @@ +''' Package version: 0.1.0 ''' + +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef struct Foo: + uint64_t bar; + + void doit(const Foo*); diff --git a/tests/expectations/package_version_both.c b/tests/expectations/package_version_both.c new file mode 100644 index 000000000..b09c9468c --- /dev/null +++ b/tests/expectations/package_version_both.c @@ -0,0 +1,12 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +typedef struct Foo { + uint64_t bar; +} Foo; + +void doit(const struct Foo*); diff --git a/tests/expectations/package_version_both.compat.c b/tests/expectations/package_version_both.compat.c new file mode 100644 index 000000000..763c3e4d4 --- /dev/null +++ b/tests/expectations/package_version_both.compat.c @@ -0,0 +1,20 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +typedef struct Foo { + uint64_t bar; +} Foo; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void doit(const struct Foo*); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/package_version_tag.c b/tests/expectations/package_version_tag.c new file mode 100644 index 000000000..b46eae6e6 --- /dev/null +++ b/tests/expectations/package_version_tag.c @@ -0,0 +1,12 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +struct Foo { + uint64_t bar; +}; + +void doit(const struct Foo*); diff --git a/tests/expectations/package_version_tag.compat.c b/tests/expectations/package_version_tag.compat.c new file mode 100644 index 000000000..0d8fb3da4 --- /dev/null +++ b/tests/expectations/package_version_tag.compat.c @@ -0,0 +1,20 @@ +/* Package version: 0.1.0 */ + +#include +#include +#include +#include + +struct Foo { + uint64_t bar; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void doit(const struct Foo*); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/package_version_tag.pyx b/tests/expectations/package_version_tag.pyx new file mode 100644 index 000000000..8f70779a7 --- /dev/null +++ b/tests/expectations/package_version_tag.pyx @@ -0,0 +1,14 @@ +''' Package version: 0.1.0 ''' + +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + cdef struct Foo: + uint64_t bar; + + void doit(const Foo*); diff --git a/tests/rust/package_version/Cargo.lock b/tests/rust/package_version/Cargo.lock new file mode 100644 index 000000000..aa2bb7ff7 --- /dev/null +++ b/tests/rust/package_version/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "package_version" +version = "0.1.0" diff --git a/tests/rust/package_version/Cargo.toml b/tests/rust/package_version/Cargo.toml new file mode 100644 index 000000000..58bcf81dc --- /dev/null +++ b/tests/rust/package_version/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "package_version" +version = "0.1.0" +authors = ["hitbear"] + +[features] +cbindgen = [] \ No newline at end of file diff --git a/tests/rust/package_version/cbindgen.toml b/tests/rust/package_version/cbindgen.toml new file mode 100644 index 000000000..1288ec1e3 --- /dev/null +++ b/tests/rust/package_version/cbindgen.toml @@ -0,0 +1 @@ +package_version = true \ No newline at end of file diff --git a/tests/rust/package_version/src/lib.rs b/tests/rust/package_version/src/lib.rs new file mode 100644 index 000000000..8dcc8c509 --- /dev/null +++ b/tests/rust/package_version/src/lib.rs @@ -0,0 +1,7 @@ +#[repr(C)] +pub struct Foo { + bar: u64, +} + +#[no_mangle] +pub extern "C" fn doit(_: &Foo) {} diff --git a/tests/tests.rs b/tests/tests.rs index 3846f326e..995f108de 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -26,6 +26,7 @@ fn run_cbindgen( cpp_compat: bool, style: Option