Skip to content

Commit e847ef1

Browse files
jbaublitzemilio
authored andcommitted
Switch to single precompiled header in macro fallback
It appears that Clang only supports a single precompiled header at a time. Because the macro fallback depends on the ability to provide multiple precompiled headers at once, this commit changes the code to include all provided headers into a single header to precompile and then pass to the TranslationUnit. This should resolve the issue where the macro fallback would not function as intended when multiple headers were provided as input. This commit also resolves an issue where clang args passed to the builder were not forwarded to the precompilation translation unit, resulting in headers not in standard system directories not being found.
1 parent ba0ccdb commit e847ef1

File tree

8 files changed

+174
-49
lines changed

8 files changed

+174
-49
lines changed

bindgen-tests/tests/expectations/tests/libclang-9/macro_fallback_non_system_dir.rs

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/expectations/tests/test_macro_fallback_non_system_dir.rs

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// bindgen-flags: --clang-macro-fallback
22

3+
#ifndef ISSUE_753_H
4+
#define ISSUE_753_H
5+
36
#define UINT32_C(c) c ## U
47

58
#define CONST UINT32_C(5)
69
#define OTHER_CONST UINT32_C(6)
710
#define LARGE_CONST UINT32_C(6 << 8)
11+
12+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef ANOTHER_HEADER_H
2+
#define ANOTHER_HEADER_H
3+
4+
#include <issue-753.h>
5+
6+
#define SHOULD_NOT_GENERATE UINT64_C(~0)
7+
#define MY_CONST UINT32_C(69)
8+
#define NEGATIVE ~0
9+
10+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef ONE_HEADER_H
2+
#define ONE_HEADER_H
3+
4+
#include <issue-753.h>
5+
6+
#define THE_CONST UINT32_C(28)
7+
8+
#endif

bindgen-tests/tests/tests.rs

+55
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,61 @@ fn test_mixed_header_and_header_contents() {
565565
}
566566
}
567567

568+
#[test]
569+
fn test_macro_fallback_non_system_dir() {
570+
let actual = builder()
571+
.header(concat!(
572+
env!("CARGO_MANIFEST_DIR"),
573+
"/tests/macro_fallback_test_headers/one_header.h"
574+
))
575+
.header(concat!(
576+
env!("CARGO_MANIFEST_DIR"),
577+
"/tests/macro_fallback_test_headers/another_header.h"
578+
))
579+
.clang_macro_fallback()
580+
.clang_arg(format!("-I{}/tests/headers", env!("CARGO_MANIFEST_DIR")))
581+
.generate()
582+
.unwrap()
583+
.to_string();
584+
585+
let actual = format_code(actual).unwrap();
586+
587+
let (expected_filename, expected) = match clang_version().parsed {
588+
Some((9, _)) => {
589+
let expected_filename = concat!(
590+
env!("CARGO_MANIFEST_DIR"),
591+
"/tests/expectations/tests/libclang-9/macro_fallback_non_system_dir.rs",
592+
);
593+
let expected = include_str!(concat!(
594+
env!("CARGO_MANIFEST_DIR"),
595+
"/tests/expectations/tests/libclang-9/macro_fallback_non_system_dir.rs",
596+
));
597+
(expected_filename, expected)
598+
}
599+
_ => {
600+
let expected_filename = concat!(
601+
env!("CARGO_MANIFEST_DIR"),
602+
"/tests/expectations/tests/test_macro_fallback_non_system_dir.rs",
603+
);
604+
let expected = include_str!(concat!(
605+
env!("CARGO_MANIFEST_DIR"),
606+
"/tests/expectations/tests/test_macro_fallback_non_system_dir.rs",
607+
));
608+
(expected_filename, expected)
609+
}
610+
};
611+
let expected = format_code(expected).unwrap();
612+
if expected != actual {
613+
error_diff_mismatch(
614+
&actual,
615+
&expected,
616+
None,
617+
Path::new(expected_filename),
618+
)
619+
.unwrap();
620+
}
621+
}
622+
568623
#[test]
569624
// Doesn't support executing sh file on Windows.
570625
// We may want to implement it in Rust so that we support all systems.

