Use absolute paths for unsaved files passed to clang and prepend -include directives to them.

Fixes #1771
Closes #1857
This commit is contained in:
Andrey Pushkar 2020-08-01 19:26:16 +03:00 committed by Emilio Cobos Álvarez
parent 9de0d64fc0
commit 51778893c4
No known key found for this signature in database
GPG Key ID: E1152D0994E4BF8A
3 changed files with 178 additions and 2 deletions

View File

@ -596,8 +596,16 @@ impl Builder {
///
/// The file `name` will be added to the clang arguments.
pub fn header_contents(mut self, name: &str, contents: &str) -> Builder {
// Apparently clang relies on having virtual FS correspondent to
// the real one, so we need absolute paths here
let absolute_path = env::current_dir()
.expect("Cannot retrieve current directory")
.join(name)
.to_str()
.expect("Cannot convert current directory name to string")
.to_owned();
self.input_header_contents
.push((name.into(), contents.into()));
.push((absolute_path, contents.into()));
self
}
@ -2154,7 +2162,10 @@ impl Bindings {
}
}
for f in options.input_unsaved_files.iter() {
for (idx, f) in options.input_unsaved_files.iter().enumerate() {
if idx != 0 || options.input_header.is_some() {
options.clang_args.push("-include".to_owned());
}
options.clang_args.push(f.name.to_str().unwrap().to_owned())
}

View File

@ -0,0 +1,111 @@
extern "C" {
pub static mut foo: ::std::option::Option<
unsafe extern "C" fn(
x: ::std::os::raw::c_int,
y: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int,
>;
}
extern "C" {
pub fn bar(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn bar2(b: *const ::std::os::raw::c_char) -> f32;
}
pub type Char = ::std::os::raw::c_char;
pub type SChar = ::std::os::raw::c_schar;
pub type UChar = ::std::os::raw::c_uchar;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Test {
pub ch: ::std::os::raw::c_char,
pub u: ::std::os::raw::c_uchar,
pub d: ::std::os::raw::c_schar,
pub cch: ::std::os::raw::c_char,
pub cu: ::std::os::raw::c_uchar,
pub cd: ::std::os::raw::c_schar,
pub Cch: Char,
pub Cu: UChar,
pub Cd: SChar,
pub Ccch: Char,
pub Ccu: UChar,
pub Ccd: SChar,
}
#[test]
fn bindgen_test_layout_Test() {
assert_eq!(
::std::mem::size_of::<Test>(),
12usize,
concat!("Size of: ", stringify!(Test))
);
assert_eq!(
::std::mem::align_of::<Test>(),
1usize,
concat!("Alignment of ", stringify!(Test))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).ch as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(ch))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).u as *const _ as usize },
1usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(u))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).d as *const _ as usize },
2usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(d))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).cch as *const _ as usize },
3usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(cch))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).cu as *const _ as usize },
4usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(cu))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).cd as *const _ as usize },
5usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(cd))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Cch as *const _ as usize },
6usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(Cch))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Cu as *const _ as usize },
7usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(Cu))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Cd as *const _ as usize },
8usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(Cd))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Ccch as *const _ as usize },
9usize,
concat!(
"Offset of field: ",
stringify!(Test),
"::",
stringify!(Ccch)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Ccu as *const _ as usize },
10usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(Ccu))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Test>())).Ccd as *const _ as usize },
11usize,
concat!("Offset of field: ", stringify!(Test), "::", stringify!(Ccd))
);
}

View File

@ -473,6 +473,60 @@ fn test_multiple_header_calls_in_builder() {
}
}
#[test]
fn test_multiple_header_contents() {
let actual = builder()
.header_contents("test.h", "int foo(const char* a);")
.header_contents("test2.h", "float foo2(const char* b);")
.clang_arg("--target=x86_64-unknown-linux")
.generate()
.unwrap()
.to_string();
let (actual, stderr) = rustfmt(actual);
println!("{}", stderr);
let (expected, _) = rustfmt(
"extern \"C\" {
pub fn foo2(b: *const ::std::os::raw::c_char) -> f32;
}
extern \"C\" {
pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
"
.to_string(),
);
assert_eq!(expected, actual);
}
#[test]
fn test_mixed_header_and_header_contents() {
let actual = builder()
.header(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/headers/func_ptr.h"
))
.header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
.header_contents("test.h", "int bar(const char* a);")
.header_contents("test2.h", "float bar2(const char* b);")
.clang_arg("--target=x86_64-unknown-linux")
.generate()
.unwrap()
.to_string();
let (actual, stderr) = rustfmt(actual);
println!("{}", stderr);
let expected = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/expectations/tests/test_mixed_header_and_header_contents.rs"
));
let (expected, _) = rustfmt(expected.to_string());
assert_eq!(expected, actual);
}
#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.