Enable staticly linking with builtin extensions

This commit is contained in:
PThorpe92
2025-01-18 22:35:29 -05:00
parent a26fc1619a
commit 3d188eba0f
9 changed files with 98 additions and 22 deletions

2
Cargo.lock generated
View File

@@ -1270,6 +1270,8 @@ dependencies = [
"libloading",
"limbo_ext",
"limbo_macros",
"limbo_percentile",
"limbo_uuid",
"log",
"miette",
"mimalloc",

View File

@@ -14,15 +14,17 @@ name = "limbo_core"
path = "lib.rs"
[features]
default = ["fs", "json", "uuid", "io_uring"]
default = ["fs", "json", "uuid", "io_uring", "percentile", "static"]
fs = []
json = [
"dep:jsonb",
"dep:pest",
"dep:pest_derive",
]
uuid = ["dep:uuid"]
uuid = ["dep:uuid", "limbo_uuid"]
io_uring = ["dep:io-uring", "rustix/io_uring"]
percentile = ["limbo_percentile"]
static = ["limbo_uuid/static", "limbo_percentile/static"]
[target.'cfg(target_os = "linux")'.dependencies]
io-uring = { version = "0.6.1", optional = true }
@@ -33,6 +35,7 @@ rustix = "0.38.34"
[target.'cfg(not(target_family = "wasm"))'.dependencies]
mimalloc = { version = "*", default-features = false }
libloading = "0.8.6"
[dependencies]
limbo_ext = { path = "../extensions/core" }
@@ -58,8 +61,9 @@ rand = "0.8.5"
bumpalo = { version = "3.16.0", features = ["collections", "boxed"] }
limbo_macros = { path = "../macros" }
uuid = { version = "1.11.0", features = ["v4", "v7"], optional = true }
limbo_uuid = { path = "../extensions/uuid", optional = true, features = ["static"] }
limbo_percentile = { path = "../extensions/percentile", optional = true, features = ["static"] }
miette = "7.4.0"
libloading = "0.8.6"
[target.'cfg(not(target_family = "windows"))'.dev-dependencies]
pprof = { version = "0.14.0", features = ["criterion", "flamegraph"] }

View File

@@ -73,4 +73,31 @@ impl Database {
register_aggregate_function,
}
}
pub fn register_builtins(&self) -> Result<(), String> {
#[cfg(feature = "uuid")]
self.register_uuid()?;
#[cfg(feature = "percentile")]
self.register_percentile()?;
Ok(())
}
#[cfg(feature = "uuid")]
pub fn register_uuid(&self) -> Result<(), String> {
let ext_api = Box::new(self.build_limbo_ext());
if unsafe { !::limbo_uuid::register_extension_static(&ext_api).is_ok() } {
return Err("Failed to register uuid extension".to_string());
}
Ok(())
}
#[cfg(feature = "percentile")]
pub fn register_percentile(&self) -> Result<(), String> {
let ext_api = self.build_limbo_ext();
let res = unsafe { ::limbo_percentile::register_extension(&ext_api) };
if !res.is_ok() {
return Err("Failed to register percentile extension".to_string());
}
Ok(())
}
}

View File

