Import 'clang-sys' package version 0.29.3

* Add OWNERS
* No Android.bp yet
Bug: 152884384
Test: make

Change-Id: I1d652df9a2f868b46957554a8ade394acbfe7af0
diff --git a/build/common.rs b/build/common.rs
new file mode 100644
index 0000000..958ef9b
--- /dev/null
+++ b/build/common.rs
@@ -0,0 +1,221 @@
+// Copyright 2018 Kyle Mayes
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate glob;
+
+use std::env;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+use glob::MatchOptions;
+
+/// `libclang` directory patterns for FreeBSD and Linux.
+const DIRECTORIES_LINUX: &[&str] = &[
+    "/usr/lib*",
+    "/usr/lib*/*",
+    "/usr/lib*/*/*",
+    "/usr/local/lib*",
+    "/usr/local/lib*/*",
+    "/usr/local/lib*/*/*",
+    "/usr/local/llvm*/lib*",
+];
+
+/// `libclang` directory patterns for macOS.
+const DIRECTORIES_MACOS: &[&str] = &[
+    "/usr/local/opt/llvm*/lib",
+    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
+    "/Library/Developer/CommandLineTools/usr/lib",
+    "/usr/local/opt/llvm*/lib/llvm*/lib",
+];
+
+/// `libclang` directory patterns for Windows.
+const DIRECTORIES_WINDOWS: &[&str] = &[
+    "C:\\LLVM\\lib",
+    "C:\\Program Files*\\LLVM\\lib",
+    "C:\\MSYS*\\MinGW*\\lib",
+];
+
+/// Executes the supplied console command, returning the `stdout` output if the
+/// command was successfully executed.
+fn run_command(command: &str, arguments: &[&str]) -> Option<String> {
+    macro_rules! warn {
+        ($error:expr) => {
+            println!(
+                "cargo:warning=couldn't execute `{} {}` ({})",
+                command,
+                arguments.join(" "),
+                $error,
+            );
+        };
+    }
+
+    let output = match Command::new(command).args(arguments).output() {
+        Ok(output) => output,
+        Err(error) => {
+            warn!(format!("error: {}", error));
+            return None;
+        }
+    };
+
+    if !output.status.success() {
+        warn!(format!("exit code: {}", output.status));
+        return None;
+    }
+
+    Some(String::from_utf8_lossy(&output.stdout).into_owned())
+}
+
+/// Executes `llvm-config`, returning the `stdout` output if the command was
+/// successfully executed.
+pub fn run_llvm_config(arguments: &[&str]) -> Option<String> {
+    let path = env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into());
+
+    let output = run_command(&path, arguments);
+    if output.is_none() {
+        println!(
+            "cargo:warning=set the LLVM_CONFIG_PATH environment variable to \
+            the full path to a valid `llvm-config` executable (including the \
+            executable itself)"
+        );
+    }
+
+    output
+}
+
+/// Returns the paths to and the filenames of the files matching the supplied
+/// filename patterns in the supplied directory.
+fn search_directory(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
+    // Join the directory to the filename patterns to obtain the path patterns.
+    let paths = filenames
+        .iter()
+        .filter_map(|f| directory.join(f).to_str().map(ToOwned::to_owned));
+
+    // Prevent wildcards from matching path separators.
+    let mut options = MatchOptions::new();
+    options.require_literal_separator = true;
+
+    paths
+        .flat_map(|p| {
+            if let Ok(paths) = glob::glob_with(&p, options) {
+                paths.filter_map(Result::ok).collect()
+            } else {
+                vec![]
+            }
+        })
+        .filter_map(|p| {
+            let filename = p.file_name().and_then(|f| f.to_str())?;
+
+            // The `libclang_shared` library has been renamed to `libclang-cpp`
+            // in Clang 10. This can cause instances of this library (e.g.,
+            // `libclang-cpp.so.10`) to be matched by patterns looking for
+            // instances of `libclang`.
+            if filename.contains("-cpp.") {
+                return None;
+            }
+
+            Some((directory.to_owned(), filename.into()))
+        })
+        .collect::<Vec<_>>()
+}
+
+/// Returns the paths to and the filenames of the files matching the supplied
+/// filename patterns in the supplied directory, checking any relevant sibling
+/// directories.
+fn search_directories(directory: &Path, filenames: &[String]) -> Vec<(PathBuf, String)> {
+    let mut results = search_directory(directory, filenames);
+
+    // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory
+    // while `libclang.lib` is usually found in the LLVM `lib` directory. To
+    // keep things consistent with other platforms, only LLVM `lib` directories
+    // are included in the backup search directory globs so we need to search
+    // the LLVM `bin` directory here.
+    if cfg!(target_os = "windows") && directory.ends_with("lib") {
+        let sibling = directory.parent().unwrap().join("bin");
+        results.extend(search_directory(&sibling, filenames).into_iter());
+    }
+
+    results
+}
+
+/// Returns the paths to and the filenames of the `libclang` static or dynamic
+/// libraries matching the supplied filename patterns.
+pub fn search_libclang_directories(files: &[String], variable: &str) -> Vec<(PathBuf, String)> {
+    // Use the path provided by the relevant environment variable.
+    if let Ok(path) = env::var(variable).map(|d| Path::new(&d).to_path_buf()) {
+        // Check if the path is referring to a matching file already.
+        if let Some(parent) = path.parent() {
+            let filename = path.file_name().unwrap().to_str().unwrap();
+            let libraries = search_directories(parent, files);
+            if libraries.iter().any(|(_, f)| f == filename) {
+                return vec![(parent.into(), filename.into())];
+            }
+        }
+
+        return search_directories(&path, files);
+    }
+
+    let mut found = vec![];
+
+    // Search the `bin` and `lib` directories in directory provided by
+    // `llvm-config --prefix`.
+    if let Some(output) = run_llvm_config(&["--prefix"]) {
+        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
+        found.extend(search_directories(&directory.join("bin"), files));
+        found.extend(search_directories(&directory.join("lib"), files));
+        found.extend(search_directories(&directory.join("lib64"), files));
+    }
+
+    // Search the toolchain directory in the directory provided by
+    // `xcode-select --print-path`.
+    if cfg!(target_os = "macos") {
+        if let Some(output) = run_command("xcode-select", &["--print-path"]) {
+            let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
+            let directory = directory.join("Toolchains/XcodeDefault.xctoolchain/usr/lib");
+            found.extend(search_directories(&directory, files));
+        }
+    }
+
+    // Search the directories provided by the `LD_LIBRARY_PATH` environment
+    // variable.
+    if let Ok(path) = env::var("LD_LIBRARY_PATH") {
+        for directory in path.split(':').map(Path::new) {
+            found.extend(search_directories(&directory, files));
+        }
+    }
+
+    // Determine the `libclang` directory patterns.
+    let directories = if cfg!(any(target_os = "freebsd", target_os = "linux")) {
+        DIRECTORIES_LINUX
+    } else if cfg!(target_os = "macos") {
+        DIRECTORIES_MACOS
+    } else if cfg!(target_os = "windows") {
+        DIRECTORIES_WINDOWS
+    } else {
+        &[]
+    };
+
+    // Search the directories provided by the `libclang` directory patterns.
+    let mut options = MatchOptions::new();
+    options.case_sensitive = false;
+    options.require_literal_separator = true;
+    for directory in directories.iter().rev() {
+        if let Ok(directories) = glob::glob_with(directory, options) {
+            for directory in directories.filter_map(Result::ok).filter(|p| p.is_dir()) {
+                found.extend(search_directories(&directory, files));
+            }
+        }
+    }
+
+    found
+}
diff --git a/build/dynamic.rs b/build/dynamic.rs
new file mode 100644
index 0000000..2054ba0
--- /dev/null
+++ b/build/dynamic.rs
@@ -0,0 +1,244 @@
+// Copyright 2018 Kyle Mayes
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::env;
+use std::fs::File;
+use std::io::{self, Error, ErrorKind, Read, Seek, SeekFrom};
+use std::path::{Path, PathBuf};
+
+use super::common;
+
+/// Returns the ELF class from the ELF header in the supplied file.
+fn parse_elf_header(path: &Path) -> io::Result<u8> {
+    let mut file = File::open(path)?;
+    let mut buffer = [0; 5];
+    file.read_exact(&mut buffer)?;
+    if buffer[..4] == [127, 69, 76, 70] {
+        Ok(buffer[4])
+    } else {
+        Err(Error::new(ErrorKind::InvalidData, "invalid ELF header"))
+    }
+}
+
+/// Returns the magic number from the PE header in the supplied file.
+fn parse_pe_header(path: &Path) -> io::Result<u16> {
+    let mut file = File::open(path)?;
+
+    // Determine the header offset.
+    let mut buffer = [0; 4];
+    let start = SeekFrom::Start(0x3C);
+    file.seek(start)?;
+    file.read_exact(&mut buffer)?;
+    let offset = i32::from_le_bytes(buffer);
+
+    // Determine the validity of the header.
+    file.seek(SeekFrom::Start(offset as u64))?;
+    file.read_exact(&mut buffer)?;
+    if buffer != [80, 69, 0, 0] {
+        return Err(Error::new(ErrorKind::InvalidData, "invalid PE header"));
+    }
+
+    // Find the magic number.
+    let mut buffer = [0; 2];
+    file.seek(SeekFrom::Current(20))?;
+    file.read_exact(&mut buffer)?;
+    Ok(u16::from_le_bytes(buffer))
+}
+
+/// Validates the header for the supplied `libclang` shared library.
+fn validate_header(path: &Path) -> Result<(), String> {
+    if cfg!(any(target_os = "freebsd", target_os = "linux")) {
+        let class = parse_elf_header(path).map_err(|e| e.to_string())?;
+
+        if cfg!(target_pointer_width = "32") && class != 1 {
+            return Err("invalid ELF class (64-bit)".into());
+        }
+
+        if cfg!(target_pointer_width = "64") && class != 2 {
+            return Err("invalid ELF class (32-bit)".into());
+        }
+
+        Ok(())
+    } else if cfg!(target_os = "windows") {
+        let magic = parse_pe_header(path).map_err(|e| e.to_string())?;
+
+        if cfg!(target_pointer_width = "32") && magic != 267 {
+            return Err("invalid DLL (64-bit)".into());
+        }
+
+        if cfg!(target_pointer_width = "64") && magic != 523 {
+            return Err("invalid DLL (32-bit)".into());
+        }
+
+        Ok(())
+    } else {
+        Ok(())
+    }
+}
+
+/// Returns the components of the version in the supplied `libclang` shared
+// library filename.
+fn parse_version(filename: &str) -> Vec<u32> {
+    let version = if filename.starts_with("libclang.so.") {
+        &filename[12..]
+    } else if filename.starts_with("libclang-") {
+        &filename[9..filename.len() - 3]
+    } else {
+        return vec![];
+    };
+
+    version.split('.').map(|s| s.parse().unwrap_or(0)).collect()
+}
+
+/// Returns the paths to, the filenames, and the versions of the `libclang`
+// shared libraries.
+fn search_libclang_directories(runtime: bool) -> Result<Vec<(PathBuf, String, Vec<u32>)>, String> {
+    let mut files = vec![format!(
+        "{}clang{}",
+        env::consts::DLL_PREFIX,
+        env::consts::DLL_SUFFIX
+    )];
+
+    if cfg!(target_os = "linux") {
+        // Some Linux distributions don't create a `libclang.so` symlink, so we
+        // need to look for versioned files (e.g., `libclang-3.9.so`).
+        files.push("libclang-*.so".into());
+
+        // Some Linux distributions don't create a `libclang.so` symlink and
+        // don't have versioned files as described above, so we need to look for
+        // suffix versioned files (e.g., `libclang.so.1`). However, `ld` cannot
+        // link to these files, so this will only be included when linking at
+        // runtime.
+        if runtime {
+            files.push("libclang.so.*".into());
+            files.push("libclang-*.so.*".into());
+        }
+    }
+
+    if cfg!(any(
+        target_os = "openbsd",
+        target_os = "freebsd",
+        target_os = "netbsd"
+    )) {
+        // Some BSD distributions don't create a `libclang.so` symlink either,
+        // but use a different naming scheme for versioned files (e.g.,
+        // `libclang.so.7.0`).
+        files.push("libclang.so.*".into());
+    }
+
+    if cfg!(target_os = "windows") {
+        // The official LLVM build uses `libclang.dll` on Windows instead of
+        // `clang.dll`. However, unofficial builds such as MinGW use `clang.dll`.
+        files.push("libclang.dll".into());
+    }
+
+    // Validate the `libclang` shared libraries and collect the versions.
+    let mut valid = vec![];
+    let mut invalid = vec![];
+    for (directory, filename) in common::search_libclang_directories(&files, "LIBCLANG_PATH") {
+        let path = directory.join(&filename);
+        match validate_header(&path) {
+            Ok(()) => {
+                let version = parse_version(&filename);
+                valid.push((directory, filename, version))
+            }
+            Err(message) => invalid.push(format!("({}: {})", path.display(), message)),
+        }
+    }
+
+    if !valid.is_empty() {
+        return Ok(valid);
+    }
+
+    let message = format!(
+        "couldn't find any valid shared libraries matching: [{}], set the \
+         `LIBCLANG_PATH` environment variable to a path where one of these files \
+         can be found (invalid: [{}])",
+        files
+            .iter()
+            .map(|f| format!("'{}'", f))
+            .collect::<Vec<_>>()
+            .join(", "),
+        invalid.join(", "),
+    );
+
+    Err(message)
+}
+
+/// Returns the directory and filename of the "best" available `libclang` shared
+/// library.
+pub fn find(runtime: bool) -> Result<(PathBuf, String), String> {
+    search_libclang_directories(runtime)?
+        .iter()
+        .max_by_key(|f| &f.2)
+        .cloned()
+        .map(|(path, filename, _)| (path, filename))
+        .ok_or_else(|| "unreachable".into())
+}
+
+/// Find and link to `libclang` dynamically.
+#[cfg(not(feature = "runtime"))]
+pub fn link() {
+    use std::fs;
+
+    let (directory, filename) = find(false).unwrap();
+    println!("cargo:rustc-link-search={}", directory.display());
+
+    if cfg!(all(target_os = "windows", target_env = "msvc")) {
+        // Find the `libclang` stub static library required for the MSVC
+        // toolchain.
+        let lib = if !directory.ends_with("bin") {
+            directory
+        } else {
+            directory.parent().unwrap().join("lib")
+        };
+
+        if lib.join("libclang.lib").exists() {
+            println!("cargo:rustc-link-search={}", lib.display());
+        } else if lib.join("libclang.dll.a").exists() {
+            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`.
+            // It is linkable with the MSVC linker, but Rust doesn't recognize
+            // the `.a` suffix, so we need to copy it with a different name.
+            //
+            // FIXME: Maybe we can just hardlink or symlink it?
+            let out = env::var("OUT_DIR").unwrap();
+            fs::copy(
+                lib.join("libclang.dll.a"),
+                Path::new(&out).join("libclang.lib"),
+            )
+            .unwrap();
+            println!("cargo:rustc-link-search=native={}", out);
+        } else {
+            panic!(
+                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be \
+                 available in {}",
+                filename,
+                lib.display(),
+            );
+        }
+
+        println!("cargo:rustc-link-lib=dylib=libclang");
+    } else {
+        let name = filename.trim_start_matches("lib");
+
+        // Strip extensions and trailing version numbers (e.g., the `.so.7.0` in
+        // `libclang.so.7.0`).
+        let name = match name.find(".dylib").or_else(|| name.find(".so")) {
+            Some(index) => &name[0..index],
+            None => &name,
+        };
+
+        println!("cargo:rustc-link-lib=dylib={}", name);
+    }
+}
diff --git a/build/static.rs b/build/static.rs
new file mode 100644
index 0000000..bacd4ad
--- /dev/null
+++ b/build/static.rs
@@ -0,0 +1,136 @@
+// Copyright 2018 Kyle Mayes
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate glob;
+
+use std::path::{Path, PathBuf};
+
+use common;
+
+/// Returns the name of an LLVM or Clang library from a path to such a library.
+fn get_library_name(path: &Path) -> Option<String> {
+    path.file_stem().map(|p| {
+        let string = p.to_string_lossy();
+        if string.starts_with("lib") {
+            string[3..].to_owned()
+        } else {
+            string.to_string()
+        }
+    })
+}
+
+/// Returns the LLVM libraries required to link to `libclang` statically.
+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 p.starts_with("-l") {
+                Some(p[2..].into())
+            } else {
+                get_library_name(Path::new(p))
+            }
+        })
+        .collect()
+}
+
+/// Clang libraries required to link to `libclang` 3.5 and later statically.
+const CLANG_LIBRARIES: &[&str] = &[
+    "clang",
+    "clangAST",
+    "clangAnalysis",
+    "clangBasic",
+    "clangDriver",
+    "clangEdit",
+    "clangFrontend",
+    "clangIndex",
+    "clangLex",
+    "clangParse",
+    "clangRewrite",
+    "clangSema",
+    "clangSerialization",
+];
+
+/// Returns the Clang libraries required to link to `libclang` statically.
+fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
+    let pattern = directory
+        .as_ref()
+        .join("libclang*.a")
+        .to_string_lossy()
+        .to_string();
+    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()
+    }
+}
+
+/// Returns a directory containing `libclang` static libraries.
+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().nth(0) {
+        directory
+    } else {
+        panic!("could not find any static libraries");
+    }
+}
+
+/// Find and link to `libclang` statically.
+pub fn link() {
+    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!(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");
+    }
+}