Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/base-db/src/input.rs25
-rw-r--r--crates/project-model/src/build_dependencies.rs115
-rw-r--r--crates/project-model/src/cargo_workspace.rs14
-rw-r--r--crates/project-model/src/lib.rs19
-rw-r--r--crates/project-model/src/sysroot.rs50
-rw-r--r--crates/project-model/src/workspace.rs66
6 files changed, 175 insertions, 114 deletions
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 8c9393bcc9..fdaebeaa93 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -30,7 +30,8 @@ pub type ProcMacroPaths =
pub enum ProcMacroLoadingError {
Disabled,
FailedToBuild,
- MissingDylibPath,
+ ExpectedProcMacroArtifact,
+ MissingDylibPath(Box<[String]>),
NotYetBuilt,
NoProcMacros,
ProcMacroSrvError(Box<str>),
@@ -39,8 +40,9 @@ impl ProcMacroLoadingError {
pub fn is_hard_error(&self) -> bool {
match self {
ProcMacroLoadingError::Disabled | ProcMacroLoadingError::NotYetBuilt => false,
- ProcMacroLoadingError::FailedToBuild
- | ProcMacroLoadingError::MissingDylibPath
+ ProcMacroLoadingError::ExpectedProcMacroArtifact
+ | ProcMacroLoadingError::FailedToBuild
+ | ProcMacroLoadingError::MissingDylibPath(_)
| ProcMacroLoadingError::NoProcMacros
| ProcMacroLoadingError::ProcMacroSrvError(_) => true,
}
@@ -51,10 +53,23 @@ impl Error for ProcMacroLoadingError {}
impl fmt::Display for ProcMacroLoadingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
+ ProcMacroLoadingError::ExpectedProcMacroArtifact => {
+ write!(f, "proc-macro crate did not build proc-macro artifact")
+ }
ProcMacroLoadingError::Disabled => write!(f, "proc-macro expansion is disabled"),
ProcMacroLoadingError::FailedToBuild => write!(f, "proc-macro failed to build"),
- ProcMacroLoadingError::MissingDylibPath => {
- write!(f, "proc-macro crate build data is missing a dylib path")
+ ProcMacroLoadingError::MissingDylibPath(candidates) if candidates.is_empty() => {
+ write!(
+ f,
+ "proc-macro crate built but the dylib path is missing, this indicates a problem with your build system."
+ )
+ }
+ ProcMacroLoadingError::MissingDylibPath(candidates) => {
+ write!(
+ f,
+ "proc-macro crate built but the dylib path is missing, this indicates a problem with your build system. Candidates not considered due to not having a dynamic library extension: {}",
+ candidates.join(", ")
+ )
}
ProcMacroLoadingError::NotYetBuilt => write!(f, "proc-macro not yet built"),
ProcMacroLoadingError::NoProcMacros => {
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index 499caa622c..664665625f 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -16,6 +16,7 @@ use la_arena::ArenaMap;
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
use rustc_hash::{FxHashMap, FxHashSet};
use serde::Deserialize as _;
+use stdx::{always, never};
use toolchain::Tool;
use crate::{
@@ -30,6 +31,15 @@ pub struct WorkspaceBuildScripts {
error: Option<String>,
}
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
+pub enum ProcMacroDylibPath {
+ Path(AbsPathBuf),
+ DylibNotFound(Box<[Utf8PathBuf]>),
+ NotProcMacro,
+ #[default]
+ NotBuilt,
+}
+
/// Output of the build script and proc-macro building step for a concrete package.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct BuildScriptOutput {
@@ -43,7 +53,7 @@ pub(crate) struct BuildScriptOutput {
/// Directory where a build script might place its output.
pub(crate) out_dir: Option<AbsPathBuf>,
/// Path to the proc-macro library file if this package exposes proc-macros.
- pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
+ pub(crate) proc_macro_dylib_path: ProcMacroDylibPath,
}
impl BuildScriptOutput {
@@ -51,7 +61,7 @@ impl BuildScriptOutput {
self.cfgs.is_empty()
&& self.envs.is_empty()
&& self.out_dir.is_none()
- && self.proc_macro_dylib_path.is_none()
+ && self.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt
}
}
@@ -126,6 +136,8 @@ impl WorkspaceBuildScripts {
|package, cb| {
if let Some(&(package, workspace)) = by_id.get(package) {
cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
+ } else {
+ never!("Received compiler message for unknown package: {}", package);
}
},
progress,
@@ -140,12 +152,9 @@ impl WorkspaceBuildScripts {
if tracing::enabled!(tracing::Level::INFO) {
for (idx, workspace) in workspaces.iter().enumerate() {
for package in workspace.packages() {
- let package_build_data = &mut res[idx].outputs[package];
+ let package_build_data: &mut BuildScriptOutput = &mut res[idx].outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- workspace[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", workspace[package].manifest,);
}
}
}
@@ -198,10 +207,33 @@ impl WorkspaceBuildScripts {
let path = dir_entry.path();
let extension = path.extension()?;
if extension == std::env::consts::DLL_EXTENSION {
- let name = path.file_stem()?.to_str()?.split_once('-')?.0.to_owned();
- let path = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).ok()?)
- .ok()?;
- return Some((name, path));
+ let name = path
+ .file_stem()?
+ .to_str()?
+ .split_once('-')?
+ .0
+ .trim_start_matches("lib")
+ .to_owned();
+ let path = match Utf8PathBuf::from_path_buf(path) {
+ Ok(path) => path,
+ Err(path) => {
+ tracing::warn!(
+ "Proc-macro dylib path contains non-UTF8 characters: {:?}",
+ path.display()
+ );
+ return None;
+ }
+ };
+ return match AbsPathBuf::try_from(path) {
+ Ok(path) => Some((name, path)),
+ Err(path) => {
+ tracing::error!(
+ "proc-macro dylib path is not absolute: {:?}",
+ path
+ );
+ None
+ }
+ };
}
}
None
@@ -209,28 +241,24 @@ impl WorkspaceBuildScripts {
.collect();
for p in rustc.packages() {
let package = &rustc[p];
- if package
- .targets
- .iter()
- .any(|&it| matches!(rustc[it].kind, TargetKind::Lib { is_proc_macro: true }))
- {
- if let Some((_, path)) = proc_macro_dylibs
- .iter()
- .find(|(name, _)| *name.trim_start_matches("lib") == package.name)
- {
- bs.outputs[p].proc_macro_dylib_path = Some(path.clone());
+ bs.outputs[p].proc_macro_dylib_path =
+ if package.targets.iter().any(|&it| {
+ matches!(rustc[it].kind, TargetKind::Lib { is_proc_macro: true })
+ }) {
+ match proc_macro_dylibs.iter().find(|(name, _)| *name == package.name) {
+ Some((_, path)) => ProcMacroDylibPath::Path(path.clone()),
+ _ => ProcMacroDylibPath::DylibNotFound(Box::default()),
+ }
+ } else {
+ ProcMacroDylibPath::NotProcMacro
}
- }
}
if tracing::enabled!(tracing::Level::INFO) {
for package in rustc.packages() {
let package_build_data = &bs.outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- rustc[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", rustc[package].manifest,);
}
}
}
@@ -263,6 +291,12 @@ impl WorkspaceBuildScripts {
|package, cb| {
if let Some(&package) = by_id.get(package) {
cb(&workspace[package].name, &mut outputs[package]);
+ } else {
+ never!(
+ "Received compiler message for unknown package: {}\n {}",
+ package,
+ by_id.keys().join(", ")
+ );
}
},
progress,
@@ -272,10 +306,7 @@ impl WorkspaceBuildScripts {
for package in workspace.packages() {
let package_build_data = &outputs[package];
if !package_build_data.is_empty() {
- tracing::info!(
- "{}: {package_build_data:?}",
- workspace[package].manifest.parent(),
- );
+ tracing::info!("{}: {package_build_data:?}", workspace[package].manifest,);
}
}
}
@@ -348,15 +379,25 @@ impl WorkspaceBuildScripts {
progress(format!(
"building compile-time-deps: proc-macro {name} built"
));
+ always!(
+ data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt,
+ "received multiple compiler artifacts for the same package: {message:?}"
+ );
+ if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
+ data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
+ }
if message.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro)
{
- // Skip rmeta file
- if let Some(filename) =
- message.filenames.iter().find(|file| is_dylib(file))
- {
- let filename = AbsPath::assert(filename);
- data.proc_macro_dylib_path = Some(filename.to_owned());
- }
+ data.proc_macro_dylib_path =
+ match message.filenames.iter().find(|file| is_dylib(file)) {
+ Some(filename) => {
+ let filename = AbsPath::assert(filename);
+ ProcMacroDylibPath::Path(filename.to_owned())
+ }
+ None => ProcMacroDylibPath::DylibNotFound(
+ message.filenames.clone().into_boxed_slice(),
+ ),
+ };
}
});
}
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 25abb19d9d..767a4aade0 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -245,7 +245,7 @@ pub enum TargetKind {
}
impl TargetKind {
- fn new(kinds: &[cargo_metadata::TargetKind]) -> TargetKind {
+ pub fn new(kinds: &[cargo_metadata::TargetKind]) -> TargetKind {
for kind in kinds {
return match kind {
cargo_metadata::TargetKind::Bin => TargetKind::Bin,
@@ -604,12 +604,12 @@ impl FetchMetadata {
// but nothing else
let mut extra_args = config.extra_args.iter();
while let Some(arg) = extra_args.next() {
- if arg == "-Z" {
- if let Some(arg) = extra_args.next() {
- needs_nightly = true;
- other_options.push("-Z".to_owned());
- other_options.push(arg.to_owned());
- }
+ if arg == "-Z"
+ && let Some(arg) = extra_args.next()
+ {
+ needs_nightly = true;
+ other_options.push("-Z".to_owned());
+ other_options.push(arg.to_owned());
}
}
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 3bf3d06e6b..d39781b150 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -59,7 +59,7 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
use rustc_hash::FxHashSet;
pub use crate::{
- build_dependencies::WorkspaceBuildScripts,
+ build_dependencies::{ProcMacroDylibPath, WorkspaceBuildScripts},
cargo_workspace::{
CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
PackageDependency, RustLibSource, Target, TargetData, TargetKind,
@@ -139,21 +139,22 @@ impl ProjectManifest {
}
fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<ManifestPath> {
- if path.file_name().unwrap_or_default() == target_file_name {
- if let Ok(manifest) = ManifestPath::try_from(path.to_path_buf()) {
- return Some(manifest);
- }
+ if path.file_name().unwrap_or_default() == target_file_name
+ && let Ok(manifest) = ManifestPath::try_from(path.to_path_buf())
+ {
+ return Some(manifest);
}
let mut curr = Some(path);
while let Some(path) = curr {
let candidate = path.join(target_file_name);
- if fs::metadata(&candidate).is_ok() {
- if let Ok(manifest) = ManifestPath::try_from(candidate) {
- return Some(manifest);
- }
+ if fs::metadata(&candidate).is_ok()
+ && let Ok(manifest) = ManifestPath::try_from(candidate)
+ {
+ return Some(manifest);
}
+
curr = path.parent();
}
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 9781c46737..c0a5009afb 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -143,12 +143,11 @@ impl Sysroot {
Some(root) => {
// special case rustc, we can look that up directly in the sysroot's bin folder
// as it should never invoke another cargo binary
- if let Tool::Rustc = tool {
- if let Some(path) =
+ if let Tool::Rustc = tool
+ && let Some(path) =
probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into())
- {
- return toolchain::command(path, current_dir, envs);
- }
+ {
+ return toolchain::command(path, current_dir, envs);
}
let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs);
@@ -291,29 +290,26 @@ impl Sysroot {
pub fn set_workspace(&mut self, workspace: RustLibSrcWorkspace) {
self.workspace = workspace;
- if self.error.is_none() {
- if let Some(src_root) = &self.rust_lib_src_root {
- let has_core = match &self.workspace {
- RustLibSrcWorkspace::Workspace(ws) => {
- ws.packages().any(|p| ws[p].name == "core")
- }
- RustLibSrcWorkspace::Json(project_json) => project_json
- .crates()
- .filter_map(|(_, krate)| krate.display_name.clone())
- .any(|name| name.canonical_name().as_str() == "core"),
- RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
- RustLibSrcWorkspace::Empty => true,
+ if self.error.is_none()
+ && let Some(src_root) = &self.rust_lib_src_root
+ {
+ let has_core = match &self.workspace {
+ RustLibSrcWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+ RustLibSrcWorkspace::Json(project_json) => project_json
+ .crates()
+ .filter_map(|(_, krate)| krate.display_name.clone())
+ .any(|name| name.canonical_name().as_str() == "core"),
+ RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
+ RustLibSrcWorkspace::Empty => true,
+ };
+ if !has_core {
+ let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
+ " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
+ } else {
+ ", try running `rustup component add rust-src` to possibly fix this"
};
- if !has_core {
- let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
- " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
- } else {
- ", try running `rustup component add rust-src` to possibly fix this"
- };
- self.error = Some(format!(
- "sysroot at `{src_root}` is missing a `core` library{var_note}",
- ));
- }
+ self.error =
+ Some(format!("sysroot at `{src_root}` is missing a `core` library{var_note}",));
}
}
}
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 655da118bb..f031fef165 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -24,7 +24,7 @@ use crate::{
CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath, Package,
ProjectJson, ProjectManifest, RustSourceWorkspaceConfig, Sysroot, TargetData, TargetKind,
WorkspaceBuildScripts,
- build_dependencies::BuildScriptOutput,
+ build_dependencies::{BuildScriptOutput, ProcMacroDylibPath},
cargo_config_file,
cargo_workspace::{CargoMetadataConfig, DepKind, FetchMetadata, PackageData, RustLibSource},
env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env},
@@ -424,12 +424,12 @@ impl ProjectWorkspace {
sysroot.set_workspace(loaded_sysroot);
}
- if !cargo.requires_rustc_private() {
- if let Err(e) = &mut rustc {
- // We don't need the rustc sources here,
- // so just discard the error.
- _ = e.take();
- }
+ if !cargo.requires_rustc_private()
+ && let Err(e) = &mut rustc
+ {
+ // We don't need the rustc sources here,
+ // so just discard the error.
+ _ = e.take();
}
Ok(ProjectWorkspace {
@@ -1163,17 +1163,15 @@ fn project_json_to_crate_graph(
crate = display_name.as_ref().map(|name| name.canonical_name().as_str()),
"added root to crate graph"
);
- if *is_proc_macro {
- if let Some(path) = proc_macro_dylib_path.clone() {
- let node = Ok((
- display_name
- .as_ref()
- .map(|it| it.canonical_name().as_str().to_owned())
- .unwrap_or_else(|| format!("crate{}", idx.0)),
- path,
- ));
- proc_macros.insert(crate_graph_crate_id, node);
- }
+ if *is_proc_macro && let Some(path) = proc_macro_dylib_path.clone() {
+ let node = Ok((
+ display_name
+ .as_ref()
+ .map(|it| it.canonical_name().as_str().to_owned())
+ .unwrap_or_else(|| format!("crate{}", idx.0)),
+ path,
+ ));
+ proc_macros.insert(crate_graph_crate_id, node);
}
(idx, crate_graph_crate_id)
},
@@ -1319,14 +1317,12 @@ fn cargo_to_crate_graph(
// Add dep edge of all targets to the package's lib target
if let Some((to, name)) = lib_tgt.clone() {
- if to != from && kind != TargetKind::BuildScript {
- // (build script can not depend on its library target)
-
- // For root projects with dashes in their name,
- // cargo metadata does not do any normalization,
- // so we do it ourselves currently
- let name = CrateName::normalize_dashes(&name);
- add_dep(crate_graph, from, name, to);
+ match to != from && kind != TargetKind::BuildScript {
+ true => {
+ let name = CrateName::normalize_dashes(&name);
+ add_dep(crate_graph, from, name, to);
+ }
+ false => (),
}
}
}
@@ -1638,9 +1634,21 @@ fn add_target_crate_root(
let proc_macro = match build_data {
Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
match proc_macro_dylib_path {
- Some(path) => Ok((cargo_name.to_owned(), path.clone())),
- None if has_errors => Err(ProcMacroLoadingError::FailedToBuild),
- None => Err(ProcMacroLoadingError::MissingDylibPath),
+ ProcMacroDylibPath::Path(path) => Ok((cargo_name.to_owned(), path.clone())),
+ ProcMacroDylibPath::NotBuilt => Err(ProcMacroLoadingError::NotYetBuilt),
+ ProcMacroDylibPath::NotProcMacro | ProcMacroDylibPath::DylibNotFound(_)
+ if has_errors =>
+ {
+ Err(ProcMacroLoadingError::FailedToBuild)
+ }
+ ProcMacroDylibPath::NotProcMacro => {
+ Err(ProcMacroLoadingError::ExpectedProcMacroArtifact)
+ }
+ ProcMacroDylibPath::DylibNotFound(candidates) => {
+ Err(ProcMacroLoadingError::MissingDylibPath(
+ candidates.iter().map(ToString::to_string).collect(),
+ ))
+ }
}
}
None => Err(ProcMacroLoadingError::NotYetBuilt),