mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
Don't fail workspace loading if sysroot can't be found
This commit is contained in:
parent
9814d79841
commit
b2598f4801
4 changed files with 121 additions and 79 deletions
|
@ -70,6 +70,10 @@ impl Sysroot {
|
||||||
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
|
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
|
||||||
self.crates.iter().map(|(id, _data)| id)
|
self.crates.iter().map(|(id, _data)| id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.crates.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sysroot {
|
impl Sysroot {
|
||||||
|
@ -79,8 +83,7 @@ impl Sysroot {
|
||||||
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
||||||
let sysroot_src_dir =
|
let sysroot_src_dir =
|
||||||
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
||||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover_rustc(
|
pub fn discover_rustc(
|
||||||
|
@ -97,11 +100,10 @@ impl Sysroot {
|
||||||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
||||||
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
|
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
|
||||||
})?;
|
})?;
|
||||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
|
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
|
||||||
let mut sysroot =
|
let mut sysroot =
|
||||||
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
|
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
|
||||||
|
|
||||||
|
@ -152,14 +154,14 @@ impl Sysroot {
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
anyhow::bail!(
|
tracing::error!(
|
||||||
"could not find libcore in sysroot path `{}`{}",
|
"could not find libcore in sysroot path `{}`{}",
|
||||||
sysroot.src_root.as_path().display(),
|
sysroot.src_root.as_path().display(),
|
||||||
var_note,
|
var_note,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sysroot)
|
sysroot
|
||||||
}
|
}
|
||||||
|
|
||||||
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
||||||
|
|
|
@ -81,7 +81,7 @@ fn get_fake_sysroot() -> Sysroot {
|
||||||
// fake sysroot, so we give them both the same path:
|
// fake sysroot, so we give them both the same path:
|
||||||
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
||||||
let sysroot_src_dir = sysroot_dir.clone();
|
let sysroot_src_dir = sysroot_dir.clone();
|
||||||
Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap()
|
Sysroot::load(sysroot_dir, sysroot_src_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
||||||
|
|
|
@ -63,7 +63,7 @@ pub struct PackageRoot {
|
||||||
pub exclude: Vec<AbsPathBuf>,
|
pub exclude: Vec<AbsPathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub enum ProjectWorkspace {
|
pub enum ProjectWorkspace {
|
||||||
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
|
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
|
||||||
Cargo {
|
Cargo {
|
||||||
|
@ -83,7 +83,6 @@ pub enum ProjectWorkspace {
|
||||||
},
|
},
|
||||||
/// Project workspace was manually specified using a `rust-project.json` file.
|
/// Project workspace was manually specified using a `rust-project.json` file.
|
||||||
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
|
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
|
||||||
|
|
||||||
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
|
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
|
||||||
// That's not the end user experience we should strive for.
|
// That's not the end user experience we should strive for.
|
||||||
// Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
|
// Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
|
||||||
|
@ -163,7 +162,7 @@ impl ProjectWorkspace {
|
||||||
project_json,
|
project_json,
|
||||||
config.target.as_deref(),
|
config.target.as_deref(),
|
||||||
&config.extra_env,
|
&config.extra_env,
|
||||||
)?
|
)
|
||||||
}
|
}
|
||||||
ProjectManifest::CargoToml(cargo_toml) => {
|
ProjectManifest::CargoToml(cargo_toml) => {
|
||||||
let cargo_version = utf8_stdout({
|
let cargo_version = utf8_stdout({
|
||||||
|
@ -193,20 +192,27 @@ impl ProjectWorkspace {
|
||||||
|
|
||||||
let sysroot = match &config.sysroot {
|
let sysroot = match &config.sysroot {
|
||||||
Some(RustcSource::Path(path)) => {
|
Some(RustcSource::Path(path)) => {
|
||||||
Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
|
match Sysroot::with_sysroot_dir(path.clone()) {
|
||||||
format!("Failed to find sysroot at {}.", path.display())
|
Ok(it) => Some(it),
|
||||||
})?)
|
Err(e) => {
|
||||||
|
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Some(RustcSource::Discover) => Some(
|
}
|
||||||
Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
|
}
|
||||||
|| {
|
Some(RustcSource::Discover) => {
|
||||||
format!(
|
match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
|
||||||
|
Ok(it) => Some(it),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!(
|
||||||
|
%e,
|
||||||
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
|
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
|
||||||
cargo_toml.display()
|
cargo_toml.display()
|
||||||
)
|
);
|
||||||
},
|
None
|
||||||
)?,
|
}
|
||||||
),
|
}
|
||||||
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
if let Some(sysroot) = &sysroot {
|
if let Some(sysroot) = &sysroot {
|
||||||
|
@ -225,18 +231,22 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
let rustc = match rustc_dir {
|
let rustc = match rustc_dir {
|
||||||
Some(rustc_dir) => Some({
|
Some(rustc_dir) => match CargoWorkspace::fetch_metadata(
|
||||||
let meta = CargoWorkspace::fetch_metadata(
|
|
||||||
&rustc_dir,
|
&rustc_dir,
|
||||||
cargo_toml.parent(),
|
cargo_toml.parent(),
|
||||||
config,
|
config,
|
||||||
progress,
|
progress,
|
||||||
)
|
) {
|
||||||
.with_context(|| {
|
Ok(meta) => Some(CargoWorkspace::new(meta)),
|
||||||
"Failed to read Cargo metadata for Rust sources".to_string()
|
Err(e) => {
|
||||||
})?;
|
tracing::error!(
|
||||||
CargoWorkspace::new(meta)
|
%e,
|
||||||
}),
|
"Failed to read Cargo metadata from rustc source at {}",
|
||||||
|
rustc_dir.display()
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -272,15 +282,14 @@ impl ProjectWorkspace {
|
||||||
project_json: ProjectJson,
|
project_json: ProjectJson,
|
||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
) -> Result<ProjectWorkspace> {
|
) -> ProjectWorkspace {
|
||||||
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
||||||
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
|
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)),
|
||||||
(Some(sysroot), None) => {
|
(Some(sysroot), None) => {
|
||||||
// assume sysroot is structured like rustup's and guess `sysroot_src`
|
// assume sysroot is structured like rustup's and guess `sysroot_src`
|
||||||
let sysroot_src =
|
let sysroot_src =
|
||||||
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
|
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
|
||||||
|
Some(Sysroot::load(sysroot, sysroot_src))
|
||||||
Some(Sysroot::load(sysroot, sysroot_src)?)
|
|
||||||
}
|
}
|
||||||
(None, Some(sysroot_src)) => {
|
(None, Some(sysroot_src)) => {
|
||||||
// assume sysroot is structured like rustup's and guess `sysroot`
|
// assume sysroot is structured like rustup's and guess `sysroot`
|
||||||
|
@ -288,7 +297,7 @@ impl ProjectWorkspace {
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
sysroot.pop();
|
sysroot.pop();
|
||||||
}
|
}
|
||||||
Some(Sysroot::load(sysroot, sysroot_src)?)
|
Some(Sysroot::load(sysroot, sysroot_src))
|
||||||
}
|
}
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
};
|
};
|
||||||
|
@ -297,7 +306,7 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
|
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
|
||||||
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
|
ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_detached_files(
|
pub fn load_detached_files(
|
||||||
|
@ -305,18 +314,29 @@ impl ProjectWorkspace {
|
||||||
config: &CargoConfig,
|
config: &CargoConfig,
|
||||||
) -> Result<ProjectWorkspace> {
|
) -> Result<ProjectWorkspace> {
|
||||||
let sysroot = match &config.sysroot {
|
let sysroot = match &config.sysroot {
|
||||||
Some(RustcSource::Path(path)) => Some(
|
Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) {
|
||||||
Sysroot::with_sysroot_dir(path.clone())
|
Ok(it) => Some(it),
|
||||||
.with_context(|| format!("Failed to find sysroot at {}.", path.display()))?,
|
Err(e) => {
|
||||||
),
|
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(RustcSource::Discover) => {
|
Some(RustcSource::Discover) => {
|
||||||
let dir = &detached_files
|
let dir = &detached_files
|
||||||
.first()
|
.first()
|
||||||
.and_then(|it| it.parent())
|
.and_then(|it| it.parent())
|
||||||
.ok_or_else(|| format_err!("No detached files to load"))?;
|
.ok_or_else(|| format_err!("No detached files to load"))?;
|
||||||
Some(Sysroot::discover(dir, &config.extra_env).with_context(|| {
|
match Sysroot::discover(dir, &config.extra_env) {
|
||||||
format!("Failed to find sysroot in {}. Is rust-src installed?", dir.display())
|
Ok(it) => Some(it),
|
||||||
})?)
|
Err(e) => {
|
||||||
|
tracing::error!(
|
||||||
|
%e,
|
||||||
|
"Failed to find sysroot for {}. Is rust-src installed?",
|
||||||
|
dir.display()
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
@ -541,7 +561,7 @@ impl ProjectWorkspace {
|
||||||
load_proc_macro,
|
load_proc_macro,
|
||||||
load,
|
load,
|
||||||
project,
|
project,
|
||||||
sysroot,
|
sysroot.as_ref(),
|
||||||
extra_env,
|
extra_env,
|
||||||
Err("rust-project.json projects have no target layout set".into()),
|
Err("rust-project.json projects have no target layout set".into()),
|
||||||
),
|
),
|
||||||
|
@ -585,6 +605,49 @@ impl ProjectWorkspace {
|
||||||
}
|
}
|
||||||
crate_graph
|
crate_graph
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Self::Cargo {
|
||||||
|
cargo,
|
||||||
|
sysroot,
|
||||||
|
rustc,
|
||||||
|
rustc_cfg,
|
||||||
|
cfg_overrides,
|
||||||
|
toolchain,
|
||||||
|
build_scripts: _,
|
||||||
|
target_layout: _,
|
||||||
|
},
|
||||||
|
Self::Cargo {
|
||||||
|
cargo: o_cargo,
|
||||||
|
sysroot: o_sysroot,
|
||||||
|
rustc: o_rustc,
|
||||||
|
rustc_cfg: o_rustc_cfg,
|
||||||
|
cfg_overrides: o_cfg_overrides,
|
||||||
|
toolchain: o_toolchain,
|
||||||
|
build_scripts: _,
|
||||||
|
target_layout: _,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
cargo == o_cargo
|
||||||
|
&& rustc == o_rustc
|
||||||
|
&& rustc_cfg == o_rustc_cfg
|
||||||
|
&& cfg_overrides == o_cfg_overrides
|
||||||
|
&& toolchain == o_toolchain
|
||||||
|
&& sysroot == o_sysroot
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Self::Json { project, sysroot, rustc_cfg },
|
||||||
|
Self::Json { project: o_project, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
|
||||||
|
) => project == o_project && rustc_cfg == o_rustc_cfg && sysroot == o_sysroot,
|
||||||
|
(
|
||||||
|
Self::DetachedFiles { files, sysroot, rustc_cfg },
|
||||||
|
Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
|
||||||
|
) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn project_json_to_crate_graph(
|
fn project_json_to_crate_graph(
|
||||||
|
@ -592,7 +655,7 @@ fn project_json_to_crate_graph(
|
||||||
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
|
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
|
||||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||||
project: &ProjectJson,
|
project: &ProjectJson,
|
||||||
sysroot: &Option<Sysroot>,
|
sysroot: Option<&Sysroot>,
|
||||||
extra_env: &FxHashMap<String, String>,
|
extra_env: &FxHashMap<String, String>,
|
||||||
target_layout: TargetLayoutLoadResult,
|
target_layout: TargetLayoutLoadResult,
|
||||||
) -> CrateGraph {
|
) -> CrateGraph {
|
||||||
|
|
|
@ -148,11 +148,11 @@ impl GlobalState {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
LinkedProject::InlineJsonProject(it) => {
|
LinkedProject::InlineJsonProject(it) => {
|
||||||
project_model::ProjectWorkspace::load_inline(
|
Ok(project_model::ProjectWorkspace::load_inline(
|
||||||
it.clone(),
|
it.clone(),
|
||||||
cargo_config.target.as_deref(),
|
cargo_config.target.as_deref(),
|
||||||
&cargo_config.extra_env,
|
&cargo_config.extra_env,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -212,35 +212,11 @@ impl GlobalState {
|
||||||
let workspaces =
|
let workspaces =
|
||||||
workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>();
|
workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>();
|
||||||
|
|
||||||
fn eq_ignore_build_data<'a>(
|
|
||||||
left: &'a ProjectWorkspace,
|
|
||||||
right: &'a ProjectWorkspace,
|
|
||||||
) -> bool {
|
|
||||||
let key = |p: &'a ProjectWorkspace| match p {
|
|
||||||
ProjectWorkspace::Cargo {
|
|
||||||
cargo,
|
|
||||||
sysroot,
|
|
||||||
rustc,
|
|
||||||
rustc_cfg,
|
|
||||||
cfg_overrides,
|
|
||||||
|
|
||||||
build_scripts: _,
|
|
||||||
toolchain: _,
|
|
||||||
target_layout: _,
|
|
||||||
} => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
match (key(left), key(right)) {
|
|
||||||
(Some(lk), Some(rk)) => lk == rk,
|
|
||||||
_ => left == right,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let same_workspaces = workspaces.len() == self.workspaces.len()
|
let same_workspaces = workspaces.len() == self.workspaces.len()
|
||||||
&& workspaces
|
&& workspaces
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.workspaces.iter())
|
.zip(self.workspaces.iter())
|
||||||
.all(|(l, r)| eq_ignore_build_data(l, r));
|
.all(|(l, r)| l.eq_ignore_build_data(r));
|
||||||
|
|
||||||
if same_workspaces {
|
if same_workspaces {
|
||||||
let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
|
let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
|
||||||
|
@ -270,7 +246,8 @@ impl GlobalState {
|
||||||
|
|
||||||
// Here, we completely changed the workspace (Cargo.toml edit), so
|
// Here, we completely changed the workspace (Cargo.toml edit), so
|
||||||
// we don't care about build-script results, they are stale.
|
// we don't care about build-script results, they are stale.
|
||||||
self.workspaces = Arc::new(workspaces)
|
// FIXME: can we abort the build scripts here?
|
||||||
|
self.workspaces = Arc::new(workspaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let FilesWatcher::Client = self.config.files().watcher {
|
if let FilesWatcher::Client = self.config.files().watcher {
|
||||||
|
|
Loading…
Reference in a new issue