aboutsummaryrefslogtreecommitdiff
path: root/crates/project_model/src/sysroot.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/project_model/src/sysroot.rs')
-rw-r--r--crates/project_model/src/sysroot.rs173
1 files changed, 173 insertions, 0 deletions
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
new file mode 100644
index 000000000..8239797b6
--- /dev/null
+++ b/crates/project_model/src/sysroot.rs
@@ -0,0 +1,173 @@
1//! FIXME: write short doc here
2
3use std::{convert::TryFrom, env, ops, path::Path, process::Command};
4
5use anyhow::{bail, format_err, Result};
6use arena::{Arena, Idx};
7use paths::{AbsPath, AbsPathBuf};
8
9use crate::utf8_stdout;
10
11#[derive(Default, Debug, Clone, Eq, PartialEq)]
12pub struct Sysroot {
13 crates: Arena<SysrootCrateData>,
14}
15
16pub type SysrootCrate = Idx<SysrootCrateData>;
17
18#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct SysrootCrateData {
20 pub name: String,
21 pub root: AbsPathBuf,
22 pub deps: Vec<SysrootCrate>,
23}
24
25impl ops::Index<SysrootCrate> for Sysroot {
26 type Output = SysrootCrateData;
27 fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
28 &self.crates[index]
29 }
30}
31
32impl Sysroot {
33 pub fn core(&self) -> Option<SysrootCrate> {
34 self.by_name("core")
35 }
36
37 pub fn alloc(&self) -> Option<SysrootCrate> {
38 self.by_name("alloc")
39 }
40
41 pub fn std(&self) -> Option<SysrootCrate> {
42 self.by_name("std")
43 }
44
45 pub fn proc_macro(&self) -> Option<SysrootCrate> {
46 self.by_name("proc_macro")
47 }
48
49 pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
50 self.crates.iter().map(|(id, _data)| id)
51 }
52
53 pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
54 let src = get_or_install_rust_src(cargo_toml)?;
55 let mut sysroot = Sysroot { crates: Arena::default() };
56 for name in SYSROOT_CRATES.trim().lines() {
57 // FIXME: remove this path when 1.47 comes out
58 // https://github.com/rust-lang/rust/pull/73265
59 let root = src.join(format!("lib{}", name)).join("lib.rs");
60 if root.exists() {
61 sysroot.crates.alloc(SysrootCrateData {
62 name: name.into(),
63 root,
64 deps: Vec::new(),
65 });
66 } else {
67 let root = src.join(name).join("src/lib.rs");
68 if root.exists() {
69 sysroot.crates.alloc(SysrootCrateData {
70 name: name.into(),
71 root,
72 deps: Vec::new(),
73 });
74 }
75 }
76 }
77 if let Some(std) = sysroot.std() {
78 for dep in STD_DEPS.trim().lines() {
79 if let Some(dep) = sysroot.by_name(dep) {
80 sysroot.crates[std].deps.push(dep)
81 }
82 }
83 }
84 if let Some(alloc) = sysroot.alloc() {
85 if let Some(core) = sysroot.core() {
86 sysroot.crates[alloc].deps.push(core);
87 }
88 }
89 Ok(sysroot)
90 }
91
92 fn by_name(&self, name: &str) -> Option<SysrootCrate> {
93 self.crates.iter().find(|(_id, data)| data.name == name).map(|(id, _data)| id)
94 }
95}
96
97fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result<AbsPathBuf> {
98 if let Ok(path) = env::var("RUST_SRC_PATH") {
99 let path = AbsPathBuf::try_from(path.as_str())
100 .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
101 return Ok(path);
102 }
103 let current_dir = cargo_toml.parent().unwrap();
104 let mut rustc = Command::new(toolchain::rustc());
105 rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
106 let stdout = utf8_stdout(rustc)?;
107 let sysroot_path = AbsPath::assert(Path::new(stdout.trim()));
108 let mut src = get_rust_src(sysroot_path);
109 if src.is_none() {
110 let mut rustup = Command::new(toolchain::rustup());
111 rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
112 utf8_stdout(rustup)?;
113 src = get_rust_src(sysroot_path);
114 }
115 match src {
116 Some(r) => Ok(r),
117 None => bail!(
118 "can't load standard library from sysroot\n\
119 {}\n\
120 (discovered via `rustc --print sysroot`)\n\
121 try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
122 sysroot_path.display(),
123 ),
124 }
125}
126
127fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
128 // try the new path first since the old one still exists
129 let mut src_path = sysroot_path.join("lib/rustlib/src/rust/library");
130 if !src_path.exists() {
131 // FIXME: remove this path when 1.47 comes out
132 // https://github.com/rust-lang/rust/pull/73265
133 src_path = sysroot_path.join("lib/rustlib/src/rust/src");
134 }
135 if src_path.exists() {
136 Some(src_path)
137 } else {
138 None
139 }
140}
141
142impl SysrootCrateData {
143 pub fn root_dir(&self) -> &AbsPath {
144 self.root.parent().unwrap()
145 }
146}
147
148const SYSROOT_CRATES: &str = "
149alloc
150core
151panic_abort
152panic_unwind
153proc_macro
154profiler_builtins
155rtstartup
156std
157stdarch
158term
159test
160unwind";
161
162const STD_DEPS: &str = "
163alloc
164core
165panic_abort
166panic_unwind
167profiler_builtins
168rtstartup
169proc_macro
170stdarch
171term
172test
173unwind";