//! The revive LLVM builder library. pub mod build_type; pub mod builtins; pub mod ccache_variant; pub mod llvm_path; pub mod llvm_project; pub mod platforms; pub mod sanitizer; pub mod target_env; pub mod target_triple; pub mod utils; pub use self::build_type::BuildType; pub use self::llvm_path::LLVMPath; pub use self::platforms::Platform; use std::collections::HashSet; use std::path::{Path, PathBuf}; use std::process::Command; pub use target_env::TargetEnv; pub use target_triple::TargetTriple; /// Initializes the LLVM submodule if not already done. pub fn init(init_emscripten: bool) -> anyhow::Result<()> { utils::check_presence("git")?; if init_emscripten { utils::install_emsdk()?; } let destination_path = PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE); if destination_path.join(".git").exists() { log::info!("LLVM submodule already initialized"); return Ok(()); } utils::command( Command::new("git").args(["submodule", "update", "--init", "--recursive"]), "LLVM submodule initialization", )?; Ok(()) } /// Executes the building of the LLVM framework for the platform determined by the cfg macro. /// Since cfg is evaluated at compile time, overriding the platform with a command-line /// argument is not possible. So for cross-platform testing, comment out all but the /// line to be tested, and perhaps also checks in the platform-specific build method. #[allow(clippy::too_many_arguments)] pub fn build( build_type: BuildType, target_env: TargetEnv, targets: HashSet, llvm_projects: HashSet, enable_rtti: bool, default_target: Option, enable_tests: bool, enable_coverage: bool, extra_args: &[String], ccache_variant: Option, enable_assertions: bool, sanitizer: Option, enable_valgrind: bool, ) -> anyhow::Result<()> { log::trace!("build type: {build_type:?}"); log::trace!("target env: {target_env:?}"); log::trace!("targets: {targets:?}"); log::trace!("llvm projects: {llvm_projects:?}"); log::trace!("enable rtti: {enable_rtti:?}"); log::trace!("default target: {default_target:?}"); log::trace!("eneable tests: {enable_tests:?}"); log::trace!("enable_coverage: {enable_coverage:?}"); log::trace!("extra args: {extra_args:?}"); log::trace!("sanitzer: {sanitizer:?}"); log::trace!("enable valgrind: {enable_valgrind:?}"); if !PathBuf::from(LLVMPath::DIRECTORY_LLVM_SOURCE).exists() { log::error!( "LLVM project source directory {} does not exist (run `revive-llvm --target-env {target_env} clone`)", LLVMPath::DIRECTORY_LLVM_SOURCE ) } std::fs::create_dir_all(llvm_path::DIRECTORY_LLVM_TARGET.get().unwrap())?; if cfg!(target_arch = "x86_64") { if cfg!(target_os = "linux") { if target_env == TargetEnv::MUSL { platforms::x86_64_linux_musl::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else if target_env == TargetEnv::GNU { platforms::x86_64_linux_gnu::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else if target_env == TargetEnv::Emscripten { platforms::wasm32_emscripten::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else { anyhow::bail!("Unsupported target environment for x86_64 and Linux"); } } else if cfg!(target_os = "macos") { platforms::x86_64_macos::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, )?; } else if cfg!(target_os = "windows") { platforms::x86_64_windows_msvc::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, )?; } else { anyhow::bail!("Unsupported target OS for x86_64"); } } else if cfg!(target_arch = "aarch64") { if cfg!(target_os = "linux") { if target_env == TargetEnv::MUSL { platforms::aarch64_linux_musl::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else if target_env == TargetEnv::GNU { platforms::aarch64_linux_gnu::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else { anyhow::bail!("Unsupported target environment for aarch64 and Linux"); } } else if cfg!(target_os = "macos") { if target_env == TargetEnv::Emscripten { platforms::wasm32_emscripten::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, enable_valgrind, )?; } else { platforms::aarch64_macos::build( build_type, targets, llvm_projects, enable_rtti, default_target, enable_tests, enable_coverage, extra_args, ccache_variant, enable_assertions, sanitizer, )?; } } else { anyhow::bail!("Unsupported target OS for aarch64"); } } else { anyhow::bail!("Unsupported target architecture"); } crate::builtins::build( build_type, target_env, default_target, extra_args, ccache_variant, sanitizer, )?; Ok(()) } /// Executes the build artifacts cleaning. pub fn clean() -> anyhow::Result<()> { let remove_if_exists = |path: &Path| { if !path.exists() { return Ok(()); } log::info!("deleting {}", path.display()); std::fs::remove_dir_all(path) }; remove_if_exists( llvm_path::DIRECTORY_LLVM_TARGET .get() .expect("target_env is always set because of the default value") .parent() .expect("target_env parent directory is target-llvm"), )?; remove_if_exists(&PathBuf::from(LLVMPath::DIRECTORY_EMSDK_SOURCE))?; Ok(()) }