bindgen/clang.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1908,7 +1908,8 @@ impl Drop for TranslationUnit {
19081908
/// Translation unit used for macro fallback parsing
19091909
pub(crate) struct FallbackTranslationUnit {
19101910
file_path: String,
1911-
pch_paths: Vec<String>,
1911+
header_path: String,
1912+
pch_path: String,
19121913
idx: Box<Index>,
19131914
tu: TranslationUnit,
19141915
}
@@ -1923,7 +1924,8 @@ impl FallbackTranslationUnit {
19231924
/// Create a new fallback translation unit
19241925
pub(crate) fn new(
19251926
file: String,
1926-
pch_paths: Vec<String>,
1927+
header_path: String,
1928+
pch_path: String,
19271929
c_args: &[Box<str>],
19281930
) -> Option<Self> {
19291931
// Create empty file
@@ -1944,7 +1946,8 @@ impl FallbackTranslationUnit {
19441946
)?;
19451947
Some(FallbackTranslationUnit {
19461948
file_path: file,
1947-
pch_paths,
1949+
header_path,
1950+
pch_path,
19481951
tu: f_translation_unit,
19491952
idx: f_index,
19501953
})
@@ -1982,9 +1985,8 @@ impl FallbackTranslationUnit {
19821985
impl Drop for FallbackTranslationUnit {
19831986
fn drop(&mut self) {
19841987
let _ = std::fs::remove_file(&self.file_path);
1985-
for pch in self.pch_paths.iter() {
1986-
let _ = std::fs::remove_file(pch);
1987-
}
1988+
let _ = std::fs::remove_file(&self.header_path);
1989+
let _ = std::fs::remove_file(&self.pch_path);
19881990
}
19891991
}
19901992

bindgen/ir/context.rs

+81-43
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ use quote::ToTokens;
2929
use std::borrow::Cow;
3030
use std::cell::{Cell, RefCell};
3131
use std::collections::{BTreeSet, HashMap as StdHashMap};
32+
use std::fs::OpenOptions;
33+
use std::io::Write;
3234
use std::mem;
3335
use std::path::Path;
3436

@@ -2081,55 +2083,91 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20812083

20822084
let index = clang::Index::new(false, false);
20832085

2084-
let mut c_args = Vec::new();
2085-
let mut pch_paths = Vec::new();
2086-
for input_header in self.options().input_headers.iter() {
2086+
let mut header_names_to_compile = Vec::new();
2087+
let mut header_paths = Vec::new();
2088+
let mut header_contents = String::new();
2089+
for input_header in self.options.input_headers.iter() {
20872090
let path = Path::new(input_header.as_ref());
2088-
let header_name = path
2089-
.file_name()
2090-
.and_then(|hn| hn.to_str())
2091-
.map(|s| s.to_owned());
2092-
let header_path = path
2093-
.parent()
2094-
.and_then(|hp| hp.to_str())
2095-
.map(|s| s.to_owned());
2096-
2097-
let (header, pch) = if let (Some(ref hp), Some(hn)) =
2098-
(header_path, header_name)
2099-
{
2100-
let header_path = if hp.is_empty() { "." } else { hp };
2101-
let header = format!("{header_path}/{hn}");
2102-
let pch_path = if let Some(ref path) =
2103-
self.options().clang_macro_fallback_build_dir
2104-
{
2105-
path.as_os_str().to_str()?
2091+
if let Some(header_path) = path.parent() {
2092+
if header_path == Path::new("") {
2093+
header_paths.push(".");
21062094
} else {
2107-
header_path
2108-
};
2109-
(header, format!("{pch_path}/{hn}.pch"))
2095+
header_paths.push(header_path.as_os_str().to_str()?);
2096+
}
21102097
} else {
2111-
return None;
2112-
};
2113-
2114-
let mut tu = clang::TranslationUnit::parse(
2115-
&index,
2116-
&header,
2117-
&[
2118-
"-x".to_owned().into_boxed_str(),
2119-
"c-header".to_owned().into_boxed_str(),
2120-
],
2121-
&[],
2122-
clang_sys::CXTranslationUnit_ForSerialization,
2123-
)?;
2124-
tu.save(&pch).ok()?;
2125-
2126-
c_args.push("-include-pch".to_string().into_boxed_str());
2127-
c_args.push(pch.clone().into_boxed_str());
2128-
pch_paths.push(pch);
2098+
header_paths.push(".");
2099+
}
2100+
let header_name = path.file_name()?.to_str()?;
2101+
header_names_to_compile
2102+
.push(header_name.split(".h").next()?.to_string());
2103+
header_contents +=
2104+
format!("\n#include <{header_name}>").as_str();
21292105
}
2106+
let header_to_precompile = format!(
2107+
"{}/{}",
2108+
match self.options().clang_macro_fallback_build_dir {
2109+
Some(ref path) => path.as_os_str().to_str()?,
2110+
None => ".",
2111+
},
2112+
header_names_to_compile.join("-") + "-precompile.h"
2113+
);
2114+
let pch = header_to_precompile.clone() + ".pch";
2115+
2116+
let mut header_to_precompile_file = OpenOptions::new()
2117+
.create(true)
2118+
.truncate(true)
2119+
.write(true)
2120+
.open(&header_to_precompile)
2121+
.ok()?;
2122+
header_to_precompile_file
2123+
.write_all(header_contents.as_bytes())
2124+
.ok()?;
21302125

2126+
let mut c_args = Vec::new();
2127+
c_args.push("-x".to_string().into_boxed_str());
2128+
c_args.push("c-header".to_string().into_boxed_str());
2129+
for header_path in header_paths {
2130+
c_args.push(format!("-I{header_path}").into_boxed_str());
2131+
}
2132+
c_args.extend(
2133+
self.options
2134+
.clang_args
2135+
.iter()
2136+
.filter(|next| {
2137+
!self.options.input_headers.contains(next) &&
2138+
next.as_ref() != "-include"
2139+
})
2140+
.cloned(),
2141+
);
2142+
let mut tu = clang::TranslationUnit::parse(
2143+
&index,
2144+
&header_to_precompile,
2145+
&c_args,
2146+
&[],
2147+
clang_sys::CXTranslationUnit_ForSerialization,
2148+
)?;
2149+
tu.save(&pch).ok()?;
2150+
2151+
let mut c_args = vec![
2152+
"-include-pch".to_string().into_boxed_str(),
2153+
pch.clone().into_boxed_str(),
2154+
];
2155+
c_args.extend(
2156+
self.options
2157+
.clang_args
2158+
.clone()
2159+
.iter()
2160+
.filter(|next| {
2161+
!self.options.input_headers.contains(next) &&
2162+
next.as_ref() != "-include"
2163+
})
2164+
.cloned(),
2165+
);
21312166
self.fallback_tu = Some(clang::FallbackTranslationUnit::new(
2132-
file, pch_paths, &c_args,
2167+
file,
2168+
header_to_precompile,
2169+
pch,
2170+
&c_args,
21332171
)?);
21342172
}
21352173

0 commit comments

Comments
 (0)