1use std::collections::HashSet;
6use std::path::Path;
7use std::process::Command;
8
9use crate::build_type::BuildType;
10use crate::ccache_variant::CcacheVariant;
11use crate::llvm_path::LLVMPath;
12use crate::llvm_project::LLVMProject;
13use crate::platforms::Platform;
14use crate::sanitizer::Sanitizer;
15use crate::target_triple::TargetTriple;
16
17#[allow(clippy::too_many_arguments)]
21pub fn build(
22 build_type: BuildType,
23 targets: HashSet<Platform>,
24 llvm_projects: HashSet<LLVMProject>,
25 enable_rtti: bool,
26 default_target: Option<TargetTriple>,
27 enable_tests: bool,
28 enable_coverage: bool,
29 extra_args: Vec<String>,
30 ccache_variant: Option<CcacheVariant>,
31 enable_assertions: bool,
32 sanitizer: Option<Sanitizer>,
33 enable_valgrind: bool,
34 valgrind_options: Vec<String>,
35) -> anyhow::Result<()> {
36 crate::utils::check_presence("cmake")?;
37 crate::utils::check_presence("clang")?;
38 crate::utils::check_presence("clang++")?;
39 crate::utils::check_presence("lld")?;
40 crate::utils::check_presence("ninja")?;
41
42 let musl_name = "musl-1.2.3";
43 let musl_build = LLVMPath::musl_build(musl_name)?;
44 let musl_target = LLVMPath::musl_target()?;
45
46 let llvm_module_llvm = LLVMPath::llvm_module_llvm()?;
47 let llvm_host_module_llvm = LLVMPath::llvm_host_module_llvm()?;
48
49 let llvm_build_crt = LLVMPath::llvm_build_crt()?;
50 let llvm_target_crt = LLVMPath::llvm_target_crt()?;
51
52 let llvm_build_host = LLVMPath::llvm_build_host()?;
53 let llvm_target_host = LLVMPath::llvm_target_host()?;
54
55 let llvm_build_final = LLVMPath::llvm_build_final()?;
56 let llvm_target_final = LLVMPath::llvm_target_final()?;
57
58 if !LLVMPath::musl_source(musl_name)?.exists() {
59 crate::utils::download_musl(musl_name)?;
60 }
61 crate::platforms::shared::build_musl(musl_build.as_path(), musl_target.as_path())?;
62 build_crt(
63 targets.clone(),
64 llvm_host_module_llvm.as_path(),
65 llvm_build_crt.as_path(),
66 llvm_target_crt.as_path(),
67 ccache_variant,
68 )?;
69 build_host(
70 llvm_host_module_llvm.as_path(),
71 llvm_build_host.as_path(),
72 llvm_target_host.as_path(),
73 musl_target.as_path(),
74 llvm_target_crt.as_path(),
75 ccache_variant,
76 )?;
77 build_target(
78 build_type,
79 targets,
80 llvm_projects,
81 enable_rtti,
82 default_target,
83 llvm_module_llvm.as_path(),
84 llvm_build_final.as_path(),
85 llvm_target_final.as_path(),
86 musl_target.as_path(),
87 llvm_target_host.as_path(),
88 enable_tests,
89 enable_coverage,
90 extra_args,
91 ccache_variant,
92 enable_assertions,
93 sanitizer,
94 enable_valgrind,
95 valgrind_options,
96 )?;
97
98 Ok(())
99}
100
101fn build_crt(
105 mut targets: HashSet<Platform>,
106 source_directory: &Path,
107 build_directory: &Path,
108 target_directory: &Path,
109 ccache_variant: Option<CcacheVariant>,
110) -> anyhow::Result<()> {
111 targets.insert(Platform::X86);
112
113 crate::utils::command(
114 Command::new("cmake")
115 .args([
116 "-S",
117 source_directory.to_string_lossy().as_ref(),
118 "-B",
119 build_directory.to_string_lossy().as_ref(),
120 "-G",
121 "Ninja",
122 format!(
123 "-DCMAKE_INSTALL_PREFIX='{}'",
124 target_directory.to_string_lossy()
125 )
126 .as_str(),
127 "-DCMAKE_BUILD_TYPE='Release'",
128 "-DCMAKE_C_COMPILER='clang'",
129 "-DCMAKE_CXX_COMPILER='clang++'",
130 "-DLLVM_ENABLE_PROJECTS='compiler-rt'",
131 format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::X86).as_str(),
132 "-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
133 "-DLLVM_BUILD_TESTS='Off'",
134 "-DLLVM_BUILD_RUNTIMES='Off'",
135 "-DLLVM_BUILD_UTILS='Off'",
136 "-DLLVM_INCLUDE_TESTS='Off'",
137 "-DLLVM_INCLUDE_RUNTIMES='Off'",
138 "-DLLVM_INCLUDE_UTILS='Off'",
139 "-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
140 "-DCOMPILER_RT_BUILD_CRT='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='x86_64-pc-linux-musl'",
203 "-DLLVM_TARGETS_TO_BUILD='X86'",
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='x86_64'",
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/x86_64-pc-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}