-
Notifications
You must be signed in to change notification settings - Fork 286
Instrument using $RUSTC_WRAPPER and cargo as a subcommand
#554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…s nothing an complicates logic going forward.
…` as a subcommand, overriding `RUSTC_WRAPPER`. More specifically, instead of using `cargo` as a dependency, which is enormous and causes some compilation issues (#488), we invoke `cargo` as a subcommand. This also has the advantage of using the correct `rustup` `cargo` wrapper so that it resolves correctly. Then we set `RUSTC_WRAPPER` to our own binary. We use `RUSTC_WRAPPER` to detect if we're being invoked as a `cargo` or `rustc` wrapper. If we're the `cargo` wrapper, we parse args using `clap` derive, determine the crate target info (that we want to instrument) using `cargo metadata` instead of the massive `cargo` dependency, and then run `cargo` as a subcommand, passing the `cargo` args as is (so all normal `cargo` invocations all work), our own executable as `$RUSTC_WRAPPER`, and the crate target info and instrumentation args serialized through `$C2RUST_INSTRUMENT_INFO`. If we're the `rustc` wrapper, we parse the instrument info, determine if we should instrument the current `rustc` command if the crate being compiled matches the crate target info passed, and based on that, either invoke `rustc` or run `RunCompiler::new(...).run()` with our `MirTransformCallbacks`, and then save the metadata to the metadata file. Note that we have to pass the `--sysroot` to `RunCompiler` as normally `rustc` looks this up relative to its executable's location, which works when the `rustup` `rustc` wrapper resolves to the toolchain-specific `rustc`, but since we're using `RunCompiler` directly and being `rustc`, we need to explicitly set the sysroot. Instead of passing `c2rust_analysis_rt` as an `--extern` and running `cargo` separately to compile it, we just add it as a normal dependency to the crate we're instrumenting. In this way it's similar to `libc`, which can be `extern`ed as it's in the sysroot, but the preferred way is to specify it as a normal dependency.
…y `cargo` arguments, including `--release` and `--profile`.
…a normal dependency, we can delete only the main binary, forcing it to be rebuilt and re-instrumented. Most of the time building used to be in building `c2rust_analysis_rt`, and on `donna`, was ~15 seconds for `c2rust instrument`. Now it takes only ~0.5 seconds, 30x faster. Thus, we now also unconditionally instrument. Before we only did when the `c2rust-instrument` binary changed, but this missed changes to the instrumented crate. Now that it's fast enough, we just always instrument.
… now use `cargo` correctly and get nice error messages.
…`cargo` args. This gets rid of another use of the binary name.
… script: `get-binary-names-from-cargo-metadata.mjs`.
…cargo` args restrictions aren't in place.
… is gone, we don't need to specify `BINARY=c2rust-analysis-test` in the snapshot test.
pdg/src/snapshots/c2rust_pdg__tests__analysis_test_pdg_snapshot.snap
Outdated
Show resolved
Hide resolved
…should be no diff now.
rinon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I think this is the right direction. Hopefully we can fix this up to not require serializing and passing the cargo target metadata to the subprocess, that's pretty cumbersome if it can be avoided (see comments).
I do have one major concern with this approach... Previously we would rebuild everything using whatever version of rustc was embedded in the dynamic instrumenter. Now, we rely on the rustc that this wrapper calls to be identical to (or at least closely compatible with) the version we linked against. We should enforce this and warn if there is a mismatch.
If the
That's a good point. One thing to note, though, is that we must depend on the system's This is also why I think that, in hindsight, the rpath embedding is suboptimal, as it embeds an absolute path in a binary that should be portable. It's not the worst, as we just get the old behavior if that absolute rpath doesn't exist, and if it does exist, it's highly likely it's correct, because it's a toolchain/version-specific path, and the dynamic libraries include their hash. Instead, I think it's better that all |
|
I'm now (2660946) detecting build scripts by checking if it is |
|
However, now I'm getting an error in the actual instrumentation code, which wasn't happening previously, but this is probably from other changes and refactors to the instrumentation code in other PRs, as it's not in the code changes from this PR.
thread 'rustc' panicked at 'operand is not of integer-castable type: op = _4, ty = src::configfile::config_t, ty.kind(): Adt(src::configfile::config_t, [])', dynamic_instrumentation/src/arg.rs:30:13
stack backtrace:
0: rust_begin_unwind
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/library/core/src/panicking.rs:143:14
2: c2rust_instrument::arg::ArgKind::from_type
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/arg.rs:30:13
3: c2rust_instrument::point::build::InstrumentationBuilder::arg_var
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/point/build.rs:83:42
4: c2rust_instrument::instrument::<impl rustc_middle::mir::visit::Visitor for c2rust_instrument::point::InstrumentationAdder>::visit_assign::{{closure}}
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/instrument.rs:181:13
5: c2rust_instrument::instrument::<impl rustc_middle::mir::visit::Visitor for c2rust_instrument::point::InstrumentationAdder>::visit_assign
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/instrument.rs:190:17
6: rustc_middle::mir::visit::Visitor::super_statement
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:381:25
7: rustc_middle::mir::visit::Visitor::visit_statement
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:95:17
8: rustc_middle::mir::visit::Visitor::super_basic_block_data
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:312:21
9: rustc_middle::mir::visit::Visitor::visit_basic_block_data
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:84:17
10: rustc_middle::mir::visit::Visitor::super_body
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:261:21
11: rustc_middle::mir::visit::Visitor::visit_body
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/compiler/rustc_middle/src/mir/visit.rs:78:17
12: c2rust_instrument::instrument::instrument_body
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/instrument.rs:406:5
13: c2rust_instrument::instrument::Instrumenter::instrument_fn
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/instrument.rs:61:9
14: c2rust_instrument::override_queries::{{closure}}
at /home/kkysen/work/rust/c2rust/dynamic_instrumentation/src/main.rs:334:13
15: core::ops::function::FnOnce::call_once
at /rustc/1e12aef3fab243407f9d71ba9956cb2a1bf105d5/library/core/src/ops/function.rs:227:5
16: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>
17: rustc_data_structures::stack::ensure_sufficient_stack::<(&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>::{closure#3}>
18: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>>
19: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_built
20: rustc_mir_transform::check_unsafety::unsafety_check_result
21: <rustc_mir_transform::check_unsafety::provide::{closure#0} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
22: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::UnsafetyCheckResult>
23: rustc_data_structures::stack::ensure_sufficient_stack::<(&rustc_middle::mir::query::UnsafetyCheckResult, rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::UnsafetyCheckResult>::{closure#3}>
24: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::UnsafetyCheckResult>>
25: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::unsafety_check_result
26: rustc_mir_transform::mir_const
27: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>
28: rustc_data_structures::stack::ensure_sufficient_stack::<(&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>::{closure#3}>
29: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, &rustc_data_structures::steal::Steal<rustc_middle::mir::Body>>>
30: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_const
31: rustc_mir_transform::mir_promoted
32: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, (&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, &rustc_data_structures::steal::Steal<rustc_index::vec::IndexVec<rustc_middle::mir::Promoted, rustc_middle::mir::Body>>)>
33: rustc_data_structures::stack::ensure_sufficient_stack::<((&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, &rustc_data_structures::steal::Steal<rustc_index::vec::IndexVec<rustc_middle::mir::Promoted, rustc_middle::mir::Body>>), rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, (&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, &rustc_data_structures::steal::Steal<rustc_index::vec::IndexVec<rustc_middle::mir::Promoted, rustc_middle::mir::Body>>)>::{closure#3}>
34: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<rustc_middle::ty::WithOptConstParam<rustc_span::def_id::LocalDefId>, (&rustc_data_structures::steal::Steal<rustc_middle::mir::Body>, &rustc_data_structures::steal::Steal<rustc_index::vec::IndexVec<rustc_middle::mir::Promoted, rustc_middle::mir::Body>>)>>
35: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_promoted
36: <rustc_borrowck::provide::{closure#0} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
37: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::BorrowCheckResult>
38: rustc_data_structures::stack::ensure_sufficient_stack::<(&rustc_middle::mir::query::BorrowCheckResult, rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::BorrowCheckResult>::{closure#3}>
39: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<rustc_span::def_id::LocalDefId, &rustc_middle::mir::query::BorrowCheckResult>>
40: <rustc_query_impl::Queries as rustc_middle::ty::query::QueryEngine>::mir_borrowck
41: <rustc_session::session::Session>::time::<(), rustc_interface::passes::analysis::{closure#2}>
42: rustc_interface::passes::analysis
43: <rustc_query_system::dep_graph::graph::DepGraph<rustc_middle::dep_graph::dep_node::DepKind>>::with_task::<rustc_middle::ty::context::TyCtxt, (), core::result::Result<(), rustc_errors::ErrorReported>>
44: rustc_data_structures::stack::ensure_sufficient_stack::<(core::result::Result<(), rustc_errors::ErrorReported>, rustc_query_system::dep_graph::graph::DepNodeIndex), rustc_query_system::query::plumbing::execute_job<rustc_query_impl::plumbing::QueryCtxt, (), core::result::Result<(), rustc_errors::ErrorReported>>::{closure#3}>
45: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::plumbing::QueryCtxt, rustc_query_system::query::caches::DefaultCache<(), core::result::Result<(), rustc_errors::ErrorReported>>>
46: rustc_query_system::query::plumbing::get_query::<rustc_query_impl::queries::analysis, rustc_query_impl::plumbing::QueryCtxt>
47: <rustc_interface::passes::QueryContext>::enter::<rustc_driver::run_compiler::{closure#1}::{closure#2}::{closure#3}, core::result::Result<(), rustc_errors::ErrorReported>>
48: rustc_interface::interface::create_compiler_and_run::<core::result::Result<(), rustc_errors::ErrorReported>, rustc_driver::run_compiler::{closure#1}>This is the code that panics: c2rust/dynamic_instrumentation/src/arg.rs Lines 20 to 31 in 2660946
@aneksteind, @fw-immunant, any thoughts? I'm not too familiar with this part of the code other than refactors. It seems to be from the hint hint |
|
The above |
|
Filed an issue for it: #570, so it shouldn't block this PR. |
rinon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR has grown somewhat beyond it's original goal, which was just to build via the cargo cli tool instead of the library. I'd like to see this get split into a few different changes. At the very least, move the script changes into a separate PR?
I put a few more comments, but this is really too large to properly review as it is now.
|
I can move the script deletions to a separate PR, but the |
| pub fn instrument( | ||
| metadata_file_path: &Path, | ||
| rt_path: &Path, | ||
| _args: &[String], | ||
| ) -> anyhow::Result<()> { | ||
| let config = Config::default().unwrap(); | ||
| config.shell().set_verbosity(Verbosity::Quiet); | ||
| let mode = CompileMode::Build; | ||
| let compile_opts = CompileOptions::new(&config, mode).unwrap(); | ||
|
|
||
| let manifest_path = find_root_manifest_for_wd(config.cwd()).unwrap(); | ||
| let ws = Workspace::new(&manifest_path, &config).unwrap(); | ||
|
|
||
| let rt_manifest_path = find_root_manifest_for_wd(rt_path).unwrap(); | ||
| let mut rt_ws = Workspace::new(&rt_manifest_path, &config).unwrap(); | ||
| rt_ws.set_target_dir(ws.target_dir()); | ||
|
|
||
| let exec = Arc::new(InstrumentationExecutor { | ||
| default: DefaultExecutor, | ||
| target_pkg: ws.current().unwrap().package_id(), | ||
| rt_crate_path: Mutex::new(String::new()), | ||
| building_rt: AtomicBool::new(true), | ||
| }); | ||
| let exec_dyn: Arc<dyn Executor> = exec.clone(); | ||
|
|
||
| let cwd = env::current_dir().unwrap(); | ||
|
|
||
| env::set_current_dir(rt_ws.root()).unwrap(); | ||
| ops::compile_with_exec(&rt_ws, &compile_opts, &exec_dyn)?; | ||
|
|
||
| exec.building_rt.store(false, Ordering::Relaxed); | ||
| env::set_current_dir(cwd).unwrap(); | ||
| ops::compile_with_exec(&ws, &compile_opts, &exec_dyn)?; | ||
|
|
||
| INSTRUMENTER.finalize(metadata_file_path) | ||
| } | ||
| struct InstrumentationExecutor { | ||
| default: DefaultExecutor, | ||
| target_pkg: PackageId, | ||
| rt_crate_path: Mutex<String>, | ||
| building_rt: AtomicBool, | ||
| } | ||
|
|
||
| impl Executor for InstrumentationExecutor { | ||
| fn init(&self, cx: &Context<'_, '_>, unit: &Unit) { | ||
| if self.building_rt.load(Ordering::Relaxed) && cx.is_primary_package(unit) { | ||
| *self.rt_crate_path.lock().unwrap() = cx.outputs(unit).unwrap()[0] | ||
| .path | ||
| .to_str() | ||
| .unwrap() | ||
| .to_owned(); | ||
| } | ||
| self.default.init(cx, unit); | ||
| } | ||
|
|
||
| fn exec( | ||
| &self, | ||
| cmd: &ProcessBuilder, | ||
| id: PackageId, | ||
| target: &Target, | ||
| _mode: CompileMode, | ||
| _on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>, | ||
| _on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>, | ||
| ) -> CargoResult<()> { | ||
| let mut args: Vec<String> = cmd | ||
| .get_args() | ||
| .iter() | ||
| .map(|a| a.to_str().unwrap().to_string()) | ||
| .collect(); | ||
| args.insert(0, cmd.get_program().to_str().unwrap().to_string()); | ||
| // We need to point the rust compiler libraries to the corresponding sysroot | ||
| args.push(format!("--sysroot={}", env!("RUST_SYSROOT"))); | ||
| for (var, val) in cmd.get_envs() { | ||
| env::set_var(var, val.as_ref().unwrap_or(&OsString::new())); | ||
| } | ||
| if id == self.target_pkg && !target.for_host() { | ||
| args.push("--extern".to_string()); | ||
| args.push(format!( | ||
| "c2rust_analysis_rt={}", | ||
| self.rt_crate_path.lock().unwrap() | ||
| )); | ||
| let mut callbacks = MirTransformCallbacks; | ||
| // TODO: Capture stdout and pass it back to cargo | ||
| rustc_driver::RunCompiler::new(&args, &mut callbacks) | ||
| .run() | ||
| .map_err(|_| anyhow!("Compilation failed")) | ||
| } else { | ||
| let mut callbacks = NullCallbacks; | ||
| rustc_driver::RunCompiler::new(&args, &mut callbacks) | ||
| .run() | ||
| .map_err(|_| anyhow!("Compilation failed")) | ||
| } | ||
| } | ||
|
|
||
| fn force_rebuild(&self, unit: &Unit) -> bool { | ||
| self.building_rt.load(Ordering::Relaxed) || self.default.force_rebuild(unit) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was deleted as it is the cargo-as-a-library code that was deleted. The rest of lib.rs was moved to the end of main.rs as-is, with only imports merged.
Is it really too large of a change to review? There are ~160 new lines of code in It's unfortunate that the Significant development-time savings are waiting on this PR with its 30-fold incremental instrumentation performance improvements, as well as the changes I'm trying to make off of this, which are hard to do while this one still changes. Splitting this PR up into more is both difficult as I'm not sure how to do so effectively, might introduce bugs that I've already fixed, and make everything waiting for this PR take much longer. There's been a lot of development on this PR, so there are a lot of commits, but a lot of those went towards simplifying things and fixing bugs. For example, the |
|
W/r/t the |
|
Oh, that's a good idea. Let me see if that works. |
… solution vs. the `--target` one used by `miri`, et. al.
fe8408f to
5abd6d6
Compare
…(hopefully) cleaner diff.
|
@fw-immunant, I tried moving that previously |
git only detects moves/renames within a single commit, so the commits moving code from but this change to the rebase plan ran into a bunch of conflicts, presumably because of the merge commits between the two. I don't really know how to work with interactive rebase in the presence of various merge commits. |
|
@fw-immunant, I think it's too hard to rebase that far back now, as doing so would require a lot of manual merges. @rinon approved now, so I think I'll just merge this as is, and then fix up the |
…rust` just forward args to discovered subcommands This changes `c2rust` to be a simpler wrapper around the other `c2rust-*` subcommand. Instead of `c2rust` having to know about all the subcommands and their arguments upfront, `c2rust $subcommand $args` just runs `c2rust-$subcommand $args`. This allows `c2rust instrument` to work as before (before #554), while also enabling `c2rust analyze` and `c2rust pdg` in the same way. The `clap` help messages are still preserved for the most part, except for the short help messages for the subcommands. Otherwise, `c2rust --help` works as before (while also suggesting the new subcommands), and `c2rust $subcommand --help` works by running `c2rust-$subcommand --help` (instead of `clap` intercepting the `--help`). The way this is implemented is, first the `c2rust` binary's directory is searched for executables named `c2rust-*` to discover subcommands. This is combined with the simple list of known subcommands (`["transpile", "instrument", "pdg", "analyze"]`) in case they're not discovered properly and we still want to suggest them. Then we check if the first argument is one of these subcommands. If it exists, we invoke it. If it doesn't exist, but is known, we suggest building it, and it doesn't exist and isn't known (or there was no subcommand given), then we run the `clap` parser and let it handle arg parsing and nice error/help messages. The reason we don't have everything go through `clap` is that I couldn't figure out a way to have `clap` just forward all arguments, even ones like `--metadata` with hyphens (`Arg::allow_hyphen_values` didn't work), without requiring a leading `--` argument.
Fixes #448 and should fix #488.
Overview
This reimplements
c2rust-instrumentby invokingcargoas a subcommand, overriding$RUSTC_WRAPPER.Implementation
More specifically, instead of using
cargoas a dependency, which is enormous (very long compile times) and causes some compilation issues (#488), we invokecargoas a subcommand. This also has the advantage of using the correctrustupcargowrapper so that it resolves correctly. See #448 for a more detailed explanation of why this is a better approach and why other tools likeclippyandmirido it this way.Then we set
$RUSTC_WRAPPERto our own binary. We use$RUSTC_WRAPPERto detect if we're being invoked as acargoorrustcwrapper.If we're the
cargowrapper, we:clapderive (Update to clap3 #395)cargoas a subcommand, passing:cargoargs as is (so all normalcargoinvocations all work)$RUSTC_WRAPPER$C2RUST_INSTRUMENT_METADATAIf we're the
rustcwrapper, we:rustccommand if$CARGO_PRIMARY_PACKAGEis setRunCompiler::new(...).run()with ourMirTransformCallbacks, orTimePassesCallbacks::default()(rustc's default) if not instrumentingNote that we have to pass the
--sysroottoRunCompileras normallyrustclooks this up relative to its executable's location, which works when therustuprustcwrapper resolves to the toolchain-specificrustc, but since we're usingRunCompilerdirectly and beingrustc, we need to explicitly set the sysroot.Usage Changes
Instead of passing
c2rust_analysis_rtas an--externand runningcargoseparately to compile it, we just add it as a normal, optional dependency to the crate we're instrumenting. In this way, it's similar tolibc, which can beexterned as it's in the sysroot,but the preferred way is to specify it as a normal dependency. Thus, we can also drop the runtime argument that seemed odd to have to specify to
c2rust instrument.The existing
c2rust-instrumentbinary in thec2rustpackage is now gone (along with its--features dynamic-instrumentation), replaced by the newc2rust-instrumentbinary indynamic-instrumentation/src/bin.rs(the crate has also been renamed toc2rust-instrument). Now,c2rust_instrumentno longer exposes a library crate, and is purely a binary crate. This is because there's no way to usec2rust-instrumentnot as a binary, as it invokes itself and thus needs control overmainto function correctly.This does cause a slight change in that
c2rustno longer sees theinstrument.yaml; onlyc2rust-instrumentdoes. This could potentially hurt shell autocompletion in the future (not currently implemented), but the drawbacks seems slim. Instead, we don't need to remember--features dynamic-instrumentationas a simplecargo buildbuilds everything. And we've upgraded to a superiorclap3 derive parser, not the deprecated YAML parser.Fast!
Furthermore, now that we use
cargonormally and includec2rust_analysis_rtas a normal dependency, we can delete only the main binary (withcargo clean --package), forcing it to be rebuilt and re-instrumented. Most of the time building used to be in buildingc2rust_analysis_rt, and on the fastdonna, was ~15 seconds forc2rust instrument. Now it takes only ~0.5 seconds, 30x faster.Also enabling this is using a separate
$CARGO_TARGET_DIR:instrument.targetinstead of the defaulttarget. This allows builds not to conflict with normal, non-instrumented builds usingcargo build, so we don't need tocargo cleaneverything every time.Thus, we now also unconditionally instrument (in
pdg.sh). Before, we only did when thec2rust-instrumentbinary changed, but this missed changes to the instrumented crate. Now that it's fast enough, we just always instrument.Previously, I was working on getting incremental instrumentation to work, but that proved harder than I thought for the corner cases (which did pop up). With this change, we remove the largest block to fast iteration times, so I think we don't need incremental instrumentation at all until we get to iterating on small edits in large instrumented crates.
Fixes and Improvements
c2rust instrumentshould apply extracargoargs #448: the primary fix. Now we can specify anycargoargs, such asbuild,run,test,--release, etc.libiconvnecessary on mac, doesn't link #488: should be fixed as the offendingcargodependency is removed, but needs to be tested by @boyland-pf.pretty-instrument-err.mjsandget-binary-names-from-cargo-metadata.mjs, the temporarynodescripts.Thus, we can remove all
nodedependencies.pdg.sh.cargodependency is dropped, saving a lot on compile time, as it is a huge dependency.--features dynamic-instrumentationis removed, so a simplecargo buildworks for everything now.