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