const FULL_FEATURED: [&str; 24] = [
"-DSQLITE_OS_OTHER",
"-DSQLITE_USE_URI",
"-DSQLITE_THREADSAFE=0",
"-DSQLITE_TEMP_STORE=2",
"-DSQLITE_DEFAULT_CACHE_SIZE=-16384",
"-DSQLITE_DEFAULT_PAGE_SIZE=8192",
"-DSQLITE_OMIT_DEPRECATED",
"-DSQLITE_OMIT_LOAD_EXTENSION",
"-DSQLITE_OMIT_SHARED_CACHE",
"-DSQLITE_ENABLE_UNLOCK_NOTIFY",
"-DSQLITE_ENABLE_API_ARMOR",
"-DSQLITE_ENABLE_MATH_FUNCTIONS",
"-DSQLITE_ENABLE_BYTECODE_VTAB",
"-DSQLITE_ENABLE_DBPAGE_VTAB",
"-DSQLITE_ENABLE_DBSTAT_VTAB",
"-DSQLITE_ENABLE_FTS5",
"-DSQLITE_ENABLE_MATH_FUNCTIONS",
"-DSQLITE_ENABLE_OFFSET_SQL_FUNC",
"-DSQLITE_ENABLE_PREUPDATE_HOOK",
"-DSQLITE_ENABLE_RTREE",
"-DSQLITE_ENABLE_SESSION",
"-DSQLITE_ENABLE_STMTVTAB",
"-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION",
"-DSQLITE_ENABLE_COLUMN_METADATA",
];
#[cfg(feature = "sqlite3mc")]
const SQLITE3_MC_FEATURED: [&str; 2] = ["-D__WASM__", "-DARGON2_NO_THREADS"];
const UPDATE_BINDGEN_ENV: &str = "SQLITE_WASM_RS_UPDATE_BINDGEN";
fn main() {
println!("cargo::rerun-if-env-changed={UPDATE_BINDGEN_ENV}");
println!("cargo::rerun-if-changed=shim");
#[cfg(feature = "sqlite3mc")]
println!("cargo::rerun-if-changed=sqlite3mc");
#[cfg(not(feature = "sqlite3mc"))]
println!("cargo::rerun-if-changed=sqlite3");
compile();
#[cfg(feature = "bindgen")]
{
let update_bindgen = std::env::var(UPDATE_BINDGEN_ENV).is_ok();
let output =
std::path::PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR env not set"))
.join("bindgen.rs");
bindgen(&output);
if update_bindgen {
#[cfg(not(feature = "sqlite3mc"))]
const SQLITE3_BINDGEN: &str = "src/bindings/sqlite3_bindgen.rs";
#[cfg(feature = "sqlite3mc")]
const SQLITE3_BINDGEN: &str = "src/bindings/sqlite3mc_bindgen.rs";
std::fs::copy(&output, SQLITE3_BINDGEN).unwrap();
}
}
}
#[cfg(feature = "bindgen")]
fn bindgen(output: &std::path::PathBuf) {
#[cfg(not(feature = "sqlite3mc"))]
const SQLITE3_HEADER: &str = "sqlite3/sqlite3.h";
#[cfg(feature = "sqlite3mc")]
const SQLITE3_HEADER: &str = "sqlite3mc/sqlite3mc_amalgamation.h";
use bindgen::callbacks::{IntKind, ParseCallbacks};
#[derive(Debug)]
struct SqliteTypeChooser;
impl ParseCallbacks for SqliteTypeChooser {
fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
if name == "SQLITE_SERIALIZE_NOCOPY"
|| name.starts_with("SQLITE_DESERIALIZE_")
|| name.starts_with("SQLITE_PREPARE_")
|| name.starts_with("SQLITE_TRACE_")
{
Some(IntKind::UInt)
} else {
None
}
}
}
let mut bindings = bindgen::builder()
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
.disable_nested_struct_naming()
.generate_cstr(true)
.trust_clang_mangling(false)
.header(SQLITE3_HEADER)
.parse_callbacks(Box::new(SqliteTypeChooser));
bindings = bindings
.blocklist_function("sqlite3_auto_extension")
.raw_line(
r#"extern "C" {
pub fn sqlite3_auto_extension(
xEntryPoint: ::core::option::Option<
unsafe extern "C" fn(
db: *mut sqlite3,
pzErrMsg: *mut *mut ::core::ffi::c_char,
_: *const sqlite3_api_routines,
) -> ::core::ffi::c_int,
>,
) -> ::core::ffi::c_int;
}"#,
)
.blocklist_function("sqlite3_cancel_auto_extension")
.raw_line(
r#"extern "C" {
pub fn sqlite3_cancel_auto_extension(
xEntryPoint: ::core::option::Option<
unsafe extern "C" fn(
db: *mut sqlite3,
pzErrMsg: *mut *mut ::core::ffi::c_char,
_: *const sqlite3_api_routines,
) -> ::core::ffi::c_int,
>,
) -> ::core::ffi::c_int;
}"#,
)
.blocklist_function("sqlite3_load_extension")
.raw_line(
r#"pub unsafe fn sqlite3_load_extension(
_db: *mut sqlite3,
_zFile: *const ::core::ffi::c_char,
_zProc: *const ::core::ffi::c_char,
_pzErrMsg: *mut *mut ::core::ffi::c_char,
) -> ::core::ffi::c_int {
// SQLITE_ERROR
1
}"#,
)
.blocklist_function("sqlite3_enable_load_extension")
.raw_line(
r#"pub unsafe fn sqlite3_enable_load_extension(
_db: *mut sqlite3,
_onoff: ::core::ffi::c_int,
) -> ::core::ffi::c_int {
// SQLITE_ERROR
1
}"#,
)
.blocklist_function("sqlite3_profile")
.blocklist_function("sqlite3_trace")
.blocklist_function(".*16.*")
.blocklist_function("sqlite3_close_v2")
.blocklist_function("sqlite3_create_collation")
.blocklist_function("sqlite3_create_function")
.blocklist_function("sqlite3_create_module")
.blocklist_function("sqlite3_prepare");
bindings = bindings.clang_args(FULL_FEATURED);
#[cfg(feature = "sqlite3mc")]
{
bindings = bindings.clang_args(SQLITE3_MC_FEATURED);
}
bindings = bindings
.blocklist_function("sqlite3_vmprintf")
.blocklist_function("sqlite3_vsnprintf")
.blocklist_function("sqlite3_str_vappendf")
.blocklist_type("va_list")
.blocklist_item("__.*");
bindings = bindings
.clang_arg("-fvisibility=default");
let bindings = bindings
.layout_tests(false)
.use_core()
.formatter(bindgen::Formatter::Prettyplease)
.generate()
.unwrap();
bindings.write_to_file(output).unwrap();
}
fn compile() {
use std::collections::HashSet;
const C_SOURCE: [&str; 36] = [
"string/memchr.c",
"string/memrchr.c",
"string/stpcpy.c",
"string/stpncpy.c",
"string/strcat.c",
"string/strchr.c",
"string/strchrnul.c",
"string/strcmp.c",
"string/strcpy.c",
"string/strcspn.c",
"string/strlen.c",
"string/strncat.c",
"string/strncmp.c",
"string/strncpy.c",
"string/strrchr.c",
"string/strspn.c",
"stdlib/atoi.c",
"stdlib/bsearch.c",
"stdlib/qsort.c",
"stdlib/qsort_nr.c",
"stdlib/strtod.c",
"stdlib/strtol.c",
"math/__fpclassifyl.c",
"math/acosh.c",
"math/asinh.c",
"math/atanh.c",
"math/fmodl.c",
"math/scalbn.c",
"math/scalbnl.c",
"math/sqrt.c",
"math/trunc.c",
"errno/__errno_location.c",
"stdio/__toread.c",
"stdio/__uflow.c",
"internal/floatscan.c",
"internal/shgetc.c",
];
#[cfg(not(feature = "sqlite3mc"))]
const SQLITE3_SOURCE: &str = "sqlite3/sqlite3.c";
#[cfg(feature = "sqlite3mc")]
const SQLITE3_SOURCE: &str = "sqlite3mc/sqlite3mc_amalgamation.c";
let mut cc = cc::Build::new();
cc.warnings(false).target("wasm32-unknown-emscripten");
if cc.get_compiler().to_command().status().is_err() {
panic!("It looks like you don't have the emscripten toolchain: https://emscripten.org/docs/getting_started/downloads.html");
}
cc.file(SQLITE3_SOURCE)
.files(C_SOURCE.map(|s| format!("shim/musl/{s}")))
.file("shim/printf/printf.c");
cc.flags(FULL_FEATURED);
#[cfg(feature = "sqlite3mc")]
cc.flags(SQLITE3_MC_FEATURED);
let target_features = std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();
let target_features = target_features
.split(',')
.map(str::trim)
.collect::<HashSet<_>>();
if target_features.contains("atomics") {
cc.flag("-pthread");
}
cc.include("shim")
.flag("-DPRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD")
.flag("-include")
.flag("shim/wasm-shim.h")
.compile("wsqlite3");
}