Skip to main content

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    utils::apply_patches()?;
86
87    std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?;
88
89    if cfg!(target_arch = "x86_64") {
90        if cfg!(target_os = "linux") {
91            if target_env == TargetEnv::MUSL {
92                platforms::x86_64_linux_musl::build(
93                    build_type,
94                    targets,
95                    llvm_projects,
96                    enable_rtti,
97                    default_target,
98                    enable_tests,
99                    enable_coverage,
100                    extra_args,
101                    ccache_variant,
102                    enable_assertions,
103                    sanitizer,
104                    enable_valgrind,
105                )?;
106            } else if target_env == TargetEnv::GNU {
107                platforms::x86_64_linux_gnu::build(
108                    build_type,
109                    targets,
110                    llvm_projects,
111                    enable_rtti,
112                    default_target,
113                    enable_tests,
114                    enable_coverage,
115                    extra_args,
116                    ccache_variant,
117                    enable_assertions,
118                    sanitizer,
119                    enable_valgrind,
120                )?;
121            } else if target_env == TargetEnv::Emscripten {
122                platforms::wasm32_emscripten::build(
123                    build_type,
124                    targets,
125                    llvm_projects,
126                    enable_rtti,
127                    default_target,
128                    enable_tests,
129                    enable_coverage,
130                    extra_args,
131                    ccache_variant,
132                    enable_assertions,
133                    sanitizer,
134                    enable_valgrind,
135                )?;
136            } else {
137                anyhow::bail!("Unsupported target environment for x86_64 and Linux");
138            }
139        } else if cfg!(target_os = "macos") {
140            platforms::x86_64_macos::build(
141                build_type,
142                targets,
143                llvm_projects,
144                enable_rtti,
145                default_target,
146                enable_tests,
147                enable_coverage,
148                extra_args,
149                ccache_variant,
150                enable_assertions,
151                sanitizer,
152            )?;
153        } else if cfg!(target_os = "windows") {
154            platforms::x86_64_windows_msvc::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            )?;
167        } else {
168            anyhow::bail!("Unsupported target OS for x86_64");
169        }
170    } else if cfg!(target_arch = "aarch64") {
171        if cfg!(target_os = "linux") {
172            if target_env == TargetEnv::MUSL {
173                platforms::aarch64_linux_musl::build(
174                    build_type,
175                    targets,
176                    llvm_projects,
177                    enable_rtti,
178                    default_target,
179                    enable_tests,
180                    enable_coverage,
181                    extra_args,
182                    ccache_variant,
183                    enable_assertions,
184                    sanitizer,
185                    enable_valgrind,
186                )?;
187            } else if target_env == TargetEnv::GNU {
188                platforms::aarch64_linux_gnu::build(
189                    build_type,
190                    targets,
191                    llvm_projects,
192                    enable_rtti,
193                    default_target,
194                    enable_tests,
195                    enable_coverage,
196                    extra_args,
197                    ccache_variant,
198                    enable_assertions,
199                    sanitizer,
200                    enable_valgrind,
201                )?;
202            } else {
203                anyhow::bail!("Unsupported target environment for aarch64 and Linux");
204            }
205        } else if cfg!(target_os = "macos") {
206            if target_env == TargetEnv::Emscripten {
207                platforms::wasm32_emscripten::build(
208                    build_type,
209                    targets,
210                    llvm_projects,
211                    enable_rtti,
212                    default_target,
213                    enable_tests,
214                    enable_coverage,
215                    extra_args,
216                    ccache_variant,
217                    enable_assertions,
218                    sanitizer,
219                    enable_valgrind,
220                )?;
221            } else {
222                platforms::aarch64_macos::build(
223                    build_type,
224                    targets,
225                    llvm_projects,
226                    enable_rtti,
227                    default_target,
228                    enable_tests,
229                    enable_coverage,
230                    extra_args,
231                    ccache_variant,
232                    enable_assertions,
233                    sanitizer,
234                )?;
235            }
236        } else {
237            anyhow::bail!("Unsupported target OS for aarch64");
238        }
239    } else {
240        anyhow::bail!("Unsupported target architecture");
241    }
242
243    crate::builtins::build(
244        build_type,
245        target_env,
246        default_target,
247        extra_args,
248        ccache_variant,
249        sanitizer,
250    )?;
251
252    Ok(())
253}
254
255/// Executes the build artifacts cleaning.
256pub fn clean() -> anyhow::Result<()> {
257    let remove_if_exists = |path: &Path| {
258        if !path.exists() {
259            return Ok(());
260        }
261        log::info!("deleting {}", path.display());
262        std::fs::remove_dir_all(path)
263    };
264
265    remove_if_exists(
266        llvm_path::DIRECTORY_LLVM_TARGET
267            .get()
268            .expect("target_env is always set because of the default value")
269            .parent()
270            .expect("target_env parent directory is target-llvm"),
271    )?;
272    remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_EMSDK_SOURCE))?;
273
274    Ok(())
275}