Remove parse_macros (fails with wrapper_ext.h)

This commit is contained in:
gwenn 2023-07-09 14:17:19 +02:00
parent 1308cdaa9d
commit 92c536b622
2 changed files with 21 additions and 43 deletions

View File

@ -23,7 +23,7 @@ min_sqlite_version_3_14_0 = ["pkg-config", "vcpkg"]
# Bundle only the bindings file. Note that this does nothing if # Bundle only the bindings file. Note that this does nothing if
# `buildtime_bindgen` is enabled. # `buildtime_bindgen` is enabled.
bundled_bindings = [] bundled_bindings = []
loadable_extension = ["atomic", "prettyplease", "quote", "regex", "syn"] loadable_extension = ["atomic", "prettyplease", "quote", "syn"]
# sqlite3_unlock_notify >= 3.6.12 # sqlite3_unlock_notify >= 3.6.12
unlock_notify = [] unlock_notify = []
# 3.13.0 # 3.13.0
@ -55,6 +55,4 @@ prettyplease = {version = "0.2", optional = true }
# like bindgen # like bindgen
quote = { version = "1", optional = true, default-features = false } quote = { version = "1", optional = true, default-features = false }
# like bindgen # like bindgen
regex = { version = "1.5", optional = true, default-features = false, features = ["std", "unicode"] }
# like bindgen
syn = { version = "2.0", optional = true, features = ["full", "extra-traits", "visit-mut"] } syn = { version = "2.0", optional = true, features = ["full", "extra-traits", "visit-mut"] }

View File

