]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/build_system/prepare.rs
Rollup merge of #103124 - ldm0:nohard_tests, r=Mark-Simulacrum
[rust.git] / compiler / rustc_codegen_cranelift / build_system / prepare.rs
1 use std::env;
2 use std::ffi::OsStr;
3 use std::fs;
4 use std::path::{Path, PathBuf};
5 use std::process::Command;
6
7 use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
8 use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
9
10 pub(crate) const ABI_CAFE: GitRepo =
11     GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
12
13 pub(crate) const RAND: GitRepo =
14     GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
15
16 pub(crate) const REGEX: GitRepo =
17     GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
18
19 pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
20     "rust-lang",
21     "portable-simd",
22     "d5cd4a8112d958bd3a252327e0d069a6363249bd",
23     "portable-simd",
24 );
25
26 pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
27     "ebobby",
28     "simple-raytracer",
29     "804a7a21b9e673a482797aa289a18ed480e4d813",
30     "<none>",
31 );
32
33 pub(crate) fn prepare() {
34     if Path::new("download").exists() {
35         std::fs::remove_dir_all(Path::new("download")).unwrap();
36     }
37     std::fs::create_dir_all(Path::new("download")).unwrap();
38
39     prepare_sysroot();
40
41     // FIXME maybe install this only locally?
42     eprintln!("[INSTALL] hyperfine");
43     Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
44
45     ABI_CAFE.fetch();
46     RAND.fetch();
47     REGEX.fetch();
48     PORTABLE_SIMD.fetch();
49     SIMPLE_RAYTRACER.fetch();
50
51     eprintln!("[LLVM BUILD] simple-raytracer");
52     let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
53     spawn_and_wait(build_cmd);
54     fs::copy(
55         SIMPLE_RAYTRACER
56             .source_dir()
57             .join("target")
58             .join("debug")
59             .join(get_file_name("main", "bin")),
60         SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
61     )
62     .unwrap();
63 }
64
65 fn prepare_sysroot() {
66     let rustc_path = get_rustc_path();
67     let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
68     let sysroot_src = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
69
70     assert!(sysroot_src_orig.exists());
71
72     if sysroot_src.exists() {
73         fs::remove_dir_all(&sysroot_src).unwrap();
74     }
75     fs::create_dir_all(sysroot_src.join("library")).unwrap();
76     eprintln!("[COPY] sysroot src");
77     copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
78
79     let rustc_version = get_rustc_version();
80     fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
81
82     eprintln!("[GIT] init");
83     let mut git_init_cmd = Command::new("git");
84     git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
85     spawn_and_wait(git_init_cmd);
86
87     init_git_repo(&sysroot_src);
88
89     apply_patches("sysroot", &sysroot_src);
90 }
91
92 pub(crate) struct GitRepo {
93     url: GitRepoUrl,
94     rev: &'static str,
95     patch_name: &'static str,
96 }
97
98 enum GitRepoUrl {
99     Github { user: &'static str, repo: &'static str },
100 }
101
102 impl GitRepo {
103     const fn github(
104         user: &'static str,
105         repo: &'static str,
106         rev: &'static str,
107         patch_name: &'static str,
108     ) -> GitRepo {
109         GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
110     }
111
112     pub(crate) fn source_dir(&self) -> PathBuf {
113         match self.url {
114             GitRepoUrl::Github { user: _, repo } => {
115                 std::env::current_dir().unwrap().join("download").join(repo)
116             }
117         }
118     }
119
120     fn fetch(&self) {
121         match self.url {
122             GitRepoUrl::Github { user, repo } => {
123                 clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
124             }
125         }
126         apply_patches(self.patch_name, &self.source_dir());
127     }
128 }
129
130 #[allow(dead_code)]
131 fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
132     eprintln!("[CLONE] {}", repo);
133     // Ignore exit code as the repo may already have been checked out
134     Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
135
136     let mut clean_cmd = Command::new("git");
137     clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
138     spawn_and_wait(clean_cmd);
139
140     let mut checkout_cmd = Command::new("git");
141     checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
142     spawn_and_wait(checkout_cmd);
143 }
144
145 fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
146     if cfg!(windows) {
147         // Older windows doesn't have tar or curl by default. Fall back to using git.
148         clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
149         return;
150     }
151
152     let downloads_dir = std::env::current_dir().unwrap().join("download");
153
154     let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
155     let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
156     let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
157
158     eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
159
160     // Remove previous results if they exists
161     let _ = std::fs::remove_file(&archive_file);
162     let _ = std::fs::remove_dir_all(&archive_dir);
163     let _ = std::fs::remove_dir_all(&download_dir);
164
165     // Download zip archive
166     let mut download_cmd = Command::new("curl");
167     download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url);
168     spawn_and_wait(download_cmd);
169
170     // Unpack tar archive
171     let mut unpack_cmd = Command::new("tar");
172     unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
173     spawn_and_wait(unpack_cmd);
174
175     // Rename unpacked dir to the expected name
176     std::fs::rename(archive_dir, &download_dir).unwrap();
177
178     init_git_repo(&download_dir);
179
180     // Cleanup
181     std::fs::remove_file(archive_file).unwrap();
182 }
183
184 fn init_git_repo(repo_dir: &Path) {
185     let mut git_init_cmd = Command::new("git");
186     git_init_cmd.arg("init").arg("-q").current_dir(repo_dir);
187     spawn_and_wait(git_init_cmd);
188
189     let mut git_add_cmd = Command::new("git");
190     git_add_cmd.arg("add").arg(".").current_dir(repo_dir);
191     spawn_and_wait(git_add_cmd);
192
193     let mut git_commit_cmd = Command::new("git");
194     git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
195     spawn_and_wait(git_commit_cmd);
196 }
197
198 fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
199     let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
200         .unwrap()
201         .map(|entry| entry.unwrap().path())
202         .filter(|path| path.extension() == Some(OsStr::new("patch")))
203         .filter(|path| {
204             path.file_name()
205                 .unwrap()
206                 .to_str()
207                 .unwrap()
208                 .split_once("-")
209                 .unwrap()
210                 .1
211                 .starts_with(crate_name)
212         })
213         .collect();
214     patches.sort();
215     patches
216 }
217
218 fn apply_patches(crate_name: &str, target_dir: &Path) {
219     if crate_name == "<none>" {
220         return;
221     }
222
223     for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
224         eprintln!(
225             "[PATCH] {:?} <- {:?}",
226             target_dir.file_name().unwrap(),
227             patch.file_name().unwrap()
228         );
229         let mut apply_patch_cmd = Command::new("git");
230         apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
231         spawn_and_wait(apply_patch_cmd);
232     }
233 }