diff --git a/Cargo.lock b/Cargo.lock index 4e88c224f5..4827e15da6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,7 @@ dependencies = [ "rustc-hash", "shlex", "syn 2.0.90", + "tempfile", ] [[package]] diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml index c01f8f0c44..7cb5f0a506 100644 --- a/bindgen/Cargo.toml +++ b/bindgen/Cargo.toml @@ -41,6 +41,7 @@ regex = { workspace = true, features = ["std", "unicode-perl"] } rustc-hash.workspace = true shlex.workspace = true syn = { workspace = true, features = ["full", "extra-traits", "visit-mut"] } +tempfile.workspace = true [features] default = ["logging", "prettyplease", "runtime"] diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 9afc6e93b1..003f37249d 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -7,6 +7,8 @@ use crate::ir::context::BindgenContext; use clang_sys::*; use std::cmp; +use std::path::{Path, PathBuf}; +use tempfile::TempDir; use std::ffi::{CStr, CString}; use std::fmt; @@ -1822,12 +1824,17 @@ impl TranslationUnit { /// Parse a source file into a translation unit. pub(crate) fn parse( ix: &Index, - file: &str, + file: Option<&Path>, cmd_args: &[Box], unsaved: &[UnsavedFile], opts: CXTranslationUnit_Flags, ) -> Option { - let fname = CString::new(file).unwrap(); + let fname = match file { + Some(file) => { + CString::new(file.as_os_str().as_encoded_bytes()).unwrap() + } + None => CString::new(&[]).unwrap(), + }; let _c_args: Vec = cmd_args .iter() .map(|s| CString::new(s.as_bytes()).unwrap()) @@ -1879,8 +1886,8 @@ impl TranslationUnit { } /// Save a translation unit to the given file. - pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> { - let Ok(file) = CString::new(file) else { + pub(crate) fn save(&mut self, file: &Path) -> Result<(), CXSaveError> { + let Ok(file) = CString::new(file.as_os_str().as_encoded_bytes()) else { return Err(CXSaveError_Unknown); }; let ret = unsafe { @@ -1913,9 +1920,10 @@ impl Drop for TranslationUnit { /// Translation unit used for macro fallback parsing pub(crate) struct FallbackTranslationUnit { - file_path: String, - header_path: String, - pch_path: String, + temp_dir: TempDir, + file_path: PathBuf, + header_path: PathBuf, + pch_path: PathBuf, idx: Box, tu: TranslationUnit, } @@ -1929,9 +1937,10 @@ impl fmt::Debug for FallbackTranslationUnit { impl FallbackTranslationUnit { /// Create a new fallback translation unit pub(crate) fn new( - file: String, - header_path: String, - pch_path: String, + temp_dir: TempDir, + file: PathBuf, + header_path: PathBuf, + pch_path: PathBuf, c_args: &[Box], ) -> Option { // Create empty file @@ -1945,12 +1954,13 @@ impl FallbackTranslationUnit { let f_index = Box::new(Index::new(true, false)); let f_translation_unit = TranslationUnit::parse( &f_index, - &file, + Some(&file), c_args, &[], CXTranslationUnit_None, )?; Some(FallbackTranslationUnit { + temp_dir, file_path: file, header_path, pch_path, @@ -1988,14 +1998,6 @@ impl FallbackTranslationUnit { } } -impl Drop for FallbackTranslationUnit { - fn drop(&mut self) { - let _ = std::fs::remove_file(&self.file_path); - let _ = std::fs::remove_file(&self.header_path); - let _ = std::fs::remove_file(&self.pch_path); - } -} - /// A diagnostic message generated while parsing a translation unit. pub(crate) struct Diagnostic { x: CXDiagnostic, @@ -2036,9 +2038,9 @@ pub(crate) struct UnsavedFile { } impl UnsavedFile { - /// Construct a new unsaved file with the given `name` and `contents`. - pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile { - let name = CString::new(name.as_bytes()).unwrap(); + /// Construct a new unsaved file with the given `path` and `contents`. + pub(crate) fn new(path: &Path, contents: &str) -> UnsavedFile { + let name = CString::new(path.as_os_str().as_encoded_bytes()).unwrap(); let contents = CString::new(contents.as_bytes()).unwrap(); let x = CXUnsavedFile { Filename: name.as_ptr(), diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index c6bc9025ec..1034f1a311 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -33,6 +33,7 @@ use std::fs::OpenOptions; use std::io::Write; use std::mem; use std::path::Path; +use tempfile::TempDir; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] @@ -557,7 +558,7 @@ impl BindgenContext { clang::TranslationUnit::parse( &index, - "", + None, &options.clang_args, input_unsaved_files, parse_options, @@ -2042,13 +2043,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" &mut self, ) -> Option<&mut clang::FallbackTranslationUnit> { if self.fallback_tu.is_none() { - let file = format!( - "{}/.macro_eval.c", - match self.options().clang_macro_fallback_build_dir { - Some(ref path) => path.as_os_str().to_str()?, - None => ".", - } - ); + let temp_dir = TempDir::new().unwrap(); + + let file = temp_dir.path().join(".macro_eval.c"); let index = clang::Index::new(false, false); @@ -2072,15 +2069,12 @@ If you encounter an error missing from this list, please file an issue or a PR!" header_contents += format!("\n#include <{header_name}>").as_str(); } - let header_to_precompile = format!( - "{}/{}", - match self.options().clang_macro_fallback_build_dir { - Some(ref path) => path.as_os_str().to_str()?, - None => ".", - }, - header_names_to_compile.join("-") + "-precompile.h" - ); - let pch = header_to_precompile.clone() + ".pch"; + let header_to_precompile = temp_dir + .path() + .join(header_names_to_compile.join("-") + "-precompile.h"); + let pch = temp_dir + .path() + .join(header_names_to_compile.join("-") + "-precompile.h.pch"); let mut header_to_precompile_file = OpenOptions::new() .create(true) @@ -2110,7 +2104,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" ); let mut tu = clang::TranslationUnit::parse( &index, - &header_to_precompile, + Some(&header_to_precompile), &c_args, &[], clang_sys::CXTranslationUnit_ForSerialization, @@ -2119,7 +2113,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" let mut c_args = vec![ "-include-pch".to_string().into_boxed_str(), - pch.clone().into_boxed_str(), + pch.to_string_lossy().into_owned().into_boxed_str(), ]; c_args.extend( self.options @@ -2133,6 +2127,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" .cloned(), ); self.fallback_tu = Some(clang::FallbackTranslationUnit::new( + temp_dir, file, header_to_precompile, pch, diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 0a8f29d158..d41f78f32d 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -359,7 +359,7 @@ impl Builder { std::mem::take(&mut self.options.input_header_contents) .into_iter() .map(|(name, contents)| { - clang::UnsavedFile::new(name.as_ref(), contents.as_ref()) + clang::UnsavedFile::new((*name).as_ref(), contents.as_ref()) }) .collect::>(); diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index 6bf652d4e1..c4dcd71e32 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -2148,22 +2148,4 @@ options! { }, as_args: "--clang-macro-fallback", } - /// Path to use for temporary files created by clang macro fallback code like precompiled - /// headers. - clang_macro_fallback_build_dir: Option { - methods: { - /// Set a path to a directory to which `.c` and `.h.pch` files should be written for the - /// purpose of using clang to evaluate macros that can't be easily parsed. - /// - /// The default location for `.h.pch` files is the directory that the corresponding - /// `.h` file is located in. The default for the temporary `.c` file used for clang - /// parsing is the current working directory. Both of these defaults are overridden - /// by this option. - pub fn clang_macro_fallback_build_dir>(mut self, path: P) -> Self { - self.options.clang_macro_fallback_build_dir = Some(path.as_ref().to_owned()); - self - } - }, - as_args: "--clang-macro-fallback-build-dir", - } }