use std::process; use std::env; use std::path::{PathBuf, Path}; fn query_llvm_config(arg: &str) -> String { let llvm_config_cmd = env::var("LLVM_CONFIG_PATH").unwrap_or("llvm-config".to_string()); let cmd_out = process::Command::new(llvm_config_cmd).arg(arg) .output() .expect("llvm-config must be in PATH or set LLVM_CONFIG_PATH to the llvm-config binary"); String::from_utf8(cmd_out.stdout).expect("utf8") .trim_end().to_owned() } fn main() { let paths = collect_search_paths(); let mut cfg = cc::Build::new(); cfg .warnings(false) .cpp(true) .file("src/extensions.cpp") .include(&paths[0]) .include(find_clang_include(&paths, "clang/AST/OperationKinds.h")) .include(find_clang_include(&paths, "llvm/Support/DataTypes.h")) .include(find_clang_include(&paths, "clang/AST/StmtNodes.inc")) .include(dunce::canonicalize("vendor").unwrap()); if !env::var("TARGET").unwrap().contains("msvc") { cfg.flag("-std=c++11").flag("-Wno-comment"); } cfg.compile("libc3_clang_extensions.a"); } fn collect_search_paths() -> Vec { let inc_path = PathBuf::from(query_llvm_config("--includedir")); let lib_inc_path = PathBuf::from(format!("{}/../include", query_llvm_config("--libdir"))); let mut paths = vec![inc_path, lib_inc_path]; if let Ok(user_paths) = env::var("LIBCLANG_INCLUDE_PATH") { paths.extend(env::split_paths(&user_paths)); } paths } fn find_clang_include(std_search_paths: &[PathBuf], file_search: &str) -> PathBuf { let fallback_paths = [ "/usr/lib/llvm-5.0/include/", "/usr/lib/llvm-4.0/include/", "C:\\Program Files\\LLVM\\include", "../clang/include/", "../../clang/include/", "../../../clang/include/", "../llvm/include/", "../../llvm/include/", "../../../llvm/include/", ]; let candidate_paths = std_search_paths.iter() .map(|p|p.as_path()) .chain(fallback_paths.iter().map(Path::new)); for fspath in candidate_paths { if fspath.exists() && fspath.join(file_search).exists() { return dunce::canonicalize(fspath).unwrap(); } if let Some(parent) = fspath.parent() { if parent.join(file_search).exists() { return dunce::canonicalize(parent).unwrap(); } } } let searched = std_search_paths.iter().map(|p|p.to_string_lossy()).collect::>().join(", "); println!("cargo:warning=Unable to find include path for '{file_search}'. Add dirs to LIBCLANG_INCLUDE_PATH"); println!("cargo:warning=Searched {searched:?}"); PathBuf::from("./clang/include/") }