1 //! Handles lowering of build-system specific workspace information (`cargo
2 //! metadata` or `rust-project.json`) into representation stored in the salsa
3 //! database -- `CrateGraph`.
5 use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
7 use anyhow::{format_err, Context, Result};
8 use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9 use cargo_workspace::DepKind;
10 use cfg::{CfgDiff, CfgOptions};
11 use paths::{AbsPath, AbsPathBuf};
12 use proc_macro_api::ProcMacroClient;
13 use rustc_hash::{FxHashMap, FxHashSet};
16 build_data::{BuildDataResult, PackageBuildData, WorkspaceBuildData},
20 sysroot::SysrootCrate,
21 utf8_stdout, BuildDataCollector, CargoConfig, CargoWorkspace, ProjectJson, ProjectManifest,
25 pub type CfgOverrides = FxHashMap<String, CfgDiff>;
27 /// `PackageRoot` describes a package root folder.
28 /// Which may be an external dependency, or a member of
29 /// the current workspace.
30 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
31 pub struct PackageRoot {
32 /// Is a member of the current workspace
34 pub include: Vec<AbsPathBuf>,
35 pub exclude: Vec<AbsPathBuf>,
38 #[derive(Clone, Eq, PartialEq)]
39 pub enum ProjectWorkspace {
40 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
42 cargo: CargoWorkspace,
44 rustc: Option<CargoWorkspace>,
45 /// Holds cfg flags for the current target. We get those by running
46 /// `rustc --print cfg`.
48 /// FIXME: make this a per-crate map, as, eg, build.rs might have a
50 rustc_cfg: Vec<CfgFlag>,
51 cfg_overrides: CfgOverrides,
53 /// Project workspace was manually specified using a `rust-project.json` file.
54 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
56 // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
57 // That's not the end user experience we should strive for.
58 // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
59 // That needs some changes on the salsa-level though.
60 // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability).
61 // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results.
62 // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files.
64 /// Project with a set of disjoint files, not belonging to any particular workspace.
65 /// Backed by basic sysroot crates for basic completion and highlighting.
66 DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Sysroot, rustc_cfg: Vec<CfgFlag> },
69 impl fmt::Debug for ProjectWorkspace {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 // Make sure this isn't too verbose.
73 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f
74 .debug_struct("Cargo")
75 .field("root", &cargo.workspace_root().file_name())
76 .field("n_packages", &cargo.packages().len())
77 .field("n_sysroot_crates", &sysroot.crates().len())
79 "n_rustc_compiler_crates",
80 &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
82 .field("n_rustc_cfg", &rustc_cfg.len())
83 .field("n_cfg_overrides", &cfg_overrides.len())
85 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
86 let mut debug_struct = f.debug_struct("Json");
87 debug_struct.field("n_crates", &project.n_crates());
88 if let Some(sysroot) = sysroot {
89 debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
91 debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
94 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
95 .debug_struct("DetachedFiles")
96 .field("n_files", &files.len())
97 .field("n_sysroot_crates", &sysroot.crates().len())
98 .field("n_rustc_cfg", &rustc_cfg.len())
104 impl ProjectWorkspace {
106 manifest: ProjectManifest,
107 config: &CargoConfig,
108 progress: &dyn Fn(String),
109 ) -> Result<ProjectWorkspace> {
110 let res = match manifest {
111 ProjectManifest::ProjectJson(project_json) => {
112 let file = fs::read_to_string(&project_json).with_context(|| {
113 format!("Failed to read json file {}", project_json.display())
115 let data = serde_json::from_str(&file).with_context(|| {
116 format!("Failed to deserialize json file {}", project_json.display())
118 let project_location = project_json.parent().unwrap().to_path_buf();
119 let project_json = ProjectJson::new(&project_location, data);
120 ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
122 ProjectManifest::CargoToml(cargo_toml) => {
123 let cargo_version = utf8_stdout({
124 let mut cmd = Command::new(toolchain::cargo());
125 cmd.arg("--version");
129 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress)
132 "Failed to read Cargo metadata from Cargo.toml file {}, {}",
133 cargo_toml.display(),
138 let sysroot = if config.no_sysroot {
141 Sysroot::discover(&cargo_toml).with_context(|| {
143 "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
149 let rustc_dir = if let Some(rustc_source) = &config.rustc_source {
150 use cargo_workspace::RustcSource;
152 RustcSource::Path(path) => Some(path.clone()),
153 RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml),
159 let rustc = if let Some(rustc_dir) = rustc_dir {
161 CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
163 format!("Failed to read Cargo metadata for Rust sources")
170 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
172 let cfg_overrides = config.cfg_overrides();
173 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides }
181 project_json: ProjectJson,
182 target: Option<&str>,
183 ) -> Result<ProjectWorkspace> {
184 let sysroot = match &project_json.sysroot_src {
185 Some(path) => Some(Sysroot::load(path)?),
188 let rustc_cfg = rustc_cfg::get(None, target);
189 Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
192 pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> {
193 let sysroot = Sysroot::discover(
194 detached_files.first().ok_or_else(|| format_err!("No detached files to load"))?,
196 let rustc_cfg = rustc_cfg::get(None, None);
197 Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
200 /// Returns the roots for the current `ProjectWorkspace`
201 /// The return type contains the path and whether or not
202 /// the root is a member of the current workspace
203 pub fn to_roots(&self, build_data: Option<&BuildDataResult>) -> Vec<PackageRoot> {
205 ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
207 .map(|(_, krate)| PackageRoot {
208 is_member: krate.is_workspace_member,
209 include: krate.include.clone(),
210 exclude: krate.exclude.clone(),
212 .collect::<FxHashSet<_>>()
214 .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| {
215 sysroot.crates().map(move |krate| PackageRoot {
217 include: vec![sysroot[krate].root_dir().to_path_buf()],
221 .collect::<Vec<_>>(),
222 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => {
226 let is_member = cargo[pkg].is_member;
227 let pkg_root = cargo[pkg].root().to_path_buf();
229 let mut include = vec![pkg_root.clone()];
232 .and_then(|it| it.get(cargo.workspace_root()))
233 .and_then(|map| map.get(&cargo[pkg].id))
234 .and_then(|it| it.out_dir.clone()),
237 let mut exclude = vec![pkg_root.join(".git")];
239 exclude.push(pkg_root.join("target"));
241 exclude.push(pkg_root.join("tests"));
242 exclude.push(pkg_root.join("examples"));
243 exclude.push(pkg_root.join("benches"));
245 PackageRoot { is_member, include, exclude }
247 .chain(sysroot.crates().map(|krate| PackageRoot {
249 include: vec![sysroot[krate].root_dir().to_path_buf()],
252 .chain(rustc.into_iter().flat_map(|rustc| {
253 rustc.packages().map(move |krate| PackageRoot {
255 include: vec![rustc[krate].root().to_path_buf()],
261 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
263 .map(|detached_file| PackageRoot {
265 include: vec![detached_file.clone()],
268 .chain(sysroot.crates().map(|krate| PackageRoot {
270 include: vec![sysroot[krate].root_dir().to_path_buf()],
277 pub fn n_packages(&self) -> usize {
279 ProjectWorkspace::Json { project, .. } => project.n_crates(),
280 ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
281 let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len());
282 cargo.packages().len() + sysroot.crates().len() + rustc_package_len
284 ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
285 sysroot.crates().len() + files.len()
290 pub fn to_crate_graph(
292 build_data: Option<&BuildDataResult>,
293 proc_macro_client: Option<&ProcMacroClient>,
294 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
296 let _p = profile::span("ProjectWorkspace::to_crate_graph");
297 let proc_macro_loader = |path: &Path| match proc_macro_client {
298 Some(client) => client.by_dylib_path(path),
302 let mut crate_graph = match self {
303 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
310 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => {
311 cargo_to_crate_graph(
317 build_data.and_then(|it| it.get(cargo.workspace_root())),
323 .and_then(|(it, map)| map.get(it.workspace_root())),
326 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
327 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
330 if crate_graph.patch_cfg_if() {
331 log::debug!("Patched std to depend on cfg-if")
333 log::debug!("Did not patch std to depend on cfg-if")
338 pub fn collect_build_data_configs(&self, collector: &mut BuildDataCollector) {
340 ProjectWorkspace::Cargo { cargo, .. } => {
341 collector.add_config(cargo.workspace_root(), cargo.build_data_config().clone());
348 fn project_json_to_crate_graph(
349 rustc_cfg: Vec<CfgFlag>,
350 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
351 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
352 project: &ProjectJson,
353 sysroot: &Option<Sysroot>,
355 let mut crate_graph = CrateGraph::default();
356 let sysroot_deps = sysroot
358 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
360 let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
361 let crates: FxHashMap<CrateId, CrateId> = project
363 .filter_map(|(crate_id, krate)| {
364 let file_path = &krate.root_module;
365 let file_id = load(file_path)?;
366 Some((crate_id, krate, file_id))
368 .map(|(crate_id, krate, file_id)| {
369 let env = krate.env.clone().into_iter().collect();
370 let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it));
372 let target_cfgs = match krate.target.as_deref() {
374 cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
379 let mut cfg_options = CfgOptions::default();
380 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
383 crate_graph.add_crate_root(
386 krate.display_name.clone(),
390 proc_macro.unwrap_or_default(),
396 for (from, krate) in project.crates() {
397 if let Some(&from) = crates.get(&from) {
398 if let Some((public_deps, _proc_macro)) = &sysroot_deps {
399 for (name, to) in public_deps.iter() {
400 add_dep(&mut crate_graph, from, name.clone(), *to)
404 for dep in &krate.deps {
405 if let Some(&to) = crates.get(&dep.crate_id) {
406 add_dep(&mut crate_graph, from, dep.name.clone(), to)
414 fn cargo_to_crate_graph(
415 rustc_cfg: Vec<CfgFlag>,
416 override_cfg: &CfgOverrides,
417 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
418 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
419 cargo: &CargoWorkspace,
420 build_data_map: Option<&WorkspaceBuildData>,
422 rustc: &Option<CargoWorkspace>,
423 rustc_build_data_map: Option<&WorkspaceBuildData>,
425 let _p = profile::span("cargo_to_crate_graph");
426 let mut crate_graph = CrateGraph::default();
427 let (public_deps, libproc_macro) =
428 sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
430 let mut cfg_options = CfgOptions::default();
431 cfg_options.extend(rustc_cfg);
433 let mut pkg_to_lib_crate = FxHashMap::default();
435 // Add test cfg for non-sysroot crates
436 cfg_options.insert_atom("test".into());
437 cfg_options.insert_atom("debug_assertions".into());
439 let mut pkg_crates = FxHashMap::default();
440 // Does any crate signal to rust-analyzer that they need the rustc_private crates?
441 let mut has_private = false;
442 // Next, create crates for each package, target pair
443 for pkg in cargo.packages() {
444 let mut cfg_options = &cfg_options;
445 let mut replaced_cfg_options;
446 if let Some(overrides) = override_cfg.get(&cargo[pkg].name) {
447 // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
448 // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
449 // working on rust-lang/rust as that's the only time it appears outside sysroot).
451 // A more ideal solution might be to reanalyze crates based on where the cursor is and
452 // figure out the set of cfgs that would have to apply to make it active.
454 replaced_cfg_options = cfg_options.clone();
455 replaced_cfg_options.apply_diff(overrides.clone());
456 cfg_options = &replaced_cfg_options;
459 has_private |= cargo[pkg].metadata.rustc_private;
460 let mut lib_tgt = None;
461 for &tgt in cargo[pkg].targets.iter() {
462 if let Some(file_id) = load(&cargo[tgt].root) {
463 let crate_id = add_target_crate_root(
466 build_data_map.and_then(|it| it.get(&cargo[pkg].id)),
472 if cargo[tgt].kind == TargetKind::Lib {
473 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
474 pkg_to_lib_crate.insert(pkg, crate_id);
476 if cargo[tgt].is_proc_macro {
477 if let Some(proc_macro) = libproc_macro {
481 CrateName::new("proc_macro").unwrap(),
487 pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
491 // Set deps to the core, std and to the lib target of the current package
492 for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
493 if let Some((to, name)) = lib_tgt.clone() {
494 if to != *from && *kind != TargetKind::BuildScript {
495 // (build script can not depend on its library target)
497 // For root projects with dashes in their name,
498 // cargo metadata does not do any normalization,
499 // so we do it ourselves currently
500 let name = CrateName::normalize_dashes(&name);
501 add_dep(&mut crate_graph, *from, name, to);
504 for (name, krate) in public_deps.iter() {
505 add_dep(&mut crate_graph, *from, name.clone(), *krate);
510 // Now add a dep edge from all targets of upstream to the lib
511 // target of downstream.
512 for pkg in cargo.packages() {
513 for dep in cargo[pkg].dependencies.iter() {
514 let name = CrateName::new(&dep.name).unwrap();
515 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
516 for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
517 if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
518 // Only build scripts may depend on build dependencies.
521 if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
522 // Build scripts may only depend on build dependencies.
526 add_dep(&mut crate_graph, *from, name.clone(), to)
533 // If the user provided a path to rustc sources, we add all the rustc_private crates
534 // and create dependencies on them for the crates which opt-in to that
535 if let Some(rustc_workspace) = rustc {
540 rustc_build_data_map,
543 &mut pkg_to_lib_crate,
553 fn detached_files_to_crate_graph(
554 rustc_cfg: Vec<CfgFlag>,
555 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
556 detached_files: &[AbsPathBuf],
559 let _p = profile::span("detached_files_to_crate_graph");
560 let mut crate_graph = CrateGraph::default();
561 let (public_deps, _libproc_macro) =
562 sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
564 let mut cfg_options = CfgOptions::default();
565 cfg_options.extend(rustc_cfg);
567 for detached_file in detached_files {
568 let file_id = match load(detached_file) {
569 Some(file_id) => file_id,
571 log::error!("Failed to load detached file {:?}", detached_file);
575 let display_name = detached_file
577 .and_then(|os_str| os_str.to_str())
578 .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
579 let detached_file_crate = crate_graph.add_crate_root(
581 Edition::Edition2018,
589 for (name, krate) in public_deps.iter() {
590 add_dep(&mut crate_graph, detached_file_crate, name.clone(), *krate);
596 fn handle_rustc_crates(
597 rustc_workspace: &CargoWorkspace,
598 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
599 crate_graph: &mut CrateGraph,
600 rustc_build_data_map: Option<&WorkspaceBuildData>,
601 cfg_options: &CfgOptions,
602 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
603 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
604 public_deps: &[(CrateName, CrateId)],
605 cargo: &CargoWorkspace,
606 pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
608 let mut rustc_pkg_crates = FxHashMap::default();
609 // The root package of the rustc-dev component is rustc_driver, so we match that
611 rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
612 // The rustc workspace might be incomplete (such as if rustc-dev is not
613 // installed for the current toolchain) and `rustcSource` is set to discover.
614 if let Some(root_pkg) = root_pkg {
615 // Iterate through every crate in the dependency subtree of rustc_driver using BFS
616 let mut queue = VecDeque::new();
617 queue.push_back(root_pkg);
618 while let Some(pkg) = queue.pop_front() {
619 // Don't duplicate packages if they are dependended on a diamond pattern
620 // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates
621 // which is not ideal
622 if rustc_pkg_crates.contains_key(&pkg) {
625 for dep in &rustc_workspace[pkg].dependencies {
626 queue.push_back(dep.pkg);
628 for &tgt in rustc_workspace[pkg].targets.iter() {
629 if rustc_workspace[tgt].kind != TargetKind::Lib {
632 if let Some(file_id) = load(&rustc_workspace[tgt].root) {
633 let crate_id = add_target_crate_root(
635 &rustc_workspace[pkg],
636 rustc_build_data_map.and_then(|it| it.get(&rustc_workspace[pkg].id)),
640 &rustc_workspace[tgt].name,
642 pkg_to_lib_crate.insert(pkg, crate_id);
643 // Add dependencies on core / std / alloc for this crate
644 for (name, krate) in public_deps.iter() {
645 add_dep(crate_graph, crate_id, name.clone(), *krate);
647 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
652 // Now add a dep edge from all targets of upstream to the lib
653 // target of downstream.
654 for pkg in rustc_pkg_crates.keys().copied() {
655 for dep in rustc_workspace[pkg].dependencies.iter() {
656 let name = CrateName::new(&dep.name).unwrap();
657 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
658 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
659 add_dep(crate_graph, from, name.clone(), to);
664 // Add a dependency on the rustc_private crates for all targets of each package
666 for dep in rustc_workspace.packages() {
667 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
669 if let Some(&to) = pkg_to_lib_crate.get(&dep) {
670 for pkg in cargo.packages() {
671 let package = &cargo[pkg];
672 if !package.metadata.rustc_private {
675 for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
676 // Avoid creating duplicate dependencies
677 // This avoids the situation where `from` depends on e.g. `arrayvec`, but
678 // `rust_analyzer` thinks that it should use the one from the `rustcSource`
679 // instead of the one from `crates.io`
680 if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
681 add_dep(crate_graph, *from, name.clone(), to);
689 fn add_target_crate_root(
690 crate_graph: &mut CrateGraph,
691 pkg: &cargo_workspace::PackageData,
692 build_data: Option<&PackageBuildData>,
693 cfg_options: &CfgOptions,
694 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
698 let edition = pkg.edition;
700 let mut opts = cfg_options.clone();
701 for feature in pkg.active_features.iter() {
702 opts.insert_key_value("feature".into(), feature.into());
704 if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
705 opts.extend(cfgs.iter().cloned());
710 let mut env = Env::default();
711 if let Some(envs) = build_data.map(|it| &it.envs) {
713 env.set(k, v.clone());
717 let proc_macro = build_data
719 .and_then(|it| it.proc_macro_dylib_path.as_ref())
720 .map(|it| proc_macro_loader(it))
721 .unwrap_or_default();
723 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
724 let mut potential_cfg_options = cfg_options.clone();
725 potential_cfg_options.extend(
728 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
731 let crate_id = crate_graph.add_crate_root(
736 potential_cfg_options,
744 fn sysroot_to_crate_graph(
745 crate_graph: &mut CrateGraph,
747 rustc_cfg: Vec<CfgFlag>,
748 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
749 ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
750 let _p = profile::span("sysroot_to_crate_graph");
751 let mut cfg_options = CfgOptions::default();
752 cfg_options.extend(rustc_cfg);
753 let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
755 .filter_map(|krate| {
756 let file_id = load(&sysroot[krate].root)?;
758 let env = Env::default();
759 let proc_macro = vec![];
760 let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
761 let crate_id = crate_graph.add_crate_root(
763 Edition::Edition2018,
770 Some((krate, crate_id))
774 for from in sysroot.crates() {
775 for &to in sysroot[from].deps.iter() {
776 let name = CrateName::new(&sysroot[to].name).unwrap();
777 if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
778 add_dep(crate_graph, from, name, to);
783 let public_deps = sysroot
785 .map(|(name, idx)| (CrateName::new(name).unwrap(), sysroot_crates[&idx]))
786 .collect::<Vec<_>>();
788 let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
789 (public_deps, libproc_macro)
792 fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
793 if let Err(err) = graph.add_dep(from, name, to) {
794 log::error!("{}", err)