revive_llvm_builder/
lib.rs

1//! The revive LLVM builder library.
2
3pub mod build_type;
4pub mod builtins;
5pub mod ccache_variant;
6pub mod llvm_path;
7pub mod llvm_project;
8pub mod platforms;
9pub mod sanitizer;
10pub mod target_env;
11pub mod target_triple;
12pub mod utils;
13
14pub use self::build_type::BuildType;
15pub use self::llvm_path::LLVMPath;
16pub use self::platforms::Platform;
17
18use std::collections::HashSet;
19use std::path::{Path, PathBuf};
20use std::process::Command;
21pub use target_env::TargetEnv;
22pub use target_triple::TargetTriple;
23
24/// Initializes the LLVM submodule if not already done.
25pub fn init(init_emscripten: bool) -> anyhow::Result<()> {
26    utils::check_presence("git")?;
27
28    if init_emscripten {
29        utils::install_emsdk()?;
30    }
31
32    let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE);
33    if destination_path.join(".git").exists() {
34        log::info!("LLVM submodule already initialized");
35        return Ok(());
36    }
37
38    utils::command(
39        Command::new("git").args(["submodule", "update", "--init", "--recursive"]),
40        "LLVM submodule initialization",
41    )?;
42
43    Ok(())
44}
45
46/// Executes the building of the LLVM framework for the platform determined by the cfg macro.
47/// Since cfg is evaluated at compile time, overriding the platform with a command-line
48/// argument is not possible. So for cross-platform testing, comment out all but the
49/// line to be tested, and perhaps also checks in the platform-specific build method.
50#[allow(clippy::too_many_arguments)]
51pub fn build(
52    build_type: BuildType,
53    target_env: TargetEnv,
54    targets: HashSet<Platform>,
55    llvm_projects: HashSet<llvm_project::LLVMProject>,
56    enable_rtti: bool,
57    default_target: Option<TargetTriple>,
58    enable_tests: bool,
59    enable_coverage: bool,
60    extra_args: &[String],
61    ccache_variant: Option<ccache_variant::CcacheVariant>,
62    enable_assertions: bool,
63    sanitizer: Option<sanitizer::Sanitizer>,
64    enable_valgrind: bool,
65) -> anyhow::Result<()> {
66    log::trace!("build type: {build_type:?}");
67    log::trace!("target env: {target_env:?}");
68    log::trace!("targets: {targets:?}");
69    log::trace!("llvm projects: {llvm_projects:?}");
70    log::trace!("enable rtti: {enable_rtti:?}");
71    log::trace!("default target: {default_target:?}");
72    log::trace!("eneable tests: {enable_tests:?}");
73    log::trace!("enable_coverage: {enable_coverage:?}");
74    log::trace!("extra args: {extra_args:?}");
75    log::trace!("sanitzer: {sanitizer:?}");
76    log::trace!("enable valgrind: {enable_valgrind:?}");
77
78    if !PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE).exists() {
79        log::error!(
80            "LLVM project source directory {} does not exist (run `revive-llvm --target-env {target_env} clone`)",
81            LLVMPath::DIRECTORY_LLVM_SOURCE
82        )
83    }
84
85    std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?;
86
87    if cfg!(target_arch = "x86_64") {
88        if cfg!(target_os = "linux") {
89            if target_env == TargetEnv::MUSL {
90                platforms::x86_64_linux_musl::build(
91                    build_type,
92                    targets,
93                    llvm_projects,
94                    enable_rtti,
95                    default_target,
96                    enable_tests,
97                    enable_coverage,
98                    extra_args,
99                    ccache_variant,
100                    enable_assertions,
101                    sanitizer,
102                    enable_valgrind,
103                )?;
104            } else if target_env == TargetEnv::GNU {
105                platforms::x86_64_linux_gnu::build(
106                    build_type,
107                    targets,
108                    llvm_projects,
109                    enable_rtti,
110                    default_target,
111                    enable_tests,
112                    enable_coverage,
113                    extra_args,
114                    ccache_variant,
115                    enable_assertions,
116                    sanitizer,
117                    enable_valgrind,
118                )?;
119            } else if target_env == TargetEnv::Emscripten {
120                platforms::wasm32_emscripten::build(
121                    build_type,
122                    targets,
123                    llvm_projects,
124                    enable_rtti,
125                    default_target,
126                    enable_tests,
127                    enable_coverage,
128                    extra_args,
129                    ccache_variant,
130                    enable_assertions,
131                    sanitizer,
132                    enable_valgrind,
133                )?;
134            } else {
135                anyhow::bail!("Unsupported target environment for x86_64 and Linux");
136            }
137        } else if cfg!(target_os = "macos") {
138            platforms::x86_64_macos::build(
139                build_type,
140                targets,
141                llvm_projects,
142                enable_rtti,
143                default_target,
144                enable_tests,
145                enable_coverage,
146                extra_args,
147                ccache_variant,
148                enable_assertions,
149                sanitizer,
150            )?;
151        } else if cfg!(target_os = "windows") {
152            platforms::x86_64_windows_msvc::build(
153                build_type,
154                targets,
155                llvm_projects,
156                enable_rtti,
157                default_target,
158                enable_tests,
159                enable_coverage,
160                extra_args,
161                ccache_variant,
162                enable_assertions,
163                sanitizer,
164            )?;
165        } else {
166            anyhow::bail!("Unsupported target OS for x86_64");
167        }
168    } else if cfg!(target_arch = "aarch64") {
169        if cfg!(target_os = "linux") {
170            if target_env == TargetEnv::MUSL {
171                platforms::aarch64_linux_musl::build(
172                    build_type,
173                    targets,
174                    llvm_projects,
175                    enable_rtti,
176                    default_target,
177                    enable_tests,
178                    enable_coverage,
179                    extra_args,
180                    ccache_variant,
181                    enable_assertions,
182                    sanitizer,
183                    enable_valgrind,
184                )?;
185            } else if target_env == TargetEnv::GNU {
186                platforms::aarch64_linux_gnu::build(
187                    build_type,
188                    targets,
189                    llvm_projects,
190                    enable_rtti,
191                    default_target,
192                    enable_tests,
193                    enable_coverage,
194                    extra_args,
195                    ccache_variant,
196                    enable_assertions,
197                    sanitizer,
198                    enable_valgrind,
199                )?;
200            } else {
201                anyhow::bail!("Unsupported target environment for aarch64 and Linux");
202            }
203        } else if cfg!(target_os = "macos") {
204            if target_env == TargetEnv::Emscripten {
205                platforms::wasm32_emscripten::build(
206                    build_type,
207                    targets,
208                    llvm_projects,
209                    enable_rtti,
210                    default_target,
211                    enable_tests,
212                    enable_coverage,
213                    extra_args,
214                    ccache_variant,
215                    enable_assertions,
216                    sanitizer,
217                    enable_valgrind,
218                )?;
219            } else {
220                platforms::aarch64_macos::build(
221                    build_type,
222                    targets,
223                    llvm_projects,
224                    enable_rtti,
225                    default_target,
226                    enable_tests,
227                    enable_coverage,
228                    extra_args,
229                    ccache_variant,
230                    enable_assertions,
231                    sanitizer,
232                )?;
233            }
234        } else {
235            anyhow::bail!("Unsupported target OS for aarch64");
236        }
237    } else {
238        anyhow::bail!("Unsupported target architecture");
239    }
240
241    crate::builtins::build(
242        build_type,
243        target_env,
244        default_target,
245        extra_args,
246        ccache_variant,
247        sanitizer,
248    )?;
249
250    Ok(())
251}
252
253/// Executes the build artifacts cleaning.
254pub fn clean() -> anyhow::Result<()> {
255    let remove_if_exists = |path: &Path| {
256        if !path.exists() {
257            return Ok(());
258        }
259        log::info!("deleting {}", path.display());
260        std::fs::remove_dir_all(path)
261    };
262
263    remove_if_exists(
264        llvm_path::DIRECTORY_LLVM_TARGET
265            .get()
266            .expect("target_env is always set because of the default value")
267            .parent()
268            .expect("target_env parent directory is target-llvm"),
269    )?;
270    remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_EMSDK_SOURCE))?;
271
272    Ok(())
273}