@@ -1,4 +1,5 @@
mod error;
#[cfg(not(target_family = "wasm"))]
mod ext;
mod function;
mod io;
@@ -138,6 +139,9 @@ impl Database {
_shared_wal: shared_wal.clone(),
syms,
};
if let Err(e) = db.register_builtins() {
return Err(LimboError::ExtensionError(e));
}
let db = Arc::new(db);
let conn = Rc::new(Connection {
db: db.clone(),

View File

@@ -7,7 +7,10 @@ license.workspace = true
repository.workspace = true
[lib]
crate-type = ["cdylib"]
crate-type = ["cdylib", "lib"]
[features]
static = []
[dependencies]
limbo_ext = { path = "../core" }

View File

@@ -9,8 +9,10 @@ repository.workspace = true
[lib]
crate-type = ["cdylib", "lib"]
[features]
static= []
[dependencies]
limbo_ext = { path = "../core"}
limbo_ext = { path = "../core" }
uuid = { version = "1.11.0", features = ["v4", "v7"] }
log = "0.4.20"

View File

@@ -1,7 +1,9 @@
use limbo_ext::{register_extension, scalar, Value, ValueType};
#[cfg(feature = "static")]
register_extension! {
scalars: { uuid4_str, uuid4_blob, uuid7_str, uuid7, uuid7_ts, uuid_str, uuid_blob }
static_build: true,
scalars: {uuid4_str, uuid4_blob, uuid7_str, uuid7, uuid7_ts, uuid_str, uuid_blob },
}
#[scalar(name = "uuid4_str", alias = "gen_random_uuid")]
@@ -133,3 +135,9 @@ fn uuid_to_unix(uuid: &[u8; 16]) -> u64 {
| ((uuid[4] as u64) << 8)
| (uuid[5] as u64)
}
#[cfg(not(feature = "static"))]
register_extension! {
static_build: false,
scalars: { uuid4_str, uuid4_blob, uuid7_str, uuid7, uuid7_ts, uuid_str, uuid_blob }
}

View File

@@ -6,43 +6,56 @@ use syn::{Ident, LitStr, Token};
pub(crate) struct RegisterExtensionInput {
pub aggregates: Vec<Ident>,
pub scalars: Vec<Ident>,
pub is_static: bool,
}
impl syn::parse::Parse for RegisterExtensionInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut aggregates = Vec::new();
let mut scalars = Vec::new();
let mut is_static = false;
while !input.is_empty() {
if input.peek(syn::Ident) && input.peek2(Token![:]) {
let section_name: Ident = input.parse()?;
input.parse::<Token![:]>()?;
let content;
syn::braced!(content in input);
if section_name == "aggregates" {
aggregates = Punctuated::<Ident, Token![,]>::parse_terminated(&content)?
.into_iter()
.collect();
} else if section_name == "scalars" {
scalars = Punctuated::<Ident, Token![,]>::parse_terminated(&content)?
if section_name == "static_build" {
let val: syn::LitBool = input.parse()?;
is_static = val.value;
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
} else if section_name == "aggregates" || section_name == "scalars" {
let content;
syn::braced!(content in input);
let parsed_items = Punctuated::<Ident, Token![,]>::parse_terminated(&content)?
.into_iter()
.collect();
if section_name == "aggregates" {
aggregates = parsed_items;
} else {
scalars = parsed_items;
}
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
} else {
return Err(syn::Error::new(section_name.span(), "Unknown section"));
}
} else {
return Err(input.error("Expected aggregates: or scalars: section"));
}
if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
}
}
Ok(Self {
aggregates,
scalars,
is_static,
})
}
}

View File

@@ -359,10 +359,10 @@ pub fn derive_agg_func(input: TokenStream) -> TokenStream {
#[proc_macro]
pub fn register_extension(input: TokenStream) -> TokenStream {
let input_ast = parse_macro_input!(input as RegisterExtensionInput);
let RegisterExtensionInput {
aggregates,
scalars,
is_static,
} = input_ast;
let scalar_calls = scalars.iter().map(|scalar_ident| {
@@ -390,15 +390,28 @@ pub fn register_extension(input: TokenStream) -> TokenStream {
}
});
let expanded = quote! {
#[no_mangle]
pub extern "C" fn register_extension(api: &::limbo_ext::ExtensionApi) -> ::limbo_ext::ResultCode {
let expanded = if is_static {
quote! {
pub unsafe extern "C" fn register_extension_static(api: &::limbo_ext::ExtensionApi) -> ::limbo_ext::ResultCode {
let api = unsafe { &*api };
#(#scalar_calls)*
#(#aggregate_calls)*
::limbo_ext::ResultCode::OK
}
}
} else {
quote! {
#[no_mangle]
pub unsafe extern "C" fn register_extension(api: &::limbo_ext::ExtensionApi) -> ::limbo_ext::ResultCode {
let api = unsafe { &*api };
#(#scalar_calls)*
#(#aggregate_calls)*
::limbo_ext::ResultCode::OK
}
}
};