1pub mod build_type;
4pub mod builtins;
5pub mod ccache_variant;
6pub mod llvm_path;
7pub mod llvm_project;
8pub mod lock;
9pub mod platforms;
10pub mod sanitizer;
11pub mod target_env;
12pub mod target_triple;
13pub mod utils;
14
15pub use self::build_type::BuildType;
16pub use self::llvm_path::LLVMPath;
17pub use self::lock::Lock;
18pub use self::platforms::Platform;
19
20use std::collections::HashSet;
21use std::path::{Path, PathBuf};
22use std::process::Command;
23pub use target_env::TargetEnv;
24pub use target_triple::TargetTriple;
25
26pub fn clone(lock: Lock, deep: bool, target_env: TargetEnv) -> anyhow::Result<()> {
28 utils::check_presence("git")?;
29
30 if target_env == TargetEnv::Emscripten {
31 utils::install_emsdk()?;
32 }
33
34 let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE);
35 if destination_path.exists() {
36 log::warn!(
37 "LLVM repository directory {} already exists, falling back to checkout",
38 destination_path.display()
39 );
40 return checkout(lock, false);
41 }
42
43 let mut clone_args = vec!["clone", "--branch", lock.branch.as_str()];
44 if !deep {
45 clone_args.push("--depth");
46 clone_args.push("1");
47 }
48
49 utils::command(
50 Command::new("git")
51 .args(clone_args)
52 .arg(lock.url.as_str())
53 .arg(destination_path.to_string_lossy().as_ref()),
54 "LLVM repository cloning",
55 )?;
56
57 if let Some(r#ref) = lock.r#ref {
58 utils::command(
59 Command::new("git")
60 .args(["checkout", r#ref.as_str()])
61 .current_dir(destination_path.to_string_lossy().as_ref()),
62 "LLVM repository commit checking out",
63 )?;
64 }
65
66 Ok(())
67}
68
69pub fn checkout(lock: Lock, force: bool) -> anyhow::Result<()> {
71 let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE);
72
73 utils::command(
74 Command::new("git")
75 .current_dir(destination_path.as_path())
76 .args(["fetch", "--all", "--tags"]),
77 "LLVM repository data fetching",
78 )?;
79
80 if force {
81 utils::command(
82 Command::new("git")
83 .current_dir(destination_path.as_path())
84 .args(["clean", "-d", "-x", "--force"]),
85 "LLVM repository cleaning",
86 )?;
87 }
88
89 utils::command(
90 Command::new("git")
91 .current_dir(destination_path.as_path())
92 .args(["checkout", "--force", lock.branch.as_str()]),
93 "LLVM repository data pulling",
94 )?;
95
96 if let Some(r#ref) = lock.r#ref {
97 let mut checkout_command = Command::new("git");
98 checkout_command.current_dir(destination_path.as_path());
99 checkout_command.arg("checkout");
100 if force {
101 checkout_command.arg("--force");
102 }
103 checkout_command.arg(r#ref);
104 utils::command(&mut checkout_command, "LLVM repository checking out")?;
105 }
106
107 Ok(())
108}
109
110#[allow(clippy::too_many_arguments)]
115pub fn build(
116 build_type: BuildType,
117 target_env: TargetEnv,
118 targets: HashSet<Platform>,
119 llvm_projects: HashSet<llvm_project::LLVMProject>,
120 enable_rtti: bool,
121 default_target: Option<TargetTriple>,
122 enable_tests: bool,
123 enable_coverage: bool,
124 extra_args: &[String],
125 ccache_variant: Option<ccache_variant::CcacheVariant>,
126 enable_assertions: bool,
127 sanitizer: Option<sanitizer::Sanitizer>,
128 enable_valgrind: bool,
129) -> anyhow::Result<()> {
130 log::trace!("build type: {build_type:?}");
131 log::trace!("target env: {target_env:?}");
132 log::trace!("targets: {targets:?}");
133 log::trace!("llvm projects: {llvm_projects:?}");
134 log::trace!("enable rtti: {enable_rtti:?}");
135 log::trace!("default target: {default_target:?}");
136 log::trace!("eneable tests: {enable_tests:?}");
137 log::trace!("enable_coverage: {enable_coverage:?}");
138 log::trace!("extra args: {extra_args:?}");
139 log::trace!("sanitzer: {sanitizer:?}");
140 log::trace!("enable valgrind: {enable_valgrind:?}");
141
142 if !PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE).exists() {
143 log::error!(
144 "LLVM project source directory {} does not exist (run `revive-llvm --target-env {target_env} clone`)",
145 LLVMPath::DIRECTORY_LLVM_SOURCE
146 )
147 }
148
149 std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?;
150
151 if cfg!(target_arch = "x86_64") {
152 if cfg!(target_os = "linux") {
153 if target_env == TargetEnv::MUSL {
154 platforms::x86_64_linux_musl::build(
155 build_type,
156 targets,
157 llvm_projects,
158 enable_rtti,
159 default_target,
160 enable_tests,
161 enable_coverage,
162 extra_args,
163 ccache_variant,
164 enable_assertions,
165 sanitizer,
166 enable_valgrind,
167 )?;
168 } else if target_env == TargetEnv::GNU {
169 platforms::x86_64_linux_gnu::build(
170 build_type,
171 targets,
172 llvm_projects,
173 enable_rtti,
174 default_target,
175 enable_tests,
176 enable_coverage,
177 extra_args,
178 ccache_variant,
179 enable_assertions,
180 sanitizer,
181 enable_valgrind,
182 )?;
183 } else if target_env == TargetEnv::Emscripten {
184 platforms::wasm32_emscripten::build(
185 build_type,
186 targets,
187 llvm_projects,
188 enable_rtti,
189 default_target,
190 enable_tests,
191 enable_coverage,
192 extra_args,
193 ccache_variant,
194 enable_assertions,
195 sanitizer,
196 enable_valgrind,
197 )?;
198 } else {
199 anyhow::bail!("Unsupported target environment for x86_64 and Linux");
200 }
201 } else if cfg!(target_os = "macos") {
202 platforms::x86_64_macos::build(
203 build_type,
204 targets,
205 llvm_projects,
206 enable_rtti,
207 default_target,
208 enable_tests,
209 enable_coverage,
210 extra_args,
211 ccache_variant,
212 enable_assertions,
213 sanitizer,
214 )?;
215 } else if cfg!(target_os = "windows") {
216 platforms::x86_64_windows_msvc::build(
217 build_type,
218 targets,
219 llvm_projects,
220 enable_rtti,
221 default_target,
222 enable_tests,
223 enable_coverage,
224 extra_args,
225 ccache_variant,
226 enable_assertions,
227 sanitizer,
228 )?;
229 } else {
230 anyhow::bail!("Unsupported target OS for x86_64");
231 }
232 } else if cfg!(target_arch = "aarch64") {
233 if cfg!(target_os = "linux") {
234 if target_env == TargetEnv::MUSL {
235 platforms::aarch64_linux_musl::build(
236 build_type,
237 targets,
238 llvm_projects,
239 enable_rtti,
240 default_target,
241 enable_tests,
242 enable_coverage,
243 extra_args,
244 ccache_variant,
245 enable_assertions,
246 sanitizer,
247 enable_valgrind,
248 )?;
249 } else if target_env == TargetEnv::GNU {
250 platforms::aarch64_linux_gnu::build(
251 build_type,
252 targets,
253 llvm_projects,
254 enable_rtti,
255 default_target,
256 enable_tests,
257 enable_coverage,
258 extra_args,
259 ccache_variant,
260 enable_assertions,
261 sanitizer,
262 enable_valgrind,
263 )?;
264 } else {
265 anyhow::bail!("Unsupported target environment for aarch64 and Linux");
266 }
267 } else if cfg!(target_os = "macos") {
268 if target_env == TargetEnv::Emscripten {
269 platforms::wasm32_emscripten::build(
270 build_type,
271 targets,
272 llvm_projects,
273 enable_rtti,
274 default_target,
275 enable_tests,
276 enable_coverage,
277 extra_args,
278 ccache_variant,
279 enable_assertions,
280 sanitizer,
281 enable_valgrind,
282 )?;
283 } else {
284 platforms::aarch64_macos::build(
285 build_type,
286 targets,
287 llvm_projects,
288 enable_rtti,
289 default_target,
290 enable_tests,
291 enable_coverage,
292 extra_args,
293 ccache_variant,
294 enable_assertions,
295 sanitizer,
296 )?;
297 }
298 } else {
299 anyhow::bail!("Unsupported target OS for aarch64");
300 }
301 } else {
302 anyhow::bail!("Unsupported target architecture");
303 }
304
305 crate::builtins::build(
306 build_type,
307 target_env,
308 default_target,
309 extra_args,
310 ccache_variant,
311 sanitizer,
312 )?;
313
314 Ok(())
315}
316
317pub fn clean() -> anyhow::Result<()> {
319 let remove_if_exists = |path: &Path| {
320 if !path.exists() {
321 return Ok(());
322 }
323 log::info!("deleting {}", path.display());
324 std::fs::remove_dir_all(path)
325 };
326
327 remove_if_exists(
328 llvm_path::DIRECTORY_LLVM_TARGET
329 .get()
330 .expect("target_env is always set because of the default value")
331 .parent()
332 .expect("target_env parent directory is target-llvm"),
333 )?;
334 remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_EMSDK_SOURCE))?;
335 remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE))?;
336 remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_LLVM_HOST_SOURCE))?;
337
338 Ok(())
339}