]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/build_system/prepare.rs
Merge commit '7d53619064ab7045c383644cb445052d2a3d46db' into sync_cg_clif-2023-02-09
[rust.git] / compiler / rustc_codegen_cranelift / build_system / prepare.rs
1 use std::ffi::OsStr;
2 use std::fs;
3 use std::path::{Path, PathBuf};
4 use std::process::Command;
5
6 use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
7 use super::path::{Dirs, RelPath};
8 use super::rustc_info::{get_default_sysroot, get_rustc_version};
9 use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
10
11 pub(crate) fn prepare(dirs: &Dirs) {
12     RelPath::DOWNLOAD.ensure_fresh(dirs);
13
14     spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", "rustc", dirs));
15
16     prepare_sysroot(dirs);
17     spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", "rustc", dirs));
18     spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", "rustc", dirs));
19
20     super::tests::RAND_REPO.fetch(dirs);
21     spawn_and_wait(super::tests::RAND.fetch("cargo", "rustc", dirs));
22     super::tests::REGEX_REPO.fetch(dirs);
23     spawn_and_wait(super::tests::REGEX.fetch("cargo", "rustc", dirs));
24     super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
25     spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", "rustc", dirs));
26 }
27
28 fn prepare_sysroot(dirs: &Dirs) {
29     let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
30     assert!(sysroot_src_orig.exists());
31
32     eprintln!("[COPY] sysroot src");
33
34     // FIXME ensure builds error out or update the copy if any of the files copied here change
35     BUILD_SYSROOT.ensure_fresh(dirs);
36     copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs));
37
38     fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap();
39     copy_dir_recursively(
40         &sysroot_src_orig.join("library"),
41         &SYSROOT_SRC.to_path(dirs).join("library"),
42     );
43
44     let rustc_version = get_rustc_version(Path::new("rustc"));
45     fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
46
47     eprintln!("[GIT] init");
48     init_git_repo(&SYSROOT_SRC.to_path(dirs));
49
50     apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs));
51 }
52
53 pub(crate) struct GitRepo {
54     url: GitRepoUrl,
55     rev: &'static str,
56     patch_name: &'static str,
57 }
58
59 enum GitRepoUrl {
60     Github { user: &'static str, repo: &'static str },
61 }
62
63 impl GitRepo {
64     pub(crate) const fn github(
65         user: &'static str,
66         repo: &'static str,
67         rev: &'static str,
68         patch_name: &'static str,
69     ) -> GitRepo {
70         GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
71     }
72
73     pub(crate) const fn source_dir(&self) -> RelPath {
74         match self.url {
75             GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
76         }
77     }
78
79     pub(crate) fn fetch(&self, dirs: &Dirs) {
80         match self.url {
81             GitRepoUrl::Github { user, repo } => {
82                 clone_repo_shallow_github(
83                     dirs,
84                     &self.source_dir().to_path(dirs),
85                     user,
86                     repo,
87                     self.rev,
88                 );
89             }
90         }
91         apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
92     }
93 }
94
95 #[allow(dead_code)]
96 fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
97     eprintln!("[CLONE] {}", repo);
98     // Ignore exit code as the repo may already have been checked out
99     git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
100
101     let mut clean_cmd = git_command(download_dir, "checkout");
102     clean_cmd.arg("--").arg(".");
103     spawn_and_wait(clean_cmd);
104
105     let mut checkout_cmd = git_command(download_dir, "checkout");
106     checkout_cmd.arg("-q").arg(rev);
107     spawn_and_wait(checkout_cmd);
108 }
109
110 fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
111     if cfg!(windows) {
112         // Older windows doesn't have tar or curl by default. Fall back to using git.
113         clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
114         return;
115     }
116
117     let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
118     let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev));
119     let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev));
120
121     eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
122
123     // Remove previous results if they exists
124     let _ = std::fs::remove_file(&archive_file);
125     let _ = std::fs::remove_dir_all(&archive_dir);
126     let _ = std::fs::remove_dir_all(&download_dir);
127
128     // Download zip archive
129     let mut download_cmd = Command::new("curl");
130     download_cmd
131         .arg("--max-time")
132         .arg("600")
133         .arg("-y")
134         .arg("30")
135         .arg("-Y")
136         .arg("10")
137         .arg("--connect-timeout")
138         .arg("30")
139         .arg("--continue-at")
140         .arg("-")
141         .arg("--location")
142         .arg("--output")
143         .arg(&archive_file)
144         .arg(archive_url);
145     retry_spawn_and_wait(5, download_cmd);
146
147     // Unpack tar archive
148     let mut unpack_cmd = Command::new("tar");
149     unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs));
150     spawn_and_wait(unpack_cmd);
151
152     // Rename unpacked dir to the expected name
153     std::fs::rename(archive_dir, &download_dir).unwrap();
154
155     init_git_repo(&download_dir);
156
157     // Cleanup
158     std::fs::remove_file(archive_file).unwrap();
159 }
160
161 fn init_git_repo(repo_dir: &Path) {
162     let mut git_init_cmd = git_command(repo_dir, "init");
163     git_init_cmd.arg("-q");
164     spawn_and_wait(git_init_cmd);
165
166     let mut git_add_cmd = git_command(repo_dir, "add");
167     git_add_cmd.arg(".");
168     spawn_and_wait(git_add_cmd);
169
170     let mut git_commit_cmd = git_command(repo_dir, "commit");
171     git_commit_cmd.arg("-m").arg("Initial commit").arg("-q");
172     spawn_and_wait(git_commit_cmd);
173 }
174
175 fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
176     let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
177         .unwrap()
178         .map(|entry| entry.unwrap().path())
179         .filter(|path| path.extension() == Some(OsStr::new("patch")))
180         .filter(|path| {
181             path.file_name()
182                 .unwrap()
183                 .to_str()
184                 .unwrap()
185                 .split_once("-")
186                 .unwrap()
187                 .1
188                 .starts_with(crate_name)
189         })
190         .collect();
191     patches.sort();
192     patches
193 }
194
195 fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
196     if crate_name == "<none>" {
197         return;
198     }
199
200     for patch in get_patches(dirs, crate_name) {
201         eprintln!(
202             "[PATCH] {:?} <- {:?}",
203             target_dir.file_name().unwrap(),
204             patch.file_name().unwrap()
205         );
206         let mut apply_patch_cmd = git_command(target_dir, "am");
207         apply_patch_cmd.arg(patch).arg("-q");
208         spawn_and_wait(apply_patch_cmd);
209     }
210 }