]>
Commit | Line | Data |
---|---|---|
c30ab7b3 SL |
1 | //! Implementation of the install aspects of the compiler. |
2 | //! | |
3 | //! This module is responsible for installing the standard library, | |
4 | //! compiler, and documentation. | |
5 | ||
32a655c1 | 6 | use std::env; |
c30ab7b3 | 7 | use std::fs; |
fc512014 | 8 | use std::path::{Component, PathBuf}; |
c30ab7b3 SL |
9 | use std::process::Command; |
10 | ||
48663c56 XL |
11 | use build_helper::t; |
12 | ||
fc512014 XL |
13 | use crate::dist::{self, sanitize_sh}; |
14 | use crate::tarball::GeneratedTarball; | |
dc9dc135 | 15 | use crate::Compiler; |
7cac9316 | 16 | |
0731742a | 17 | use crate::builder::{Builder, RunConfig, ShouldRun, Step}; |
3dfed10e | 18 | use crate::config::{Config, TargetSelection}; |
7cac9316 | 19 | |
cdc7bbd5 XL |
20 | #[cfg(target_os = "illumos")] |
21 | const SHELL: &str = "bash"; | |
22 | #[cfg(not(target_os = "illumos"))] | |
23 | const SHELL: &str = "sh"; | |
24 | ||
3b2f2976 | 25 | fn install_sh( |
9fa01778 | 26 | builder: &Builder<'_>, |
3b2f2976 | 27 | package: &str, |
3b2f2976 | 28 | stage: u32, |
3dfed10e | 29 | host: Option<TargetSelection>, |
fc512014 | 30 | tarball: &GeneratedTarball, |
3b2f2976 | 31 | ) { |
83c7162d | 32 | builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); |
3b2f2976 | 33 | |
fc512014 XL |
34 | let prefix = default_path(&builder.config.prefix, "/usr/local"); |
35 | let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); | |
36 | let datadir = prefix.join(default_path(&builder.config.datadir, "share")); | |
37 | let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust")); | |
38 | let mandir = prefix.join(default_path(&builder.config.mandir, "share/man")); | |
39 | let libdir = prefix.join(default_path(&builder.config.libdir, "lib")); | |
40 | let bindir = prefix.join(&builder.config.bindir); // Default in config.rs | |
3b2f2976 | 41 | |
83c7162d | 42 | let empty_dir = builder.out.join("tmp/empty_dir"); |
3b2f2976 | 43 | t!(fs::create_dir_all(&empty_dir)); |
7cac9316 | 44 | |
cdc7bbd5 | 45 | let mut cmd = Command::new(SHELL); |
3b2f2976 | 46 | cmd.current_dir(&empty_dir) |
fc512014 XL |
47 | .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) |
48 | .arg(format!("--prefix={}", prepare_dir(prefix))) | |
49 | .arg(format!("--sysconfdir={}", prepare_dir(sysconfdir))) | |
50 | .arg(format!("--datadir={}", prepare_dir(datadir))) | |
51 | .arg(format!("--docdir={}", prepare_dir(docdir))) | |
52 | .arg(format!("--bindir={}", prepare_dir(bindir))) | |
53 | .arg(format!("--libdir={}", prepare_dir(libdir))) | |
54 | .arg(format!("--mandir={}", prepare_dir(mandir))) | |
3b2f2976 | 55 | .arg("--disable-ldconfig"); |
83c7162d | 56 | builder.run(&mut cmd); |
3b2f2976 | 57 | t!(fs::remove_dir_all(&empty_dir)); |
c30ab7b3 | 58 | } |
32a655c1 | 59 | |
fc512014 | 60 | fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf { |
6a06907d | 61 | config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)) |
fc512014 XL |
62 | } |
63 | ||
64 | fn prepare_dir(mut path: PathBuf) -> String { | |
65 | // The DESTDIR environment variable is a standard way to install software in a subdirectory | |
66 | // while keeping the original directory structure, even if the prefix or other directories | |
67 | // contain absolute paths. | |
68 | // | |
69 | // More information on the environment variable is available here: | |
70 | // https://www.gnu.org/prep/standards/html_node/DESTDIR.html | |
71 | if let Some(destdir) = env::var_os("DESTDIR").map(PathBuf::from) { | |
72 | let without_destdir = path.clone(); | |
73 | path = destdir; | |
74 | // Custom .join() which ignores disk roots. | |
75 | for part in without_destdir.components() { | |
76 | if let Component::Normal(s) = part { | |
77 | path.push(s) | |
78 | } | |
32a655c1 SL |
79 | } |
80 | } | |
fc512014 XL |
81 | |
82 | // The installation command is not executed from the current directory, but from a temporary | |
83 | // directory. To prevent relative paths from breaking this converts relative paths to absolute | |
84 | // paths. std::fs::canonicalize is not used as that requires the path to actually be present. | |
85 | if path.is_relative() { | |
86 | path = std::env::current_dir().expect("failed to get the current directory").join(path); | |
87 | assert!(path.is_absolute(), "could not make the path relative"); | |
88 | } | |
89 | ||
90 | sanitize_sh(&path) | |
32a655c1 | 91 | } |
3b2f2976 XL |
92 | |
93 | macro_rules! install { | |
94 | (($sel:ident, $builder:ident, $_config:ident), | |
95 | $($name:ident, | |
96 | $path:expr, | |
97 | $default_cond:expr, | |
98 | only_hosts: $only_hosts:expr, | |
99 | $run_item:block $(, $c:ident)*;)+) => { | |
100 | $( | |
101 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
102 | pub struct $name { | |
dc9dc135 | 103 | pub compiler: Compiler, |
3dfed10e | 104 | pub target: TargetSelection, |
3b2f2976 XL |
105 | } |
106 | ||
2c00a5a8 XL |
107 | impl $name { |
108 | #[allow(dead_code)] | |
109 | fn should_build(config: &Config) -> bool { | |
110 | config.extended && config.tools.as_ref() | |
111 | .map_or(true, |t| t.contains($path)) | |
112 | } | |
2c00a5a8 XL |
113 | } |
114 | ||
3b2f2976 XL |
115 | impl Step for $name { |
116 | type Output = (); | |
117 | const DEFAULT: bool = true; | |
3b2f2976 XL |
118 | const ONLY_HOSTS: bool = $only_hosts; |
119 | $(const $c: bool = true;)* | |
120 | ||
9fa01778 | 121 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
122 | let $_config = &run.builder.config; |
123 | run.path($path).default_condition($default_cond) | |
124 | } | |
125 | ||
9fa01778 | 126 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 127 | run.builder.ensure($name { |
dc9dc135 | 128 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 | 129 | target: run.target, |
3b2f2976 XL |
130 | }); |
131 | } | |
132 | ||
9fa01778 | 133 | fn run($sel, $builder: &Builder<'_>) { |
3b2f2976 XL |
134 | $run_item |
135 | } | |
136 | })+ | |
137 | } | |
138 | } | |
139 | ||
140 | install!((self, builder, _config), | |
141 | Docs, "src/doc", _config.docs, only_hosts: false, { | |
94222f64 XL |
142 | let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs"); |
143 | install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball); | |
3b2f2976 | 144 | }; |
1b1a35ee | 145 | Std, "library/std", true, only_hosts: false, { |
83c7162d | 146 | for target in &builder.targets { |
17df50a5 XL |
147 | // `expect` should be safe, only None when host != build, but this |
148 | // only runs when host == build | |
fc512014 | 149 | let tarball = builder.ensure(dist::Std { |
dc9dc135 | 150 | compiler: self.compiler, |
abe05a73 | 151 | target: *target |
fc512014 XL |
152 | }).expect("missing std"); |
153 | install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball); | |
abe05a73 | 154 | } |
3b2f2976 | 155 | }; |
2c00a5a8 | 156 | Cargo, "cargo", Self::should_build(_config), only_hosts: true, { |
94222f64 XL |
157 | let tarball = builder |
158 | .ensure(dist::Cargo { compiler: self.compiler, target: self.target }) | |
159 | .expect("missing cargo"); | |
fc512014 | 160 | install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball); |
3b2f2976 | 161 | }; |
2c00a5a8 | 162 | Rls, "rls", Self::should_build(_config), only_hosts: true, { |
fc512014 XL |
163 | if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) { |
164 | install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball); | |
abe05a73 | 165 | } else { |
dc9dc135 XL |
166 | builder.info( |
167 | &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target), | |
168 | ); | |
abe05a73 XL |
169 | } |
170 | }; | |
f035d41b | 171 | RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, { |
17df50a5 XL |
172 | if let Some(tarball) = |
173 | builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target }) | |
174 | { | |
175 | install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball); | |
176 | } else { | |
177 | builder.info( | |
178 | &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target), | |
179 | ); | |
180 | } | |
f035d41b | 181 | }; |
8faf50e0 | 182 | Clippy, "clippy", Self::should_build(_config), only_hosts: true, { |
94222f64 XL |
183 | let tarball = builder |
184 | .ensure(dist::Clippy { compiler: self.compiler, target: self.target }) | |
185 | .expect("missing clippy"); | |
fc512014 | 186 | install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball); |
8faf50e0 | 187 | }; |
0731742a | 188 | Miri, "miri", Self::should_build(_config), only_hosts: true, { |
fc512014 XL |
189 | if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) { |
190 | install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); | |
0731742a | 191 | } else { |
dc9dc135 XL |
192 | builder.info( |
193 | &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target), | |
194 | ); | |
0731742a XL |
195 | } |
196 | }; | |
2c00a5a8 | 197 | Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { |
fc512014 | 198 | if let Some(tarball) = builder.ensure(dist::Rustfmt { |
dc9dc135 XL |
199 | compiler: self.compiler, |
200 | target: self.target | |
fc512014 XL |
201 | }) { |
202 | install_sh(builder, "rustfmt", self.compiler.stage, Some(self.target), &tarball); | |
abe05a73 | 203 | } else { |
83c7162d | 204 | builder.info( |
dc9dc135 XL |
205 | &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target), |
206 | ); | |
abe05a73 | 207 | } |
3b2f2976 | 208 | }; |
cdc7bbd5 XL |
209 | RustDemangler, "rust-demangler", Self::should_build(_config), only_hosts: true, { |
210 | // Note: Even though `should_build` may return true for `extended` default tools, | |
211 | // dist::RustDemangler may still return None, unless the target-dependent `profiler` config | |
212 | // is also true, or the `tools` array explicitly includes "rust-demangler". | |
213 | if let Some(tarball) = builder.ensure(dist::RustDemangler { | |
214 | compiler: self.compiler, | |
215 | target: self.target | |
216 | }) { | |
217 | install_sh(builder, "rust-demangler", self.compiler.stage, Some(self.target), &tarball); | |
218 | } else { | |
219 | builder.info( | |
220 | &format!("skipping Install RustDemangler stage{} ({})", | |
221 | self.compiler.stage, self.target), | |
222 | ); | |
223 | } | |
224 | }; | |
2c00a5a8 | 225 | Analysis, "analysis", Self::should_build(_config), only_hosts: false, { |
17df50a5 XL |
226 | // `expect` should be safe, only None with host != build, but this |
227 | // only uses the `build` compiler | |
fc512014 | 228 | let tarball = builder.ensure(dist::Analysis { |
dc9dc135 XL |
229 | // Find the actual compiler (handling the full bootstrap option) which |
230 | // produced the save-analysis data because that data isn't copied | |
231 | // through the sysroot uplifting. | |
232 | compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target), | |
3b2f2976 | 233 | target: self.target |
fc512014 XL |
234 | }).expect("missing analysis"); |
235 | install_sh(builder, "analysis", self.compiler.stage, Some(self.target), &tarball); | |
3b2f2976 | 236 | }; |
3b2f2976 | 237 | Rustc, "src/librustc", true, only_hosts: true, { |
fc512014 | 238 | let tarball = builder.ensure(dist::Rustc { |
60c5eb7d | 239 | compiler: builder.compiler(builder.top_stage, self.target), |
3b2f2976 | 240 | }); |
fc512014 | 241 | install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball); |
3b2f2976 XL |
242 | }; |
243 | ); | |
0531ce1d XL |
244 | |
245 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
246 | pub struct Src { | |
247 | pub stage: u32, | |
248 | } | |
249 | ||
250 | impl Step for Src { | |
251 | type Output = (); | |
252 | const DEFAULT: bool = true; | |
253 | const ONLY_HOSTS: bool = true; | |
254 | ||
9fa01778 | 255 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
0531ce1d | 256 | let config = &run.builder.config; |
dc9dc135 | 257 | let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src")); |
0531ce1d XL |
258 | run.path("src").default_condition(cond) |
259 | } | |
260 | ||
9fa01778 | 261 | fn make_run(run: RunConfig<'_>) { |
dc9dc135 | 262 | run.builder.ensure(Src { stage: run.builder.top_stage }); |
0531ce1d XL |
263 | } |
264 | ||
9fa01778 | 265 | fn run(self, builder: &Builder<'_>) { |
fc512014 XL |
266 | let tarball = builder.ensure(dist::Src); |
267 | install_sh(builder, "src", self.stage, None, &tarball); | |
0531ce1d XL |
268 | } |
269 | } |