Skip to content

Commit 6939702

Browse files
committed
fix recursion issues with crawling paths, embed linker arguments at build time to avoid toolchain issues
1 parent 8d81050 commit 6939702

File tree

6 files changed

+91
-23
lines changed

6 files changed

+91
-23
lines changed

codegen/build.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,48 @@
1-
fn main() {
1+
use std::{
2+
path::{Path, PathBuf},
3+
process::Command,
4+
};
5+
6+
fn rustc_path(channel: &str) -> PathBuf {
7+
let output = Command::new("rustup")
8+
.args(["which", "--toolchain", channel, "rustc"])
9+
.output()
10+
.expect("failed to run rustup which");
11+
12+
let rustc_path = String::from_utf8(output.stdout).unwrap();
13+
14+
PathBuf::from(rustc_path.trim())
15+
}
16+
17+
fn target_libdir(rustc: &Path) -> PathBuf {
18+
let output = Command::new(rustc)
19+
.args(["--print", "target-libdir"])
20+
.output()
21+
.expect("failed to run rustc --print target-libdir");
22+
23+
let libdir = String::from_utf8(output.stdout).unwrap();
24+
25+
PathBuf::from(libdir.trim())
26+
}
27+
28+
pub fn main() {
229
// Use to set RUSTC_CHANNEL so we can compute target dir from rustc_plugin
330
let toolchain_toml = include_str!("rust-toolchain.toml");
431
let toolchain_table = toolchain_toml.parse::<toml::Table>().unwrap();
532
let toolchain = toolchain_table["toolchain"].as_table().unwrap();
633
let channel = toolchain["channel"].as_str().unwrap();
734
println!("cargo:rustc-env=RUSTC_CHANNEL={channel}");
35+
36+
// I believe there was some sort of change in cargo, which motivated this change in the original rustc_plugin:
37+
// https://github.com/cognitive-engineering-lab/rustc_plugin/pull/41
38+
//
39+
// This solves issues with linking to the rustc driver dynamic library, as cargo does not seem to put in the correct LD_LIBRARY_PATH for the driver binary instantiations
40+
// Embedding this in the binary solves the problem
41+
let rustc_path = rustc_path(channel);
42+
let target_libdir = target_libdir(&rustc_path);
43+
44+
println!(
45+
"cargo::rustc-link-arg=-Wl,-rpath,{}",
46+
target_libdir.display()
47+
);
848
}

codegen/src/driver/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub const CARGO_VERBOSE: &str = "CARGO_VERBOSE";
1919
pub const WORKSPACE_GRAPH_FILE_ENV: &str = "WORKSPACE_GRAPH_FILE";
2020

2121
pub fn fetch_target_directory(metadata: &Metadata) -> Utf8PathBuf {
22-
let plugin_subdir = format!("plugin-{}", env!("RUSTC_CHANNEL"));
22+
let plugin_subdir = format!("plugin-{}", crate::CHANNEL);
2323
metadata.target_directory.join(plugin_subdir)
2424
}
2525

@@ -197,7 +197,7 @@ pub fn driver_main<T: RustcPlugin>(plugin: T) {
197197
// the driver directly without having to pass --sysroot or anything
198198
let mut args: Vec<String> = orig_args.clone();
199199
if !have_sys_root_arg {
200-
args.extend(["--sysroot".into(), sys_root]);
200+
args.extend(["--sysroot".into(), sys_root.clone()]);
201201
};
202202

203203
// On a given invocation of rustc, we have to decide whether to act as rustc,
@@ -215,16 +215,15 @@ pub fn driver_main<T: RustcPlugin>(plugin: T) {
215215

216216
let run_plugin = !normal_rustc && is_target_crate;
217217

218+
// TODO: this is dangerous
219+
// ignore all lints that could break the comp in crates that we don't care about
220+
// args.extend([String::from("--cap-lints"), String::from("warn")]);
218221
if run_plugin {
219-
// TODO: this is dangerous
220-
args.extend([String::from("--cap-lints"), String::from("warn")]);
221222
log::debug!("Running plugin on crate: {crate_being_built}");
222223
let plugin_args: T::Args =
223224
serde_json::from_str(&env::var(PLUGIN_ARGS).unwrap()).unwrap();
224225
plugin.run(args, plugin_args);
225226
} else {
226-
// ignore all lints that could break the comp in crates that we don't care about
227-
args.extend([String::from("--cap-lints"), String::from("warn")]);
228227
log::debug!(
229228
"Running normal Rust. Relevant variables:\
230229
normal_rustc={normal_rustc}, \

codegen/src/import_path.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ pub(crate) enum ImportPathElement {
1414
Item(DefId),
1515
}
1616

17+
impl ImportPathElement {
18+
pub fn def_id(&self) -> DefId {
19+
match self {
20+
Self::Rename(did, _) => *did,
21+
Self::Item(did) => *did,
22+
}
23+
}
24+
}
25+
1726
impl std::fmt::Debug for ImportPathElement {
1827
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1928
match self {
@@ -55,11 +64,12 @@ impl<'tcx> ImportPathFinder<'tcx> {
5564
fn crawl_module(&mut self, did: DefId, frontier: &[ImportPathElement]) {
5665
trace!("Crawling module {did:?}");
5766

67+
// Push current module onto the path frontier
5868
let mut new_frontier = frontier.to_vec();
5969
new_frontier.push(ImportPathElement::Item(did));
60-
// do not allow modification or weird things happen
6170
let new_frontier = &new_frontier;
6271

72+
// Get children of the module
6373
let children = if did.is_local() {
6474
self.tcx.module_children_local(did.expect_local())
6575
} else {
@@ -69,15 +79,16 @@ impl<'tcx> ImportPathFinder<'tcx> {
6979
for child in children {
7080
let rename = child.ident.to_string();
7181

82+
// Skip private items if we don't include them
7283
if !self.include_private_paths && !child.vis.is_public() {
7384
trace!("Skipping private child {rename:?}");
7485
continue;
7586
}
7687

77-
let did = if let Some(did) = child.res.opt_def_id() {
78-
did
79-
} else {
80-
continue;
88+
// Skip if the child has no DefId
89+
let did = match child.res.opt_def_id() {
90+
Some(did) => did,
91+
None => continue,
8192
};
8293

8394
trace!(
@@ -87,16 +98,24 @@ impl<'tcx> ImportPathFinder<'tcx> {
8798
);
8899

89100
match self.tcx.def_kind(did) {
90-
DefKind::Mod => self.crawl_module(did, new_frontier),
91-
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait => {
92-
// save the rename and the def id
101+
DefKind::Mod => {
102+
// Only recurse if this DefId is not already in the current path
103+
if new_frontier.iter().any(|el| el.def_id() == did) {
104+
trace!("Cycle detected for {did:?}, skipping recursion");
105+
continue;
106+
}
107+
self.crawl_module(did, new_frontier)
108+
}
93109

94-
let mut new_frontier = new_frontier.clone();
95-
new_frontier.push(ImportPathElement::Rename(did, rename));
110+
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait => {
111+
// Save the rename and the DefId
112+
let mut path_for_item = new_frontier.clone();
113+
path_for_item.push(ImportPathElement::Rename(did, rename));
96114

97-
trace!("saving import path for {did:?}: {new_frontier:?}");
98-
self.cache.entry(did).or_default().push(new_frontier);
115+
trace!("Saving import path for {did:?}: {path_for_item:?}");
116+
self.cache.entry(did).or_default().push(path_for_item);
99117
}
118+
100119
_ => continue,
101120
}
102121
}

codegen/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ pub use template::{
3939
Collect, Crate, TEMPLATE_DIR, TemplateKind, configure_tera, extend_context_with_args,
4040
};
4141
pub mod driver;
42+
43+
/// The rustc toolchain this crate was built with and needs to work with
44+
pub const CHANNEL: &str = env!("RUSTC_CHANNEL");

codegen/src/plugin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl crate::driver::RustcPlugin for BevyAnalyzer {
5050

5151
// make cargo chatty as well
5252
if args.verbose.get_log_level_int() >= 3 {
53-
cmd.arg("-v");
53+
cmd.arg("-vv");
5454
} else {
5555
cmd.arg("-q");
5656
}
@@ -74,7 +74,7 @@ impl crate::driver::RustcPlugin for BevyAnalyzer {
7474
.map(|a| a.to_string_lossy())
7575
.collect::<Vec<_>>()
7676
.join(" ");
77-
log::debug!("Running: \n{all_env} {bin_name} {args}",);
77+
log::debug!("Running cargo build command: \n{all_env} {bin_name} {args}",);
7878
}
7979
}
8080

xtask/src/main.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,16 +1196,19 @@ impl Xtasks {
11961196
}
11971197

11981198
let api_gen_dir = Self::codegen_crate_dir(&main_workspace_app_settings)?;
1199+
let codegen_toolchain = Self::read_rust_toolchain(&api_gen_dir);
11991200
let codegen_app_settings = main_workspace_app_settings
12001201
.clone()
12011202
.with_workspace_dir(api_gen_dir.clone());
1203+
// .with_toolchain(codegen_toolchain.clone()); // don't think it's needed, the rust toolchain file sorts that out
12021204

12031205
let bevy_repo_app_settings = main_workspace_app_settings
12041206
.clone()
12051207
.with_workspace_dir(bevy_dir.clone())
1206-
.with_toolchain(Self::read_rust_toolchain(&api_gen_dir));
1208+
.with_toolchain(codegen_toolchain.clone());
12071209

12081210
// run cargo install
1211+
log::info!("Running bevy_api_gen against toolchain: {codegen_toolchain}");
12091212
Self::run_system_command(
12101213
&codegen_app_settings,
12111214
"cargo",
@@ -2235,9 +2238,13 @@ fn pop_cargo_env() -> Result<()> {
22352238
let env = std::env::vars().collect::<Vec<_>>();
22362239
// RUSTUP TOOLCHAIN exclude is a temporary fix, it might make deving the api codegen crate not work
22372240
let exclude_list = ["CARGO_HOME"];
2241+
let include_list = []; //"LD_LIBRARY_PATH"
22382242

22392243
for (key, value) in env.iter() {
2240-
if key.starts_with("CARGO_") && !exclude_list.contains(&(key.as_str())) {
2244+
let key_str = &(key.as_str());
2245+
if (include_list.contains(key_str) || key.starts_with("CARGO_"))
2246+
&& !exclude_list.contains(key_str)
2247+
{
22412248
let new_key = format!("MAIN_{key}");
22422249
unsafe { std::env::set_var(new_key, value) };
22432250
unsafe { std::env::remove_var(key) };

0 commit comments

Comments
 (0)