1use crate::build_type::BuildType;
6use crate::ccache_variant::CcacheVariant;
7use crate::llvm_path::LLVMPath;
8use crate::llvm_project::LLVMProject;
9use crate::platforms::Platform;
10use crate::sanitizer::Sanitizer;
11use crate::target_triple::TargetTriple;
12use std::collections::HashSet;
13use std::path::Path;
14use std::process::Command;
15
16#[allow(clippy::too_many_arguments)]
20pub fn build(
21 build_type: BuildType,
22 targets: HashSet<Platform>,
23 llvm_projects: HashSet<LLVMProject>,
24 enable_rtti: bool,
25 default_target: Option<TargetTriple>,
26 enable_tests: bool,
27 enable_coverage: bool,
28 extra_args: Vec<String>,
29 ccache_variant: Option<CcacheVariant>,
30 enable_assertions: bool,
31 sanitizer: Option<Sanitizer>,
32 enable_valgrind: bool,
33 valgrind_options: Vec<String>,
34) -> anyhow::Result<()> {
35 crate::utils::check_presence("cmake")?;
36 crate::utils::check_presence("clang")?;
37 crate::utils::check_presence("clang++")?;
38 crate::utils::check_presence("lld")?;
39 crate::utils::check_presence("ninja")?;
40
41 let musl_name = "musl-1.2.3";
42 let musl_build = LLVMPath::musl_build(musl_name)?;
43 let musl_target = LLVMPath::musl_target()?;
44
45 let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
46 let llvm_host_module_llvm = LLVMPath::llvm_host_module_llvm()?;
47
48 let llvm_build_crt = LLVMPath::llvm_build_crt()?;
49 let llvm_target_crt = LLVMPath::llvm_target_crt()?;
50
51 let llvm_build_host = LLVMPath::llvm_build_host()?;
52 let llvm_target_host = LLVMPath::llvm_target_host()?;
53
54 let llvm_build_final = LLVMPath::llvm_build_final()?;
55 let llvm_target_final = LLVMPath::llvm_target_final()?;
56
57 if !LLVMPath::musl_source(musl_name)?.exists() {
58 crate::utils::download_musl(musl_name)?;
59 }
60 crate::platforms::shared::build_musl(musl_build.as_path(), musl_target.as_path())?;
61 build_crt(
62 targets.clone(),
63 llvm_host_module_llvm.as_path(),
64 llvm_build_crt.as_path(),
65 llvm_target_crt.as_path(),
66 ccache_variant,
67 )?;
68 build_host(
69 llvm_host_module_llvm.as_path(),
70 llvm_build_host.as_path(),
71 llvm_target_host.as_path(),
72 musl_target.as_path(),
73 llvm_target_crt.as_path(),
74 ccache_variant,
75 )?;
76 build_target(
77 build_type,
78 targets,
79 llvm_projects,
80 enable_rtti,
81 default_target,
82 llvm_module_llvm.as_path(),
83 llvm_build_final.as_path(),
84 llvm_target_final.as_path(),
85 musl_target.as_path(),
86 llvm_target_host.as_path(),
87 enable_tests,
88 enable_coverage,
89 extra_args,
90 ccache_variant,
91 enable_assertions,
92 sanitizer,
93 enable_valgrind,
94 valgrind_options,
95 )?;
96
97 Ok(())
98}
99
100fn build_crt(
104 mut targets: HashSet<Platform>,
105 source_directory: &Path,
106 build_directory: &Path,
107 target_directory: &Path,
108 ccache_variant: Option<CcacheVariant>,
109) -> anyhow::Result<()> {
110 targets.insert(Platform::AArch64);
111
112 crate::utils::command(
113 Command::new("cmake")
114 .args([
115 "-S",
116 source_directory.to_string_lossy().as_ref(),
117 "-B",
118 build_directory.to_string_lossy().as_ref(),
119 "-G",
120 "Ninja",
121 format!(
122 "-DCMAKE_INSTALL_PREFIX='{}'",
123 target_directory.to_string_lossy()
124 )
125 .as_str(),
126 "-DCMAKE_BUILD_TYPE='Release'",
127 "-DCMAKE_C_COMPILER='clang'",
128 "-DCMAKE_CXX_COMPILER='clang++'",
129 "-DLLVM_ENABLE_PROJECTS='compiler-rt'",
130 format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::AArch64).as_str(),
131 "-DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-unknown-linux-musl'",
132 "-DLLVM_BUILD_TESTS='Off'",
133 "-DLLVM_BUILD_RUNTIMES='Off'",
134 "-DLLVM_BUILD_UTILS='Off'",
135 "-DLLVM_INCLUDE_TESTS='Off'",
136 "-DLLVM_INCLUDE_RUNTIMES='Off'",
137 "-DLLVM_INCLUDE_UTILS='Off'",
138 "-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
139 "-DCOMPILER_RT_BUILD_CRT='On'",
140 "-DCOMPILER_RT_BUILD_BUILTINS='On'",
141 "-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
142 "-DCOMPILER_RT_BUILD_XRAY='Off'",
143 "-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
144 "-DCOMPILER_RT_BUILD_PROFILE='Off'",
145 "-DCOMPILER_RT_BUILD_MEMPROF='Off'",
146 "-DCOMPILER_RT_BUILD_ORC='Off'",
147 ])
148 .args(crate::platforms::shared::SHARED_BUILD_OPTS)
149 .args(crate::platforms::shared::shared_build_opts_ccache(
150 ccache_variant,
151 )),
152 "CRT building cmake",
153 )?;
154
155 crate::utils::command(
156 Command::new("ninja")
157 .arg("-C")
158 .arg(build_directory)
159 .arg("install-crt"),
160 "CRT building ninja",
161 )?;
162
163 Ok(())
164}
165
166fn build_host(
170 source_directory: &Path,
171 build_directory: &Path,
172 target_directory: &Path,
173 musl_target_directory: &Path,
174 crt_target_directory: &Path,
175 ccache_variant: Option<CcacheVariant>,
176) -> anyhow::Result<()> {
177 crate::utils::command(
178 Command::new("cmake")
179 .args([
180 "-S",
181 source_directory.to_string_lossy().as_ref(),
182 "-B",
183 build_directory.to_string_lossy().as_ref(),
184 "-G",
185 "Ninja",
186 format!(
187 "-DDEFAULT_SYSROOT='{}'",
188 musl_target_directory.to_string_lossy()
189 )
190 .as_str(),
191 "-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
192 format!(
193 "-DCMAKE_INSTALL_PREFIX='{}'",
194 target_directory.to_string_lossy()
195 )
196 .as_str(),
197 "-DCMAKE_BUILD_TYPE='Release'",
198 "-DCMAKE_C_COMPILER='clang'",
199 "-DCMAKE_CXX_COMPILER='clang++'",
200 "-DCLANG_DEFAULT_CXX_STDLIB='libc++'",
201 "-DCLANG_DEFAULT_RTLIB='compiler-rt'",
202 "-DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-unknown-linux-musl'",
203 "-DLLVM_TARGETS_TO_BUILD='AArch64'",
204 "-DLLVM_BUILD_TESTS='Off'",
205 "-DLLVM_BUILD_UTILS='Off'",
206 "-DLLVM_INCLUDE_TESTS='Off'",
207 "-DLLVM_INCLUDE_UTILS='Off'",
208 "-DLLVM_ENABLE_PROJECTS='clang;lld'",
209 "-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
210 "-DLIBCXX_CXX_ABI='libcxxabi'",
211 "-DLIBCXX_HAS_MUSL_LIBC='On'",
212 "-DLIBCXX_ENABLE_SHARED='Off'",
213 "-DLIBCXX_ENABLE_STATIC='On'",
214 "-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY='On'",
215 "-DLIBCXXABI_ENABLE_SHARED='Off'",
216 "-DLIBCXXABI_ENABLE_STATIC='On'",
217 "-DLIBCXXABI_ENABLE_STATIC_UNWINDER='On'",
218 "-DLIBCXXABI_USE_LLVM_UNWINDER='On'",
219 "-DLIBCXXABI_USE_COMPILER_RT='On'",
220 "-DLIBUNWIND_ENABLE_STATIC='On'",
221 "-DLIBUNWIND_ENABLE_SHARED='Off'",
222 "-DCOMPILER_RT_BUILD_CRT='On'",
223 "-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
224 "-DCOMPILER_RT_BUILD_XRAY='Off'",
225 "-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
226 "-DCOMPILER_RT_BUILD_PROFILE='On'",
227 "-DCOMPILER_RT_BUILD_MEMPROF='Off'",
228 "-DCOMPILER_RT_BUILD_ORC='Off'",
229 "-DCOMPILER_RT_DEFAULT_TARGET_ARCH='aarch64'",
230 "-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
231 ])
232 .args(crate::platforms::shared::SHARED_BUILD_OPTS)
233 .args(crate::platforms::shared::shared_build_opts_ccache(
234 ccache_variant,
235 )),
236 "LLVM host building cmake",
237 )?;
238
239 let mut crt_lib_directory = crt_target_directory.to_path_buf();
240 crt_lib_directory.push("lib/");
241
242 let mut build_lib_directory = build_directory.to_path_buf();
243 build_lib_directory.push("lib/");
244
245 let copy_options = fs_extra::dir::CopyOptions {
246 overwrite: true,
247 copy_inside: true,
248 content_only: true,
249 ..Default::default()
250 };
251 fs_extra::dir::copy(crt_lib_directory, build_lib_directory, ©_options)?;
252
253 crate::utils::command(
254 Command::new("ninja")
255 .arg("-C")
256 .arg(build_directory)
257 .arg("install"),
258 "LLVM host building ninja",
259 )?;
260
261 Ok(())
262}
263
264#[allow(clippy::too_many_arguments)]
268fn build_target(
269 build_type: BuildType,
270 targets: HashSet<Platform>,
271 llvm_projects: HashSet<LLVMProject>,
272 enable_rtti: bool,
273 default_target: Option<TargetTriple>,
274 source_directory: &Path,
275 build_directory: &Path,
276 target_directory: &Path,
277 musl_target_directory: &Path,
278 host_target_directory: &Path,
279 enable_tests: bool,
280 enable_coverage: bool,
281 extra_args: Vec<String>,
282 ccache_variant: Option<CcacheVariant>,
283 enable_assertions: bool,
284 sanitizer: Option<Sanitizer>,
285 enable_valgrind: bool,
286 valgrind_options: Vec<String>,
287) -> anyhow::Result<()> {
288 let mut clang_path = host_target_directory.to_path_buf();
289 clang_path.push("bin/clang");
290
291 let mut clang_cxx_path = host_target_directory.to_path_buf();
292 clang_cxx_path.push("bin/clang++");
293
294 crate::utils::command(
295 Command::new("cmake")
296 .args([
297 "-S",
298 source_directory.to_string_lossy().as_ref(),
299 "-B",
300 build_directory.to_string_lossy().as_ref(),
301 "-G",
302 "Ninja",
303 "-DBUILD_SHARED_LIBS='Off'",
304 "-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
305 format!(
306 "-DCMAKE_INSTALL_PREFIX='{}'",
307 target_directory.to_string_lossy()
308 )
309 .as_str(),
310 format!("-DCMAKE_BUILD_TYPE='{build_type}'").as_str(),
311 format!("-DCMAKE_C_COMPILER='{}'", clang_path.to_string_lossy()).as_str(),
312 format!(
313 "-DCMAKE_CXX_COMPILER='{}'",
314 clang_cxx_path.to_string_lossy()
315 )
316 .as_str(),
317 "-DCMAKE_FIND_LIBRARY_SUFFIXES='.a'",
318 "-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
319 "-DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld -static'",
320 format!(
321 "-DLLVM_TARGETS_TO_BUILD='{}'",
322 targets
323 .into_iter()
324 .map(|platform| platform.to_string())
325 .collect::<Vec<String>>()
326 .join(";")
327 )
328 .as_str(),
329 format!(
330 "-DLLVM_ENABLE_PROJECTS='{}'",
331 llvm_projects
332 .into_iter()
333 .map(|project| project.to_string())
334 .collect::<Vec<String>>()
335 .join(";")
336 )
337 .as_str(),
338 ])
339 .args(crate::platforms::shared::shared_build_opts_default_target(
340 default_target,
341 ))
342 .args(crate::platforms::shared::SHARED_BUILD_OPTS)
343 .args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
344 .args(crate::platforms::shared::shared_build_opts_werror())
345 .args(crate::platforms::shared::shared_build_opts_tests(
346 enable_tests,
347 ))
348 .args(crate::platforms::shared::shared_build_opts_coverage(
349 enable_coverage,
350 ))
351 .args(extra_args)
352 .args(crate::platforms::shared::shared_build_opts_ccache(
353 ccache_variant,
354 ))
355 .args(crate::platforms::shared::shared_build_opts_assertions(
356 enable_assertions,
357 ))
358 .args(crate::platforms::shared::shared_build_opts_rtti(
359 enable_rtti,
360 ))
361 .args(crate::platforms::shared::shared_build_opts_sanitizers(
362 sanitizer,
363 ))
364 .args(crate::platforms::shared::shared_build_opts_valgrind(
365 enable_valgrind,
366 valgrind_options,
367 )),
368 "LLVM target building cmake",
369 )?;
370
371 crate::utils::ninja(build_directory)?;
372
373 let mut musl_lib_directory = musl_target_directory.to_path_buf();
374 musl_lib_directory.push("lib/");
375
376 let mut host_lib_directory = host_target_directory.to_path_buf();
377 host_lib_directory.push("lib/aarch64-unknown-linux-musl/");
378
379 let mut target_lib_directory = target_directory.to_path_buf();
380 target_lib_directory.push("lib/");
381
382 let copy_options = fs_extra::dir::CopyOptions {
383 overwrite: true,
384 copy_inside: true,
385 content_only: true,
386 ..Default::default()
387 };
388 fs_extra::dir::copy(
389 musl_lib_directory,
390 target_lib_directory.as_path(),
391 ©_options,
392 )?;
393 fs_extra::dir::copy(
394 host_lib_directory,
395 target_lib_directory.as_path(),
396 ©_options,
397 )?;
398
399 Ok(())
400}