Skip to content

Commit

Permalink
Added support for integrating the package_version information in a co…
Browse files Browse the repository at this point in the history
…mment of the header file.

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 <emilio@crisal.io>
  • Loading branch information
Hitbear authored and emilio committed Apr 14, 2024
1 parent 400f437 commit af46999
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 7 deletions.
2 changes: 1 addition & 1 deletion rust-toolchain.toml
@@ -1,2 +1,2 @@
[toolchain]
channel = "nightly"
channel = "nightly"
39 changes: 34 additions & 5 deletions src/bindgen/bindings.rs
Expand Up @@ -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)]
Expand All @@ -53,6 +54,7 @@ impl Bindings {
functions: Vec<Function>,
source_files: Vec<path::PathBuf>,
noop: bool,
package_version: String,
) -> Bindings {
Bindings {
config,
Expand All @@ -65,6 +67,7 @@ impl Bindings {
functions,
source_files,
noop,
package_version,
}
}

Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/bindgen/builder.rs
Expand Up @@ -361,6 +361,7 @@ impl Builder {
Default::default(),
Default::default(),
true,
String::new(),
));
}

Expand Down Expand Up @@ -405,6 +406,7 @@ impl Builder {
result.typedefs,
result.functions,
result.source_files,
result.package_version,
)
.generate()
}
Expand Down
3 changes: 3 additions & 0 deletions src/bindgen/config.rs
Expand Up @@ -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<String>,
/// Include a comment with the version of cbindgen used to generate the file
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/bindgen/ir/constant.rs
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/bindgen/library.rs
Expand Up @@ -27,6 +27,7 @@ pub struct Library {
typedefs: ItemMap<Typedef>,
functions: Vec<Function>,
source_files: Vec<PathBuf>,
package_version: String,
}

impl Library {
Expand All @@ -42,6 +43,7 @@ impl Library {
typedefs: ItemMap<Typedef>,
functions: Vec<Function>,
source_files: Vec<PathBuf>,
package_version: String,
) -> Library {
Library {
config,
Expand All @@ -54,6 +56,7 @@ impl Library {
typedefs,
functions,
source_files,
package_version,
}
}

Expand Down Expand Up @@ -141,6 +144,7 @@ impl Library {
functions,
self.source_files,
false,
self.package_version,
))
}

Expand Down
10 changes: 10 additions & 0 deletions src/bindgen/parser.rs
Expand Up @@ -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)
}

Expand Down Expand Up @@ -409,6 +416,7 @@ pub struct Parse {
pub typedefs: ItemMap<Typedef>,
pub functions: Vec<Function>,
pub source_files: Vec<FilePathBuf>,
pub package_version: String,
}

impl Parse {
Expand All @@ -423,6 +431,7 @@ impl Parse {
typedefs: ItemMap::default(),
functions: Vec::new(),
source_files: Vec::new(),
package_version: String::new(),
}
}

Expand Down Expand Up @@ -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>(
Expand Down
10 changes: 10 additions & 0 deletions src/main.rs
Expand Up @@ -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::<String>("style") {
Ok(Some(style)) => {
config.style = bindgen::Style::from_str(style).unwrap();
Expand Down Expand Up @@ -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")
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/package_version.c
@@ -0,0 +1,12 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
uint64_t bar;
} Foo;

void doit(const Foo*);
20 changes: 20 additions & 0 deletions tests/expectations/package_version.compat.c
@@ -0,0 +1,20 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
uint64_t bar;
} Foo;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void doit(const Foo*);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
17 changes: 17 additions & 0 deletions tests/expectations/package_version.cpp
@@ -0,0 +1,17 @@
/* Package version: 0.1.0 */

#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>

struct Foo {
uint64_t bar;
};

extern "C" {

void doit(const Foo*);

} // extern "C"
14 changes: 14 additions & 0 deletions 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*);
12 changes: 12 additions & 0 deletions tests/expectations/package_version_both.c
@@ -0,0 +1,12 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct Foo {
uint64_t bar;
} Foo;

void doit(const struct Foo*);
20 changes: 20 additions & 0 deletions tests/expectations/package_version_both.compat.c
@@ -0,0 +1,20 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct Foo {
uint64_t bar;
} Foo;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void doit(const struct Foo*);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
12 changes: 12 additions & 0 deletions tests/expectations/package_version_tag.c
@@ -0,0 +1,12 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

struct Foo {
uint64_t bar;
};

void doit(const struct Foo*);
20 changes: 20 additions & 0 deletions tests/expectations/package_version_tag.compat.c
@@ -0,0 +1,20 @@
/* Package version: 0.1.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

struct Foo {
uint64_t bar;
};

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void doit(const struct Foo*);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
14 changes: 14 additions & 0 deletions 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*);
5 changes: 5 additions & 0 deletions tests/rust/package_version/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions tests/rust/package_version/Cargo.toml
@@ -0,0 +1,7 @@
[package]
name = "package_version"
version = "0.1.0"
authors = ["hitbear"]

[features]
cbindgen = []
1 change: 1 addition & 0 deletions tests/rust/package_version/cbindgen.toml
@@ -0,0 +1 @@
package_version = true
7 changes: 7 additions & 0 deletions 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) {}

0 comments on commit af46999

Please sign in to comment.