diff options
Diffstat (limited to 'crates/project_model/src')
-rw-r--r-- | crates/project_model/src/build_data.rs | 206 | ||||
-rw-r--r-- | crates/project_model/src/cargo_workspace.rs | 208 | ||||
-rw-r--r-- | crates/project_model/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/project_model/src/rustc_cfg.rs | 34 | ||||
-rw-r--r-- | crates/project_model/src/workspace.rs | 143 |
5 files changed, 332 insertions, 261 deletions
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs new file mode 100644 index 000000000..cf32995e0 --- /dev/null +++ b/crates/project_model/src/build_data.rs | |||
@@ -0,0 +1,206 @@ | |||
1 | //! Handles build script specific information | ||
2 | |||
3 | use std::{ | ||
4 | ffi::OsStr, | ||
5 | io::BufReader, | ||
6 | path::{Path, PathBuf}, | ||
7 | process::{Command, Stdio}, | ||
8 | }; | ||
9 | |||
10 | use anyhow::Result; | ||
11 | use cargo_metadata::{BuildScript, Message, Package, PackageId}; | ||
12 | use itertools::Itertools; | ||
13 | use paths::{AbsPath, AbsPathBuf}; | ||
14 | use rustc_hash::FxHashMap; | ||
15 | use stdx::JodChild; | ||
16 | |||
17 | use crate::{cfg_flag::CfgFlag, CargoConfig}; | ||
18 | |||
19 | #[derive(Debug, Clone, Default)] | ||
20 | pub(crate) struct BuildDataMap { | ||
21 | data: FxHashMap<PackageId, BuildData>, | ||
22 | } | ||
23 | #[derive(Debug, Clone, Default, PartialEq, Eq)] | ||
24 | pub struct BuildData { | ||
25 | /// List of config flags defined by this package's build script | ||
26 | pub cfgs: Vec<CfgFlag>, | ||
27 | /// List of cargo-related environment variables with their value | ||
28 | /// | ||
29 | /// If the package has a build script which defines environment variables, | ||
30 | /// they can also be found here. | ||
31 | pub envs: Vec<(String, String)>, | ||
32 | /// Directory where a build script might place its output | ||
33 | pub out_dir: Option<AbsPathBuf>, | ||
34 | /// Path to the proc-macro library file if this package exposes proc-macros | ||
35 | pub proc_macro_dylib_path: Option<AbsPathBuf>, | ||
36 | } | ||
37 | |||
38 | impl BuildDataMap { | ||
39 | pub(crate) fn new( | ||
40 | cargo_toml: &AbsPath, | ||
41 | cargo_features: &CargoConfig, | ||
42 | packages: &Vec<Package>, | ||
43 | progress: &dyn Fn(String), | ||
44 | ) -> Result<BuildDataMap> { | ||
45 | let mut cmd = Command::new(toolchain::cargo()); | ||
46 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) | ||
47 | .arg(cargo_toml.as_ref()); | ||
48 | |||
49 | // --all-targets includes tests, benches and examples in addition to the | ||
50 | // default lib and bins. This is an independent concept from the --targets | ||
51 | // flag below. | ||
52 | cmd.arg("--all-targets"); | ||
53 | |||
54 | if let Some(target) = &cargo_features.target { | ||
55 | cmd.args(&["--target", target]); | ||
56 | } | ||
57 | |||
58 | if cargo_features.all_features { | ||
59 | cmd.arg("--all-features"); | ||
60 | } else { | ||
61 | if cargo_features.no_default_features { | ||
62 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
63 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
64 | cmd.arg("--no-default-features"); | ||
65 | } | ||
66 | if !cargo_features.features.is_empty() { | ||
67 | cmd.arg("--features"); | ||
68 | cmd.arg(cargo_features.features.join(" ")); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); | ||
73 | |||
74 | let mut child = cmd.spawn().map(JodChild)?; | ||
75 | let child_stdout = child.stdout.take().unwrap(); | ||
76 | let stdout = BufReader::new(child_stdout); | ||
77 | |||
78 | let mut res = BuildDataMap::default(); | ||
79 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
80 | if let Ok(message) = message { | ||
81 | match message { | ||
82 | Message::BuildScriptExecuted(BuildScript { | ||
83 | package_id, | ||
84 | out_dir, | ||
85 | cfgs, | ||
86 | env, | ||
87 | .. | ||
88 | }) => { | ||
89 | let cfgs = { | ||
90 | let mut acc = Vec::new(); | ||
91 | for cfg in cfgs { | ||
92 | match cfg.parse::<CfgFlag>() { | ||
93 | Ok(it) => acc.push(it), | ||
94 | Err(err) => { | ||
95 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
96 | } | ||
97 | }; | ||
98 | } | ||
99 | acc | ||
100 | }; | ||
101 | let res = res.data.entry(package_id.clone()).or_default(); | ||
102 | // cargo_metadata crate returns default (empty) path for | ||
103 | // older cargos, which is not absolute, so work around that. | ||
104 | if out_dir != PathBuf::default() { | ||
105 | let out_dir = AbsPathBuf::assert(out_dir); | ||
106 | res.out_dir = Some(out_dir); | ||
107 | res.cfgs = cfgs; | ||
108 | } | ||
109 | |||
110 | res.envs = env; | ||
111 | } | ||
112 | Message::CompilerArtifact(message) => { | ||
113 | progress(format!("metadata {}", message.target.name)); | ||
114 | |||
115 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
116 | let package_id = message.package_id; | ||
117 | // Skip rmeta file | ||
118 | if let Some(filename) = | ||
119 | message.filenames.iter().find(|name| is_dylib(name)) | ||
120 | { | ||
121 | let filename = AbsPathBuf::assert(filename.clone()); | ||
122 | let res = res.data.entry(package_id.clone()).or_default(); | ||
123 | res.proc_macro_dylib_path = Some(filename); | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | Message::CompilerMessage(message) => { | ||
128 | progress(message.target.name.clone()); | ||
129 | } | ||
130 | Message::Unknown => (), | ||
131 | Message::BuildFinished(_) => {} | ||
132 | Message::TextLine(_) => {} | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | res.inject_cargo_env(packages); | ||
137 | Ok(res) | ||
138 | } | ||
139 | |||
140 | pub(crate) fn with_cargo_env(packages: &Vec<Package>) -> Self { | ||
141 | let mut res = Self::default(); | ||
142 | res.inject_cargo_env(packages); | ||
143 | res | ||
144 | } | ||
145 | |||
146 | pub(crate) fn get(&self, id: &PackageId) -> Option<&BuildData> { | ||
147 | self.data.get(id) | ||
148 | } | ||
149 | |||
150 | fn inject_cargo_env(&mut self, packages: &Vec<Package>) { | ||
151 | for meta_pkg in packages { | ||
152 | let resource = self.data.entry(meta_pkg.id.clone()).or_default(); | ||
153 | inject_cargo_env(meta_pkg, &mut resource.envs); | ||
154 | |||
155 | if let Some(out_dir) = &resource.out_dir { | ||
156 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
157 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
158 | resource.envs.push(("OUT_DIR".to_string(), out_dir)); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // FIXME: File a better way to know if it is a dylib | ||
166 | fn is_dylib(path: &Path) -> bool { | ||
167 | match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) { | ||
168 | None => false, | ||
169 | Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), | ||
170 | } | ||
171 | } | ||
172 | |||
173 | /// Recreates the compile-time environment variables that Cargo sets. | ||
174 | /// | ||
175 | /// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> | ||
176 | fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { | ||
177 | // FIXME: Missing variables: | ||
178 | // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name> | ||
179 | |||
180 | let mut manifest_dir = package.manifest_path.clone(); | ||
181 | manifest_dir.pop(); | ||
182 | if let Some(cargo_manifest_dir) = manifest_dir.to_str() { | ||
183 | env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into())); | ||
184 | } | ||
185 | |||
186 | env.push(("CARGO_PKG_VERSION".into(), package.version.to_string())); | ||
187 | env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string())); | ||
188 | env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string())); | ||
189 | env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string())); | ||
190 | |||
191 | let pre = package.version.pre.iter().map(|id| id.to_string()).format("."); | ||
192 | env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string())); | ||
193 | |||
194 | let authors = package.authors.join(";"); | ||
195 | env.push(("CARGO_PKG_AUTHORS".into(), authors)); | ||
196 | |||
197 | env.push(("CARGO_PKG_NAME".into(), package.name.clone())); | ||
198 | env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default())); | ||
199 | //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default())); | ||
200 | env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default())); | ||
201 | env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default())); | ||
202 | |||
203 | let license_file = | ||
204 | package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default(); | ||
205 | env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file)); | ||
206 | } | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index c0ed37fc1..c8a5333c4 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,24 +1,15 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{convert::TryInto, ops, process::Command}; |
4 | convert::TryInto, | ||
5 | ffi::OsStr, | ||
6 | io::BufReader, | ||
7 | ops, | ||
8 | path::{Path, PathBuf}, | ||
9 | process::{Command, Stdio}, | ||
10 | }; | ||
11 | 4 | ||
12 | use anyhow::{Context, Result}; | 5 | use anyhow::{Context, Result}; |
13 | use base_db::Edition; | 6 | use base_db::Edition; |
14 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; | 7 | use cargo_metadata::{CargoOpt, MetadataCommand}; |
15 | use itertools::Itertools; | ||
16 | use la_arena::{Arena, Idx}; | 8 | use la_arena::{Arena, Idx}; |
17 | use paths::{AbsPath, AbsPathBuf}; | 9 | use paths::{AbsPath, AbsPathBuf}; |
18 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
19 | use stdx::JodChild; | ||
20 | 11 | ||
21 | use crate::cfg_flag::CfgFlag; | 12 | use crate::build_data::{BuildData, BuildDataMap}; |
22 | use crate::utf8_stdout; | 13 | use crate::utf8_stdout; |
23 | 14 | ||
24 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo | 15 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo |
@@ -99,19 +90,12 @@ pub struct PackageData { | |||
99 | pub dependencies: Vec<PackageDependency>, | 90 | pub dependencies: Vec<PackageDependency>, |
100 | /// Rust edition for this package | 91 | /// Rust edition for this package |
101 | pub edition: Edition, | 92 | pub edition: Edition, |
102 | /// List of features to activate | 93 | /// Features provided by the crate, mapped to the features required by that feature. |
103 | pub features: Vec<String>, | 94 | pub features: FxHashMap<String, Vec<String>>, |
104 | /// List of config flags defined by this package's build script | 95 | /// List of features enabled on this package |
105 | pub cfgs: Vec<CfgFlag>, | 96 | pub active_features: Vec<String>, |
106 | /// List of cargo-related environment variables with their value | 97 | /// Build script related data for this package |
107 | /// | 98 | pub build_data: BuildData, |
108 | /// If the package has a build script which defines environment variables, | ||
109 | /// they can also be found here. | ||
110 | pub envs: Vec<(String, String)>, | ||
111 | /// Directory where a build script might place its output | ||
112 | pub out_dir: Option<AbsPathBuf>, | ||
113 | /// Path to the proc-macro library file if this package exposes proc-macros | ||
114 | pub proc_macro_dylib_path: Option<AbsPathBuf>, | ||
115 | } | 99 | } |
116 | 100 | ||
117 | #[derive(Debug, Clone, Eq, PartialEq)] | 101 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -244,17 +228,11 @@ impl CargoWorkspace { | |||
244 | ) | 228 | ) |
245 | })?; | 229 | })?; |
246 | 230 | ||
247 | let mut out_dir_by_id = FxHashMap::default(); | 231 | let resources = if config.load_out_dirs_from_check { |
248 | let mut cfgs = FxHashMap::default(); | 232 | BuildDataMap::new(cargo_toml, config, &meta.packages, progress)? |
249 | let mut envs = FxHashMap::default(); | 233 | } else { |
250 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 234 | BuildDataMap::with_cargo_env(&meta.packages) |
251 | if config.load_out_dirs_from_check { | 235 | }; |
252 | let resources = load_extern_resources(cargo_toml, config, progress)?; | ||
253 | out_dir_by_id = resources.out_dirs; | ||
254 | cfgs = resources.cfgs; | ||
255 | envs = resources.env; | ||
256 | proc_macro_dylib_paths = resources.proc_dylib_paths; | ||
257 | } | ||
258 | 236 | ||
259 | let mut pkg_by_id = FxHashMap::default(); | 237 | let mut pkg_by_id = FxHashMap::default(); |
260 | let mut packages = Arena::default(); | 238 | let mut packages = Arena::default(); |
@@ -265,7 +243,7 @@ impl CargoWorkspace { | |||
265 | meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); | 243 | meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); |
266 | for meta_pkg in meta.packages { | 244 | for meta_pkg in meta.packages { |
267 | let id = meta_pkg.id.clone(); | 245 | let id = meta_pkg.id.clone(); |
268 | inject_cargo_env(&meta_pkg, envs.entry(id).or_default()); | 246 | let build_data = resources.get(&id).cloned().unwrap_or_default(); |
269 | 247 | ||
270 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = | 248 | let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = |
271 | meta_pkg; | 249 | meta_pkg; |
@@ -281,11 +259,9 @@ impl CargoWorkspace { | |||
281 | is_member, | 259 | is_member, |
282 | edition, | 260 | edition, |
283 | dependencies: Vec::new(), | 261 | dependencies: Vec::new(), |
284 | features: Vec::new(), | 262 | features: meta_pkg.features.into_iter().collect(), |
285 | cfgs: cfgs.get(&id).cloned().unwrap_or_default(), | 263 | active_features: Vec::new(), |
286 | envs: envs.get(&id).cloned().unwrap_or_default(), | 264 | build_data, |
287 | out_dir: out_dir_by_id.get(&id).cloned(), | ||
288 | proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(), | ||
289 | }); | 265 | }); |
290 | let pkg_data = &mut packages[pkg]; | 266 | let pkg_data = &mut packages[pkg]; |
291 | pkg_by_id.insert(id, pkg); | 267 | pkg_by_id.insert(id, pkg); |
@@ -328,7 +304,7 @@ impl CargoWorkspace { | |||
328 | let dep = PackageDependency { name: dep_node.name, pkg }; | 304 | let dep = PackageDependency { name: dep_node.name, pkg }; |
329 | packages[source].dependencies.push(dep); | 305 | packages[source].dependencies.push(dep); |
330 | } | 306 | } |
331 | packages[source].features.extend(node.features); | 307 | packages[source].active_features.extend(node.features); |
332 | } | 308 | } |
333 | 309 | ||
334 | let workspace_root = AbsPathBuf::assert(meta.workspace_root); | 310 | let workspace_root = AbsPathBuf::assert(meta.workspace_root); |
@@ -362,149 +338,3 @@ impl CargoWorkspace { | |||
362 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 | 338 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 |
363 | } | 339 | } |
364 | } | 340 | } |
365 | |||
366 | #[derive(Debug, Clone, Default)] | ||
367 | pub(crate) struct ExternResources { | ||
368 | out_dirs: FxHashMap<PackageId, AbsPathBuf>, | ||
369 | proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>, | ||
370 | cfgs: FxHashMap<PackageId, Vec<CfgFlag>>, | ||
371 | env: FxHashMap<PackageId, Vec<(String, String)>>, | ||
372 | } | ||
373 | |||
374 | pub(crate) fn load_extern_resources( | ||
375 | cargo_toml: &Path, | ||
376 | cargo_features: &CargoConfig, | ||
377 | progress: &dyn Fn(String), | ||
378 | ) -> Result<ExternResources> { | ||
379 | let mut cmd = Command::new(toolchain::cargo()); | ||
380 | cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | ||
381 | |||
382 | // --all-targets includes tests, benches and examples in addition to the | ||
383 | // default lib and bins. This is an independent concept from the --targets | ||
384 | // flag below. | ||
385 | cmd.arg("--all-targets"); | ||
386 | |||
387 | if let Some(target) = &cargo_features.target { | ||
388 | cmd.args(&["--target", target]); | ||
389 | } | ||
390 | |||
391 | if cargo_features.all_features { | ||
392 | cmd.arg("--all-features"); | ||
393 | } else { | ||
394 | if cargo_features.no_default_features { | ||
395 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
396 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
397 | cmd.arg("--no-default-features"); | ||
398 | } | ||
399 | if !cargo_features.features.is_empty() { | ||
400 | cmd.arg("--features"); | ||
401 | cmd.arg(cargo_features.features.join(" ")); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); | ||
406 | |||
407 | let mut child = cmd.spawn().map(JodChild)?; | ||
408 | let child_stdout = child.stdout.take().unwrap(); | ||
409 | let stdout = BufReader::new(child_stdout); | ||
410 | |||
411 | let mut res = ExternResources::default(); | ||
412 | for message in cargo_metadata::Message::parse_stream(stdout) { | ||
413 | if let Ok(message) = message { | ||
414 | match message { | ||
415 | Message::BuildScriptExecuted(BuildScript { | ||
416 | package_id, | ||
417 | out_dir, | ||
418 | cfgs, | ||
419 | env, | ||
420 | .. | ||
421 | }) => { | ||
422 | let cfgs = { | ||
423 | let mut acc = Vec::new(); | ||
424 | for cfg in cfgs { | ||
425 | match cfg.parse::<CfgFlag>() { | ||
426 | Ok(it) => acc.push(it), | ||
427 | Err(err) => { | ||
428 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
429 | } | ||
430 | }; | ||
431 | } | ||
432 | acc | ||
433 | }; | ||
434 | // cargo_metadata crate returns default (empty) path for | ||
435 | // older cargos, which is not absolute, so work around that. | ||
436 | if out_dir != PathBuf::default() { | ||
437 | let out_dir = AbsPathBuf::assert(out_dir); | ||
438 | res.out_dirs.insert(package_id.clone(), out_dir); | ||
439 | res.cfgs.insert(package_id.clone(), cfgs); | ||
440 | } | ||
441 | |||
442 | res.env.insert(package_id, env); | ||
443 | } | ||
444 | Message::CompilerArtifact(message) => { | ||
445 | progress(format!("metadata {}", message.target.name)); | ||
446 | |||
447 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
448 | let package_id = message.package_id; | ||
449 | // Skip rmeta file | ||
450 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) | ||
451 | { | ||
452 | let filename = AbsPathBuf::assert(filename.clone()); | ||
453 | res.proc_dylib_paths.insert(package_id, filename); | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | Message::CompilerMessage(message) => { | ||
458 | progress(message.target.name.clone()); | ||
459 | } | ||
460 | Message::Unknown => (), | ||
461 | Message::BuildFinished(_) => {} | ||
462 | Message::TextLine(_) => {} | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | Ok(res) | ||
467 | } | ||
468 | |||
469 | // FIXME: File a better way to know if it is a dylib | ||
470 | fn is_dylib(path: &Path) -> bool { | ||
471 | match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) { | ||
472 | None => false, | ||
473 | Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /// Recreates the compile-time environment variables that Cargo sets. | ||
478 | /// | ||
479 | /// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> | ||
480 | fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) { | ||
481 | // FIXME: Missing variables: | ||
482 | // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name> | ||
483 | |||
484 | let mut manifest_dir = package.manifest_path.clone(); | ||
485 | manifest_dir.pop(); | ||
486 | if let Some(cargo_manifest_dir) = manifest_dir.to_str() { | ||
487 | env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into())); | ||
488 | } | ||
489 | |||
490 | env.push(("CARGO_PKG_VERSION".into(), package.version.to_string())); | ||
491 | env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string())); | ||
492 | env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string())); | ||
493 | env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string())); | ||
494 | |||
495 | let pre = package.version.pre.iter().map(|id| id.to_string()).format("."); | ||
496 | env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string())); | ||
497 | |||
498 | let authors = package.authors.join(";"); | ||
499 | env.push(("CARGO_PKG_AUTHORS".into(), authors)); | ||
500 | |||
501 | env.push(("CARGO_PKG_NAME".into(), package.name.clone())); | ||
502 | env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default())); | ||
503 | //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default())); | ||
504 | env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default())); | ||
505 | env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default())); | ||
506 | |||
507 | let license_file = | ||
508 | package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default(); | ||
509 | env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file)); | ||
510 | } | ||
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index aabb7a47d..525c336e6 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -5,6 +5,8 @@ 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; | ||
9 | mod build_data; | ||
8 | 10 | ||
9 | use std::{ | 11 | use std::{ |
10 | fs::{read_dir, ReadDir}, | 12 | 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/workspace.rs b/crates/project_model/src/workspace.rs index 06a0be284..bc5041e5a 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 | } |
@@ -79,7 +91,7 @@ impl ProjectWorkspace { | |||
79 | })?; | 91 | })?; |
80 | let project_location = project_json.parent().unwrap().to_path_buf(); | 92 | let project_location = project_json.parent().unwrap().to_path_buf(); |
81 | let project_json = ProjectJson::new(&project_location, data); | 93 | let project_json = ProjectJson::new(&project_location, data); |
82 | ProjectWorkspace::load_inline(project_json)? | 94 | ProjectWorkspace::load_inline(project_json, config.target.as_deref())? |
83 | } | 95 | } |
84 | ProjectManifest::CargoToml(cargo_toml) => { | 96 | ProjectManifest::CargoToml(cargo_toml) => { |
85 | let cargo_version = utf8_stdout({ | 97 | let cargo_version = utf8_stdout({ |
@@ -117,21 +129,24 @@ impl ProjectWorkspace { | |||
117 | } else { | 129 | } else { |
118 | None | 130 | None |
119 | }; | 131 | }; |
120 | 132 | let rustc_cfg = rustc_cfg::get(config.target.as_deref()); | |
121 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } | 133 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } |
122 | } | 134 | } |
123 | }; | 135 | }; |
124 | 136 | ||
125 | Ok(res) | 137 | Ok(res) |
126 | } | 138 | } |
127 | 139 | ||
128 | 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> { | ||
129 | let sysroot = match &project_json.sysroot_src { | 144 | let sysroot = match &project_json.sysroot_src { |
130 | Some(path) => Some(Sysroot::load(path)?), | 145 | Some(path) => Some(Sysroot::load(path)?), |
131 | None => None, | 146 | None => None, |
132 | }; | 147 | }; |
133 | 148 | let rustc_cfg = rustc_cfg::get(target); | |
134 | Ok(ProjectWorkspace::Json { project: project_json, sysroot }) | 149 | Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }) |
135 | } | 150 | } |
136 | 151 | ||
137 | /// Returns the roots for the current `ProjectWorkspace` | 152 | /// Returns the roots for the current `ProjectWorkspace` |
@@ -139,7 +154,7 @@ impl ProjectWorkspace { | |||
139 | /// the root is a member of the current workspace | 154 | /// the root is a member of the current workspace |
140 | pub fn to_roots(&self) -> Vec<PackageRoot> { | 155 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
141 | match self { | 156 | match self { |
142 | ProjectWorkspace::Json { project, sysroot } => project | 157 | ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project |
143 | .crates() | 158 | .crates() |
144 | .map(|(_, krate)| PackageRoot { | 159 | .map(|(_, krate)| PackageRoot { |
145 | is_member: krate.is_workspace_member, | 160 | is_member: krate.is_workspace_member, |
@@ -156,14 +171,14 @@ impl ProjectWorkspace { | |||
156 | }) | 171 | }) |
157 | })) | 172 | })) |
158 | .collect::<Vec<_>>(), | 173 | .collect::<Vec<_>>(), |
159 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => cargo | 174 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo |
160 | .packages() | 175 | .packages() |
161 | .map(|pkg| { | 176 | .map(|pkg| { |
162 | let is_member = cargo[pkg].is_member; | 177 | let is_member = cargo[pkg].is_member; |
163 | let pkg_root = cargo[pkg].root().to_path_buf(); | 178 | let pkg_root = cargo[pkg].root().to_path_buf(); |
164 | 179 | ||
165 | let mut include = vec![pkg_root.clone()]; | 180 | let mut include = vec![pkg_root.clone()]; |
166 | include.extend(cargo[pkg].out_dir.clone()); | 181 | include.extend(cargo[pkg].build_data.out_dir.clone()); |
167 | 182 | ||
168 | let mut exclude = vec![pkg_root.join(".git")]; | 183 | let mut exclude = vec![pkg_root.join(".git")]; |
169 | if is_member { | 184 | if is_member { |
@@ -194,7 +209,7 @@ impl ProjectWorkspace { | |||
194 | pub fn n_packages(&self) -> usize { | 209 | pub fn n_packages(&self) -> usize { |
195 | match self { | 210 | match self { |
196 | ProjectWorkspace::Json { project, .. } => project.n_crates(), | 211 | ProjectWorkspace::Json { project, .. } => project.n_crates(), |
197 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 212 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => { |
198 | 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()); |
199 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len | 214 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len |
200 | } | 215 | } |
@@ -203,22 +218,31 @@ impl ProjectWorkspace { | |||
203 | 218 | ||
204 | pub fn to_crate_graph( | 219 | pub fn to_crate_graph( |
205 | &self, | 220 | &self, |
206 | target: Option<&str>, | ||
207 | proc_macro_client: Option<&ProcMacroClient>, | 221 | proc_macro_client: Option<&ProcMacroClient>, |
208 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 222 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
209 | ) -> CrateGraph { | 223 | ) -> CrateGraph { |
224 | let _p = profile::span("ProjectWorkspace::to_crate_graph"); | ||
210 | let proc_macro_loader = |path: &Path| match proc_macro_client { | 225 | let proc_macro_loader = |path: &Path| match proc_macro_client { |
211 | Some(client) => client.by_dylib_path(path), | 226 | Some(client) => client.by_dylib_path(path), |
212 | None => Vec::new(), | 227 | None => Vec::new(), |
213 | }; | 228 | }; |
214 | 229 | ||
215 | let mut crate_graph = match self { | 230 | let mut crate_graph = match self { |
216 | ProjectWorkspace::Json { project, sysroot } => { | 231 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( |
217 | project_json_to_crate_graph(target, &proc_macro_loader, load, project, sysroot) | 232 | rustc_cfg.clone(), |
218 | } | 233 | &proc_macro_loader, |
219 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { | 234 | load, |
220 | cargo_to_crate_graph(target, &proc_macro_loader, load, cargo, sysroot, rustc) | 235 | project, |
221 | } | 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 | ), | ||
222 | }; | 246 | }; |
223 | if crate_graph.patch_cfg_if() { | 247 | if crate_graph.patch_cfg_if() { |
224 | log::debug!("Patched std to depend on cfg-if") | 248 | log::debug!("Patched std to depend on cfg-if") |
@@ -230,7 +254,7 @@ impl ProjectWorkspace { | |||
230 | } | 254 | } |
231 | 255 | ||
232 | fn project_json_to_crate_graph( | 256 | fn project_json_to_crate_graph( |
233 | target: Option<&str>, | 257 | rustc_cfg: Vec<CfgFlag>, |
234 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 258 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
235 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 259 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
236 | project: &ProjectJson, | 260 | project: &ProjectJson, |
@@ -239,9 +263,9 @@ fn project_json_to_crate_graph( | |||
239 | let mut crate_graph = CrateGraph::default(); | 263 | let mut crate_graph = CrateGraph::default(); |
240 | let sysroot_deps = sysroot | 264 | let sysroot_deps = sysroot |
241 | .as_ref() | 265 | .as_ref() |
242 | .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)); |
243 | 267 | ||
244 | let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); | 268 | let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default(); |
245 | let crates: FxHashMap<CrateId, CrateId> = project | 269 | let crates: FxHashMap<CrateId, CrateId> = project |
246 | .crates() | 270 | .crates() |
247 | .filter_map(|(crate_id, krate)| { | 271 | .filter_map(|(crate_id, krate)| { |
@@ -253,9 +277,12 @@ fn project_json_to_crate_graph( | |||
253 | let env = krate.env.clone().into_iter().collect(); | 277 | let env = krate.env.clone().into_iter().collect(); |
254 | 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)); |
255 | 279 | ||
256 | let target = krate.target.as_deref().or(target); | 280 | let target_cfgs = match krate.target.as_deref() { |
257 | let target_cfgs = | 281 | Some(target) => { |
258 | 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 | }; | ||
259 | 286 | ||
260 | let mut cfg_options = CfgOptions::default(); | 287 | let mut cfg_options = CfgOptions::default(); |
261 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); | 288 | cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); |
@@ -292,19 +319,20 @@ fn project_json_to_crate_graph( | |||
292 | } | 319 | } |
293 | 320 | ||
294 | fn cargo_to_crate_graph( | 321 | fn cargo_to_crate_graph( |
295 | target: Option<&str>, | 322 | rustc_cfg: Vec<CfgFlag>, |
296 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 323 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
297 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 324 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
298 | cargo: &CargoWorkspace, | 325 | cargo: &CargoWorkspace, |
299 | sysroot: &Sysroot, | 326 | sysroot: &Sysroot, |
300 | rustc: &Option<CargoWorkspace>, | 327 | rustc: &Option<CargoWorkspace>, |
301 | ) -> CrateGraph { | 328 | ) -> CrateGraph { |
329 | let _p = profile::span("cargo_to_crate_graph"); | ||
302 | let mut crate_graph = CrateGraph::default(); | 330 | let mut crate_graph = CrateGraph::default(); |
303 | let (public_deps, libproc_macro) = | 331 | let (public_deps, libproc_macro) = |
304 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | 332 | sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); |
305 | 333 | ||
306 | let mut cfg_options = CfgOptions::default(); | 334 | let mut cfg_options = CfgOptions::default(); |
307 | cfg_options.extend(get_rustc_cfg_options(target)); | 335 | cfg_options.extend(rustc_cfg); |
308 | 336 | ||
309 | let mut pkg_to_lib_crate = FxHashMap::default(); | 337 | let mut pkg_to_lib_crate = FxHashMap::default(); |
310 | 338 | ||
@@ -453,26 +481,24 @@ fn add_target_crate_root( | |||
453 | let edition = pkg.edition; | 481 | let edition = pkg.edition; |
454 | let cfg_options = { | 482 | let cfg_options = { |
455 | let mut opts = cfg_options.clone(); | 483 | let mut opts = cfg_options.clone(); |
456 | for feature in pkg.features.iter() { | 484 | for feature in pkg.active_features.iter() { |
457 | opts.insert_key_value("feature".into(), feature.into()); | 485 | opts.insert_key_value("feature".into(), feature.into()); |
458 | } | 486 | } |
459 | opts.extend(pkg.cfgs.iter().cloned()); | 487 | opts.extend(pkg.build_data.cfgs.iter().cloned()); |
460 | opts | 488 | opts |
461 | }; | 489 | }; |
462 | 490 | ||
463 | let mut env = Env::default(); | 491 | let mut env = Env::default(); |
464 | for (k, v) in &pkg.envs { | 492 | for (k, v) in &pkg.build_data.envs { |
465 | env.set(k, v.clone()); | 493 | env.set(k, v.clone()); |
466 | } | 494 | } |
467 | if let Some(out_dir) = &pkg.out_dir { | ||
468 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
469 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
470 | env.set("OUT_DIR", out_dir); | ||
471 | } | ||
472 | } | ||
473 | 495 | ||
474 | let proc_macro = | 496 | let proc_macro = pkg |
475 | pkg.proc_macro_dylib_path.as_ref().map(|it| proc_macro_loader(&it)).unwrap_or_default(); | 497 | .build_data |
498 | .proc_macro_dylib_path | ||
499 | .as_ref() | ||
500 | .map(|it| proc_macro_loader(&it)) | ||
501 | .unwrap_or_default(); | ||
476 | 502 | ||
477 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); | 503 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); |
478 | let crate_id = crate_graph.add_crate_root( | 504 | let crate_id = crate_graph.add_crate_root( |
@@ -490,11 +516,12 @@ fn add_target_crate_root( | |||
490 | fn sysroot_to_crate_graph( | 516 | fn sysroot_to_crate_graph( |
491 | crate_graph: &mut CrateGraph, | 517 | crate_graph: &mut CrateGraph, |
492 | sysroot: &Sysroot, | 518 | sysroot: &Sysroot, |
493 | target: Option<&str>, | 519 | rustc_cfg: Vec<CfgFlag>, |
494 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 520 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
495 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { | 521 | ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) { |
522 | let _p = profile::span("sysroot_to_crate_graph"); | ||
496 | let mut cfg_options = CfgOptions::default(); | 523 | let mut cfg_options = CfgOptions::default(); |
497 | cfg_options.extend(get_rustc_cfg_options(target)); | 524 | cfg_options.extend(rustc_cfg); |
498 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot | 525 | let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot |
499 | .crates() | 526 | .crates() |
500 | .filter_map(|krate| { | 527 | .filter_map(|krate| { |
@@ -533,34 +560,6 @@ fn sysroot_to_crate_graph( | |||
533 | (public_deps, libproc_macro) | 560 | (public_deps, libproc_macro) |
534 | } | 561 | } |
535 | 562 | ||
536 | fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> { | ||
537 | let mut res = Vec::new(); | ||
538 | |||
539 | // Some nightly-only cfgs, which are required for stdlib | ||
540 | res.push(CfgFlag::Atom("target_thread_local".into())); | ||
541 | for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() { | ||
542 | for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() { | ||
543 | res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() }); | ||
544 | } | ||
545 | } | ||
546 | |||
547 | let rustc_cfgs = { | ||
548 | let mut cmd = Command::new(toolchain::rustc()); | ||
549 | cmd.args(&["--print", "cfg", "-O"]); | ||
550 | if let Some(target) = target { | ||
551 | cmd.args(&["--target", target]); | ||
552 | } | ||
553 | utf8_stdout(cmd) | ||
554 | }; | ||
555 | |||
556 | match rustc_cfgs { | ||
557 | Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())), | ||
558 | Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), | ||
559 | } | ||
560 | |||
561 | res | ||
562 | } | ||
563 | |||
564 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { | 563 | fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { |
565 | if let Err(err) = graph.add_dep(from, name, to) { | 564 | if let Err(err) = graph.add_dep(from, name, to) { |
566 | log::error!("{}", err) | 565 | log::error!("{}", err) |