16cdb10c1Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 26cdb10c1Sopenharmony_ci 36cdb10c1Sopenharmony_ciextern crate glob; 46cdb10c1Sopenharmony_ci 56cdb10c1Sopenharmony_ciuse std::path::{Path, PathBuf}; 66cdb10c1Sopenharmony_ci 76cdb10c1Sopenharmony_ciuse glob::Pattern; 86cdb10c1Sopenharmony_ci 96cdb10c1Sopenharmony_ciuse common; 106cdb10c1Sopenharmony_ci 116cdb10c1Sopenharmony_ci//================================================ 126cdb10c1Sopenharmony_ci// Searching 136cdb10c1Sopenharmony_ci//================================================ 146cdb10c1Sopenharmony_ci 156cdb10c1Sopenharmony_ci/// Clang static libraries required to link to `libclang` 3.5 and later. 166cdb10c1Sopenharmony_ciconst CLANG_LIBRARIES: &[&str] = &[ 176cdb10c1Sopenharmony_ci "clang", 186cdb10c1Sopenharmony_ci "clangAST", 196cdb10c1Sopenharmony_ci "clangAnalysis", 206cdb10c1Sopenharmony_ci "clangBasic", 216cdb10c1Sopenharmony_ci "clangDriver", 226cdb10c1Sopenharmony_ci "clangEdit", 236cdb10c1Sopenharmony_ci "clangFrontend", 246cdb10c1Sopenharmony_ci "clangIndex", 256cdb10c1Sopenharmony_ci "clangLex", 266cdb10c1Sopenharmony_ci "clangParse", 276cdb10c1Sopenharmony_ci "clangRewrite", 286cdb10c1Sopenharmony_ci "clangSema", 296cdb10c1Sopenharmony_ci "clangSerialization", 306cdb10c1Sopenharmony_ci]; 316cdb10c1Sopenharmony_ci 326cdb10c1Sopenharmony_ci/// Gets the name of an LLVM or Clang static library from a path. 336cdb10c1Sopenharmony_cifn get_library_name(path: &Path) -> Option<String> { 346cdb10c1Sopenharmony_ci path.file_stem().map(|p| { 356cdb10c1Sopenharmony_ci let string = p.to_string_lossy(); 366cdb10c1Sopenharmony_ci if let Some(name) = string.strip_prefix("lib") { 376cdb10c1Sopenharmony_ci name.to_owned() 386cdb10c1Sopenharmony_ci } else { 396cdb10c1Sopenharmony_ci string.to_string() 406cdb10c1Sopenharmony_ci } 416cdb10c1Sopenharmony_ci }) 426cdb10c1Sopenharmony_ci} 436cdb10c1Sopenharmony_ci 446cdb10c1Sopenharmony_ci/// Gets the LLVM static libraries required to link to `libclang`. 456cdb10c1Sopenharmony_cifn get_llvm_libraries() -> Vec<String> { 466cdb10c1Sopenharmony_ci common::run_llvm_config(&["--libs"]) 476cdb10c1Sopenharmony_ci .unwrap() 486cdb10c1Sopenharmony_ci .split_whitespace() 496cdb10c1Sopenharmony_ci .filter_map(|p| { 506cdb10c1Sopenharmony_ci // Depending on the version of `llvm-config` in use, listed 516cdb10c1Sopenharmony_ci // libraries may be in one of two forms, a full path to the library 526cdb10c1Sopenharmony_ci // or simply prefixed with `-l`. 536cdb10c1Sopenharmony_ci if let Some(path) = p.strip_prefix("-l") { 546cdb10c1Sopenharmony_ci Some(path.into()) 556cdb10c1Sopenharmony_ci } else { 566cdb10c1Sopenharmony_ci get_library_name(Path::new(p)) 576cdb10c1Sopenharmony_ci } 586cdb10c1Sopenharmony_ci }) 596cdb10c1Sopenharmony_ci .collect() 606cdb10c1Sopenharmony_ci} 616cdb10c1Sopenharmony_ci 626cdb10c1Sopenharmony_ci/// Gets the Clang static libraries required to link to `libclang`. 636cdb10c1Sopenharmony_cifn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> { 646cdb10c1Sopenharmony_ci // Escape the directory in case it contains characters that have special 656cdb10c1Sopenharmony_ci // meaning in glob patterns (e.g., `[` or `]`). 666cdb10c1Sopenharmony_ci let directory = Pattern::escape(directory.as_ref().to_str().unwrap()); 676cdb10c1Sopenharmony_ci let directory = Path::new(&directory); 686cdb10c1Sopenharmony_ci 696cdb10c1Sopenharmony_ci let pattern = directory.join("libclang*.a").to_str().unwrap().to_owned(); 706cdb10c1Sopenharmony_ci if let Ok(libraries) = glob::glob(&pattern) { 716cdb10c1Sopenharmony_ci libraries 726cdb10c1Sopenharmony_ci .filter_map(|l| l.ok().and_then(|l| get_library_name(&l))) 736cdb10c1Sopenharmony_ci .collect() 746cdb10c1Sopenharmony_ci } else { 756cdb10c1Sopenharmony_ci CLANG_LIBRARIES.iter().map(|l| (*l).to_string()).collect() 766cdb10c1Sopenharmony_ci } 776cdb10c1Sopenharmony_ci} 786cdb10c1Sopenharmony_ci 796cdb10c1Sopenharmony_ci/// Finds a directory containing LLVM and Clang static libraries and returns the 806cdb10c1Sopenharmony_ci/// path to that directory. 816cdb10c1Sopenharmony_cifn find() -> PathBuf { 826cdb10c1Sopenharmony_ci let name = if cfg!(target_os = "windows") { 836cdb10c1Sopenharmony_ci "libclang.lib" 846cdb10c1Sopenharmony_ci } else { 856cdb10c1Sopenharmony_ci "libclang.a" 866cdb10c1Sopenharmony_ci }; 876cdb10c1Sopenharmony_ci 886cdb10c1Sopenharmony_ci let files = common::search_libclang_directories(&[name.into()], "LIBCLANG_STATIC_PATH"); 896cdb10c1Sopenharmony_ci if let Some((directory, _)) = files.into_iter().next() { 906cdb10c1Sopenharmony_ci directory 916cdb10c1Sopenharmony_ci } else { 926cdb10c1Sopenharmony_ci panic!("could not find any static libraries"); 936cdb10c1Sopenharmony_ci } 946cdb10c1Sopenharmony_ci} 956cdb10c1Sopenharmony_ci 966cdb10c1Sopenharmony_ci//================================================ 976cdb10c1Sopenharmony_ci// Linking 986cdb10c1Sopenharmony_ci//================================================ 996cdb10c1Sopenharmony_ci 1006cdb10c1Sopenharmony_ci/// Finds and links to `libclang` static libraries. 1016cdb10c1Sopenharmony_cipub fn link() { 1026cdb10c1Sopenharmony_ci let cep = common::CommandErrorPrinter::default(); 1036cdb10c1Sopenharmony_ci 1046cdb10c1Sopenharmony_ci let directory = find(); 1056cdb10c1Sopenharmony_ci 1066cdb10c1Sopenharmony_ci // Specify required Clang static libraries. 1076cdb10c1Sopenharmony_ci println!("cargo:rustc-link-search=native={}", directory.display()); 1086cdb10c1Sopenharmony_ci for library in get_clang_libraries(directory) { 1096cdb10c1Sopenharmony_ci println!("cargo:rustc-link-lib=static={}", library); 1106cdb10c1Sopenharmony_ci } 1116cdb10c1Sopenharmony_ci 1126cdb10c1Sopenharmony_ci // Determine the shared mode used by LLVM. 1136cdb10c1Sopenharmony_ci let mode = common::run_llvm_config(&["--shared-mode"]).map(|m| m.trim().to_owned()); 1146cdb10c1Sopenharmony_ci let prefix = if mode.map_or(false, |m| m == "static") { 1156cdb10c1Sopenharmony_ci "static=" 1166cdb10c1Sopenharmony_ci } else { 1176cdb10c1Sopenharmony_ci "" 1186cdb10c1Sopenharmony_ci }; 1196cdb10c1Sopenharmony_ci 1206cdb10c1Sopenharmony_ci // Specify required LLVM static libraries. 1216cdb10c1Sopenharmony_ci println!( 1226cdb10c1Sopenharmony_ci "cargo:rustc-link-search=native={}", 1236cdb10c1Sopenharmony_ci common::run_llvm_config(&["--libdir"]).unwrap().trim_end() 1246cdb10c1Sopenharmony_ci ); 1256cdb10c1Sopenharmony_ci for library in get_llvm_libraries() { 1266cdb10c1Sopenharmony_ci println!("cargo:rustc-link-lib={}{}", prefix, library); 1276cdb10c1Sopenharmony_ci } 1286cdb10c1Sopenharmony_ci 1296cdb10c1Sopenharmony_ci // Specify required system libraries. 1306cdb10c1Sopenharmony_ci // MSVC doesn't need this, as it tracks dependencies inside `.lib` files. 1316cdb10c1Sopenharmony_ci if cfg!(target_os = "freebsd") { 1326cdb10c1Sopenharmony_ci println!("cargo:rustc-flags=-l ffi -l ncursesw -l c++ -l z"); 1336cdb10c1Sopenharmony_ci } else if cfg!(any(target_os = "haiku", target_os = "linux")) { 1346cdb10c1Sopenharmony_ci println!("cargo:rustc-flags=-l ffi -l ncursesw -l stdc++ -l z"); 1356cdb10c1Sopenharmony_ci } else if cfg!(target_os = "macos") { 1366cdb10c1Sopenharmony_ci println!("cargo:rustc-flags=-l ffi -l ncurses -l c++ -l z"); 1376cdb10c1Sopenharmony_ci } 1386cdb10c1Sopenharmony_ci 1396cdb10c1Sopenharmony_ci cep.discard(); 1406cdb10c1Sopenharmony_ci} 141