Avoid blocking the main loop when editing Cargo.toml
I've noticed a bunch of "main loop too long" warnings in console when typing in Cargo.toml. Profiling showed that the culprit is `rustc --print cfg` call. I moved it to the background project loading phase, where it belongs. This highlighted a problem: we generally use single `cfg`, while it really should be per crate.
This commit is contained in:
parent
cc963d2b11
commit
add87f5424
@ -5,6 +5,7 @@
|
||||
mod project_json;
|
||||
mod sysroot;
|
||||
mod workspace;
|
||||
mod rustc_cfg;
|
||||
|
||||
use std::{
|
||||
fs::{read_dir, ReadDir},
|
||||
|
34
crates/project_model/src/rustc_cfg.rs
Normal file
34
crates/project_model/src/rustc_cfg.rs
Normal file
@ -0,0 +1,34 @@
|
||||
//! Runs `rustc --print cfg` to get built-in cfg flags.
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
use crate::{cfg_flag::CfgFlag, utf8_stdout};
|
||||
|
||||
pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
|
||||
let _p = profile::span("rustc_cfg::get");
|
||||
let mut res = Vec::new();
|
||||
|
||||
// Some nightly-only cfgs, which are required for stdlib
|
||||
res.push(CfgFlag::Atom("target_thread_local".into()));
|
||||
for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() {
|
||||
for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() {
|
||||
res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
|
||||
}
|
||||
}
|
||||
|
||||
let rustc_cfgs = {
|
||||
let mut cmd = Command::new(toolchain::rustc());
|
||||
cmd.args(&["--print", "cfg", "-O"]);
|
||||
if let Some(target) = target {
|
||||
cmd.args(&["--target", target]);
|
||||
}
|
||||
utf8_stdout(cmd)
|
||||
};
|
||||
|
||||
match rustc_cfgs {
|
||||
Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
|
||||
Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
|
||||
}
|
||||
|
||||
res
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::{
|
||||
cargo_workspace, cfg_flag::CfgFlag, sysroot::SysrootCrate, utf8_stdout, CargoConfig,
|
||||
cargo_workspace, cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, utf8_stdout, CargoConfig,
|
||||
CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind,
|
||||
};
|
||||
|
||||
@ -34,15 +34,25 @@ pub struct PackageRoot {
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub enum ProjectWorkspace {
|
||||
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
|
||||
Cargo { cargo: CargoWorkspace, sysroot: Sysroot, rustc: Option<CargoWorkspace> },
|
||||
Cargo {
|
||||
cargo: CargoWorkspace,
|
||||
sysroot: Sysroot,
|
||||
rustc: Option<CargoWorkspace>,
|
||||
/// Holds cfg flags for the current target. We get those by running
|
||||
/// `rustc --print cfg`.
|
||||
///
|
||||
/// FIXME: make this a per-crate map, as, eg, build.rs might have a
|
||||
/// different target.
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
},
|
||||
/// Project workspace was manually specified using a `rust-project.json` file.
|
||||
Json { project: ProjectJson, sysroot: Option<Sysroot> },
|
||||
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
|
||||
}
|
||||
|
||||
impl fmt::Debug for ProjectWorkspace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => f
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f
|
||||
.debug_struct("Cargo")
|
||||
.field("n_packages", &cargo.packages().len())
|
||||
.field("n_sysroot_crates", &sysroot.crates().len())
|
||||
@ -50,13 +60,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
"n_rustc_compiler_crates",
|
||||
&rustc.as_ref().map_or(0, |rc| rc.packages().len()),
|
||||
)
|
||||
.field("rustc_cfg", rustc_cfg)
|
||||
.finish(),
|
||||
ProjectWorkspace::Json { project, sysroot } => {
|
||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
|
||||
let mut debug_struct = f.debug_struct("Json");
|
||||
debug_struct.field("n_crates", &project.n_crates());
|
||||
if let Some(sysroot) = sysroot {
|
||||
debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
|
||||
}
|
||||
debug_struct.field("rustc_cfg", rustc_cfg);
|
||||
debug_struct.finish()
|
||||
}
|
||||
}
|
||||
@ -79,7 +91,7 @@ pub fn load(
|
||||
})?;
|
||||
let project_location = project_json.parent().unwrap().to_path_buf();
|
||||
let project_json = ProjectJson::new(&project_location, data);
|
||||
ProjectWorkspace::load_inline(project_json)?
|
||||
ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
|
||||
}
|
||||
ProjectManifest::CargoToml(cargo_toml) => {
|
||||
let cargo_version = utf8_stdout({
|
||||
@ -117,21 +129,24 @@ pub fn load(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc }
|
||||
let rustc_cfg = rustc_cfg::get(config.target.as_deref());
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
|
||||
}
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> {
|
||||
pub fn load_inline(
|
||||
project_json: ProjectJson,
|
||||
target: Option<&str>,
|
||||
) -> Result<ProjectWorkspace> {
|
||||
let sysroot = match &project_json.sysroot_src {
|
||||
Some(path) => Some(Sysroot::load(path)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(ProjectWorkspace::Json { project: project_json, sysroot })
|
||||
let rustc_cfg = rustc_cfg::get(target);
|
||||
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
|
||||
}
|
||||
|
||||
/// Returns the roots for the current `ProjectWorkspace`
|
||||
@ -139,7 +154,7 @@ pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> {
|
||||
/// the root is a member of the current workspace
|
||||
pub fn to_roots(&self) -> Vec<PackageRoot> {
|
||||
match self {
|
||||
ProjectWorkspace::Json { project, sysroot } => project
|
||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
|
||||
.crates()
|
||||
.map(|(_, krate)| PackageRoot {
|
||||
is_member: krate.is_workspace_member,
|
||||
@ -156,7 +171,7 @@ pub fn to_roots(&self) -> Vec<PackageRoot> {
|
||||
})
|
||||
}))
|
||||
.collect::<Vec<_>>(),
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo
|
||||
.packages()
|
||||
.map(|pkg| {
|
||||
let is_member = cargo[pkg].is_member;
|
||||
@ -194,7 +209,7 @@ pub fn to_roots(&self) -> Vec<PackageRoot> {
|
||||
pub fn n_packages(&self) -> usize {
|
||||
match self {
|
||||
ProjectWorkspace::Json { project, .. } => project.n_crates(),
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
|
||||
let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len());
|
||||
cargo.packages().len() + sysroot.crates().len() + rustc_package_len
|
||||
}
|
||||
@ -203,7 +218,6 @@ pub fn n_packages(&self) -> usize {
|
||||
|
||||
pub fn to_crate_graph(
|
||||
&self,
|
||||
target: Option<&str>,
|
||||
proc_macro_client: Option<&ProcMacroClient>,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
) -> CrateGraph {
|
||||
@ -214,12 +228,21 @@ pub fn to_crate_graph(
|
||||
};
|
||||
|
||||
let mut crate_graph = match self {
|
||||
ProjectWorkspace::Json { project, sysroot } => {
|
||||
project_json_to_crate_graph(target, &proc_macro_loader, load, project, sysroot)
|
||||
}
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
|
||||
cargo_to_crate_graph(target, &proc_macro_loader, load, cargo, sysroot, rustc)
|
||||
}
|
||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
|
||||
rustc_cfg.clone(),
|
||||
&proc_macro_loader,
|
||||
load,
|
||||
project,
|
||||
sysroot,
|
||||
),
|
||||
ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph(
|
||||
rustc_cfg.clone(),
|
||||
&proc_macro_loader,
|
||||
load,
|
||||
cargo,
|
||||
sysroot,
|
||||
rustc,
|
||||
),
|
||||
};
|
||||
if crate_graph.patch_cfg_if() {
|
||||
log::debug!("Patched std to depend on cfg-if")
|
||||
@ -231,7 +254,7 @@ pub fn to_crate_graph(
|
||||
}
|
||||
|
||||
fn project_json_to_crate_graph(
|
||||
target: Option<&str>,
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
project: &ProjectJson,
|
||||
@ -240,9 +263,9 @@ fn project_json_to_crate_graph(
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
let sysroot_deps = sysroot
|
||||
.as_ref()
|
||||
.map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
|
||||
.map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
|
||||
|
||||
let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
|
||||
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
|
||||
let crates: FxHashMap<CrateId, CrateId> = project
|
||||
.crates()
|
||||
.filter_map(|(crate_id, krate)| {
|
||||
@ -254,9 +277,12 @@ fn project_json_to_crate_graph(
|
||||
let env = krate.env.clone().into_iter().collect();
|
||||
let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it));
|
||||
|
||||
let target = krate.target.as_deref().or(target);
|
||||
let target_cfgs =
|
||||
cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target));
|
||||
let target_cfgs = match krate.target.as_deref() {
|
||||
Some(target) => {
|
||||
cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target)))
|
||||
}
|
||||
None => &rustc_cfg,
|
||||
};
|
||||
|
||||
let mut cfg_options = CfgOptions::default();
|
||||
cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
|
||||
@ -293,7 +319,7 @@ fn project_json_to_crate_graph(
|
||||
}
|
||||
|
||||
fn cargo_to_crate_graph(
|
||||
target: Option<&str>,
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
cargo: &CargoWorkspace,
|
||||
@ -303,10 +329,10 @@ fn cargo_to_crate_graph(
|
||||
let _p = profile::span("cargo_to_crate_graph");
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
let (public_deps, libproc_macro) =
|
||||
sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
|
||||
sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
|
||||
|
||||
let mut cfg_options = CfgOptions::default();
|
||||
cfg_options.extend(get_rustc_cfg_options(target));
|
||||
cfg_options.extend(rustc_cfg);
|
||||
|
||||
let mut pkg_to_lib_crate = FxHashMap::default();
|
||||
|
||||
@ -492,12 +518,12 @@ fn add_target_crate_root(
|
||||
fn sysroot_to_crate_graph(
|
||||
crate_graph: &mut CrateGraph,
|
||||
sysroot: &Sysroot,
|
||||
target: Option<&str>,
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
|
||||
let _p = profile::span("sysroot_to_crate_graph");
|
||||
let mut cfg_options = CfgOptions::default();
|
||||
cfg_options.extend(get_rustc_cfg_options(target));
|
||||
cfg_options.extend(rustc_cfg);
|
||||
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
|
||||
.crates()
|
||||
.filter_map(|krate| {
|
||||
@ -536,35 +562,6 @@ fn sysroot_to_crate_graph(
|
||||
(public_deps, libproc_macro)
|
||||
}
|
||||
|
||||
fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> {
|
||||
let _p = profile::span("get_rustc_cfg_options");
|
||||
let mut res = Vec::new();
|
||||
|
||||
// Some nightly-only cfgs, which are required for stdlib
|
||||
res.push(CfgFlag::Atom("target_thread_local".into()));
|
||||
for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() {
|
||||
for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() {
|
||||
res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
|
||||
}
|
||||
}
|
||||
|
||||
let rustc_cfgs = {
|
||||
let mut cmd = Command::new(toolchain::rustc());
|
||||
cmd.args(&["--print", "cfg", "-O"]);
|
||||
if let Some(target) = target {
|
||||
cmd.args(&["--target", target]);
|
||||
}
|
||||
utf8_stdout(cmd)
|
||||
};
|
||||
|
||||
match rustc_cfgs {
|
||||
Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
|
||||
Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
|
||||
if let Err(err) = graph.add_dep(from, name, to) {
|
||||
log::error!("{}", err)
|
||||
|
@ -39,7 +39,7 @@ pub fn load_cargo(
|
||||
None
|
||||
};
|
||||
|
||||
let crate_graph = ws.to_crate_graph(None, proc_macro_client.as_ref(), &mut |path: &AbsPath| {
|
||||
let crate_graph = ws.to_crate_graph(proc_macro_client.as_ref(), &mut |path: &AbsPath| {
|
||||
let contents = loader.load_sync(path);
|
||||
let path = vfs::VfsPath::from(path.to_path_buf());
|
||||
vfs.set_file_contents(path.clone(), contents);
|
||||
|
@ -135,7 +135,10 @@ pub(crate) fn fetch_workspaces_if_needed(&mut self) {
|
||||
)
|
||||
}
|
||||
LinkedProject::InlineJsonProject(it) => {
|
||||
project_model::ProjectWorkspace::load_inline(it.clone())
|
||||
project_model::ProjectWorkspace::load_inline(
|
||||
it.clone(),
|
||||
cargo_config.target.as_deref(),
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@ -253,11 +256,7 @@ pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<Projec
|
||||
res
|
||||
};
|
||||
for ws in workspaces.iter() {
|
||||
crate_graph.extend(ws.to_crate_graph(
|
||||
self.config.cargo().target.as_deref(),
|
||||
self.proc_macro_client.as_ref(),
|
||||
&mut load,
|
||||
));
|
||||
crate_graph.extend(ws.to_crate_graph(self.proc_macro_client.as_ref(), &mut load));
|
||||
}
|
||||
|
||||
crate_graph
|
||||
@ -289,9 +288,7 @@ fn reload_flycheck(&mut self) {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(id, w)| match w {
|
||||
ProjectWorkspace::Cargo { cargo, sysroot: _, rustc: _ } => {
|
||||
Some((id, cargo.workspace_root()))
|
||||
}
|
||||
ProjectWorkspace::Cargo { cargo, .. } => Some((id, cargo.workspace_root())),
|
||||
ProjectWorkspace::Json { project, .. } => {
|
||||
// Enable flychecks for json projects if a custom flycheck command was supplied
|
||||
// in the workspace configuration.
|
||||
|
Loading…
Reference in New Issue
Block a user