Skip to content
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

Use build scripts from rustc source workspace #15991

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/load-cargo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn load_workspace_at(
) -> anyhow::Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroServer>)> {
let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
let root = ProjectManifest::discover_single(&root)?;
let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
let mut workspace = ProjectWorkspace::load(root, cargo_config, progress, false)?;

if load_config.load_out_dirs_from_check {
let build_scripts = workspace.run_build_scripts(cargo_config, progress)?;
Expand Down Expand Up @@ -81,6 +81,7 @@ pub fn load_workspace(
vfs.file_id(&path)
},
extra_env,
None,
);
let proc_macros = {
let proc_macro_server = match &proc_macro_server {
Expand Down
2 changes: 1 addition & 1 deletion crates/project-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub use crate::{
manifest_path::ManifestPath,
project_json::{ProjectJson, ProjectJsonData},
sysroot::Sysroot,
workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
workspace::{CfgOverrides, PackageRoot, ProjectWorkspace, RustcWorkspace},
};

#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
Expand Down
10 changes: 6 additions & 4 deletions crates/project-model/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use rustc_hash::FxHashMap;
use serde::de::DeserializeOwned;

use crate::{
CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
WorkspaceBuildScripts,
CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, RustcWorkspace,
Sysroot, WorkspaceBuildScripts,
};

fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) {
Expand All @@ -29,7 +29,7 @@ fn load_cargo_with_overrides(
cargo: cargo_workspace,
build_scripts: WorkspaceBuildScripts::default(),
sysroot: Err(None),
rustc: Err(None),
rustc: RustcWorkspace::Loaded(Err(None)),
rustc_cfg: Vec::new(),
cfg_overrides,
toolchain: None,
Expand All @@ -48,7 +48,7 @@ fn load_cargo_with_sysroot(
cargo: cargo_workspace,
build_scripts: WorkspaceBuildScripts::default(),
sysroot: Ok(get_fake_sysroot()),
rustc: Err(None),
rustc: RustcWorkspace::Loaded(Err(None)),
rustc_cfg: Vec::new(),
cfg_overrides: Default::default(),
toolchain: None,
Expand All @@ -62,6 +62,7 @@ fn load_cargo_with_sysroot(
}
},
&Default::default(),
None,
)
}

Expand Down Expand Up @@ -146,6 +147,7 @@ fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacro
}
},
&Default::default(),
None,
)
}

Expand Down
140 changes: 84 additions & 56 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use crate::{
project_json::Crate,
rustc_cfg::{self, RustcCfgConfig},
sysroot::SysrootCrate,
target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, ManifestPath,
Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
target_data_layout, utf8_stdout, CargoConfig, CargoWorkspace, InvocationStrategy, Package,
ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts,
};

/// A set of cfg-overrides per crate.
Expand Down Expand Up @@ -53,14 +53,34 @@ pub struct PackageRoot {
pub exclude: Vec<AbsPathBuf>,
}

#[derive(Clone, PartialEq)]
pub enum RustcWorkspace {
/// A globally-configured rustc source location is being opened as a rust-analyzer workspace
Opening,
/// The rustc source is loaded, e.g. from sysroot, but is not a rust-analyzer workspace
Loaded(Result<(CargoWorkspace, WorkspaceBuildScripts), Option<String>>),
}

impl RustcWorkspace {
/// Returns the loaded `CargoWorkspace` of the rustc source.
/// Will be `None` if either the rustc source is opened as a rust-analyzer workspace
/// or its loading failed.
fn loaded(&self) -> Option<&(CargoWorkspace, WorkspaceBuildScripts)> {
match self {
Self::Opening => None,
Self::Loaded(res) => res.as_ref().ok(),
}
}
}

