use std::path::Path; use cmd_lib::*; use eyre::{Result, WrapErr}; use paste::paste; use super::*; use cmake::Options; fn config_llvm(global_cfg: &Global, llvm_cfg: &LlvmBuilder) -> Result<()> { // To reduce the need to clean CMakeCache.txt, all cmake vars for LLVM // are explicitly given defaults if they are optional in the cfg gile. let mut cmake_options = Options::new(); let llvm_linker = llvm_cfg.llvm.linker.as_deref().unwrap_or(Path::new("ld")); let launcher = global_cfg.sccache.as_deref().unwrap_or(Path::new("")); let archs = llvm_cfg.archs.as_ref().map(|l| (l, ";")); let exp_archs = llvm_cfg.experimental_archs.as_ref().map(|l| (l, ";")); cmake_options.add("CMAKE_BUILD_TYPE", "RelWithDebInfo"); cmake_options.add("CMAKE_INSTALL_PREFIX", &*global_cfg.prefix); cmake_options.add("LLVM_USE_LINKER", llvm_linker); cmake_options.add("CMAKE_C_COMPILER_LAUNCHER", launcher); cmake_options.add("CMAKE_CXX_COMPILER_LAUNCHER", launcher); cmake_options.add_or("LLVM_TARGETS_TO_BUILD", "all", archs); cmake_options.add_or("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", "", exp_archs); cmake_options.add("BUILD_SHARED_LIBS", llvm_cfg.llvm.shared); cmake_options.add("LLVM_ENABLE_ASSERTIONS", llvm_cfg.llvm.assertions); do_config( "llvm", cmake_options.collect()?, collect_path(&[&global_cfg.llvm_root.try_to_str()?, "llvm"]), )?; Ok(()) } fn config_clang(global_cfg: &Global, llvm_cfg: &LlvmBuilder) -> Result<()> { let llvm_dir = if llvm_cfg.install { None } else { Some(collect_path(&[ env::current_dir()?.try_to_str()?, "build-llvm", "lib", "cmake", "llvm", ])) }; let mut cmake_options = Options::new(); let llvm_dir = llvm_dir.as_deref().unwrap_or(Path::new("")); let llvm_linker = llvm_cfg.llvm.linker.as_deref().unwrap_or(Path::new("ld")); let launcher = global_cfg.sccache.as_deref().unwrap_or(Path::new("")); cmake_options.add("CMAKE_BUILD_TYPE", "Release"); cmake_options.add("CMAKE_INSTALL_PREFIX", &*global_cfg.prefix); cmake_options.add("LLVM_DIR", llvm_dir); cmake_options.add("LLVM_USE_LINKER", llvm_linker); cmake_options.add("CMAKE_C_COMPILER_LAUNCHER", launcher); cmake_options.add("CMAKE_CXX_COMPILER_LAUNCHER", launcher); do_config( "clang", cmake_options.collect()?, collect_path(&[&global_cfg.llvm_root.try_to_str()?, "clang"]), )?; Ok(()) } fn config_lld(global_cfg: &Global, llvm_cfg: &LlvmBuilder) -> Result<()> { let llvm_dir = if llvm_cfg.install { None } else { Some(collect_path(&[ env::current_dir()?.try_to_str()?, "build-llvm", "lib", "cmake", "llvm", ])) }; let mut cmake_options = Options::new(); let llvm_dir = llvm_dir.as_deref().unwrap_or(Path::new("")); let llvm_linker = llvm_cfg.llvm.linker.as_deref().unwrap_or(Path::new("ld")); let launcher = global_cfg.sccache.as_deref().unwrap_or(Path::new("")); cmake_options.add("CMAKE_BUILD_TYPE", "Release"); cmake_options.add("CMAKE_INSTALL_PREFIX", &*global_cfg.prefix); cmake_options.add("LLVM_DIR", llvm_dir); cmake_options.add("LLVM_USE_LINKER", llvm_linker); cmake_options.add("CMAKE_C_COMPILER_LAUNCHER", launcher); cmake_options.add("CMAKE_CXX_COMPILER_LAUNCHER", launcher); do_config( "lld", cmake_options.collect()?, collect_path(&[&global_cfg.llvm_root.try_to_str()?, "lld"]), )?; Ok(()) } fn do_config(t: &str, cmake_options: Vec, src_root: PathBuf) -> Result<()> { run_cmd!( mkdir -p build-$t; cd build-$t; cmake -G "Ninja" $[cmake_options] $src_root; ) .wrap_err("could not build toolchain") } fn do_build(t: &str, _global_cfg: &Global, llvm_cfg: &LlvmBuilder, _mode: &BuildMode) -> Result<()> { run_cmd!( cd build-$t; ninja -j8; )?; if llvm_cfg.install { run_cmd!( cd build-$t; ninja install; )?; } Ok(()) } macro_rules! build_function { ($t:ident) => { paste! { pub fn [](global_cfg: &Global, llvm_cfg: &LlvmBuilder, mode: &BuildMode) -> Result<()> { if !mode.no_config { [](global_cfg, llvm_cfg)?; } if !mode.no_build { do_build(stringify!($t), global_cfg, llvm_cfg, mode)?; } Ok(()) } } } } use build_function; build_function!(llvm); build_function!(clang); build_function!(lld);