Skip to content

Commit 0757fe4

Browse files
authored
Allow running multiple transpiles in parallel (#1241)
If c2rust-transpile needs to generate a temporary compile_commands.json, previously it used a fixed path for it across all invocations. Instead, create a uniquely-named temporary directory for it, so that parallel transpiles don't clobber each other. I've used a two-year-old release of tempfile to avoid adding a bunch of duplicate versions of other crates to Cargo.lock, but presumably some upgrades ought to happen sooner or later.
2 parents 85733fc + 5b1516b commit 0757fe4

File tree

4 files changed

+33
-20
lines changed

4 files changed

+33
-20
lines changed

Cargo.lock

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

c2rust-transpile/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ smallvec = "1.0"
3737
strum = "0.24"
3838
strum_macros = "0.24"
3939
syn = { version = "1.0", features = ["full", "extra-traits", "parsing", "printing"]}
40+
tempfile = "3.5.0"
4041

4142
[features]
4243
# Force static linking of LLVM

c2rust-transpile/src/lib.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use itertools::Itertools;
2525
use log::{info, warn};
2626
use regex::Regex;
2727
use serde_derive::Serialize;
28+
pub use tempfile::TempDir;
2829

2930
use crate::c_ast::Printer;
3031
use crate::c_ast::*;
@@ -226,8 +227,18 @@ fn get_module_name(
226227
file.to_str().map(String::from)
227228
}
228229

229-
pub fn create_temp_compile_commands(sources: &[PathBuf]) -> PathBuf {
230-
let temp_path = std::env::temp_dir().join("compile_commands.json");
230+
pub fn create_temp_compile_commands(sources: &[PathBuf]) -> (TempDir, PathBuf) {
231+
// If we generate the same path here on every run, then we can't run
232+
// multiple transpiles in parallel, so we need a unique path. But clang
233+
// won't read this file unless it is named exactly "compile_commands.json",
234+
// so we can't change the filename. Instead, create a temporary directory
235+
// with a unique name, and put the file there.
236+
let temp_dir = tempfile::Builder::new()
237+
.prefix("c2rust-")
238+
.tempdir()
239+
.expect("Failed to create temporary directory for compile_commands.json");
240+
let temp_path = temp_dir.path().join("compile_commands.json");
241+
231242
let compile_commands: Vec<CompileCmd> = sources
232243
.iter()
233244
.map(|source_file| {
@@ -252,8 +263,7 @@ pub fn create_temp_compile_commands(sources: &[PathBuf]) -> PathBuf {
252263
File::create(&temp_path).expect("Failed to create temporary compile_commands.json");
253264
file.write_all(json_content.as_bytes())
254265
.expect("Failed to write to temporary compile_commands.json");
255-
256-
temp_path
266+
(temp_dir, temp_path)
257267
}
258268

259269
/// Main entry point to transpiler. Called from CLI tools with the result of

c2rust/src/bin/c2rust-transpile.rs

+17-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clap::{Parser, ValueEnum};
22
use log::LevelFilter;
33
use regex::Regex;
4-
use std::{fs, path::PathBuf};
4+
use std::{ffi::OsStr, fs, path::PathBuf};
55

66
use c2rust_transpile::{Diagnostic, ReplaceMode, TranspilerConfig};
77

@@ -226,28 +226,29 @@ fn main() {
226226
tcfg.emit_modules = true
227227
};
228228

229-
let mut created_temp_compile_commands = false;
229+
let mut temp_compile_commands_dir = None;
230230

231-
let compile_commands = if args.compile_commands.len() == 1
232-
&& args.compile_commands[0].extension() == Some(std::ffi::OsStr::new("json"))
231+
let compile_commands = if args
232+
.compile_commands
233+
.iter()
234+
.any(|path| path.extension() == Some(OsStr::new("json")))
233235
{
236+
if args.compile_commands.len() != 1 {
237+
// More than one file provided and at least one is a JSON file
238+
panic!("Compile commands JSON and multiple sources provided.
239+
Exactly one compile_commands.json file should be provided, or a list of source files, but not both.");
240+
}
234241
// Only one file provided and it's a JSON file
235242
match fs::canonicalize(&args.compile_commands[0]) {
236243
Ok(canonical_path) => canonical_path,
237244
Err(e) => panic!("Failed to canonicalize path: {:?}", e),
238245
}
239-
} else if args
240-
.compile_commands
241-
.iter()
242-
.any(|path| path.extension() == Some(std::ffi::OsStr::new("json")))
243-
{
244-
// More than one file provided and at least one is a JSON file
245-
panic!("Compile commands JSON and multiple sources provided.
246-
Exactly one compile_commands.json file should be provided, or a list of source files, but not both.");
247246
} else {
248247
// Handle as a list of source files
249-
created_temp_compile_commands = true;
250-
c2rust_transpile::create_temp_compile_commands(&args.compile_commands)
248+
let (temp_dir, temp_path) =
249+
c2rust_transpile::create_temp_compile_commands(&args.compile_commands);
250+
temp_compile_commands_dir = Some(temp_dir);
251+
temp_path
251252
};
252253

253254
let extra_args = args
@@ -259,8 +260,8 @@ fn main() {
259260
c2rust_transpile::transpile(tcfg, &compile_commands, &extra_args);
260261

261262
// Remove the temporary compile_commands.json if it was created
262-
if created_temp_compile_commands {
263-
std::fs::remove_file(&compile_commands)
263+
if let Some(temp) = temp_compile_commands_dir {
264+
temp.close()
264265
.expect("Failed to remove temporary compile_commands.json");
265266
}
266267
}

0 commit comments

Comments
 (0)