aboutsummaryrefslogtreecommitdiff
path: root/crates/project_model
diff options
context:
space:
mode:
Diffstat (limited to 'crates/project_model')
-rw-r--r--crates/project_model/Cargo.toml5
-rw-r--r--crates/project_model/src/cargo_workspace.rs30
-rw-r--r--crates/project_model/src/lib.rs1
-rw-r--r--crates/project_model/src/rustc_cfg.rs34
-rw-r--r--crates/project_model/src/sysroot.rs2
-rw-r--r--crates/project_model/src/workspace.rs143
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]
13log = "0.4.8" 13log = "0.4.8"
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15cargo_metadata = "=0.12.0" 15cargo_metadata = "0.12.2"
16serde = { version = "1.0.106", features = ["derive"] } 16serde = { version = "1.0.106", features = ["derive"] }
17serde_json = "1.0.48" 17serde_json = "1.0.48"
18anyhow = "1.0.26" 18anyhow = "1.0.26"
19itertools = "0.10.0" 19itertools = "0.10.0"
20la-arena = { version = "0.2.0", path = "../../lib/arena" }
20 21
21arena = { path = "../arena", version = "0.0.0" }
22cfg = { path = "../cfg", version = "0.0.0" } 22cfg = { path = "../cfg", version = "0.0.0" }
23base_db = { path = "../base_db", version = "0.0.0" } 23base_db = { path = "../base_db", version = "0.0.0" }
24toolchain = { path = "../toolchain", version = "0.0.0" } 24toolchain = { path = "../toolchain", version = "0.0.0" }
25proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } 25proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
26paths = { path = "../paths", version = "0.0.0" } 26paths = { path = "../paths", version = "0.0.0" }
27stdx = { path = "../stdx", version = "0.0.0" } 27stdx = { path = "../stdx", version = "0.0.0" }
28profile = { 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 @@
3use std::{ 3use 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
11use anyhow::{Context, Result}; 12use anyhow::{Context, Result};
12use arena::{Arena, Idx};
13use base_db::Edition; 13use base_db::Edition;
14use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 14use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
15use itertools::Itertools; 15use itertools::Itertools;
16use la_arena::{Arena, Idx};
16use paths::{AbsPath, AbsPathBuf}; 17use paths::{AbsPath, AbsPathBuf};
17use rustc_hash::FxHashMap; 18use rustc_hash::FxHashMap;
19use stdx::JodChild;
18 20
19use crate::cfg_flag::CfgFlag; 21use crate::cfg_flag::CfgFlag;
20use crate::utf8_stdout; 22use 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 {
368pub(crate) fn load_extern_resources( 374pub(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;
5mod project_json; 5mod project_json;
6mod sysroot; 6mod sysroot;
7mod workspace; 7mod workspace;
8mod rustc_cfg;
8 9
9use std::{ 10use 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
3use std::process::Command;
4
5use crate::{cfg_flag::CfgFlag, utf8_stdout};
6
7pub(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 @@
7use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command}; 7use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command};
8 8
9use anyhow::{format_err, Result}; 9use anyhow::{format_err, Result};
10use arena::{Arena, Idx}; 10use la_arena::{Arena, Idx};
11use paths::{AbsPath, AbsPathBuf}; 11use paths::{AbsPath, AbsPathBuf};
12 12
13use crate::utf8_stdout; 13use 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;
16use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
17 17
18use crate::{ 18use 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)]
35pub enum ProjectWorkspace { 35pub 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
42impl fmt::Debug for ProjectWorkspace { 52impl 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
66impl ProjectWorkspace { 78impl 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
226fn project_json_to_crate_graph( 256fn 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
288fn cargo_to_crate_graph( 321fn 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(
484fn sysroot_to_crate_graph( 518fn 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
530fn 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
558fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { 565fn 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)