]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/install.rs
bump version to 1.74.1+dfsg1-1~bpo12+pve1
[rustc.git] / src / bootstrap / install.rs
CommitLineData
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 6use std::env;
c30ab7b3 7use std::fs;
923072b8 8use std::path::{Component, Path, PathBuf};
c30ab7b3
SL
9use std::process::Command;
10
5e7ed085 11use crate::util::t;
48663c56 12
923072b8 13use crate::dist;
fc512014 14use crate::tarball::GeneratedTarball;
49aad941 15use crate::{Compiler, Kind};
7cac9316 16
0731742a 17use crate::builder::{Builder, RunConfig, ShouldRun, Step};
3dfed10e 18use crate::config::{Config, TargetSelection};
7cac9316 19
cdc7bbd5
XL
20#[cfg(target_os = "illumos")]
21const SHELL: &str = "bash";
22#[cfg(not(target_os = "illumos"))]
23const SHELL: &str = "sh";
24
923072b8
FG
25// We have to run a few shell scripts, which choke quite a bit on both `\`
26// characters and on `C:\` paths, so normalize both of them away.
27fn sanitize_sh(path: &Path) -> String {
28 let path = path.to_str().unwrap().replace("\\", "/");
29 return change_drive(unc_to_lfs(&path)).unwrap_or(path);
30
31 fn unc_to_lfs(s: &str) -> &str {
32 s.strip_prefix("//?/").unwrap_or(s)
33 }
34
35 fn change_drive(s: &str) -> Option<String> {
36 let mut ch = s.chars();
37 let drive = ch.next().unwrap_or('C');
38 if ch.next() != Some(':') {
39 return None;
40 }
41 if ch.next() != Some('/') {
42 return None;
43 }
44 Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
45 }
46}
47
781aab86
FG
48fn is_dir_writable_for_user(dir: &PathBuf) -> bool {
49 let tmp = dir.join(".tmp");
50 match fs::create_dir_all(&tmp) {
51 Ok(_) => {
52 fs::remove_dir_all(tmp).unwrap();
53 true
54 }
55 Err(e) => {
56 if e.kind() == std::io::ErrorKind::PermissionDenied {
57 false
58 } else {
59 panic!("Failed the write access check for the current user. {}", e);
60 }
61 }
62 }
63}
64
3b2f2976 65fn install_sh(
9fa01778 66 builder: &Builder<'_>,
3b2f2976 67 package: &str,
3b2f2976 68 stage: u32,
3dfed10e 69 host: Option<TargetSelection>,
fc512014 70 tarball: &GeneratedTarball,
3b2f2976 71) {
49aad941 72 let _guard = builder.msg(Kind::Install, stage, package, host, host);
3b2f2976 73
fc512014
XL
74 let prefix = default_path(&builder.config.prefix, "/usr/local");
75 let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
781aab86
FG
76 let destdir_env = env::var_os("DESTDIR").map(PathBuf::from);
77
78 // Sanity checks on the write access of user.
79 //
80 // When the `DESTDIR` environment variable is present, there is no point to
81 // check write access for `prefix` and `sysconfdir` individually, as they
82 // are combined with the path from the `DESTDIR` environment variable. In
83 // this case, we only need to check the `DESTDIR` path, disregarding the
84 // `prefix` and `sysconfdir` paths.
85 if let Some(destdir) = &destdir_env {
86 assert!(is_dir_writable_for_user(destdir), "User doesn't have write access on DESTDIR.");
87 } else {
88 assert!(
89 is_dir_writable_for_user(&prefix),
90 "User doesn't have write access on `install.prefix` path in the `config.toml`.",
91 );
92 assert!(
93 is_dir_writable_for_user(&sysconfdir),
94 "User doesn't have write access on `install.sysconfdir` path in `config.toml`."
95 );
96 }
97
fc512014
XL
98 let datadir = prefix.join(default_path(&builder.config.datadir, "share"));
99 let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust"));
100 let mandir = prefix.join(default_path(&builder.config.mandir, "share/man"));
101 let libdir = prefix.join(default_path(&builder.config.libdir, "lib"));
102 let bindir = prefix.join(&builder.config.bindir); // Default in config.rs
3b2f2976 103
83c7162d 104 let empty_dir = builder.out.join("tmp/empty_dir");
3b2f2976 105 t!(fs::create_dir_all(&empty_dir));
7cac9316 106
cdc7bbd5 107 let mut cmd = Command::new(SHELL);
3b2f2976 108 cmd.current_dir(&empty_dir)
fc512014 109 .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
781aab86
FG
110 .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
111 .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir)))
112 .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir)))
113 .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir)))
114 .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir)))
115 .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
116 .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
3b2f2976 117 .arg("--disable-ldconfig");
83c7162d 118 builder.run(&mut cmd);
3b2f2976 119 t!(fs::remove_dir_all(&empty_dir));
c30ab7b3 120}
32a655c1 121
fc512014 122fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
6a06907d 123 config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
fc512014
XL
124}
125
781aab86 126fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf) -> String {
fc512014
XL
127 // The DESTDIR environment variable is a standard way to install software in a subdirectory
128 // while keeping the original directory structure, even if the prefix or other directories
129 // contain absolute paths.
130 //
131 // More information on the environment variable is available here:
132 // https://www.gnu.org/prep/standards/html_node/DESTDIR.html
781aab86 133 if let Some(destdir) = destdir_env {
fc512014 134 let without_destdir = path.clone();
781aab86 135 path = destdir.clone();
fc512014
XL
136 // Custom .join() which ignores disk roots.
137 for part in without_destdir.components() {
138 if let Component::Normal(s) = part {
139 path.push(s)
140 }
32a655c1
SL
141 }
142 }
fc512014
XL
143
144 // The installation command is not executed from the current directory, but from a temporary
145 // directory. To prevent relative paths from breaking this converts relative paths to absolute
146 // paths. std::fs::canonicalize is not used as that requires the path to actually be present.
147 if path.is_relative() {
148 path = std::env::current_dir().expect("failed to get the current directory").join(path);
149 assert!(path.is_absolute(), "could not make the path relative");
150 }
151
152 sanitize_sh(&path)
32a655c1 153}
3b2f2976
XL
154
155macro_rules! install {
156 (($sel:ident, $builder:ident, $_config:ident),
157 $($name:ident,
04454e1e 158 $condition_name: ident = $path_or_alias: literal,
3b2f2976
XL
159 $default_cond:expr,
160 only_hosts: $only_hosts:expr,
161 $run_item:block $(, $c:ident)*;)+) => {
162 $(
163 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
164 pub struct $name {
dc9dc135 165 pub compiler: Compiler,
3dfed10e 166 pub target: TargetSelection,
3b2f2976
XL
167 }
168
2c00a5a8
XL
169 impl $name {
170 #[allow(dead_code)]
171 fn should_build(config: &Config) -> bool {
172 config.extended && config.tools.as_ref()
04454e1e 173 .map_or(true, |t| t.contains($path_or_alias))
2c00a5a8 174 }
2c00a5a8
XL
175 }
176
3b2f2976
XL
177 impl Step for $name {
178 type Output = ();
179 const DEFAULT: bool = true;
3b2f2976
XL
180 const ONLY_HOSTS: bool = $only_hosts;
181 $(const $c: bool = true;)*
182
9fa01778 183 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 184 let $_config = &run.builder.config;
04454e1e 185 run.$condition_name($path_or_alias).default_condition($default_cond)
3b2f2976
XL
186 }
187
9fa01778 188 fn make_run(run: RunConfig<'_>) {
3b2f2976 189 run.builder.ensure($name {
dc9dc135 190 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
3b2f2976 191 target: run.target,
3b2f2976
XL
192 });
193 }
194
9fa01778 195 fn run($sel, $builder: &Builder<'_>) {
3b2f2976
XL
196 $run_item
197 }
198 })+
199 }
200}
201
202install!((self, builder, _config),
04454e1e 203 Docs, path = "src/doc", _config.docs, only_hosts: false, {
94222f64
XL
204 let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
205 install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
3b2f2976 206 };
04454e1e 207 Std, path = "library/std", true, only_hosts: false, {
83c7162d 208 for target in &builder.targets {
17df50a5
XL
209 // `expect` should be safe, only None when host != build, but this
210 // only runs when host == build
fc512014 211 let tarball = builder.ensure(dist::Std {
dc9dc135 212 compiler: self.compiler,
abe05a73 213 target: *target
fc512014
XL
214 }).expect("missing std");
215 install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball);
abe05a73 216 }
3b2f2976 217 };
04454e1e 218 Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, {
94222f64
XL
219 let tarball = builder
220 .ensure(dist::Cargo { compiler: self.compiler, target: self.target })
221 .expect("missing cargo");
fc512014 222 install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball);
3b2f2976 223 };
04454e1e 224 RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, {
17df50a5
XL
225 if let Some(tarball) =
226 builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
227 {
228 install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball);
229 } else {
230 builder.info(
231 &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target),
232 );
233 }
f035d41b 234 };
04454e1e 235 Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, {
94222f64
XL
236 let tarball = builder
237 .ensure(dist::Clippy { compiler: self.compiler, target: self.target })
238 .expect("missing clippy");
fc512014 239 install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
8faf50e0 240 };
04454e1e 241 Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
487cf647
FG
242 if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) {
243 install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
244 } else {
245 // Miri is only available on nightly
246 builder.info(
247 &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target),
248 );
249 }
0731742a 250 };
9c376795 251 LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
353b0b11
FG
252 if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
253 install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
254 } else {
255 builder.info(
256 &format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target),
257 );
258 }
9c376795 259 };
04454e1e 260 Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
fc512014 261 if let Some(tarball) = builder.ensure(dist::Rustfmt {
dc9dc135
XL
262 compiler: self.compiler,
263 target: self.target
fc512014
XL
264 }) {
265 install_sh(builder, "rustfmt", self.compiler.stage, Some(self.target), &tarball);
abe05a73 266 } else {
83c7162d 267 builder.info(
dc9dc135
XL
268 &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target),
269 );
abe05a73 270 }
3b2f2976 271 };
04454e1e 272 RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, {
cdc7bbd5
XL
273 // Note: Even though `should_build` may return true for `extended` default tools,
274 // dist::RustDemangler may still return None, unless the target-dependent `profiler` config
275 // is also true, or the `tools` array explicitly includes "rust-demangler".
276 if let Some(tarball) = builder.ensure(dist::RustDemangler {
277 compiler: self.compiler,
278 target: self.target
279 }) {
280 install_sh(builder, "rust-demangler", self.compiler.stage, Some(self.target), &tarball);
281 } else {
282 builder.info(
283 &format!("skipping Install RustDemangler stage{} ({})",
284 self.compiler.stage, self.target),
285 );
286 }
287 };
04454e1e 288 Rustc, path = "compiler/rustc", true, only_hosts: true, {
fc512014 289 let tarball = builder.ensure(dist::Rustc {
60c5eb7d 290 compiler: builder.compiler(builder.top_stage, self.target),
3b2f2976 291 });
fc512014 292 install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball);
3b2f2976
XL
293 };
294);
0531ce1d
XL
295
296#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
297pub struct Src {
298 pub stage: u32,
299}
300
301impl Step for Src {
302 type Output = ();
303 const DEFAULT: bool = true;
304 const ONLY_HOSTS: bool = true;
305
9fa01778 306 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
0531ce1d 307 let config = &run.builder.config;
dc9dc135 308 let cond = config.extended && config.tools.as_ref().map_or(true, |t| t.contains("src"));
0531ce1d
XL
309 run.path("src").default_condition(cond)
310 }
311
9fa01778 312 fn make_run(run: RunConfig<'_>) {
dc9dc135 313 run.builder.ensure(Src { stage: run.builder.top_stage });
0531ce1d
XL
314 }
315
9fa01778 316 fn run(self, builder: &Builder<'_>) {
fc512014
XL
317 let tarball = builder.ensure(dist::Src);
318 install_sh(builder, "src", self.stage, None, &tarball);
0531ce1d
XL
319 }
320}