aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_project_model/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_project_model/src')
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs67
-rw-r--r--crates/ra_project_model/src/json_project.rs1
-rw-r--r--crates/ra_project_model/src/lib.rs57
3 files changed, 110 insertions, 15 deletions
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 4fea459d5..10ecfa951 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -3,8 +3,9 @@
3use std::path::{Path, PathBuf}; 3use std::path::{Path, PathBuf};
4 4
5use anyhow::{Context, Result}; 5use anyhow::{Context, Result};
6use cargo_metadata::{CargoOpt, MetadataCommand}; 6use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId};
7use ra_arena::{impl_arena_id, Arena, RawId}; 7use ra_arena::{impl_arena_id, Arena, RawId};
8use ra_cargo_watch::run_cargo;
8use ra_db::Edition; 9use ra_db::Edition;
9use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
10use serde::Deserialize; 11use serde::Deserialize;
@@ -35,11 +36,19 @@ pub struct CargoFeatures {
35 /// List of features to activate. 36 /// List of features to activate.
36 /// This will be ignored if `cargo_all_features` is true. 37 /// This will be ignored if `cargo_all_features` is true.
37 pub features: Vec<String>, 38 pub features: Vec<String>,
39
40 /// Runs cargo check on launch to figure out the correct values of OUT_DIR
41 pub load_out_dirs_from_check: bool,
38} 42}
39 43
40impl Default for CargoFeatures { 44impl Default for CargoFeatures {
41 fn default() -> Self { 45 fn default() -> Self {
42 CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() } 46 CargoFeatures {
47 no_default_features: false,
48 all_features: true,
49 features: Vec::new(),
50 load_out_dirs_from_check: false,
51 }
43 } 52 }
44} 53}
45 54
@@ -60,6 +69,7 @@ struct PackageData {
60 dependencies: Vec<PackageDependency>, 69 dependencies: Vec<PackageDependency>,
61 edition: Edition, 70 edition: Edition,
62 features: Vec<String>, 71 features: Vec<String>,
72 out_dir: Option<PathBuf>,
63} 73}
64 74
65#[derive(Debug, Clone)] 75#[derive(Debug, Clone)]
@@ -131,6 +141,9 @@ impl Package {
131 ) -> impl Iterator<Item = &'a PackageDependency> + 'a { 141 ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
132 ws.packages[self].dependencies.iter() 142 ws.packages[self].dependencies.iter()
133 } 143 }
144 pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> {
145 ws.packages[self].out_dir.as_ref().map(PathBuf::as_path)
146 }
134} 147}
135 148
136impl Target { 149impl Target {
@@ -173,6 +186,12 @@ impl CargoWorkspace {
173 let meta = meta.exec().with_context(|| { 186 let meta = meta.exec().with_context(|| {
174 format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) 187 format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
175 })?; 188 })?;
189
190 let mut out_dir_by_id = FxHashMap::default();
191 if cargo_features.load_out_dirs_from_check {
192 out_dir_by_id = load_out_dirs(cargo_toml, cargo_features);
193 }
194
176 let mut pkg_by_id = FxHashMap::default(); 195 let mut pkg_by_id = FxHashMap::default();
177 let mut packages = Arena::default(); 196 let mut packages = Arena::default();
178 let mut targets = Arena::default(); 197 let mut targets = Arena::default();
@@ -193,6 +212,7 @@ impl CargoWorkspace {
193 edition, 212 edition,
194 dependencies: Vec::new(), 213 dependencies: Vec::new(),
195 features: Vec::new(), 214 features: Vec::new(),
215 out_dir: out_dir_by_id.get(&id).cloned(),
196 }); 216 });
197 let pkg_data = &mut packages[pkg]; 217 let pkg_data = &mut packages[pkg];
198 pkg_by_id.insert(id, pkg); 218 pkg_by_id.insert(id, pkg);
@@ -252,3 +272,46 @@ impl CargoWorkspace {
252 &self.workspace_root 272 &self.workspace_root
253 } 273 }
254} 274}
275
276pub fn load_out_dirs(
277 cargo_toml: &Path,
278 cargo_features: &CargoFeatures,
279) -> FxHashMap<PackageId, PathBuf> {
280 let mut args: Vec<String> = vec![
281 "check".to_string(),
282 "--message-format=json".to_string(),
283 "--manifest-path".to_string(),
284 format!("{}", cargo_toml.display()),
285 ];
286
287 if cargo_features.all_features {
288 args.push("--all-features".to_string());
289 } else if cargo_features.no_default_features {
290 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
291 // https://github.com/oli-obk/cargo_metadata/issues/79
292 args.push("--no-default-features".to_string());
293 } else if !cargo_features.features.is_empty() {
294 for feature in &cargo_features.features {
295 args.push(feature.clone());
296 }
297 }
298
299 let mut res = FxHashMap::default();
300 let mut child = run_cargo(&args, cargo_toml.parent(), &mut |message| {
301 match message {
302 Message::BuildScriptExecuted(message) => {
303 let package_id = message.package_id;
304 let out_dir = message.out_dir;
305 res.insert(package_id, out_dir);
306 }
307
308 Message::CompilerArtifact(_) => (),
309 Message::CompilerMessage(_) => (),
310 Message::Unknown => (),
311 }
312 true
313 });
314
315 let _ = child.wait();
316 res
317}
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 {
22 pub(crate) deps: Vec<Dep>, 22 pub(crate) deps: Vec<Dep>,
23 pub(crate) atom_cfgs: FxHashSet<String>, 23 pub(crate) atom_cfgs: FxHashSet<String>,
24 pub(crate) key_value_cfgs: FxHashMap<String, String>, 24 pub(crate) key_value_cfgs: FxHashMap<String, String>,
25 pub(crate) out_dir: Option<PathBuf>,
25} 26}
26 27
27#[derive(Clone, Copy, Debug, Deserialize)] 28#[derive(Clone, Copy, Debug, Deserialize)]
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 897874813..081b1fec2 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -150,6 +150,29 @@ impl ProjectWorkspace {
150 } 150 }
151 } 151 }
152 152
153 pub fn out_dirs(&self) -> Vec<PathBuf> {
154 match self {
155 ProjectWorkspace::Json { project } => {
156 let mut out_dirs = Vec::with_capacity(project.crates.len());
157 for krate in &project.crates {
158 if let Some(out_dir) = &krate.out_dir {
159 out_dirs.push(out_dir.to_path_buf());
160 }
161 }
162 out_dirs
163 }
164 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => {
165 let mut out_dirs = Vec::with_capacity(cargo.packages().len());
166 for pkg in cargo.packages() {
167 if let Some(out_dir) = pkg.out_dir(&cargo) {
168 out_dirs.push(out_dir.to_path_buf());
169 }
170 }
171 out_dirs
172 }
173 }
174 }
175
153 pub fn n_packages(&self) -> usize { 176 pub fn n_packages(&self) -> usize {
154 match self { 177 match self {
155 ProjectWorkspace::Json { project } => project.crates.len(), 178 ProjectWorkspace::Json { project } => project.crates.len(),
@@ -162,7 +185,7 @@ impl ProjectWorkspace {
162 pub fn to_crate_graph( 185 pub fn to_crate_graph(
163 &self, 186 &self,
164 default_cfg_options: &CfgOptions, 187 default_cfg_options: &CfgOptions,
165 outdirs: &FxHashMap<String, (ExternSourceId, String)>, 188 extern_source_roots: &FxHashMap<PathBuf, ExternSourceId>,
166 load: &mut dyn FnMut(&Path) -> Option<FileId>, 189 load: &mut dyn FnMut(&Path) -> Option<FileId>,
167 ) -> CrateGraph { 190 ) -> CrateGraph {
168 let mut crate_graph = CrateGraph::default(); 191 let mut crate_graph = CrateGraph::default();
@@ -187,6 +210,16 @@ impl ProjectWorkspace {
187 opts 210 opts
188 }; 211 };
189 212
213 let mut env = Env::default();
214 let mut extern_source = ExternSource::default();
215 if let Some(out_dir) = &krate.out_dir {
216 // FIXME: We probably mangle non UTF-8 paths here, figure out a better solution
217 env.set("OUT_DIR", out_dir.to_string_lossy().to_string());
218 if let Some(&extern_source_id) = extern_source_roots.get(out_dir) {
219 extern_source.set_extern_path(&out_dir, extern_source_id);
220 }
221 }
222
190 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env 223 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
191 crates.insert( 224 crates.insert(
192 crate_id, 225 crate_id,
@@ -196,8 +229,8 @@ impl ProjectWorkspace {
196 // FIXME json definitions can store the crate name 229 // FIXME json definitions can store the crate name
197 None, 230 None,
198 cfg_options, 231 cfg_options,
199 Env::default(), 232 env,
200 Default::default(), 233 extern_source,
201 ), 234 ),
202 ); 235 );
203 } 236 }
@@ -235,13 +268,8 @@ impl ProjectWorkspace {
235 opts 268 opts
236 }; 269 };
237 270
238 let mut env = Env::default(); 271 let env = Env::default();
239 let mut extern_source = ExternSource::default(); 272 let extern_source = ExternSource::default();
240 if let Some((id, path)) = outdirs.get(krate.name(&sysroot)) {
241 env.set("OUT_DIR", path.clone());
242 extern_source.set_extern_path(&path, *id);
243 }
244
245 let crate_id = crate_graph.add_crate_root( 273 let crate_id = crate_graph.add_crate_root(
246 file_id, 274 file_id,
247 Edition::Edition2018, 275 Edition::Edition2018,
@@ -292,9 +320,12 @@ impl ProjectWorkspace {
292 }; 320 };
293 let mut env = Env::default(); 321 let mut env = Env::default();
294 let mut extern_source = ExternSource::default(); 322 let mut extern_source = ExternSource::default();
295 if let Some((id, path)) = outdirs.get(pkg.name(&cargo)) { 323 if let Some(out_dir) = pkg.out_dir(cargo) {
296 env.set("OUT_DIR", path.clone()); 324 // FIXME: We probably mangle non UTF-8 paths here, figure out a better solution
297 extern_source.set_extern_path(&path, *id); 325 env.set("OUT_DIR", out_dir.to_string_lossy().to_string());
326 if let Some(&extern_source_id) = extern_source_roots.get(out_dir) {
327 extern_source.set_extern_path(&out_dir, extern_source_id);
328 }
298 } 329 }
299 let crate_id = crate_graph.add_crate_root( 330 let crate_id = crate_graph.add_crate_root(
300 file_id, 331 file_id,