use std::{env, fs::File, io::Write, path::Path, process::Command, str}; fn dll_extension<'a>() -> &'a str { match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() { "windwos" => "dll", "macos" | "ios" => "dylib", _ => "so", } } fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = Path::new(&out_dir); let src_dir = Path::new("src"); let dest_path = Path::new(&out_dir).join("clang_constants.rs"); let mut clang_constants_file = File::create(&dest_path).expect("Could not create file"); let llvm_config = env::var("LLVM_CONFIG").unwrap_or_else(|_| "llvm-config".into()); if let Ok(output) = Command::new(&llvm_config).args(&["--bindir"]).output() { let llvm_bindir = Path::new( str::from_utf8(&output.stdout) .expect("Invalid llvm-config output") .trim(), ); write!( &mut clang_constants_file, "// These constants are autogenerated by build.rs pub const CLANG_PATH: &str = {:?}; pub const CLANGXX_PATH: &str = {:?}; ", llvm_bindir.join("clang"), llvm_bindir.join("clang++") ) .expect("Could not write file"); println!("cargo:rerun-if-changed=src/cmplog-routines-pass.cc"); let output = Command::new(&llvm_config) .args(&["--cxxflags"]) .output() .expect("Failed to execute llvm-config"); let cxxflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output"); let output = Command::new(&llvm_config) .args(&["--ldflags"]) .output() .expect("Failed to execute llvm-config"); let ldflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output"); let cxxflags: Vec<&str> = cxxflags.trim().split_whitespace().collect(); let mut ldflags: Vec<&str> = ldflags.trim().split_whitespace().collect(); match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() { // Needed on macos. // Explanation at https://github.com/banach-space/llvm-tutor/blob/787b09ed31ff7f0e7bdd42ae20547d27e2991512/lib/CMakeLists.txt#L59 "macos" | "ios" => { ldflags.push("-undefined"); ldflags.push("dynamic_lookup"); } _ => (), }; let _ = Command::new(llvm_bindir.join("clang++")) .args(&cxxflags) .arg(src_dir.join("cmplog-routines-pass.cc")) .args(&ldflags) .args(&["-fPIC", "-shared", "-o"]) .arg(out_dir.join(format!("cmplog-routines-pass.{}", dll_extension()))) .status() .expect("Failed to compile cmplog-routines-pass.cc"); } else { write!( &mut clang_constants_file, "// These constants are autogenerated by build.rs pub const CLANG_PATH: &str = \"clang\"; pub const CLANGXX_PATH: &str = \"clang++\"; " ) .expect("Could not write file"); println!( "cargo:warning=Failed to locate the LLVM path using {}, we will not build LLVM passes", llvm_config ); } println!("cargo:rerun-if-changed=build.rs"); }