summaryrefslogtreecommitdiffstats
path: root/third_party/rust/clang-sys/build/static.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/clang-sys/build/static.rs')
-rw-r--r--third_party/rust/clang-sys/build/static.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/third_party/rust/clang-sys/build/static.rs b/third_party/rust/clang-sys/build/static.rs
new file mode 100644
index 0000000000..79f4baf0c6
--- /dev/null
+++ b/third_party/rust/clang-sys/build/static.rs
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: Apache-2.0
+
+extern crate glob;
+
+use std::path::{Path, PathBuf};
+
+use glob::Pattern;
+
+use common;
+
+//================================================
+// Searching
+//================================================
+
+/// Clang static libraries required to link to `libclang` 3.5 and later.
+const CLANG_LIBRARIES: &[&str] = &[
+ "clang",
+ "clangAST",
+ "clangAnalysis",
+ "clangBasic",
+ "clangDriver",
+ "clangEdit",
+ "clangFrontend",
+ "clangIndex",
+ "clangLex",
+ "clangParse",
+ "clangRewrite",
+ "clangSema",
+ "clangSerialization",
+];
+
+/// Gets the name of an LLVM or Clang static library from a path.
+fn get_library_name(path: &Path) -> Option<String> {
+ path.file_stem().map(|p| {
+ let string = p.to_string_lossy();
+ if let Some(name) = string.strip_prefix("lib") {
+ name.to_owned()
+ } else {
+ string.to_string()
+ }
+ })
+}
+
+/// Gets the LLVM static libraries required to link to `libclang`.
+fn get_llvm_libraries() -> Vec<String> {
+ common::run_llvm_config(&["--libs"])
+ .unwrap()
+ .split_whitespace()
+ .filter_map(|p| {
+ // Depending on the version of `llvm-config` in use, listed
+ // libraries may be in one of two forms, a full path to the library
+ // or simply prefixed with `-l`.
+ if let Some(path) = p.strip_prefix("-l") {
+ Some(path.into())
+ } else {
+ get_library_name(Path::new(p))
+ }
+ })
+ .collect()
+}
+
+/// Gets the Clang static libraries required to link to `libclang`.
+fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
+ // Escape the directory in case it contains characters that have special
+ // meaning in glob patterns (e.g., `[` or `]`).
+ let directory = Pattern::escape(directory.as_ref().to_str().unwrap());
+ let directory = Path::new(&directory);
+
+ let pattern = directory.join("libclang*.a").to_str().unwrap().to_owned();
+ if let Ok(libraries) = glob::glob(&pattern) {
+ libraries
+ .filter_map(|l| l.ok().and_then(|l| get_library_name(&l)))
+ .collect()
+ } else {
+ CLANG_LIBRARIES.iter().map(|l| (*l).to_string()).collect()
+ }
+}
+
+/// Finds a directory containing LLVM and Clang static libraries and returns the
+/// path to that directory.
+fn find() -> PathBuf {
+ let name = if cfg!(target_os = "windows") {
+ "libclang.lib"
+ } else {
+ "libclang.a"
+ };
+
+ let files = common::search_libclang_directories(&[name.into()], "LIBCLANG_STATIC_PATH");
+ if let Some((directory, _)) = files.into_iter().next() {
+ directory
+ } else {
+ panic!("could not find any static libraries");
+ }
+}
+
+//================================================
+// Linking
+//================================================
+
+/// Finds and links to `libclang` static libraries.
+pub fn link() {
+ let cep = common::CommandErrorPrinter::default();
+
+ let directory = find();
+
+ // Specify required Clang static libraries.
+ println!("cargo:rustc-link-search=native={}", directory.display());
+ for library in get_clang_libraries(directory) {
+ println!("cargo:rustc-link-lib=static={}", library);
+ }
+
+ // Determine the shared mode used by LLVM.
+ let mode = common::run_llvm_config(&["--shared-mode"]).map(|m| m.trim().to_owned());
+ let prefix = if mode.map_or(false, |m| m == "static") {
+ "static="
+ } else {
+ ""
+ };
+
+ // Specify required LLVM static libraries.
+ println!(
+ "cargo:rustc-link-search=native={}",
+ common::run_llvm_config(&["--libdir"]).unwrap().trim_end()
+ );
+ for library in get_llvm_libraries() {
+ println!("cargo:rustc-link-lib={}{}", prefix, library);
+ }
+
+ // Specify required system libraries.
+ // MSVC doesn't need this, as it tracks dependencies inside `.lib` files.
+ if cfg!(target_os = "freebsd") {
+ println!("cargo:rustc-flags=-l ffi -l ncursesw -l c++ -l z");
+ } else if cfg!(any(target_os = "haiku", target_os = "linux")) {
+ println!("cargo:rustc-flags=-l ffi -l ncursesw -l stdc++ -l z");
+ } else if cfg!(target_os = "macos") {
+ println!("cargo:rustc-flags=-l ffi -l ncurses -l c++ -l z");
+ }
+
+ cep.discard();
+}