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