1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. use super::allocator::HostAllocatorPtr; use super::plugin_api::CoprocessorPlugin; /// Name of the exported constructor with signature [`PluginConstructorSignature`] for the plugin. pub static PLUGIN_CONSTRUCTOR_SYMBOL: &[u8] = b"_plugin_create"; /// Name of the exported function with signature [`PluginGetBuildInfoSignature`] to get build /// information about the plugin. pub static PLUGIN_GET_BUILD_INFO_SYMBOL: &[u8] = b"_plugin_get_build_info"; /// Name of the exported function with signature [`PluginGetPluginInfoSignature`] to get some /// information about the plugin. pub static PLUGIN_GET_PLUGIN_INFO_SYMBOL: &[u8] = b"_plugin_get_plugin_info"; /// Type signature of the exported function with symbol [`PLUGIN_CONSTRUCTOR_SYMBOL`]. pub type PluginConstructorSignature = unsafe fn(host_allocator: HostAllocatorPtr) -> *mut dyn CoprocessorPlugin; /// Type signature of the exported function with symbol [`PLUGIN_GET_BUILD_INFO_SYMBOL`]. pub type PluginGetBuildInfoSignature = extern "C" fn() -> BuildInfo; /// Type signature of the exported function with symbol [`PLUGIN_GET_PLUGIN_INFO_SYMBOL`]. pub type PluginGetPluginInfoSignature = extern "C" fn() -> PluginInfo; /// Automatically collected build information about the plugin that is exposed from the library. /// /// Will be automatically created when using [`declare_plugin!(...)`](declare_plugin) and will be /// used by TiKV when a plugin is loaded to determine whether there are compilation mismatches. #[repr(C)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct BuildInfo { /// Version of the [`coprocessor_plugin_api`](crate) crate that was used to compile this plugin. pub api_version: &'static str, /// Target triple for which platform this plugin was compiled. pub target: &'static str, /// Version of the Rust compiler that was used for compilation. pub rustc: &'static str, } impl BuildInfo { pub const fn get() -> Self { Self { api_version: env!("API_VERSION"), target: env!("TARGET"), rustc: env!("RUSTC_VERSION"), } } } /// Information about the plugin, like its name and version. #[repr(C)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct PluginInfo { /// The name of the plugin. pub name: &'static str, /// The version string of the plugin. Should follow semantic versioning. pub version: &'static str, } /// Declare a plugin for the library so that it can be loaded by TiKV. /// /// The macro has three different versions: /// * `declare_plugin!(plugin_name, plugin_version, plugin_ctor)` which gives you full control. /// * `declare_plugin!(plugin_name, plugin_ctor)` automatically fetches the version from `Cargo.toml`. /// * `declare_plugin!(plugin_ctor)` automatically fetches plugin name and version from `Cargo.toml`. /// /// The types of `plugin_name` and `plugin_version` have to be `&'static str` literals. /// /// # Notes /// This works by automatically generating an `extern "C"` function with a /// pre-defined signature and symbol name. Therefore you will only be able to /// declare one plugin per library. /// /// Further, it sets the `#[global_allocator]` of the plugin to use the hosts /// allocator. This makes passing owned data between TiKV and plugin easier /// but at the cost of not being able to use a custom allocator. #[macro_export] macro_rules! declare_plugin { ($plugin_ctor:expr) => { declare_plugin!( env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), $plugin_ctor ); }; ($plugin_name:expr, $plugin_ctor:expr) => { declare_plugin!($plugin_name, env!("CARGO_PKG_VERSION"), $plugin_ctor); }; ($plugin_name:expr, $plugin_version:expr, $plugin_ctor:expr) => { #[cfg(not(test))] #[global_allocator] static HOST_ALLOCATOR: $crate::allocator::HostAllocator = $crate::allocator::HostAllocator::new(); #[no_mangle] pub unsafe extern "C" fn _plugin_get_build_info() -> $crate::util::BuildInfo { $crate::util::BuildInfo::get() } #[no_mangle] pub unsafe extern "C" fn _plugin_get_plugin_info() -> $crate::util::PluginInfo { $crate::util::PluginInfo { name: $plugin_name, version: $plugin_version, } } #[no_mangle] pub unsafe extern "C" fn _plugin_create( host_allocator: $crate::allocator::HostAllocatorPtr, ) -> *mut $crate::CoprocessorPlugin { #[cfg(not(test))] HOST_ALLOCATOR.set_allocator(host_allocator); let boxed: Box<dyn $crate::CoprocessorPlugin> = Box::new($plugin_ctor); Box::into_raw(boxed) } }; } /// Transforms the name of a package into the name of the compiled library. /// /// The result of the function can be used to correctly locate build artifacts of `dylib` on /// different platforms. /// /// The name of the `dylib` is /// * `lib<pkgname>.so` on Linux /// * `lib<pkgname>.dylib` on MaxOS /// * `lib<pkgname>.dll` on Windows /// /// See also <https://doc.rust-lang.org/reference/linkage.html> /// /// *Note: Depending on artifacts of other crates will be easier with /// [this RFC](https://github.com/rust-lang/cargo/issues/9096).* pub fn pkgname_to_libname(pkgname: &str) -> String { let pkgname = pkgname.to_string().replace("-", "_"); if cfg!(target_os = "windows") { format!("{}.dll", pkgname) } else if cfg!(target_os = "macos") { format!("lib{}.dylib", pkgname) } else { format!("lib{}.so", pkgname) } }