From 33c6c7abc6621f8b0cf083a98f7e4788cf4b5b54 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Mon, 16 Mar 2020 13:43:29 +0100 Subject: Support loading OUT_DIR from cargo check at launch --- crates/ra_project_model/src/cargo_workspace.rs | 67 +++++++++++++++++++++++++- crates/ra_project_model/src/lib.rs | 43 ++++++++++++++--- 2 files changed, 101 insertions(+), 9 deletions(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 4fea459d5..eeeb10233 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -3,8 +3,9 @@ use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; -use cargo_metadata::{CargoOpt, MetadataCommand}; +use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId}; use ra_arena::{impl_arena_id, Arena, RawId}; +use ra_cargo_watch::run_cargo; use ra_db::Edition; use rustc_hash::FxHashMap; use serde::Deserialize; @@ -35,11 +36,19 @@ pub struct CargoFeatures { /// List of features to activate. /// This will be ignored if `cargo_all_features` is true. pub features: Vec, + + /// Runs cargo check on launch to figure out the correct values of OUT_DIR + pub load_out_dirs_from_check: bool, } impl Default for CargoFeatures { fn default() -> Self { - CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() } + CargoFeatures { + no_default_features: false, + all_features: true, + features: Vec::new(), + load_out_dirs_from_check: false, + } } } @@ -60,6 +69,7 @@ struct PackageData { dependencies: Vec, edition: Edition, features: Vec, + out_dir: Option, } #[derive(Debug, Clone)] @@ -131,6 +141,9 @@ impl Package { ) -> impl Iterator + 'a { ws.packages[self].dependencies.iter() } + pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> { + ws.packages[self].out_dir.as_ref().map(|od| od.as_path()) + } } impl Target { @@ -173,6 +186,12 @@ impl CargoWorkspace { let meta = meta.exec().with_context(|| { format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) })?; + + let mut out_dir_by_id = FxHashMap::default(); + if cargo_features.load_out_dirs_from_check { + out_dir_by_id = load_out_dirs(cargo_toml, cargo_features); + } + let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); let mut targets = Arena::default(); @@ -193,6 +212,7 @@ impl CargoWorkspace { edition, dependencies: Vec::new(), features: Vec::new(), + out_dir: out_dir_by_id.get(&id).cloned(), }); let pkg_data = &mut packages[pkg]; pkg_by_id.insert(id, pkg); @@ -252,3 +272,46 @@ impl CargoWorkspace { &self.workspace_root } } + +pub fn load_out_dirs( + cargo_toml: &Path, + cargo_features: &CargoFeatures, +) -> FxHashMap { + let mut args: Vec = vec![ + "check".to_string(), + "--message-format=json".to_string(), + "--manifest-path".to_string(), + format!("{}", cargo_toml.display()), + ]; + + if cargo_features.all_features { + args.push("--all-features".to_string()); + } else if cargo_features.no_default_features { + // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` + // https://github.com/oli-obk/cargo_metadata/issues/79 + args.push("--no-default-features".to_string()); + } else if !cargo_features.features.is_empty() { + for feature in &cargo_features.features { + args.push(feature.clone()); + } + } + + let mut res = FxHashMap::default(); + let mut child = run_cargo(&args, cargo_toml.parent(), |message| { + match message { + Message::BuildScriptExecuted(message) => { + let package_id = message.package_id; + let out_dir = message.out_dir; + res.insert(package_id, out_dir); + } + + Message::CompilerArtifact(_) => (), + Message::CompilerMessage(_) => (), + Message::Unknown => (), + } + true + }); + + let _ = child.wait(); + res +} diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 897874813..43f834253 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -150,6 +150,21 @@ impl ProjectWorkspace { } } + pub fn out_dirs(&self) -> Vec { + match self { + ProjectWorkspace::Json { project: _project } => vec![], + ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => { + let mut out_dirs = Vec::with_capacity(cargo.packages().len()); + for pkg in cargo.packages() { + if let Some(out_dir) = pkg.out_dir(&cargo) { + out_dirs.push(out_dir.to_path_buf()); + } + } + out_dirs + } + } + } + pub fn n_packages(&self) -> usize { match self { ProjectWorkspace::Json { project } => project.crates.len(), @@ -162,7 +177,8 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, default_cfg_options: &CfgOptions, - outdirs: &FxHashMap, + additional_out_dirs: &FxHashMap, + extern_source_roots: &FxHashMap, load: &mut dyn FnMut(&Path) -> Option, ) -> CrateGraph { let mut crate_graph = CrateGraph::default(); @@ -237,9 +253,11 @@ impl ProjectWorkspace { let mut env = Env::default(); let mut extern_source = ExternSource::default(); - if let Some((id, path)) = outdirs.get(krate.name(&sysroot)) { - env.set("OUT_DIR", path.clone()); - extern_source.set_extern_path(&path, *id); + if let Some(path) = additional_out_dirs.get(krate.name(&sysroot)) { + env.set("OUT_DIR", path.to_string_lossy().to_string()); + if let Some(extern_source_id) = extern_source_roots.get(path) { + extern_source.set_extern_path(&path, *extern_source_id); + } } let crate_id = crate_graph.add_crate_root( @@ -292,9 +310,20 @@ impl ProjectWorkspace { }; let mut env = Env::default(); let mut extern_source = ExternSource::default(); - if let Some((id, path)) = outdirs.get(pkg.name(&cargo)) { - env.set("OUT_DIR", path.clone()); - extern_source.set_extern_path(&path, *id); + if let Some(out_dir) = dbg!(pkg.out_dir(cargo)) { + env.set("OUT_DIR", out_dir.to_string_lossy().to_string()); + if let Some(extern_source_id) = + dbg!(dbg!(&extern_source_roots).get(out_dir)) + { + extern_source.set_extern_path(&out_dir, *extern_source_id); + } + } else { + if let Some(path) = additional_out_dirs.get(pkg.name(&cargo)) { + env.set("OUT_DIR", path.to_string_lossy().to_string()); + if let Some(extern_source_id) = extern_source_roots.get(path) { + extern_source.set_extern_path(&path, *extern_source_id); + } + } } let crate_id = crate_graph.add_crate_root( file_id, -- cgit v1.2.3 From f5a2fcf8f59eda3498bbdcb87568e5ba6b4db8b7 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Mon, 16 Mar 2020 14:10:13 +0100 Subject: Change existing OUT_DIR override config to make use of new infrastructure --- crates/ra_project_model/src/cargo_workspace.rs | 8 ++++++++ crates/ra_project_model/src/lib.rs | 28 ++++++-------------------- 2 files changed, 14 insertions(+), 22 deletions(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index eeeb10233..97fa48b8b 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -39,6 +39,9 @@ pub struct CargoFeatures { /// Runs cargo check on launch to figure out the correct values of OUT_DIR pub load_out_dirs_from_check: bool, + + /// Fine grained controls for additional `OUT_DIR` env variables + pub out_dir_overrides: FxHashMap, } impl Default for CargoFeatures { @@ -48,6 +51,7 @@ impl Default for CargoFeatures { all_features: true, features: Vec::new(), load_out_dirs_from_check: false, + out_dir_overrides: FxHashMap::default(), } } } @@ -191,6 +195,10 @@ impl CargoWorkspace { if cargo_features.load_out_dirs_from_check { out_dir_by_id = load_out_dirs(cargo_toml, cargo_features); } + // We explicitly extend afterwards to allow overriding the value returned by cargo + out_dir_by_id.extend( + cargo_features.out_dir_overrides.iter().map(|(id, path)| (id.clone(), path.clone())), + ); let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 43f834253..b2c3e576d 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -177,7 +177,6 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, default_cfg_options: &CfgOptions, - additional_out_dirs: &FxHashMap, extern_source_roots: &FxHashMap, load: &mut dyn FnMut(&Path) -> Option, ) -> CrateGraph { @@ -251,15 +250,8 @@ impl ProjectWorkspace { opts }; - let mut env = Env::default(); - let mut extern_source = ExternSource::default(); - if let Some(path) = additional_out_dirs.get(krate.name(&sysroot)) { - env.set("OUT_DIR", path.to_string_lossy().to_string()); - if let Some(extern_source_id) = extern_source_roots.get(path) { - extern_source.set_extern_path(&path, *extern_source_id); - } - } - + let env = Env::default(); + let extern_source = ExternSource::default(); let crate_id = crate_graph.add_crate_root( file_id, Edition::Edition2018, @@ -310,19 +302,11 @@ impl ProjectWorkspace { }; let mut env = Env::default(); let mut extern_source = ExternSource::default(); - if let Some(out_dir) = dbg!(pkg.out_dir(cargo)) { + if let Some(out_dir) = pkg.out_dir(cargo) { + // FIXME: We probably mangle non UTF-8 paths here, figure out a better solution env.set("OUT_DIR", out_dir.to_string_lossy().to_string()); - if let Some(extern_source_id) = - dbg!(dbg!(&extern_source_roots).get(out_dir)) - { - extern_source.set_extern_path(&out_dir, *extern_source_id); - } - } else { - if let Some(path) = additional_out_dirs.get(pkg.name(&cargo)) { - env.set("OUT_DIR", path.to_string_lossy().to_string()); - if let Some(extern_source_id) = extern_source_roots.get(path) { - extern_source.set_extern_path(&path, *extern_source_id); - } + if let Some(&extern_source_id) = extern_source_roots.get(out_dir) { + extern_source.set_extern_path(&out_dir, extern_source_id); } } let crate_id = crate_graph.add_crate_root( -- cgit v1.2.3 From 4fb79f2ca033a6ba8dc4797b62fe0015b117f280 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Mon, 16 Mar 2020 14:17:32 +0100 Subject: Support specifying OUT_DIR in json project --- crates/ra_project_model/src/json_project.rs | 1 + crates/ra_project_model/src/lib.rs | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs index 1bacb1d09..336446e58 100644 --- a/crates/ra_project_model/src/json_project.rs +++ b/crates/ra_project_model/src/json_project.rs @@ -22,6 +22,7 @@ pub struct Crate { pub(crate) deps: Vec, pub(crate) atom_cfgs: FxHashSet, pub(crate) key_value_cfgs: FxHashMap, + pub(crate) out_dir: Option, } #[derive(Clone, Copy, Debug, Deserialize)] diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index b2c3e576d..081b1fec2 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -152,7 +152,15 @@ impl ProjectWorkspace { pub fn out_dirs(&self) -> Vec { match self { - ProjectWorkspace::Json { project: _project } => vec![], + ProjectWorkspace::Json { project } => { + let mut out_dirs = Vec::with_capacity(project.crates.len()); + for krate in &project.crates { + if let Some(out_dir) = &krate.out_dir { + out_dirs.push(out_dir.to_path_buf()); + } + } + out_dirs + } ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => { let mut out_dirs = Vec::with_capacity(cargo.packages().len()); for pkg in cargo.packages() { @@ -202,6 +210,16 @@ impl ProjectWorkspace { opts }; + let mut env = Env::default(); + let mut extern_source = ExternSource::default(); + if let Some(out_dir) = &krate.out_dir { + // FIXME: We probably mangle non UTF-8 paths here, figure out a better solution + env.set("OUT_DIR", out_dir.to_string_lossy().to_string()); + if let Some(&extern_source_id) = extern_source_roots.get(out_dir) { + extern_source.set_extern_path(&out_dir, extern_source_id); + } + } + // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env crates.insert( crate_id, @@ -211,8 +229,8 @@ impl ProjectWorkspace { // FIXME json definitions can store the crate name None, cfg_options, - Env::default(), - Default::default(), + env, + extern_source, ), ); } -- cgit v1.2.3 From e154132c911be41b75e84d01de5c7efa4da9168e Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Tue, 17 Mar 2020 14:55:44 +0100 Subject: Remove outDirOverrides --- crates/ra_project_model/src/cargo_workspace.rs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 97fa48b8b..eeeb10233 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -39,9 +39,6 @@ pub struct CargoFeatures { /// Runs cargo check on launch to figure out the correct values of OUT_DIR pub load_out_dirs_from_check: bool, - - /// Fine grained controls for additional `OUT_DIR` env variables - pub out_dir_overrides: FxHashMap, } impl Default for CargoFeatures { @@ -51,7 +48,6 @@ impl Default for CargoFeatures { all_features: true, features: Vec::new(), load_out_dirs_from_check: false, - out_dir_overrides: FxHashMap::default(), } } } @@ -195,10 +191,6 @@ impl CargoWorkspace { if cargo_features.load_out_dirs_from_check { out_dir_by_id = load_out_dirs(cargo_toml, cargo_features); } - // We explicitly extend afterwards to allow overriding the value returned by cargo - out_dir_by_id.extend( - cargo_features.out_dir_overrides.iter().map(|(id, path)| (id.clone(), path.clone())), - ); let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); -- cgit v1.2.3 From 5af81b8456b5fedcc981145bbead7cc7b6b2fc19 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Tue, 17 Mar 2020 14:56:14 +0100 Subject: Slight readablity improvement --- crates/ra_project_model/src/cargo_workspace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index eeeb10233..72cb5d388 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -142,7 +142,7 @@ impl Package { ws.packages[self].dependencies.iter() } pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> { - ws.packages[self].out_dir.as_ref().map(|od| od.as_path()) + ws.packages[self].out_dir.as_ref().map(PathBuf::as_path) } } -- cgit v1.2.3 From 2dd887de4761e2493f4df56233b0e11185d74d63 Mon Sep 17 00:00:00 2001 From: Emil Lauridsen Date: Tue, 17 Mar 2020 14:56:53 +0100 Subject: Use dyn-ref instead of impl to impact compile times the least --- crates/ra_project_model/src/cargo_workspace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_project_model/src') diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 72cb5d388..10ecfa951 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -297,7 +297,7 @@ pub fn load_out_dirs( } let mut res = FxHashMap::default(); - let mut child = run_cargo(&args, cargo_toml.parent(), |message| { + let mut child = run_cargo(&args, cargo_toml.parent(), &mut |message| { match message { Message::BuildScriptExecuted(message) => { let package_id = message.package_id; -- cgit v1.2.3