16cdb10c1Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 26cdb10c1Sopenharmony_ci 36cdb10c1Sopenharmony_ci//================================================ 46cdb10c1Sopenharmony_ci// Macros 56cdb10c1Sopenharmony_ci//================================================ 66cdb10c1Sopenharmony_ci 76cdb10c1Sopenharmony_ci#[cfg(feature = "runtime")] 86cdb10c1Sopenharmony_cimacro_rules! link { 96cdb10c1Sopenharmony_ci ( 106cdb10c1Sopenharmony_ci @LOAD: 116cdb10c1Sopenharmony_ci $(#[doc=$doc:expr])* 126cdb10c1Sopenharmony_ci #[cfg($cfg:meta)] 136cdb10c1Sopenharmony_ci fn $name:ident($($pname:ident: $pty:ty), *) $(-> $ret:ty)* 146cdb10c1Sopenharmony_ci ) => ( 156cdb10c1Sopenharmony_ci $(#[doc=$doc])* 166cdb10c1Sopenharmony_ci #[cfg($cfg)] 176cdb10c1Sopenharmony_ci pub fn $name(library: &mut super::SharedLibrary) { 186cdb10c1Sopenharmony_ci let symbol = unsafe { library.library.get(stringify!($name).as_bytes()) }.ok(); 196cdb10c1Sopenharmony_ci library.functions.$name = match symbol { 206cdb10c1Sopenharmony_ci Some(s) => *s, 216cdb10c1Sopenharmony_ci None => None, 226cdb10c1Sopenharmony_ci }; 236cdb10c1Sopenharmony_ci } 246cdb10c1Sopenharmony_ci 256cdb10c1Sopenharmony_ci #[cfg(not($cfg))] 266cdb10c1Sopenharmony_ci pub fn $name(_: &mut super::SharedLibrary) {} 276cdb10c1Sopenharmony_ci ); 286cdb10c1Sopenharmony_ci 296cdb10c1Sopenharmony_ci ( 306cdb10c1Sopenharmony_ci @LOAD: 316cdb10c1Sopenharmony_ci fn $name:ident($($pname:ident: $pty:ty), *) $(-> $ret:ty)* 326cdb10c1Sopenharmony_ci ) => ( 336cdb10c1Sopenharmony_ci link!(@LOAD: #[cfg(feature = "runtime")] fn $name($($pname: $pty), *) $(-> $ret)*); 346cdb10c1Sopenharmony_ci ); 356cdb10c1Sopenharmony_ci 366cdb10c1Sopenharmony_ci ( 376cdb10c1Sopenharmony_ci $( 386cdb10c1Sopenharmony_ci $(#[doc=$doc:expr] #[cfg($cfg:meta)])* 396cdb10c1Sopenharmony_ci pub fn $name:ident($($pname:ident: $pty:ty), *) $(-> $ret:ty)*; 406cdb10c1Sopenharmony_ci )+ 416cdb10c1Sopenharmony_ci ) => ( 426cdb10c1Sopenharmony_ci use std::cell::{RefCell}; 436cdb10c1Sopenharmony_ci use std::sync::{Arc}; 446cdb10c1Sopenharmony_ci use std::path::{Path, PathBuf}; 456cdb10c1Sopenharmony_ci 466cdb10c1Sopenharmony_ci /// The (minimum) version of a `libclang` shared library. 476cdb10c1Sopenharmony_ci #[allow(missing_docs)] 486cdb10c1Sopenharmony_ci #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 496cdb10c1Sopenharmony_ci pub enum Version { 506cdb10c1Sopenharmony_ci V3_5 = 35, 516cdb10c1Sopenharmony_ci V3_6 = 36, 526cdb10c1Sopenharmony_ci V3_7 = 37, 536cdb10c1Sopenharmony_ci V3_8 = 38, 546cdb10c1Sopenharmony_ci V3_9 = 39, 556cdb10c1Sopenharmony_ci V4_0 = 40, 566cdb10c1Sopenharmony_ci V5_0 = 50, 576cdb10c1Sopenharmony_ci V6_0 = 60, 586cdb10c1Sopenharmony_ci V7_0 = 70, 596cdb10c1Sopenharmony_ci V8_0 = 80, 606cdb10c1Sopenharmony_ci V9_0 = 90, 616cdb10c1Sopenharmony_ci } 626cdb10c1Sopenharmony_ci 636cdb10c1Sopenharmony_ci /// The set of functions loaded dynamically. 646cdb10c1Sopenharmony_ci #[derive(Debug, Default)] 656cdb10c1Sopenharmony_ci pub struct Functions { 666cdb10c1Sopenharmony_ci $( 676cdb10c1Sopenharmony_ci $(#[doc=$doc] #[cfg($cfg)])* 686cdb10c1Sopenharmony_ci pub $name: Option<unsafe extern fn($($pname: $pty), *) $(-> $ret)*>, 696cdb10c1Sopenharmony_ci )+ 706cdb10c1Sopenharmony_ci } 716cdb10c1Sopenharmony_ci 726cdb10c1Sopenharmony_ci /// A dynamically loaded instance of the `libclang` library. 736cdb10c1Sopenharmony_ci #[derive(Debug)] 746cdb10c1Sopenharmony_ci pub struct SharedLibrary { 756cdb10c1Sopenharmony_ci library: libloading::Library, 766cdb10c1Sopenharmony_ci path: PathBuf, 776cdb10c1Sopenharmony_ci pub functions: Functions, 786cdb10c1Sopenharmony_ci } 796cdb10c1Sopenharmony_ci 806cdb10c1Sopenharmony_ci impl SharedLibrary { 816cdb10c1Sopenharmony_ci fn new(library: libloading::Library, path: PathBuf) -> Self { 826cdb10c1Sopenharmony_ci Self { library, path, functions: Functions::default() } 836cdb10c1Sopenharmony_ci } 846cdb10c1Sopenharmony_ci 856cdb10c1Sopenharmony_ci /// Returns the path to this `libclang` shared library. 866cdb10c1Sopenharmony_ci pub fn path(&self) -> &Path { 876cdb10c1Sopenharmony_ci &self.path 886cdb10c1Sopenharmony_ci } 896cdb10c1Sopenharmony_ci 906cdb10c1Sopenharmony_ci /// Returns the (minimum) version of this `libclang` shared library. 916cdb10c1Sopenharmony_ci /// 926cdb10c1Sopenharmony_ci /// If this returns `None`, it indicates that the version is too old 936cdb10c1Sopenharmony_ci /// to be supported by this crate (i.e., `3.4` or earlier). If the 946cdb10c1Sopenharmony_ci /// version of this shared library is more recent than that fully 956cdb10c1Sopenharmony_ci /// supported by this crate, the most recent fully supported version 966cdb10c1Sopenharmony_ci /// will be returned. 976cdb10c1Sopenharmony_ci pub fn version(&self) -> Option<Version> { 986cdb10c1Sopenharmony_ci macro_rules! check { 996cdb10c1Sopenharmony_ci ($fn:expr, $version:ident) => { 1006cdb10c1Sopenharmony_ci if self.library.get::<unsafe extern fn()>($fn).is_ok() { 1016cdb10c1Sopenharmony_ci return Some(Version::$version); 1026cdb10c1Sopenharmony_ci } 1036cdb10c1Sopenharmony_ci }; 1046cdb10c1Sopenharmony_ci } 1056cdb10c1Sopenharmony_ci 1066cdb10c1Sopenharmony_ci unsafe { 1076cdb10c1Sopenharmony_ci check!(b"clang_Cursor_isAnonymousRecordDecl", V9_0); 1086cdb10c1Sopenharmony_ci check!(b"clang_Cursor_getObjCPropertyGetterName", V8_0); 1096cdb10c1Sopenharmony_ci check!(b"clang_File_tryGetRealPathName", V7_0); 1106cdb10c1Sopenharmony_ci check!(b"clang_CXIndex_setInvocationEmissionPathOption", V6_0); 1116cdb10c1Sopenharmony_ci check!(b"clang_Cursor_isExternalSymbol", V5_0); 1126cdb10c1Sopenharmony_ci check!(b"clang_EvalResult_getAsLongLong", V4_0); 1136cdb10c1Sopenharmony_ci check!(b"clang_CXXConstructor_isConvertingConstructor", V3_9); 1146cdb10c1Sopenharmony_ci check!(b"clang_CXXField_isMutable", V3_8); 1156cdb10c1Sopenharmony_ci check!(b"clang_Cursor_getOffsetOfField", V3_7); 1166cdb10c1Sopenharmony_ci check!(b"clang_Cursor_getStorageClass", V3_6); 1176cdb10c1Sopenharmony_ci check!(b"clang_Type_getNumTemplateArguments", V3_5); 1186cdb10c1Sopenharmony_ci } 1196cdb10c1Sopenharmony_ci 1206cdb10c1Sopenharmony_ci None 1216cdb10c1Sopenharmony_ci } 1226cdb10c1Sopenharmony_ci } 1236cdb10c1Sopenharmony_ci 1246cdb10c1Sopenharmony_ci thread_local!(static LIBRARY: RefCell<Option<Arc<SharedLibrary>>> = RefCell::new(None)); 1256cdb10c1Sopenharmony_ci 1266cdb10c1Sopenharmony_ci /// Returns whether a `libclang` shared library is loaded on this thread. 1276cdb10c1Sopenharmony_ci pub fn is_loaded() -> bool { 1286cdb10c1Sopenharmony_ci LIBRARY.with(|l| l.borrow().is_some()) 1296cdb10c1Sopenharmony_ci } 1306cdb10c1Sopenharmony_ci 1316cdb10c1Sopenharmony_ci fn with_library<T, F>(f: F) -> Option<T> where F: FnOnce(&SharedLibrary) -> T { 1326cdb10c1Sopenharmony_ci LIBRARY.with(|l| { 1336cdb10c1Sopenharmony_ci match l.borrow().as_ref() { 1346cdb10c1Sopenharmony_ci Some(library) => Some(f(&library)), 1356cdb10c1Sopenharmony_ci _ => None, 1366cdb10c1Sopenharmony_ci } 1376cdb10c1Sopenharmony_ci }) 1386cdb10c1Sopenharmony_ci } 1396cdb10c1Sopenharmony_ci 1406cdb10c1Sopenharmony_ci $( 1416cdb10c1Sopenharmony_ci #[cfg_attr(feature="cargo-clippy", allow(clippy::missing_safety_doc))] 1426cdb10c1Sopenharmony_ci #[cfg_attr(feature="cargo-clippy", allow(clippy::too_many_arguments))] 1436cdb10c1Sopenharmony_ci $(#[doc=$doc] #[cfg($cfg)])* 1446cdb10c1Sopenharmony_ci pub unsafe fn $name($($pname: $pty), *) $(-> $ret)* { 1456cdb10c1Sopenharmony_ci let f = with_library(|l| { 1466cdb10c1Sopenharmony_ci l.functions.$name.expect(concat!( 1476cdb10c1Sopenharmony_ci "`libclang` function not loaded: `", 1486cdb10c1Sopenharmony_ci stringify!($name), 1496cdb10c1Sopenharmony_ci "`. This crate requires that `libclang` 3.9 or later be installed on your ", 1506cdb10c1Sopenharmony_ci "system. For more information on how to accomplish this, see here: ", 1516cdb10c1Sopenharmony_ci "https://rust-lang.github.io/rust-bindgen/requirements.html#installing-clang-39")) 1526cdb10c1Sopenharmony_ci }).expect("a `libclang` shared library is not loaded on this thread"); 1536cdb10c1Sopenharmony_ci f($($pname), *) 1546cdb10c1Sopenharmony_ci } 1556cdb10c1Sopenharmony_ci 1566cdb10c1Sopenharmony_ci $(#[doc=$doc] #[cfg($cfg)])* 1576cdb10c1Sopenharmony_ci pub mod $name { 1586cdb10c1Sopenharmony_ci pub fn is_loaded() -> bool { 1596cdb10c1Sopenharmony_ci super::with_library(|l| l.functions.$name.is_some()).unwrap_or(false) 1606cdb10c1Sopenharmony_ci } 1616cdb10c1Sopenharmony_ci } 1626cdb10c1Sopenharmony_ci )+ 1636cdb10c1Sopenharmony_ci 1646cdb10c1Sopenharmony_ci mod load { 1656cdb10c1Sopenharmony_ci $(link!(@LOAD: $(#[cfg($cfg)])* fn $name($($pname: $pty), *) $(-> $ret)*);)+ 1666cdb10c1Sopenharmony_ci } 1676cdb10c1Sopenharmony_ci 1686cdb10c1Sopenharmony_ci /// Loads a `libclang` shared library and returns the library instance. 1696cdb10c1Sopenharmony_ci /// 1706cdb10c1Sopenharmony_ci /// This function does not attempt to load any functions from the shared library. The caller 1716cdb10c1Sopenharmony_ci /// is responsible for loading the functions they require. 1726cdb10c1Sopenharmony_ci /// 1736cdb10c1Sopenharmony_ci /// # Failures 1746cdb10c1Sopenharmony_ci /// 1756cdb10c1Sopenharmony_ci /// * a `libclang` shared library could not be found 1766cdb10c1Sopenharmony_ci /// * the `libclang` shared library could not be opened 1776cdb10c1Sopenharmony_ci pub fn load_manually() -> Result<SharedLibrary, String> { 1786cdb10c1Sopenharmony_ci mod build { 1796cdb10c1Sopenharmony_ci pub mod common { include!(concat!(env!("OUT_DIR"), "/common.rs")); } 1806cdb10c1Sopenharmony_ci pub mod dynamic { include!(concat!(env!("OUT_DIR"), "/dynamic.rs")); } 1816cdb10c1Sopenharmony_ci } 1826cdb10c1Sopenharmony_ci 1836cdb10c1Sopenharmony_ci let (directory, filename) = build::dynamic::find(true)?; 1846cdb10c1Sopenharmony_ci let path = directory.join(filename); 1856cdb10c1Sopenharmony_ci 1866cdb10c1Sopenharmony_ci unsafe { 1876cdb10c1Sopenharmony_ci let library = libloading::Library::new(&path).map_err(|e| { 1886cdb10c1Sopenharmony_ci format!( 1896cdb10c1Sopenharmony_ci "the `libclang` shared library at {} could not be opened: {}", 1906cdb10c1Sopenharmony_ci path.display(), 1916cdb10c1Sopenharmony_ci e, 1926cdb10c1Sopenharmony_ci ) 1936cdb10c1Sopenharmony_ci }); 1946cdb10c1Sopenharmony_ci 1956cdb10c1Sopenharmony_ci let mut library = SharedLibrary::new(library?, path); 1966cdb10c1Sopenharmony_ci $(load::$name(&mut library);)+ 1976cdb10c1Sopenharmony_ci Ok(library) 1986cdb10c1Sopenharmony_ci } 1996cdb10c1Sopenharmony_ci } 2006cdb10c1Sopenharmony_ci 2016cdb10c1Sopenharmony_ci /// Loads a `libclang` shared library for use in the current thread. 2026cdb10c1Sopenharmony_ci /// 2036cdb10c1Sopenharmony_ci /// This functions attempts to load all the functions in the shared library. Whether a 2046cdb10c1Sopenharmony_ci /// function has been loaded can be tested by calling the `is_loaded` function on the 2056cdb10c1Sopenharmony_ci /// module with the same name as the function (e.g., `clang_createIndex::is_loaded()` for 2066cdb10c1Sopenharmony_ci /// the `clang_createIndex` function). 2076cdb10c1Sopenharmony_ci /// 2086cdb10c1Sopenharmony_ci /// # Failures 2096cdb10c1Sopenharmony_ci /// 2106cdb10c1Sopenharmony_ci /// * a `libclang` shared library could not be found 2116cdb10c1Sopenharmony_ci /// * the `libclang` shared library could not be opened 2126cdb10c1Sopenharmony_ci #[allow(dead_code)] 2136cdb10c1Sopenharmony_ci pub fn load() -> Result<(), String> { 2146cdb10c1Sopenharmony_ci let library = Arc::new(load_manually()?); 2156cdb10c1Sopenharmony_ci LIBRARY.with(|l| *l.borrow_mut() = Some(library)); 2166cdb10c1Sopenharmony_ci Ok(()) 2176cdb10c1Sopenharmony_ci } 2186cdb10c1Sopenharmony_ci 2196cdb10c1Sopenharmony_ci /// Unloads the `libclang` shared library in use in the current thread. 2206cdb10c1Sopenharmony_ci /// 2216cdb10c1Sopenharmony_ci /// # Failures 2226cdb10c1Sopenharmony_ci /// 2236cdb10c1Sopenharmony_ci /// * a `libclang` shared library is not in use in the current thread 2246cdb10c1Sopenharmony_ci pub fn unload() -> Result<(), String> { 2256cdb10c1Sopenharmony_ci let library = set_library(None); 2266cdb10c1Sopenharmony_ci if library.is_some() { 2276cdb10c1Sopenharmony_ci Ok(()) 2286cdb10c1Sopenharmony_ci } else { 2296cdb10c1Sopenharmony_ci Err("a `libclang` shared library is not in use in the current thread".into()) 2306cdb10c1Sopenharmony_ci } 2316cdb10c1Sopenharmony_ci } 2326cdb10c1Sopenharmony_ci 2336cdb10c1Sopenharmony_ci /// Returns the library instance stored in TLS. 2346cdb10c1Sopenharmony_ci /// 2356cdb10c1Sopenharmony_ci /// This functions allows for sharing library instances between threads. 2366cdb10c1Sopenharmony_ci pub fn get_library() -> Option<Arc<SharedLibrary>> { 2376cdb10c1Sopenharmony_ci LIBRARY.with(|l| l.borrow_mut().clone()) 2386cdb10c1Sopenharmony_ci } 2396cdb10c1Sopenharmony_ci 2406cdb10c1Sopenharmony_ci /// Sets the library instance stored in TLS and returns the previous library. 2416cdb10c1Sopenharmony_ci /// 2426cdb10c1Sopenharmony_ci /// This functions allows for sharing library instances between threads. 2436cdb10c1Sopenharmony_ci pub fn set_library(library: Option<Arc<SharedLibrary>>) -> Option<Arc<SharedLibrary>> { 2446cdb10c1Sopenharmony_ci LIBRARY.with(|l| mem::replace(&mut *l.borrow_mut(), library)) 2456cdb10c1Sopenharmony_ci } 2466cdb10c1Sopenharmony_ci ) 2476cdb10c1Sopenharmony_ci} 2486cdb10c1Sopenharmony_ci 2496cdb10c1Sopenharmony_ci#[cfg(not(feature = "runtime"))] 2506cdb10c1Sopenharmony_cimacro_rules! link { 2516cdb10c1Sopenharmony_ci ( 2526cdb10c1Sopenharmony_ci $( 2536cdb10c1Sopenharmony_ci $(#[doc=$doc:expr] #[cfg($cfg:meta)])* 2546cdb10c1Sopenharmony_ci pub fn $name:ident($($pname:ident: $pty:ty), *) $(-> $ret:ty)*; 2556cdb10c1Sopenharmony_ci )+ 2566cdb10c1Sopenharmony_ci ) => ( 2576cdb10c1Sopenharmony_ci extern { 2586cdb10c1Sopenharmony_ci $( 2596cdb10c1Sopenharmony_ci $(#[doc=$doc] #[cfg($cfg)])* 2606cdb10c1Sopenharmony_ci pub fn $name($($pname: $pty), *) $(-> $ret)*; 2616cdb10c1Sopenharmony_ci )+ 2626cdb10c1Sopenharmony_ci } 2636cdb10c1Sopenharmony_ci 2646cdb10c1Sopenharmony_ci $( 2656cdb10c1Sopenharmony_ci $(#[doc=$doc] #[cfg($cfg)])* 2666cdb10c1Sopenharmony_ci pub mod $name { 2676cdb10c1Sopenharmony_ci pub fn is_loaded() -> bool { true } 2686cdb10c1Sopenharmony_ci } 2696cdb10c1Sopenharmony_ci )+ 2706cdb10c1Sopenharmony_ci ) 2716cdb10c1Sopenharmony_ci} 272