Skip to content

Commit

Permalink
Merge pull request #2 from ferrous-systems/amanjeev/test-generate-inl…
Browse files Browse the repository at this point in the history
…ine-functions

Test generate inline functions
  • Loading branch information
pvdrz authored Jan 23, 2023
2 parents d5d96e2 + 5dd5b3b commit 4efcc6f
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 35 deletions.
8 changes: 2 additions & 6 deletions bindgen-cli/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,15 +1182,11 @@ where
builder = builder.generate_extern_functions(true);
}

if let Some(file_name) =
matches.get_one::<String>("extern-functions-file-name")
{
if let Some(file_name) = matches.get_one::<String>("extern-functions-file-name") {
builder = builder.extern_functions_file_name(file_name);
}

if let Some(directory) =
matches.get_one::<String>("extern-functions-directory")
{
if let Some(directory) = matches.get_one::<String>("extern-functions-directory") {
builder = builder.extern_functions_directory(directory);
}

Expand Down
118 changes: 90 additions & 28 deletions bindgen-integration/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate cc;
use bindgen::callbacks::{
DeriveInfo, IntKind, MacroParsingBehavior, ParseCallbacks,
};
use bindgen::{Builder, EnumVariation};
use bindgen::{Builder, CargoCallbacks, EnumVariation};
use std::collections::HashSet;
use std::env;
use std::path::PathBuf;
Expand All @@ -28,21 +28,14 @@ impl ParseCallbacks for MacroCallback {
MacroParsingBehavior::Default
}

fn item_name(&self, original_item_name: &str) -> Option<String> {
if original_item_name.starts_with("my_prefixed_") {
Some(
original_item_name
.trim_start_matches("my_prefixed_")
.to_string(),
)
} else if original_item_name.starts_with("MY_PREFIXED_") {
Some(
original_item_name
.trim_start_matches("MY_PREFIXED_")
.to_string(),
)
} else {
None
fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
match name {
"TESTMACRO_CUSTOMINTKIND_PATH" => Some(IntKind::Custom {
name: "crate::MacroInteger",
is_signed: true,
}),

_ => None,
}
}

Expand All @@ -67,17 +60,6 @@ impl ParseCallbacks for MacroCallback {
}
}

fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
match name {
"TESTMACRO_CUSTOMINTKIND_PATH" => Some(IntKind::Custom {
name: "crate::MacroInteger",
is_signed: true,
}),

_ => None,
}
}

fn func_macro(&self, name: &str, value: &[&[u8]]) {
match name {
"TESTMACRO_NONFUNCTIONAL" => {
Expand Down Expand Up @@ -122,6 +104,24 @@ impl ParseCallbacks for MacroCallback {
}
}

fn item_name(&self, original_item_name: &str) -> Option<String> {
if original_item_name.starts_with("my_prefixed_") {
Some(
original_item_name
.trim_start_matches("my_prefixed_")
.to_string(),
)
} else if original_item_name.starts_with("MY_PREFIXED_") {
Some(
original_item_name
.trim_start_matches("MY_PREFIXED_")
.to_string(),
)
} else {
None
}
}

// Test the "custom derives" capability by adding `PartialEq` to the `Test` struct.
fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec<String> {
if info.name == "Test" {
Expand Down Expand Up @@ -149,7 +149,7 @@ impl Drop for MacroCallback {
}
}

fn main() {
fn setup_macro_test() {
cc::Build::new()
.cpp(true)
.file("cpp/Test.cc")
Expand Down Expand Up @@ -204,3 +204,65 @@ fn main() {
"including stub via include dir must produce correct dep path",
);
}

fn setup_extern_test() {
// GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090
// set output directory under /target so it is easy to clean generated files
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_rust_file = out_path.join("extern.rs");

let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/").canonicalize()
.expect("Cannot canonicalize libdir path");
let input_header_file_path = input_header_dir.join("generate-extern-functions.h");
let input_header_file_path_str = input_header_file_path.to_str()
.expect("Path could not be converted to a str");

// generate external bindings with the external .c and .h files
let bindings = Builder::default()
.header(input_header_file_path_str)
.parse_callbacks(Box::new(CargoCallbacks))
.generate_extern_functions(true)
.extern_functions_directory(out_path.display().to_string())
.generate()
.expect("Unable to generate bindings");

println!("cargo:rustc-link-lib=extern"); // tell cargo to link libextern
println!("bindings generated: {}", bindings);

let obj_path = out_path.join("extern.o");
let lib_path = out_path.join("libextern.a");

// build the external files to check if they work
if !std::process::Command::new("clang")
.arg("-c")
.arg("-o")
.arg(&obj_path)
.arg(out_path.join("extern.c"))
.arg("-include")
.arg(input_header_file_path)
.output()
.expect("`clang` command error")
.status
.success() {
panic!("Could not compile object file");
}

if !std::process::Command::new("ar")
.arg("rcs")
.arg(lib_path)
.arg(obj_path)
.output()
.expect("`ar` command error")
.status
.success() {
panic!("Could not emit library file");
}

bindings.write_to_file(out_rust_file)
.expect("Cound not write bindings to the Rust file");
}

fn main() {
setup_macro_test();
setup_extern_test();
}
16 changes: 16 additions & 0 deletions bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ mod bindings {
include!(concat!(env!("OUT_DIR"), "/test.rs"));
}

mod extern_bindings {
include!(concat!(env!("OUT_DIR"), "/extern.rs"));
}

use std::ffi::CStr;
use std::mem;
use std::os::raw::c_int;
Expand Down Expand Up @@ -286,3 +290,15 @@ fn test_custom_derive() {
assert!(meter < lightyear);
assert!(meter > micron);
}

#[test]
fn test_extern_bindings() {
// GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090
unsafe {
let f = extern_bindings::foo();
assert_eq!(11, f);

let b = extern_bindings::bar();
assert_eq!(1, b);
}
}
4 changes: 4 additions & 0 deletions bindgen-tests/tests/expectations/tests/generated/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Generated C, C++, Header files

This directory contains files for features where extra files are generated
as a part of the feature. For example, `--generated-extern-functions`.
2 changes: 2 additions & 0 deletions bindgen-tests/tests/expectations/tests/generated/extern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int foo__extern() { return foo(); }
int bar__extern() { return bar(); }
2 changes: 2 additions & 0 deletions bindgen-tests/tests/expectations/tests/generated/extern.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
int foo__extern();
int bar__extern();
2 changes: 1 addition & 1 deletion bindgen-tests/tests/headers/generate-extern-functions.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// bindgen-flags: --generate-extern-functions

static inline int foo() {
return 0;
return 11;
}
static int bar() {
return 1;
Expand Down
50 changes: 50 additions & 0 deletions bindgen-tests/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,3 +713,53 @@ fn commandline_multiple_headers() {
.header("tests/headers/16-byte-alignment.h");
build_flags_output_helper(&bindings);
}

#[test]
fn test_extern_generated_headers() {
// This test is for testing diffs of the generated C source and header files
// TODO: If another such feature is added, convert this test into a more generic
// test that looks at `tests/headers/generated` directory.
let expect_path = PathBuf::from("tests/expectations/tests/generated");
println!("In path is ::: {}", expect_path.to_str().unwrap());

let generated_path = PathBuf::from(env::var("OUT_DIR").unwrap());
println!("Out path is ::: {}", generated_path.to_str().unwrap());

let _bindings = Builder::default()
.header("tests/headers/generate-extern-functions.h")
.generate_extern_functions(true)
.extern_functions_directory(generated_path.display().to_string())
.generate()
.expect("Failed to generate bindings");

let expected_c = fs::read_to_string(expect_path.join("extern.c"))
.expect("Could not read generated extern.c");
let expected_h = fs::read_to_string(expect_path.join("extern.h"))
.expect("Could not read generated extern.h");

let actual_c = fs::read_to_string(generated_path.join("extern.c"))
.expect("Could not read actual extern.c");
let actual_h = fs::read_to_string(generated_path.join("extern.h"))
.expect("Could not read actual extern.h");

if expected_c != actual_c {
error_diff_mismatch(
&actual_c,
&expected_c,
None,
Path::new(expect_path.join("extern.c").to_str().unwrap()),
)
.unwrap();
}

if expected_h != actual_h {
error_diff_mismatch(
&actual_h,
&expected_h,
None,
Path::new(expect_path.join("extern.h").to_str().unwrap()),
)
.unwrap();
}

}

0 comments on commit 4efcc6f

Please sign in to comment.