From eac4e92732e3e3074d42ebfddf2e8fd37d5d3520 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 07:22:39 -0800 Subject: [PATCH 1/7] transpile: partially revert "break c2rust dependency on c2rust-refactor" This partially reverts 2bd339d92e1112faa4baf97e295223804b294d67, but only the changes to `c2rust-transpile/src/lib.rs`. We can't move `c2rust-refactor/src/bin/c2rust-refactor.rs` back to `c2rust/src/bin/c2rust-refactor.rs` because that introduces a dependency on `c2rust-refactor` from `c2rust`, which we can't have. `c2rust-refactor` is nightly-pinned, but `c2rust` (and its dependent `c2rust-transpile`) work on stable. Otherwise, `cargo install c2rust` won't work anymore. By keeping the explicit dependency detached, `--reorganize-definitions` should work if the `c2rust-refactor` binary exists. Furthermore, with the explicit dependency, the wrong `librustc_driver-*.so` was dependended on, which broke `c2rust-refactor`'s dynamic dependencies. Without it, it works. --- c2rust-transpile/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index e94ab9ecb8..4c5a67a669 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -464,8 +464,43 @@ fn get_extra_args_macos() -> Vec { args } -fn invoke_refactor(_build_dir: &Path) -> Result<(), Error> { - Ok(()) +fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { + // Make sure the crate builds cleanly + let status = process::Command::new("cargo") + .args(&["check"]) + .env("RUSTFLAGS", "-Awarnings") + .current_dir(build_dir) + .status()?; + if !status.success() { + return Err(failure::format_err!("Crate does not compile.")); + } + + // Assumes the subcommand executable is in the same directory as this program. + let cmd_path = std::env::current_exe().expect("Cannot get current executable path"); + let mut cmd_path = cmd_path.as_path().canonicalize().unwrap(); + cmd_path.pop(); // remove current executable + cmd_path.push(format!("c2rust-refactor")); + assert!(cmd_path.exists(), "{:?} is missing", cmd_path); + let args = [ + "--cargo", + "--rewrite-mode", + "inplace", + "rename_unnamed", + ";", + "reorganize_definitions", + ]; + let status = process::Command::new(cmd_path.into_os_string()) + .args(&args) + .current_dir(build_dir) + .status()?; + if status.success() { + Ok(()) + } else { + Err(failure::format_err!( + "Refactoring failed. Please fix errors above and re-run:\n c2rust refactor {}", + args.join(" "), + )) + } } fn reorganize_definitions( From 82e7653324f6a48e43677896d58aaab57865f12d Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 07:24:13 -0800 Subject: [PATCH 2/7] c2rust: add `refactor` as a known subcommand so `c2rust` can suggest it This should work for suggestions even if `c2rust-refactor` is not installed, which may be the case since `c2rust` doesn't (and can't) explicitly depend on `c2rust-refactor`. --- c2rust/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust/src/main.rs b/c2rust/src/main.rs index 5da573a665..f4158f1d0c 100644 --- a/c2rust/src/main.rs +++ b/c2rust/src/main.rs @@ -60,7 +60,7 @@ impl SubCommand { /// Get all known [`SubCommand`]s. These have no [`SubCommand::path`]. /// Even if the subcommand executables aren't there, we can still suggest them. pub fn known() -> impl Iterator { - ["transpile", "instrument", "pdg", "analyze"] + ["transpile", "refactor", "instrument", "pdg", "analyze"] .into_iter() .map(|name| Self { path: None, From 5470417fb345f4c58fcfaecbb4cc24281ac2bb6d Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 07:28:51 -0800 Subject: [PATCH 3/7] transpile: `use std::env` instead of using the full path --- c2rust-transpile/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index 4c5a67a669..134e2fba7d 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -14,10 +14,10 @@ pub mod with_stmts; use std::collections::HashSet; use std::fs::{self, File}; -use std::io; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process; +use std::{env, io}; use crate::compile_cmds::CompileCmd; use failure::Error; @@ -476,7 +476,7 @@ fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { } // Assumes the subcommand executable is in the same directory as this program. - let cmd_path = std::env::current_exe().expect("Cannot get current executable path"); + let cmd_path = env::current_exe().expect("Cannot get current executable path"); let mut cmd_path = cmd_path.as_path().canonicalize().unwrap(); cmd_path.pop(); // remove current executable cmd_path.push(format!("c2rust-refactor")); From fda679b9654010d6ccc77ee4f5e9770907bc56d8 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 07:32:26 -0800 Subject: [PATCH 4/7] transpile: `use std::process::Command` --- c2rust-transpile/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index 134e2fba7d..da3244ffde 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -16,7 +16,7 @@ use std::collections::HashSet; use std::fs::{self, File}; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process; +use std::process::Command; use std::{env, io}; use crate::compile_cmds::CompileCmd; @@ -445,7 +445,7 @@ fn get_extra_args_macos() -> Vec { if cfg!(target_os = "macos") { let usr_incl = Path::new("/usr/include"); if !usr_incl.exists() { - let output = process::Command::new("xcrun") + let output = Command::new("xcrun") .args(["--show-sdk-path"]) .output() .expect("failed to run `xcrun` subcommand"); @@ -466,7 +466,7 @@ fn get_extra_args_macos() -> Vec { fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { // Make sure the crate builds cleanly - let status = process::Command::new("cargo") + let status = Command::new("cargo") .args(&["check"]) .env("RUSTFLAGS", "-Awarnings") .current_dir(build_dir) @@ -489,7 +489,7 @@ fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { ";", "reorganize_definitions", ]; - let status = process::Command::new(cmd_path.into_os_string()) + let status = Command::new(cmd_path.into_os_string()) .args(&args) .current_dir(build_dir) .status()?; @@ -515,7 +515,7 @@ fn reorganize_definitions( invoke_refactor(build_dir)?; // fix the formatting of the output of `c2rust-refactor` - let status = process::Command::new("cargo") + let status = Command::new("cargo") .args(["fmt"]) .current_dir(build_dir) .status()?; From 4998502ff029cf14e8808ae725ad49b22a9e5332 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 08:00:53 -0800 Subject: [PATCH 5/7] transpile: improve error message for when `c2rust-refactor` isn't found and don't use racy `.exists()` check --- c2rust-transpile/src/lib.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index da3244ffde..3d7d959ca2 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -476,11 +476,9 @@ fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { } // Assumes the subcommand executable is in the same directory as this program. - let cmd_path = env::current_exe().expect("Cannot get current executable path"); - let mut cmd_path = cmd_path.as_path().canonicalize().unwrap(); - cmd_path.pop(); // remove current executable - cmd_path.push(format!("c2rust-refactor")); - assert!(cmd_path.exists(), "{:?} is missing", cmd_path); + let refactor = env::current_exe() + .expect("Cannot get current executable path") + .with_file_name("c2rust-refactor"); let args = [ "--cargo", "--rewrite-mode", @@ -489,10 +487,14 @@ fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { ";", "reorganize_definitions", ]; - let status = Command::new(cmd_path.into_os_string()) - .args(&args) + let status = Command::new(&refactor) + .args(args) .current_dir(build_dir) - .status()?; + .status() + .map_err(|e| { + let refactor = refactor.display(); + failure::format_err!("unable to run {refactor}: {e}\nNote that c2rust-refactor must be installed separately from c2rust and c2rust-transpile.") + })?; if status.success() { Ok(()) } else { From 012b1dda25f756eda2cb133111a01c0cd35f93ee Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 08:34:36 -0800 Subject: [PATCH 6/7] transpile: remove a redundant `&` in `fn invoke_refactor` --- c2rust-transpile/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index 3d7d959ca2..5a68bf21f6 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -467,7 +467,7 @@ fn get_extra_args_macos() -> Vec { fn invoke_refactor(build_dir: &Path) -> Result<(), Error> { // Make sure the crate builds cleanly let status = Command::new("cargo") - .args(&["check"]) + .args(["check"]) .env("RUSTFLAGS", "-Awarnings") .current_dir(build_dir) .status()?; From eae4cac330987108f92a9978522f5f35b207943f Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Mon, 10 Nov 2025 08:35:55 -0800 Subject: [PATCH 7/7] refactor: move `c2rust-refactor` bin target from `bin/c2rust-refactor.rs` to `main.rs` --- c2rust-refactor/src/{bin/c2rust-refactor.rs => main.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename c2rust-refactor/src/{bin/c2rust-refactor.rs => main.rs} (99%) diff --git a/c2rust-refactor/src/bin/c2rust-refactor.rs b/c2rust-refactor/src/main.rs similarity index 99% rename from c2rust-refactor/src/bin/c2rust-refactor.rs rename to c2rust-refactor/src/main.rs index 633e948800..d84fdbb3e2 100644 --- a/c2rust-refactor/src/bin/c2rust-refactor.rs +++ b/c2rust-refactor/src/main.rs @@ -8,7 +8,7 @@ use std::str::FromStr; use c2rust_refactor::{file_io, CargoTarget, Command, Cursor, Mark, Options, RustcArgSource}; fn main() { - let yaml = load_yaml!("../refactor.yaml"); + let yaml = load_yaml!("refactor.yaml"); let args = App::from_yaml(yaml).get_matches(); let opts = match parse_opts(&args) {