diff options
Diffstat (limited to 'crates/project_model')
-rw-r--r-- | crates/project_model/Cargo.toml | 5 | ||||
-rw-r--r-- | crates/project_model/src/cargo_workspace.rs | 30 | ||||
-rw-r--r-- | crates/project_model/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/project_model/src/rustc_cfg.rs | 34 | ||||
-rw-r--r-- | crates/project_model/src/sysroot.rs | 2 | ||||
-rw-r--r-- | crates/project_model/src/workspace.rs | 143 |
6 files changed, 136 insertions, 79 deletions
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index a65e42261..293cb5bfe 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -12,16 +12,17 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | log = "0.4.8" | 13 | log = "0.4.8" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | cargo_metadata = "=0.12.0" | 15 | cargo_metadata = "0.12.2" |
16 | serde = { version = "1.0.106", features = ["derive"] } | 16 | serde = { version = "1.0.106", features = ["derive"] } |
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
19 | itertools = "0.10.0" | 19 | itertools = "0.10.0" |
20 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | ||
20 | 21 | ||
21 | arena = { path = "../arena", version = "0.0.0" } | ||
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
23 | base_db = { path = "../base_db", version = "0.0.0" } | 23 | base_db = { path = "../base_db", version = "0.0.0" } |
24 | toolchain = { path = "../toolchain", version = "0.0.0" } | 24 | toolchain = { path = "../toolchain", version = "0.0.0" } |
25 | proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } | 25 | proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } |
26 | paths = { path = "../paths", version = "0.0.0" } | 26 | paths = { path = "../paths", version = "0.0.0" } |
27 | stdx = { path = "../stdx", version = "0.0.0" } | 27 | stdx = { path = "../stdx", version = "0.0.0" } |
28 | profile = { path = "../profile", version = "0.0.0" } | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index 0e6679542..c0ed37fc1 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -3,18 +3,20 @@ | |||
3 | use std::{ | 3 | use std::{ |
4 | convert::TryInto, | 4 | convert::TryInto, |
5 | ffi::OsStr, | 5 | ffi::OsStr, |
6 | io::BufReader, | ||
6 | ops, | 7 | ops, |
7 | path::{Path, PathBuf}, | 8 | path::{Path, PathBuf}, |
8 | process::Command, | 9 | process::{Command, Stdio}, |
9 | }; | 10 | }; |
10 | 11 | ||
11 | use anyhow::{Context, Result}; | 12 | use anyhow::{Context, Result}; |
12 | use arena::{Arena, Idx}; | ||
13 | use base_db::Edition; | 13 | use base_db::Edition; |
14 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; | 14 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; |
15 | use itertools::Itertools; | 15 | use itertools::Itertools; |
16 | use la_arena::{Arena, Idx}; | ||
16 | use paths::{AbsPath, AbsPathBuf}; | 17 | use paths::{AbsPath, AbsPathBuf}; |
17 | use rustc_hash::FxHashMap; | 18 | use rustc_hash::FxHashMap; |
19 | use stdx::JodChild; | ||
18 | 20 | ||
19 | use crate::cfg_flag::CfgFlag; | 21 | use crate::cfg_flag::CfgFlag; |
20 | use crate::utf8_stdout; | 22 | use crate::utf8_stdout; |
@@ -171,6 +173,7 @@ impl CargoWorkspace { | |||
171 | pub fn from_cargo_metadata( | 173 | pub fn from_cargo_metadata( |
172 | cargo_toml: &AbsPath, | 174 | cargo_toml: &AbsPath, |
173 | config: &CargoConfig, | 175 | config: &CargoConfig, |
176 | progress: &dyn Fn(String), | ||
174 | ) -> Result<CargoWorkspace> { | 177 | ) -> Result<CargoWorkspace> { |
175 | let mut meta = MetadataCommand::new(); | 178 | let mut meta = MetadataCommand::new(); |
176 | meta.cargo_path(toolchain::cargo()); | 179 | meta.cargo_path(toolchain::cargo()); |
@@ -220,6 +223,9 @@ impl CargoWorkspace { | |||
220 | meta.other_options(vec![String::from("--filter-platform"), target]); | 223 | meta.other_options(vec![String::from("--filter-platform"), target]); |
221 | } | 224 | } |
222 | 225 | ||
226 | // FIXME: Currently MetadataCommand is not based on parse_stream, | ||
227 | // So we just report it as a whole | ||
228 | progress("metadata".to_string()); | ||
223 | let mut meta = meta.exec().with_context(|| { | 229 | let mut meta = meta.exec().with_context(|| { |
224 | let cwd: Option<AbsPathBuf> = | 230 | let cwd: Option<AbsPathBuf> = |
225 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); | 231 | std::env::current_dir().ok().and_then(|p| p.try_into().ok()); |
@@ -243,7 +249,7 @@ impl CargoWorkspace { | |||
243 | let mut envs = FxHashMap::default(); | 249 | let mut envs = FxHashMap::default(); |
244 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 250 | let mut proc_macro_dylib_paths = FxHashMap::default(); |
245 | if config.load_out_dirs_from_check { | 251 | if config.load_out_dirs_from_check { |
246 | let resources = load_extern_resources(cargo_toml, config)?; | 252 | let resources = load_extern_resources(cargo_toml, config, progress)?; |
247 | out_dir_by_id = resources.out_dirs; | 253 | out_dir_by_id = resources.out_dirs; |
248 | cfgs = resources.cfgs; | 254 | cfgs = resources.cfgs; |
249 | envs = resources.env; | 255 | envs = resources.env; |
@@ -368,9 +374,10 @@ pub(crate) struct ExternResources { | |||
368 | pub(crate) fn load_extern_resources( | 374 | pub(crate) fn load_extern_resources( |
369 | cargo_toml: &Path, | 375 | cargo_toml: &Path, |
370 | cargo_features: &CargoConfig, | 376 | cargo_features: &CargoConfig, |
377 | progress: &dyn Fn(String), | ||
371 | ) -> Result<ExternResources> { | 378 | ) -> Result<ExternResources> { |
372 | let mut cmd = Command::new(toolchain::cargo()); | 379 | let mut cmd = Command::new(toolchain::cargo()); |
373 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | 380 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
374 | 381 | ||
375 | // --all-targets includes tests, benches and examples in addition to the | 382 | // --all-targets includes tests, benches and examples in addition to the |
376 | // default lib and bins. This is an independent concept from the --targets | 383 | // default lib and bins. This is an independent concept from the --targets |
@@ -395,11 +402,14 @@ pub(crate) fn load_extern_resources( | |||
395 | } | 402 | } |
396 | } | 403 | } |
397 | 404 | ||
398 | let output = cmd.output()?; | 405 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); |
399 | 406 | ||
400 | let mut res = ExternResources::default(); | 407 | let mut child = cmd.spawn().map(JodChild)?; |
408 | let child_stdout = child.stdout.take().unwrap(); | ||
409 | let stdout = BufReader::new(child_stdout); | ||
401 | 410 | ||
402 | for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) { | 411 | let mut res = ExternResources::default(); |
412 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
403 | if let Ok(message) = message { | 413 | if let Ok(message) = message { |
404 | match message { | 414 | match message { |
405 | Message::BuildScriptExecuted(BuildScript { | 415 | Message::BuildScriptExecuted(BuildScript { |
@@ -432,6 +442,8 @@ pub(crate) fn load_extern_resources( | |||
432 | res.env.insert(package_id, env); | 442 | res.env.insert(package_id, env); |
433 | } | 443 | } |
434 | Message::CompilerArtifact(message) => { | 444 | Message::CompilerArtifact(message) => { |
445 | progress(format!("metadata {}", message.target.name)); | ||
446 | |||
435 | if message.target.kind.contains(&"proc-macro".to_string()) { | 447 | if message.target.kind.contains(&"proc-macro".to_string()) { |
436 | let package_id = message.package_id; | 448 | let package_id = message.package_id; |
437 | // Skip rmeta file | 449 | // Skip rmeta file |
@@ -442,7 +454,9 @@ pub(crate) fn load_extern_resources( | |||
442 | } | 454 | } |
443 | } | 455 | } |
444 | } | 456 | } |
445 | Message::CompilerMessage(_) => (), | 457 | Message::CompilerMessage(message) => { |
458 | progress(message.target.name.clone()); | ||
459 | } | ||
446 | Message::Unknown => (), | 460 | Message::Unknown => (), |
447 | Message::BuildFinished(_) => {} | 461 | Message::BuildFinished(_) => {} |
448 | Message::TextLine(_) => {} | 462 | Message::TextLine(_) => {} |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index aabb7a47d..970a7e140 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -5,6 +5,7 @@ mod cfg_flag; | |||
5 | mod project_json; | 5 | mod project_json; |
6 | mod sysroot; | 6 | mod sysroot; |
7 | mod workspace; | 7 | mod workspace; |
8 | mod rustc_cfg; | ||
8 | 9 | ||
9 | use std::{ | 10 | use std::{ |
10 | fs::{read_dir, ReadDir}, | 11 | fs::{read_dir, ReadDir}, |
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs new file mode 100644 index 000000000..4a7bd8ae3 --- /dev/null +++ b/crates/project_model/src/rustc_cfg.rs | |||
@@ -0,0 +1,34 @@ | |||
1 | //! Runs `rustc --print cfg` to get built-in cfg flags. | ||
2 | |||
3 | use std::process::Command; | ||
4 | |||
5 | use crate::{cfg_flag::CfgFlag, utf8_stdout}; | ||
6 | |||
7 | pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> { | ||
8 | let _p = profile::span("rustc_cfg::get"); | ||
9 | let mut res = Vec::new(); | ||
10 | |||
11 | // Some nightly-only cfgs, which are required for stdlib | ||
12 | res.push(CfgFlag::Atom("target_thread_local".into())); | ||
13 | for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() { | ||
14 | for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() { | ||
15 | res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); | ||
16 | } | ||
17 | } | ||
18 | |||
19 | let rustc_cfgs = { | ||
20 | let mut cmd = Command::new(toolchain::rustc()); | ||
21 | cmd.args(&["--print", "cfg", "-O"]); | ||
22 | if let Some(target) = target { | ||
23 | cmd.args(&["--target", target]); | ||
24 | } | ||
25 | utf8_stdout(cmd) | ||
26 | }; | ||
27 | |||
28 | match rustc_cfgs { | ||
29 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), | ||
30 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | ||
31 | } | ||
32 | |||
33 | res | ||
34 | } | ||
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index 95b622715..ff44dae4a 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -7,7 +7,7 @@ | |||
7 | use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command}; | 7 | use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command}; |
8 | 8 | ||
9 | use anyhow::{format_err, Result}; | 9 | use anyhow::{format_err, Result}; |
10 | use arena::{Arena, Idx}; | 10 | use la_arena::{Arena, Idx}; |
11 | use paths::{AbsPath, AbsPathBuf}; | 11 | use paths::{AbsPath, AbsPathBuf}; |
12 | 12 | ||
13 | use crate::utf8_stdout; | 13 | use crate::utf8_stdout; |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 68a235ce3..8e0481ae9 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -16,7 +16,7 @@ use proc_macro_api::ProcMacroClient; | |||
16 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | cargo_workspace, cfg_flag::CfgFlag, sysroot::SysrootCrate, utf8_stdout, CargoConfig, | 19 | cargo_workspace, cfg_flag::CfgFlag, rustc_cfg, sysroot::SysrootCrate, utf8_stdout, CargoConfig, |
20 | CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind, | 20 | CargoWorkspace, ProjectJson, ProjectManifest, Sysroot, TargetKind, |
21 | }; | 21 | }; |
22 | 22 | ||
@@ -34,15 +34,25 @@ pub struct PackageRoot { | |||
34 | #[derive(Clone, Eq, PartialEq)] | 34 | #[derive(Clone, Eq, PartialEq)] |
35 | pub enum ProjectWorkspace { | 35 | pub enum ProjectWorkspace { |
36 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 36 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
37 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot, rustc: Option<CargoWorkspace> }, | 37 | Cargo { |
38 | cargo: CargoWorkspace, | ||
39 | sysroot: Sysroot, | ||
40 | rustc: Option<CargoWorkspace>, | ||
41 | /// Holds cfg flags for the current target. We get those by running | ||
42 | /// `rustc --print cfg`. | ||
43 | /// | ||
44 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a | ||
45 | /// different target. | ||
46 | rustc_cfg: Vec<CfgFlag>, | ||
47 | }, | ||
38 | /// Project workspace was manually specified using a `rust-project.json` file. | 48 | /// Project workspace was manually specified using a `rust-project.json` file. |
39 | Json { project: ProjectJson, sysroot: Option<Sysroot> }, | 49 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
40 | } | 50 | } |
41 | 51 | ||
42 | impl fmt::Debug for ProjectWorkspace { | 52 | impl fmt::Debug for ProjectWorkspace { |
43 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
44 | match self { | 54 | match self { |
45 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => f | 55 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f |
46 | .debug_struct("Cargo") | 56 | .debug_struct("Cargo") |
47 | .field("n_packages", &cargo.packages().len()) | 57 | .field("n_packages", &cargo.packages().len()) |
48 | .field("n_sysroot_crates", &sysroot.crates().len()) | 58 | .field("n_sysroot_crates", &sysroot.crates().len()) |
@@ -50,13 +60,15 @@ impl fmt::Debug for ProjectWorkspace { | |||
50 | "n_rustc_compiler_crates", | 60 | "n_rustc_compiler_crates", |
51 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | 61 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), |
52 | ) | 62 | ) |
63 | .field("rustc_cfg", rustc_cfg) | ||
53 | .finish(), | 64 | .finish(), |
54 | ProjectWorkspace::Json { project, sysroot } => { | 65 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { |
55 | let mut debug_struct = f.debug_struct("Json"); | 66 | let mut debug_struct = f.debug_struct("Json"); |
56 | debug_struct.field("n_crates", &project.n_crates()); | 67 | debug_struct.field("n_crates", &project.n_crates()); |
57 | if let Some(sysroot) = sysroot { | 68 | if let Some(sysroot) = sysroot { |
58 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); | 69 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); |
59 | } | 70 | } |
71 | debug_struct.field("rustc_cfg", rustc_cfg); | ||
60 | debug_struct.finish() | 72 | debug_struct.finish() |
61 | } | 73 | } |
62 | } | 74 | } |
@@ -64,7 +76,11 @@ impl fmt::Debug for ProjectWorkspace { | |||
64 | } | 76 | } |
65 | 77 | ||
66 | impl ProjectWorkspace { | 78 | impl ProjectWorkspace { |
67 | pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result<ProjectWorkspace> { | 79 | pub fn load( |
80 | manifest: ProjectManifest, | ||
81 | config: &CargoConfig, | ||
82 | progress: &dyn Fn(String), | ||
83 | ) -> Result<ProjectWorkspace> { | ||
68 | let res = match manifest { | 84 | let res = match manifest { |
69 | ProjectManifest::ProjectJson(project_json) => { | 85 | ProjectManifest::ProjectJson(project_json) => { |
70 | let file = fs::read_to_string(&project_json).with_context(|| { | 86 | let file = fs::read_to_string(&project_json).with_context(|| { |
@@ -75,7 +91,7 @@ impl ProjectWorkspace { | |||
75 | })?; | 91 | })?; |
76 | let project_location = project_json.parent().unwrap().to_path_buf(); | 92 | let project_location = project_json.parent().unwrap().to_path_buf(); |
77 | let project_json = ProjectJson::new(&project_location, data); | 93 | let project_json = ProjectJson::new(&project_location, data); |
78 | ProjectWorkspace::load_inline(project_json)? | 94 | ProjectWorkspace::load_inline(project_json, config.target.as_deref())? |
79 | } | 95 | } |
80 | ProjectManifest::CargoToml(cargo_toml) => { | 96 | ProjectManifest::CargoToml(cargo_toml) => { |
81 | let cargo_version = utf8_stdout({ | 97 | let cargo_version = utf8_stdout({ |
@@ -84,15 +100,14 @@ impl ProjectWorkspace { | |||
84 | cmd | 100 | cmd |
85 | })?; | 101 | })?; |
86 | 102 | ||
87 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config).with_context( | 103 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress) |
88 | || { | 104 | .with_context(|| { |
89 | format!( | 105 | format!( |
90 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", | 106 | "Failed to read Cargo metadata from Cargo.toml file {}, {}", |
91 | cargo_toml.display(), | 107 | cargo_toml.display(), |
92 | cargo_version | 108 | cargo_version |
93 | ) | 109 | ) |
94 | }, | 110 | })?; |
95 | )?; | ||
96 | let sysroot = if config.no_sysroot { | 111 | let sysroot = if config.no_sysroot { |
97 | Sysroot::default() | 112 | Sysroot::default() |
98 | } else { | 113 | } else { |
@@ -105,27 +120,33 @@ impl ProjectWorkspace { | |||
105 | }; | 120 | }; |
106 | 121 | ||
107 | let rustc = if let Some(rustc_dir) = &config.rustc_source { | 122 | let rustc = if let Some(rustc_dir) = &config.rustc_source { |
108 | Some(CargoWorkspace::from_cargo_metadata(&rustc_dir, config).with_context( | 123 | Some( |
109 | || format!("Failed to read Cargo metadata for Rust sources"), | 124 | CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) |
110 | )?) | 125 | .with_context(|| { |
126 | format!("Failed to read Cargo metadata for Rust sources") | ||
127 | })?, | ||
128 | ) | ||
111 | } else { | 129 | } else { |
112 | None | 130 | None |
113 | }; | 131 | }; |
114 | 132 | let rustc_cfg = rustc_cfg::get(config.target.as_deref()); | |
115 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } | 133 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } |
116 | } | 134 | } |
117 | }; | 135 | }; |
118 | 136 | ||
119 | Ok(res) | 137 | Ok(res) |
120 | } | 138 | } |
121 | 139 | ||
122 | pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> { | 140 | pub fn load_inline( |
141 | project_json: ProjectJson, | ||
142 | target: Option<&str>, | ||
143 | ) -> Result<ProjectWorkspace> { | ||
123 | let sysroot = match &project_json.sysroot_src { | 144 | let sysroot = match &project_json.sysroot_src { |
124 | Some(path) => Some(Sysroot::load(path)?), | 145 | Some(path) => Some(Sysroot::load(path)?), |
125 | None => None, | 146 | None => None, |
126 | }; | 147 | }; |
127 | 148 | let rustc_cfg = rustc_cfg::get(target); | |
128 | Ok(ProjectWorkspace::Json { project: project_json, sysroot }) | 149 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) |
129 | } | 150 | } |
130 | 151 | ||
131 | /// Returns the roots for the current `ProjectWorkspace` | 152 | /// Returns the roots for the current `ProjectWorkspace` |
@@ -133,7 +154,7 @@ impl ProjectWorkspace { | |||
133 | /// the root is a member of the current workspace | 154 | /// the root is a member of the current workspace |
134 | pub fn to_roots(&self) -> Vec<PackageRoot> { | 155 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
135 | match self { | 156 | match self { |
136 | ProjectWorkspace::Json { project, sysroot } => project | 157 | ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project |
137 | .crates() | 158 | .crates() |
138 | .map(|(_, krate)| PackageRoot { | 159 | .map(|(_, krate)| PackageRoot { |
139 | is_member: krate.is_workspace_member, | 160 | is_member: krate.is_workspace_member, |
@@ -150,7 +171,7 @@ impl ProjectWorkspace { | |||
150 | }) | 171 | }) |
151 | })) | 172 | })) |
152 | .collect::<Vec<_>>(), | 173 | .collect::<Vec<_>>(), |
153 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo | 174 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo |
154 | .packages() | 175 | .packages() |
155 | .map(|pkg| { | 176 | .map(|pkg| { |
156 | let is_member = cargo[pkg].is_member; | 177 | let is_member = cargo[pkg].is_member; |
@@ -188,7 +209,7 @@ impl ProjectWorkspace { | |||
188 | pub fn n_packages(&self) -> usize { | 209 | pub fn n_packages(&self) -> usize { |
189 | match self { | 210 | match self { |
190 | ProjectWorkspace::Json { project, .. } => project.n_crates(), | 211 | ProjectWorkspace::Json { project, .. } => project.n_crates(), |
191 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 212 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { |
192 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); | 213 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); |
193 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len | 214 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len |
194 | } | 215 | } |
@@ -197,22 +218,31 @@ impl ProjectWorkspace { | |||
197 | 218 | ||
198 | pub fn to_crate_graph( | 219 | pub fn to_crate_graph( |
199 | &self, | 220 | &self, |
200 | target: Option<&str>, | ||
201 | proc_macro_client: Option<&ProcMacroClient>, | 221 | proc_macro_client: Option<&ProcMacroClient>, |
202 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 222 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
203 | ) -> CrateGraph { | 223 | ) -> CrateGraph { |
224 | let _p = profile::span("ProjectWorkspace::to_crate_graph"); | ||
204 | let proc_macro_loader = |path: &Path| match proc_macro_client { | 225 | let proc_macro_loader = |path: &Path| match proc_macro_client { |
205 | Some(client) => client.by_dylib_path(path), | 226 | Some(client) => client.by_dylib_path(path), |
206 | None => Vec::new(), | 227 | None => Vec::new(), |
207 | }; | 228 | }; |
208 | 229 | ||
209 | let mut crate_graph = match self { | 230 | let mut crate_graph = match self { |
210 | ProjectWorkspace::Json { project, sysroot } => { | 231 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( |
211 | project_json_to_crate_graph(target, &proc_macro_loader, load, project, sysroot) | 232 | rustc_cfg.clone(), |
212 | } | 233 | &proc_macro_loader, |
213 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 234 | load, |
214 | cargo_to_crate_graph(target, &proc_macro_loader, load, cargo, sysroot, rustc) | 235 | project, |
215 | } | 236 | sysroot, |
237 | ), | ||
238 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( | ||
239 | rustc_cfg.clone(), | ||
240 | &proc_macro_loader, | ||
241 | load, | ||
242 | cargo, | ||
243 | sysroot, | ||
244 | rustc, | ||
245 | ), | ||
216 | }; | 246 | }; |
217 | if crate_graph.patch_cfg_if() { | 247 | if crate_graph.patch_cfg_if() { |
218 | log::debug!("Patched std to depend on cfg-if") | 248 | log::debug!("Patched std to depend on cfg-if") |
@@ -224,7 +254,7 @@ impl ProjectWorkspace { | |||
224 | } | 254 | } |
225 | 255 | ||
226 | fn project_json_to_crate_graph( | 256 | fn project_json_to_crate_graph( |
227 | target: Option<&str>, | 257 | rustc_cfg: Vec<CfgFlag>, |
228 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 258 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
229 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 259 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
230 | project: &ProjectJson, | 260 | project: &ProjectJson, |
@@ -233,9 +263,9 @@ fn project_json_to_crate_graph( | |||
233 | let mut crate_graph = CrateGraph::default(); | 263 | let mut crate_graph = CrateGraph::default(); |
234 | let sysroot_deps = sysroot | 264 | let sysroot_deps = sysroot |
235 | .as_ref() | 265 | .as_ref() |
236 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); | 266 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load)); |
237 | 267 | ||
238 | let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); | 268 | let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default(); |
239 | let crates: FxHashMap<CrateId, CrateId> = project | 269 | let crates: FxHashMap<CrateId, CrateId> = project |
240 | .crates() | 270 | .crates() |
241 | .filter_map(|(crate_id, krate)| { | 271 | .filter_map(|(crate_id, krate)| { |
@@ -247,9 +277,12 @@ fn project_json_to_crate_graph( | |||
247 | let env = krate.env.clone().into_iter().collect(); | 277 | let env = krate.env.clone().into_iter().collect(); |
248 | let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it)); | 278 | let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it)); |
249 | 279 | ||
250 | let target = krate.target.as_deref().or(target); | 280 | let target_cfgs = match krate.target.as_deref() { |
251 | let target_cfgs = | 281 | Some(target) => { |
252 | cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target)); | 282 | cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(Some(target))) |
283 | } | ||
284 | None => &rustc_cfg, | ||
285 | }; | ||
253 | 286 | ||
254 | let mut cfg_options = CfgOptions::default(); | 287 | let mut cfg_options = CfgOptions::default(); |
255 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); | 288 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); |
@@ -286,19 +319,20 @@ fn project_json_to_crate_graph( | |||
286 | } | 319 | } |
287 | 320 | ||
288 | fn cargo_to_crate_graph( | 321 | fn cargo_to_crate_graph( |
289 | target: Option<&str>, | 322 | rustc_cfg: Vec<CfgFlag>, |
290 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 323 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
291 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 324 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
292 | cargo: &CargoWorkspace, | 325 | cargo: &CargoWorkspace, |
293 | sysroot: &Sysroot, | 326 | sysroot: &Sysroot, |
294 | rustc: &Option<CargoWorkspace>, | 327 | rustc: &Option<CargoWorkspace>, |
295 | ) -> CrateGraph { | 328 | ) -> CrateGraph { |
329 | let _p = profile::span("cargo_to_crate_graph"); | ||
296 | let mut crate_graph = CrateGraph::default(); | 330 | let mut crate_graph = CrateGraph::default(); |
297 | let (public_deps, libproc_macro) = | 331 | let (public_deps, libproc_macro) = |
298 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | 332 | sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); |
299 | 333 | ||
300 | let mut cfg_options = CfgOptions::default(); | 334 | let mut cfg_options = CfgOptions::default(); |
301 | cfg_options.extend(get_rustc_cfg_options(target)); | 335 | cfg_options.extend(rustc_cfg); |
302 | 336 | ||
303 | let mut pkg_to_lib_crate = FxHashMap::default(); | 337 | let mut pkg_to_lib_crate = FxHashMap::default(); |
304 | 338 | ||
@@ -484,11 +518,12 @@ fn add_target_crate_root( | |||
484 | fn sysroot_to_crate_graph( | 518 | fn sysroot_to_crate_graph( |
485 | crate_graph: &mut CrateGraph, | 519 | crate_graph: &mut CrateGraph, |
486 | sysroot: &Sysroot, | 520 | sysroot: &Sysroot, |
487 | target: Option<&str>, | 521 | rustc_cfg: Vec<CfgFlag>, |
488 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 522 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
489 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { | 523 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { |
524 | let _p = profile::span("sysroot_to_crate_graph"); | ||
490 | let mut cfg_options = CfgOptions::default(); | 525 | let mut cfg_options = CfgOptions::default(); |
491 | cfg_options.extend(get_rustc_cfg_options(target)); | 526 | cfg_options.extend(rustc_cfg); |
492 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot | 527 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot |
493 | .crates() | 528 | .crates() |
494 | .filter_map(|krate| { | 529 | .filter_map(|krate| { |
@@ -527,34 +562,6 @@ fn sysroot_to_crate_graph( | |||
527 | (public_deps, libproc_macro) | 562 | (public_deps, libproc_macro) |
528 | } | 563 | } |
529 | 564 | ||
530 | fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> { | ||
531 | let mut res = Vec::new(); | ||
532 | |||
533 | // Some nightly-only cfgs, which are required for stdlib | ||
534 | res.push(CfgFlag::Atom("target_thread_local".into())); | ||
535 | for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() { | ||
536 | for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() { | ||
537 | res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | let rustc_cfgs = { | ||
542 | let mut cmd = Command::new(toolchain::rustc()); | ||
543 | cmd.args(&["--print", "cfg", "-O"]); | ||
544 | if let Some(target) = target { | ||
545 | cmd.args(&["--target", target]); | ||
546 | } | ||
547 | utf8_stdout(cmd) | ||
548 | }; | ||
549 | |||
550 | match rustc_cfgs { | ||
551 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), | ||
552 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | ||
553 | } | ||
554 | |||
555 | res | ||
556 | } | ||
557 | |||
558 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { | 565 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { |
559 | if let Err(err) = graph.add_dep(from, name, to) { | 566 | if let Err(err) = graph.add_dep(from, name, to) { |
560 | log::error!("{}", err) | 567 | log::error!("{}", err) |