Skip to content

Commit

Permalink
break out compile_commands.json logic from the transpile logic
Browse files Browse the repository at this point in the history
  • Loading branch information
aneksteind committed Nov 8, 2023
1 parent 62533dd commit 6c497c7
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 69 deletions.
91 changes: 33 additions & 58 deletions c2rust-transpile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub mod translator;
pub mod with_stmts;

use std::collections::HashSet;
use std::fs::{self, read_dir, File};
use std::fs::{self, File};
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -226,63 +226,42 @@ fn get_module_name(
file.to_str().map(String::from)
}

/// Main entry point to transpiler. Called from CLI tools with the result of
/// clap::App::get_matches().
pub fn transpile(tcfg: TranspilerConfig, source_or_cc_db: &Path, extra_clang_args: &[&str]) {
diagnostics::init(tcfg.enabled_warnings.clone(), tcfg.log_level);
pub fn create_temp_compile_commands(sources: &[PathBuf]) -> PathBuf {
let temp_path = std::env::temp_dir().join("compile_commands.json");
let compile_commands: Vec<CompileCmd> = sources
.iter()
.map(|source_file| {
let absolute_path = fs::canonicalize(source_file)
.unwrap_or_else(|_| panic!("Could not canonicalize {}", source_file.display()));

CompileCmd {
directory: absolute_path.parent().unwrap().to_path_buf(),
file: absolute_path.clone(),
arguments: vec![
"clang".to_string(),
absolute_path.to_str().unwrap().to_owned(),
],
command: None,
output: None,
}
})
.collect();

let build_dir = get_build_dir(&tcfg, source_or_cc_db);
let mut temp_json_path = std::env::temp_dir();
temp_json_path.push("compile_commands.json");
let json_content = serde_json::to_string(&compile_commands).unwrap();
let mut file =
File::create(&temp_path).expect("Failed to create temporary compile_commands.json");
file.write_all(json_content.as_bytes())
.expect("Failed to write to temporary compile_commands.json");

let ext = source_or_cc_db.extension().unwrap_or_default();
let is_c_or_h_file = ext == "c" || ext == "h";
let is_wildcard = source_or_cc_db
.file_name()
.unwrap_or_default()
.to_string_lossy()
.contains('*');

let format_compile_command = |build_dir: &Path, file_path: &Path| -> String {
let compile_cmd = CompileCmd {
directory: build_dir.to_path_buf(),
file: file_path.to_path_buf(),
arguments: vec!["clang".to_string(), file_path.to_str().unwrap().to_owned()],
command: None,
output: None,
};
serde_json::to_string(&compile_cmd).unwrap()
};

let mut temp_json = Vec::new();
if is_c_or_h_file {
let command = format_compile_command(&build_dir, source_or_cc_db);
temp_json.push(command);
} else if is_wildcard {
for entry in read_dir(build_dir.clone()).unwrap() {
if let Ok(entry) = entry {
let path = entry.path();
let ext = path.extension().unwrap_or_default();
if ext == "c" || ext == "h" {
let command = format_compile_command(&build_dir, &path);
temp_json.push(command);
}
}
}
}
temp_path
}

if !temp_json.is_empty() {
let temp_json_content = format!("[{}]", temp_json.join(","));
fs::File::create(temp_json_path.clone())
.and_then(|mut f| f.write_all(temp_json_content.as_bytes()))
.expect("Failed to create temporary compile_commands.json");
}
/// Main entry point to transpiler. Called from CLI tools with the result of
/// clap::App::get_matches().
pub fn transpile(tcfg: TranspilerConfig, cc_db: &Path, extra_clang_args: &[&str]) {
diagnostics::init(tcfg.enabled_warnings.clone(), tcfg.log_level);

let cc_db = if !temp_json.is_empty() {
Path::new(&temp_json_path)
} else {
source_or_cc_db
};
let build_dir = get_build_dir(&tcfg, cc_db);

let lcmds = get_compile_commands(&cc_db, &tcfg.filter).unwrap_or_else(|_| {
panic!(
Expand Down Expand Up @@ -421,10 +400,6 @@ pub fn transpile(tcfg: TranspilerConfig, source_or_cc_db: &Path, extra_clang_arg
}

tcfg.check_if_all_binaries_used(&transpiled_modules);

if is_c_or_h_file {
let _ = fs::remove_file(cc_db);
}
}

/// Ensure that clang can locate the system headers on macOS 10.14+.
Expand Down
35 changes: 24 additions & 11 deletions c2rust/src/bin/c2rust-transpile.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::{Parser, ValueEnum};
use log::LevelFilter;
use regex::Regex;
use std::path::{Path, PathBuf};
use std::path::PathBuf;

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

Expand Down Expand Up @@ -85,8 +85,17 @@ struct Args {
debug_labels: bool,

/// Input compile_commands.json file or path to source files
#[clap()]
compile_commands_or_source: PathBuf,
#[clap(long, parse(from_os_str), required = false, conflicts_with = "source")]
compile_commands: Option<PathBuf>,

/// Source files to process, only valid if compile_commands.json path is not provided.
#[clap(
long = "source",
parse(from_os_str),
multiple_values = true,
required = false
)]
source: Vec<PathBuf>,

/// How to handle violated invariants or invalid code
#[clap(long, value_enum, default_value_t = InvalidCodes::CompileError)]
Expand Down Expand Up @@ -226,19 +235,23 @@ fn main() {
tcfg.emit_modules = true
};

let source_or_cc_db = Path::new(&args.compile_commands_or_source);
let source_or_cc_db = source_or_cc_db.canonicalize().unwrap_or_else(|_| {
panic!(
"Could not find compile_commands.json or source files at path: {}",
source_or_cc_db.display()
)
});
let compile_commands = if let Some(compile_commands_path) = args.compile_commands {
compile_commands_path
} else {
c2rust_transpile::create_temp_compile_commands(&args.source)
};

let extra_args = args
.extra_clang_args
.iter()
.map(AsRef::as_ref)
.collect::<Vec<_>>();

c2rust_transpile::transpile(tcfg, &source_or_cc_db, &extra_args);
c2rust_transpile::transpile(tcfg, &compile_commands, &extra_args);

// Remove the temporary compile_commands.json if it was created
if !args.source.is_empty() {
std::fs::remove_file(&compile_commands)
.expect("Failed to remove temporary compile_commands.json");
}
}

0 comments on commit 6c497c7

Please sign in to comment.