#[derive(Clone)]
pub enum ProjectWorkspace {
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
Cargo {
cargo: CargoWorkspace,
build_scripts: WorkspaceBuildScripts,
sysroot: Result<Sysroot, Option<String>>,
rustc: Result<(CargoWorkspace, WorkspaceBuildScripts), Option<String>>,
rustc: RustcWorkspace,
/// Holds cfg flags for the current target. We get those by running
/// `rustc --print cfg`.
///
Expand Down Expand Up @@ -119,7 +139,7 @@ impl fmt::Debug for ProjectWorkspace {
.field("sysroot", &sysroot.is_ok())
.field(
"n_rustc_compiler_crates",
&rustc.as_ref().map_or(0, |(rc, _)| rc.packages().len()),
&rustc.loaded().map_or(0, |(rc, _)| rc.packages().len()),
)
.field("n_rustc_cfg", &rustc_cfg.len())
.field("n_cfg_overrides", &cfg_overrides.len())
Expand Down Expand Up @@ -151,15 +171,17 @@ impl ProjectWorkspace {
manifest: ProjectManifest,
config: &CargoConfig,
progress: &dyn Fn(String),
opening_rustc_workspace: bool,
) -> anyhow::Result<ProjectWorkspace> {
ProjectWorkspace::load_inner(&manifest, config, progress)
ProjectWorkspace::load_inner(&manifest, config, progress, opening_rustc_workspace)
.with_context(|| format!("Failed to load the project at {manifest}"))
}

fn load_inner(
manifest: &ProjectManifest,
config: &CargoConfig,
progress: &dyn Fn(String),
opening_rustc_workspace: bool,
) -> anyhow::Result<ProjectWorkspace> {
let version = |current_dir, cmd_path, prefix: &str| {
let cargo_version = utf8_stdout({
Expand Down Expand Up @@ -236,48 +258,56 @@ impl ProjectWorkspace {
tracing::info!(workspace = %cargo_toml, src_root = %sysroot.src_root(), root = %sysroot.root(), "Using sysroot");
}

let rustc_dir = match &config.rustc_source {
Some(RustLibSource::Path(path)) => ManifestPath::try_from(path.clone())
.map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
Some(RustLibSource::Discover) => {
sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
|| Some(format!("Failed to discover rustc source for sysroot.")),
)
}
None => Err(None),
};

let rustc = rustc_dir.and_then(|rustc_dir| {
tracing::info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
match CargoWorkspace::fetch_metadata(
&rustc_dir,
cargo_toml.parent(),
&CargoConfig {
features: crate::CargoFeatures::default(),
..config.clone()
},
progress,
) {
Ok(meta) => {
let workspace = CargoWorkspace::new(meta);
let buildscripts = WorkspaceBuildScripts::rustc_crates(
&workspace,
cargo_toml.parent(),
&config.extra_env,
);
Ok((workspace, buildscripts))
let rustc = if opening_rustc_workspace {
RustcWorkspace::Opening
} else {
let rustc_dir = match &config.rustc_source {
// `config.rustc_source == Some(Path(...))` while `!opening_rustc_workspace` should only occur if
// `ManifestPath::try_from(rustc_dir)` failed in `fetch_workspaces`, so no need to attempt it here
// again.
Some(RustLibSource::Path(path)) => {
Err(Some(format!("rustc source path is not absolute: {path}")))
}
Err(e) => {
tracing::error!(
%e,
"Failed to read Cargo metadata from rustc source at {rustc_dir}",
);
Err(Some(format!(
"Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
)))
Some(RustLibSource::Discover) => {
sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
|| Some(format!("Failed to discover rustc source for sysroot.")),
)
}
}
});
None => Err(None),
};

RustcWorkspace::Loaded(rustc_dir.and_then(|rustc_dir| {
tracing::info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source");
match CargoWorkspace::fetch_metadata(
&rustc_dir,
cargo_toml.parent(),
&CargoConfig {
features: crate::CargoFeatures::default(),
..config.clone()
},
progress,
) {
Ok(meta) => {
let workspace = CargoWorkspace::new(meta);
let buildscripts = WorkspaceBuildScripts::rustc_crates(
&workspace,
cargo_toml.parent(),
&config.extra_env,
);
Ok((workspace, buildscripts))
}
Err(e) => {
tracing::error!(
%e,
"Failed to read Cargo metadata from rustc source at {rustc_dir}",
);
Err(Some(format!(
"Failed to read Cargo metadata from rustc source at {rustc_dir}: {e}"
)))
}
}
}))
};

let rustc_cfg = rustc_cfg::get(
config.target.as_deref(),
Expand Down Expand Up @@ -564,7 +594,7 @@ impl ProjectWorkspace {
PackageRoot { is_local, include, exclude }
})
.chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root())))
.chain(rustc.iter().flat_map(|(rustc, _)| {
.chain(rustc.loaded().iter().flat_map(|(rustc, _)| {
rustc.packages().map(move |krate| PackageRoot {
is_local: false,
include: vec![rustc[krate].manifest.parent().to_path_buf()],
Expand Down Expand Up @@ -592,7 +622,7 @@ impl ProjectWorkspace {
sysroot_package_len + project.n_crates()
}
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
let rustc_package_len = rustc.as_ref().map_or(0, |(it, _)| it.packages().len());
let rustc_package_len = rustc.loaded().map_or(0, |(it, _)| it.packages().len());
let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.crates().len());
cargo.packages().len() + sysroot_package_len + rustc_package_len
}
Expand All @@ -607,6 +637,7 @@ impl ProjectWorkspace {
&self,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
extra_env: &FxHashMap<String, String>,
opened_rustc_workspace: Option<(&CargoWorkspace, &WorkspaceBuildScripts)>,
) -> (CrateGraph, ProcMacroPaths) {
let _p = profile::span("ProjectWorkspace::to_crate_graph");

Expand All @@ -633,7 +664,10 @@ impl ProjectWorkspace {
target_layout,
} => cargo_to_crate_graph(
load,
rustc.as_ref().ok(),
match rustc {
RustcWorkspace::Opening => opened_rustc_workspace,
RustcWorkspace::Loaded(res) => res.as_ref().ok().map(|(a, b)| (a, b)),
},
cargo,
sysroot.as_ref().ok(),
rustc_cfg.clone(),
Expand Down Expand Up @@ -844,7 +878,7 @@ fn project_json_to_crate_graph(

fn cargo_to_crate_graph(
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
rustc: Option<(&CargoWorkspace, &WorkspaceBuildScripts)>,
cargo: &CargoWorkspace,
sysroot: Option<&Sysroot>,
rustc_cfg: Vec<CfgFlag>,
Expand Down Expand Up @@ -1030,13 +1064,7 @@ fn cargo_to_crate_graph(
&pkg_crates,
&cfg_options,
override_cfg,
if rustc_workspace.workspace_root() == cargo.workspace_root() {
// the rustc workspace does not use the installed toolchain's proc-macro server
// so we need to make sure we don't use the pre compiled proc-macros there either
build_scripts
} else {
rustc_build_scripts
},
rustc_build_scripts,
target_layout,
channel,
);
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-analyzer/src/cli/analysis_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl flags::AnalysisStats {
let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
let manifest = ProjectManifest::discover_single(&path)?;

let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
let mut workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress, false)?;
let metadata_time = db_load_sw.elapsed();
let load_cargo_config = LoadCargoConfig {
load_out_dirs_from_check: !self.disable_build_scripts,
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-analyzer/src/cli/lsif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl flags::Lsif {
let path = AbsPathBuf::assert(env::current_dir()?.join(&self.path));
let manifest = ProjectManifest::discover_single(&path)?;

let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress, false)?;

let (host, vfs, _proc_macro) =
load_workspace(workspace, &cargo_config.extra_env, &load_cargo_config)?;
Expand Down
Loading