@ -659,31 +659,30 @@ mod bindings {
.generate() .generate()
.unwrap_or_else(|_| panic!("could not run bindgen on header {}", header)); .unwrap_or_else(|_| panic!("could not run bindgen on header {}", header));
if cfg!(feature = "loadable_extension") { #[cfg(feature = "loadable_extension")]
{
let mut output = Vec::new(); let mut output = Vec::new();
bindings bindings
.write(Box::new(&mut output)) .write(Box::new(&mut output))
.expect("could not write output of bindgen"); .expect("could not write output of bindgen");
let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!"); let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");
super::loadable_extension::generate_functions(&header, &mut output); super::loadable_extension::generate_functions(&mut output);
std::fs::write(out_path, output.as_bytes()) std::fs::write(out_path, output.as_bytes())
} else { .unwrap_or_else(|_| panic!("Could not write to {:?}", out_path));
bindings.write_to_file(out_path)
} }
.unwrap_or_else(|_| panic!("Could not write to {:?}", out_path)); #[cfg(not(feature = "loadable_extension"))]
bindings
.write_to_file(out_path)
.unwrap_or_else(|_| panic!("Could not write to {:?}", out_path));
} }
} }
#[cfg(all(feature = "buildtime_bindgen", feature = "loadable_extension"))] #[cfg(all(feature = "buildtime_bindgen", feature = "loadable_extension"))]
mod loadable_extension { mod loadable_extension {
use std::collections::HashMap;
/// try to generate similar rust code for all `#define sqlite3_xyz /// try to generate similar rust code for all `#define sqlite3_xyz
/// sqlite3_api->abc` macros` in sqlite3ext.h /// sqlite3_api->abc` macros` in sqlite3ext.h
pub fn generate_functions(header: &str, output: &mut String) { pub fn generate_functions(output: &mut String) {
// (1) parse macros in sqlite3ext.h // (1) parse sqlite3_api_routines fields from bindgen output
let mappings = parse_macros(header);
// (2) parse sqlite3_api_routines fields from bindgen output
let ast: syn::File = syn::parse_str(output).expect("could not parse bindgen output"); let ast: syn::File = syn::parse_str(output).expect("could not parse bindgen output");
let sqlite3_api_routines: syn::ItemStruct = ast let sqlite3_api_routines: syn::ItemStruct = ast
.items .items
@ -703,7 +702,7 @@ mod loadable_extension {
let sqlite3_api_routines_ident = sqlite3_api_routines.ident; let sqlite3_api_routines_ident = sqlite3_api_routines.ident;
let p_api = quote::format_ident!("p_api"); let p_api = quote::format_ident!("p_api");
let mut stores = Vec::new(); let mut stores = Vec::new();
// (3) `#define sqlite3_xyz sqlite3_api->abc` => `pub unsafe fn // (2) `#define sqlite3_xyz sqlite3_api->abc` => `pub unsafe fn
// sqlite3_xyz(args) -> ty {...}` for each `abc` field: // sqlite3_xyz(args) -> ty {...}` for each `abc` field:
for field in sqlite3_api_routines.fields { for field in sqlite3_api_routines.fields {
let ident = field.ident.expect("unamed field"); let ident = field.ident.expect("unamed field");
@ -712,12 +711,16 @@ mod loadable_extension {
if name == "vmprintf" || name == "xvsnprintf" || name == "str_vappendf" { if name == "vmprintf" || name == "xvsnprintf" || name == "str_vappendf" {
continue; // skip va_list continue; // skip va_list
} }
let sqlite3_name = mappings let sqlite3_name = match name.as_ref() {
.get(&name) "xthreadsafe" => "sqlite3_threadsafe".to_owned(),
.unwrap_or_else(|| panic!("no mapping for {name}")); "interruptx" => "sqlite3_interrupt".to_owned(),
_ => {
format!("sqlite3_{name}")
}
};
let ptr_name = let ptr_name =
syn::Ident::new(format!("__{}", sqlite3_name.to_uppercase()).as_ref(), span); syn::Ident::new(format!("__{}", sqlite3_name.to_uppercase()).as_ref(), span);
let sqlite3_fn_name = syn::Ident::new(sqlite3_name, span); let sqlite3_fn_name = syn::Ident::new(&sqlite3_name, span);
let method = let method =
extract_method(&field.ty).unwrap_or_else(|| panic!("unexpected type for {name}")); extract_method(&field.ty).unwrap_or_else(|| panic!("unexpected type for {name}"));
let arg_names: syn::punctuated::Punctuated<&syn::Ident, syn::token::Comma> = method let arg_names: syn::punctuated::Punctuated<&syn::Ident, syn::token::Comma> = method
@ -768,7 +771,7 @@ mod loadable_extension {
); );
}); });
} }
// (4) generate rust code similar to SQLITE_EXTENSION_INIT2 macro // (3) generate rust code similar to SQLITE_EXTENSION_INIT2 macro
let tokens = quote::quote! { let tokens = quote::quote! {
/// Loadable extension initialization error /// Loadable extension initialization error
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -813,29 +816,6 @@ mod loadable_extension {
output.push('\n'); output.push('\n');
} }
// Load all `#define sqlite3_xyz sqlite3_api->abc` in sqlite3ext.h
// as a map `{abc => sqlite3_xyz}`
// See https://github.com/rust-lang/rust-bindgen/issues/2544
fn parse_macros(header: &str) -> HashMap<String, String> {
use regex::Regex;
use std::fs::File;
use std::io::{BufRead, BufReader};
let re = Regex::new(r"^#define\s+(sqlite3_\w+)\s+sqlite3_api->(\w+)").unwrap();
let f = File::open(header).expect("could not read sqlite3ext.h");
let f = BufReader::new(f);
let mut mappings = HashMap::new();
for line in f.lines() {
let line = line.expect("could not read line");
if let Some(caps) = re.captures(&line) {
mappings.insert(
caps.get(2).unwrap().as_str().to_owned(),
caps.get(1).unwrap().as_str().to_owned(),
);
}
}
mappings
}
fn extract_method(ty: &syn::Type) -> Option<&syn::TypeBareFn> { fn extract_method(ty: &syn::Type) -> Option<&syn::TypeBareFn> {
match ty { match ty {
syn::Type::Path(tp) => tp.path.segments.last(), syn::Type::Path(tp) => tp.path.segments.last(),