2018-10-29 01:16:48 +08:00
use std ::env ;
use std ::path ::Path ;
2021-05-28 15:00:39 +08:00
/// Tells whether we're building for Windows. This is more suitable than a plain
/// `cfg!(windows)`, since the latter does not properly handle cross-compilation
///
/// Note that there is no way to know at compile-time which system we'll be
/// targetting, and this test must be made at run-time (of the build script) See
/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
fn win_target ( ) -> bool {
std ::env ::var ( " CARGO_CFG_WINDOWS " ) . is_ok ( )
}
/// Tells whether we're building for Android.
/// See [`win_target`]
#[ cfg(any(feature = " bundled " , feature = " bundled-windows " )) ]
fn android_target ( ) -> bool {
std ::env ::var ( " CARGO_CFG_TARGET_OS " ) . map_or ( false , | v | v = = " android " )
}
/// Tells whether a given compiler will be used `compiler_name` is compared to
/// the content of `CARGO_CFG_TARGET_ENV` (and is always lowercase)
///
/// See [`win_target`]
fn is_compiler ( compiler_name : & str ) -> bool {
std ::env ::var ( " CARGO_CFG_TARGET_ENV " ) . map_or ( false , | v | v = = compiler_name )
}
2017-03-04 03:57:40 +08:00
fn main ( ) {
2018-10-29 01:16:48 +08:00
let out_dir = env ::var ( " OUT_DIR " ) . unwrap ( ) ;
let out_path = Path ::new ( & out_dir ) . join ( " bindgen.rs " ) ;
2020-04-03 00:12:36 +08:00
if cfg! ( feature = " in_gecko " ) {
// When inside mozilla-central, we are included into the build with
// sqlite3.o directly, so we don't want to provide any linker arguments.
std ::fs ::copy ( " sqlite3/bindgen_bundled_version.rs " , out_path )
. expect ( " Could not copy bindings to output directory " ) ;
return ;
}
2021-06-03 03:07:56 +08:00
if cfg! ( all (
feature = " sqlcipher " ,
not ( feature = " bundled-sqlcipher " )
) ) {
2021-05-28 15:00:39 +08:00
if cfg! ( feature = " bundled " ) | | ( win_target ( ) & & cfg! ( feature = " bundled-windows " ) ) {
2019-04-20 01:22:03 +08:00
println! (
2021-06-03 03:07:56 +08:00
" cargo:warning=For backwards compatibility, feature 'sqlcipher' overrides
features ' bundled ' and ' bundled - windows ' . If you want a bundled build of
SQLCipher ( available for the moment only on Unix ) , use feature ' bundled - sqlcipher '
or ' bundled - sqlcipher - vendored - openssl ' to also bundle OpenSSL crypto . "
)
2019-04-20 01:22:03 +08:00
}
build_linked ::main ( & out_dir , & out_path )
2021-06-03 03:07:56 +08:00
} else if cfg! ( feature = " bundled " )
| | ( win_target ( ) & & cfg! ( feature = " bundled-windows " ) )
| | cfg! ( feature = " bundled-sqlcipher " )
{
#[ cfg(any(
feature = " bundled " ,
feature = " bundled-windows " ,
feature = " bundled-sqlcipher "
) ) ]
2021-05-28 15:00:39 +08:00
build_bundled ::main ( & out_dir , & out_path ) ;
2021-06-03 03:07:56 +08:00
#[ cfg(not(any(
feature = " bundled " ,
feature = " bundled-windows " ,
feature = " bundled-sqlcipher "
) ) ) ]
2021-05-28 15:00:39 +08:00
panic! ( " The runtime test should not run this branch, which has not compiled any logic. " )
2019-04-20 01:22:03 +08:00
} else {
2021-05-28 15:00:39 +08:00
build_linked ::main ( & out_dir , & out_path )
2019-04-20 01:22:03 +08:00
}
2017-02-08 09:37:52 +08:00
}
2021-06-03 03:07:56 +08:00
#[ cfg(any(
feature = " bundled " ,
feature = " bundled-windows " ,
feature = " bundled-sqlcipher "
) ) ]
2019-04-20 01:22:03 +08:00
mod build_bundled {
2019-05-16 00:41:23 +08:00
use std ::env ;
2021-06-03 03:07:56 +08:00
use std ::ffi ::OsString ;
use std ::path ::{ Path , PathBuf } ;
2017-02-09 10:41:34 +08:00
2021-05-28 15:00:39 +08:00
use super ::{ is_compiler , win_target } ;
2018-10-29 01:16:48 +08:00
pub fn main ( out_dir : & str , out_path : & Path ) {
2021-06-03 03:07:56 +08:00
let lib_name = super ::lib_name ( ) ;
2017-10-24 16:54:48 +08:00
2021-05-28 15:00:39 +08:00
if cfg! ( feature = " bundled-windows " ) & & ! cfg! ( feature = " bundled " ) & & ! win_target ( ) {
// This is just a sanity check, the top level `main` should ensure this.
panic! ( " This module should not be used: we're not on Windows and the bundled feature has not been enabled " ) ;
}
2018-10-29 01:16:48 +08:00
#[ cfg(feature = " buildtime_bindgen " ) ]
{
use super ::{ bindings , HeaderLocation } ;
2021-06-03 03:07:56 +08:00
let header = HeaderLocation ::FromPath ( format! ( " {} /sqlite3.h " , lib_name ) ) ;
2018-10-29 01:16:48 +08:00
bindings ::write_to_out_dir ( header , out_path ) ;
}
#[ cfg(not(feature = " buildtime_bindgen " )) ]
{
use std ::fs ;
2021-06-03 03:07:56 +08:00
fs ::copy ( format! ( " {} /bindgen_bundled_version.rs " , lib_name ) , out_path )
2018-10-29 01:16:48 +08:00
. expect ( " Could not copy bindings to output directory " ) ;
}
2021-06-03 03:07:56 +08:00
// println!("cargo:rerun-if-changed=sqlite3/sqlite3.c");
// println!("cargo:rerun-if-changed=sqlcipher/sqlite3.c");
println! ( " cargo:rerun-if-changed= {} /sqlite3.c " , lib_name ) ;
2020-07-17 17:09:56 +08:00
println! ( " cargo:rerun-if-changed=sqlite3/wasm32-wasi-vfs.c " ) ;
2017-09-21 03:28:19 +08:00
let mut cfg = cc ::Build ::new ( ) ;
2021-06-03 03:07:56 +08:00
cfg . file ( format! ( " {} /sqlite3.c " , lib_name ) )
2017-03-04 03:57:40 +08:00
. flag ( " -DSQLITE_CORE " )
. flag ( " -DSQLITE_DEFAULT_FOREIGN_KEYS=1 " )
. flag ( " -DSQLITE_ENABLE_API_ARMOR " )
. flag ( " -DSQLITE_ENABLE_COLUMN_METADATA " )
. flag ( " -DSQLITE_ENABLE_DBSTAT_VTAB " )
. flag ( " -DSQLITE_ENABLE_FTS3 " )
. flag ( " -DSQLITE_ENABLE_FTS3_PARENTHESIS " )
. flag ( " -DSQLITE_ENABLE_FTS5 " )
. flag ( " -DSQLITE_ENABLE_JSON1 " )
. flag ( " -DSQLITE_ENABLE_LOAD_EXTENSION=1 " )
. flag ( " -DSQLITE_ENABLE_MEMORY_MANAGEMENT " )
. flag ( " -DSQLITE_ENABLE_RTREE " )
. flag ( " -DSQLITE_ENABLE_STAT2 " )
. flag ( " -DSQLITE_ENABLE_STAT4 " )
. flag ( " -DSQLITE_SOUNDEX " )
. flag ( " -DSQLITE_THREADSAFE=1 " )
. flag ( " -DSQLITE_USE_URI " )
2020-04-07 01:43:43 +08:00
. flag ( " -DHAVE_USLEEP=1 " )
2020-06-27 19:37:26 +08:00
. flag ( " -D_POSIX_THREAD_SAFE_FUNCTIONS " ) // cross compile with MinGW
2020-04-07 01:43:43 +08:00
. warnings ( false ) ;
2020-04-16 17:38:40 +08:00
2021-06-03 03:07:56 +08:00
if cfg! ( feature = " bundled-sqlcipher " ) {
cfg . flag ( " -DSQLITE_HAS_CODEC " ) . flag ( " -DSQLITE_TEMP_STORE=2 " ) ;
let target = env ::var ( " TARGET " ) . unwrap ( ) ;
let host = env ::var ( " HOST " ) . unwrap ( ) ;
let is_windows = host . contains ( " windows " ) & & target . contains ( " windows " ) ;
let is_apple = host . contains ( " apple " ) & & target . contains ( " apple " ) ;
let lib_dir = env ( " OPENSSL_LIB_DIR " ) . map ( PathBuf ::from ) ;
let inc_dir = env ( " OPENSSL_INCLUDE_DIR " ) . map ( PathBuf ::from ) ;
let mut use_openssl = false ;
let ( lib_dir , inc_dir ) = match ( lib_dir , inc_dir ) {
( Some ( lib_dir ) , Some ( inc_dir ) ) = > {
use_openssl = true ;
( lib_dir , inc_dir )
}
( lib_dir , inc_dir ) = > match find_openssl_dir ( & host , & target ) {
None = > {
if is_windows & & ! cfg! ( feature = " bundled-sqlcipher-vendored-openssl " ) {
panic! ( " Missing environment variable OPENSSL_DIR or OPENSSL_DIR is not set " )
} else {
( PathBuf ::new ( ) , PathBuf ::new ( ) )
}
}
Some ( openssl_dir ) = > {
let lib_dir = lib_dir . unwrap_or_else ( | | openssl_dir . join ( " lib " ) ) ;
let inc_dir = inc_dir . unwrap_or_else ( | | openssl_dir . join ( " include " ) ) ;
if ! Path ::new ( & lib_dir ) . exists ( ) {
panic! (
" OpenSSL library directory does not exist: {} " ,
lib_dir . to_string_lossy ( )
) ;
}
if ! Path ::new ( & inc_dir ) . exists ( ) {
panic! (
" OpenSSL include directory does not exist: {} " ,
inc_dir . to_string_lossy ( )
)
}
use_openssl = true ;
( lib_dir , inc_dir )
}
} ,
} ;
if cfg! ( feature = " bundled-sqlcipher-vendored-openssl " ) {
cfg . include ( std ::env ::var ( " DEP_OPENSSL_INCLUDE " ) . unwrap ( ) ) ;
2021-10-06 13:04:04 +08:00
// cargo will resolve downstream to the static lib in openssl-sys
2021-06-03 03:07:56 +08:00
} else if is_windows {
2021-10-06 13:04:04 +08:00
// Windows without `-vendored-openssl` takes this to link against a prebuilt OpenSSL lib
2021-06-03 03:07:56 +08:00
cfg . include ( inc_dir . to_string_lossy ( ) . as_ref ( ) ) ;
2021-10-06 13:04:04 +08:00
let lib = lib_dir . join ( " libcrypto.lib " ) ;
cfg . flag ( lib . to_string_lossy ( ) . as_ref ( ) ) ;
2021-06-03 03:07:56 +08:00
} else if use_openssl {
cfg . include ( inc_dir . to_string_lossy ( ) . as_ref ( ) ) ;
2021-10-06 13:04:04 +08:00
// branch not taken on Windows, just `crypto` is fine.
2021-06-03 03:07:56 +08:00
println! ( " cargo:rustc-link-lib=dylib=crypto " ) ;
2021-10-06 13:04:04 +08:00
println! ( " cargo:rustc-link-search= {} " , lib_dir . to_string_lossy ( ) ) ;
2021-06-03 03:07:56 +08:00
} else if is_apple {
cfg . flag ( " -DSQLCIPHER_CRYPTO_CC " ) ;
println! ( " cargo:rustc-link-lib=framework=SecurityFoundation " ) ;
println! ( " cargo:rustc-link-lib=framework=CoreFoundation " ) ;
} else {
2021-10-06 13:04:04 +08:00
// branch not taken on Windows, just `crypto` is fine.
2021-06-03 03:07:56 +08:00
println! ( " cargo:rustc-link-lib=dylib=crypto " ) ;
}
}
2021-04-17 01:27:59 +08:00
// on android sqlite can't figure out where to put the temp files.
// the bundled sqlite on android also uses `SQLITE_TEMP_STORE=3`.
// https://android.googlesource.com/platform/external/sqlite/+/2c8c9ae3b7e6f340a19a0001c2a889a211c9d8b2/dist/Android.mk
2021-05-28 15:00:39 +08:00
if super ::android_target ( ) {
2021-04-17 01:27:59 +08:00
cfg . flag ( " -DSQLITE_TEMP_STORE=3 " ) ;
}
2020-04-16 17:38:40 +08:00
if cfg! ( feature = " with-asan " ) {
cfg . flag ( " -fsanitize=address " ) ;
}
2021-09-27 21:01:48 +08:00
// If explicitly requested: enable static linking against the Microsoft Visual C++ Runtime to avoid dependencies on vcruntime140.dll and similar libraries.
if cfg! ( target_feature = " crt-static " ) & & is_compiler ( " msvc " ) {
cfg . static_crt ( true ) ;
}
2019-08-10 02:03:46 +08:00
// Older versions of visual studio don't support c99 (including isnan), which
// causes a build failure when the linker fails to find the `isnan`
2021-05-02 19:46:04 +08:00
// function. `sqlite` provides its own implementation, using the fact
2019-08-10 02:03:46 +08:00
// that x != x when x is NaN.
2019-05-10 20:42:02 +08:00
//
2019-08-10 02:03:46 +08:00
// There may be other platforms that don't support `isnan`, they should be
// tested for here.
2021-05-28 15:00:39 +08:00
if is_compiler ( " msvc " ) {
2019-08-17 14:18:37 +08:00
use cc ::windows_registry ::{ find_vs_version , VsVers } ;
2019-05-10 20:42:02 +08:00
let vs_has_nan = match find_vs_version ( ) {
Ok ( ver ) = > ver ! = VsVers ::Vs12 ,
Err ( _msg ) = > false ,
} ;
if vs_has_nan {
2020-06-11 05:06:16 +08:00
cfg . flag ( " -DHAVE_ISNAN " ) ;
2019-05-10 20:42:02 +08:00
}
} else {
2020-06-11 05:06:16 +08:00
cfg . flag ( " -DHAVE_ISNAN " ) ;
2019-05-10 20:42:02 +08:00
}
2021-05-28 15:00:39 +08:00
if ! win_target ( ) {
2020-05-30 07:32:19 +08:00
cfg . flag ( " -DHAVE_LOCALTIME_R " ) ;
}
2020-07-17 17:09:56 +08:00
// Target wasm32-wasi can't compile the default VFS
2021-05-28 15:00:39 +08:00
if is_compiler ( " wasm32-wasi " ) {
2020-07-21 02:04:55 +08:00
cfg . flag ( " -DSQLITE_OS_OTHER " )
2020-07-17 17:09:56 +08:00
// https://github.com/rust-lang/rust/issues/74393
. flag ( " -DLONGDOUBLE_TYPE=double " ) ;
2020-07-21 02:04:55 +08:00
if cfg! ( feature = " wasm32-wasi-vfs " ) {
cfg . file ( " sqlite3/wasm32-wasi-vfs.c " ) ;
}
2020-07-17 17:09:56 +08:00
}
2017-09-21 03:28:19 +08:00
if cfg! ( feature = " unlock_notify " ) {
cfg . flag ( " -DSQLITE_ENABLE_UNLOCK_NOTIFY " ) ;
}
2019-01-13 19:46:19 +08:00
if cfg! ( feature = " preupdate_hook " ) {
cfg . flag ( " -DSQLITE_ENABLE_PREUPDATE_HOOK " ) ;
}
if cfg! ( feature = " session " ) {
cfg . flag ( " -DSQLITE_ENABLE_SESSION " ) ;
}
2019-05-16 02:23:20 +08:00
2019-05-16 00:41:23 +08:00
if let Ok ( limit ) = env ::var ( " SQLITE_MAX_VARIABLE_NUMBER " ) {
cfg . flag ( & format! ( " -DSQLITE_MAX_VARIABLE_NUMBER= {} " , limit ) ) ;
}
2019-05-16 02:23:20 +08:00
println! ( " cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER " ) ;
2019-05-16 00:41:23 +08:00
if let Ok ( limit ) = env ::var ( " SQLITE_MAX_EXPR_DEPTH " ) {
cfg . flag ( & format! ( " -DSQLITE_MAX_EXPR_DEPTH= {} " , limit ) ) ;
}
2019-05-16 02:23:20 +08:00
println! ( " cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH " ) ;
2019-05-16 00:41:23 +08:00
2020-06-11 05:06:47 +08:00
if let Ok ( extras ) = env ::var ( " LIBSQLITE3_FLAGS " ) {
for extra in extras . split_whitespace ( ) {
if extra . starts_with ( " -D " ) | | extra . starts_with ( " -U " ) {
cfg . flag ( extra ) ;
} else if extra . starts_with ( " SQLITE_ " ) {
cfg . flag ( & format! ( " -D {} " , extra ) ) ;
} else {
panic! ( " Don't understand {} in LIBSQLITE3_FLAGS " , extra ) ;
}
}
}
println! ( " cargo:rerun-if-env-changed=LIBSQLITE3_FLAGS " ) ;
2021-06-03 03:07:56 +08:00
cfg . compile ( lib_name ) ;
2018-06-30 06:20:59 +08:00
println! ( " cargo:lib_dir= {} " , out_dir ) ;
2017-03-04 03:57:40 +08:00
}
2021-06-03 03:07:56 +08:00
fn env ( name : & str ) -> Option < OsString > {
let prefix = env ::var ( " TARGET " ) . unwrap ( ) . to_uppercase ( ) . replace ( " - " , " _ " ) ;
let prefixed = format! ( " {} _ {} " , prefix , name ) ;
let var = env ::var_os ( & prefixed ) ;
match var {
None = > env ::var_os ( name ) ,
_ = > var ,
}
}
fn find_openssl_dir ( _host : & str , _target : & str ) -> Option < PathBuf > {
let openssl_dir = env ( " OPENSSL_DIR " ) ;
openssl_dir . map ( PathBuf ::from )
}
2017-02-08 09:37:52 +08:00
}
2018-10-29 01:16:48 +08:00
fn env_prefix ( ) -> & 'static str {
2021-06-03 03:07:56 +08:00
if cfg! ( any ( feature = " sqlcipher " , feature = " bundled-sqlcipher " ) ) {
2018-10-29 01:16:48 +08:00
" SQLCIPHER "
} else {
" SQLITE3 "
}
}
2021-06-03 03:07:56 +08:00
fn lib_name ( ) -> & 'static str {
if cfg! ( any ( feature = " sqlcipher " , feature = " bundled-sqlcipher " ) ) {
" sqlcipher "
} else if cfg! ( all ( windows , feature = " winsqlite3 " ) ) {
" winsqlite3 "
} else {
" sqlite3 "
}
}
2018-10-29 01:16:48 +08:00
pub enum HeaderLocation {
FromEnvironment ,
Wrapper ,
FromPath ( String ) ,
}
impl From < HeaderLocation > for String {
fn from ( header : HeaderLocation ) -> String {
match header {
HeaderLocation ::FromEnvironment = > {
let prefix = env_prefix ( ) ;
2019-12-20 03:08:04 +08:00
let mut header = env ::var ( format! ( " {} _INCLUDE_DIR " , prefix ) ) . unwrap_or_else ( | _ | {
panic! (
" {}_INCLUDE_DIR must be set if {}_LIB_DIR is set " ,
prefix , prefix
)
} ) ;
2018-10-29 01:16:48 +08:00
header . push_str ( " /sqlite3.h " ) ;
header
}
HeaderLocation ::Wrapper = > " wrapper.h " . into ( ) ,
HeaderLocation ::FromPath ( path ) = > path ,
}
}
}
2019-04-20 01:22:03 +08:00
mod build_linked {
2021-05-28 15:00:39 +08:00
#[ cfg(feature = " vcpkg " ) ]
2017-05-28 11:35:46 +08:00
extern crate vcpkg ;
2021-06-03 03:07:56 +08:00
use super ::{ bindings , env_prefix , is_compiler , lib_name , win_target , HeaderLocation } ;
2017-03-04 03:57:40 +08:00
use std ::env ;
2018-10-29 01:16:48 +08:00
use std ::path ::Path ;
2017-03-04 03:57:40 +08:00
2018-10-29 01:16:48 +08:00
pub fn main ( _out_dir : & str , out_path : & Path ) {
2017-03-04 03:57:40 +08:00
let header = find_sqlite ( ) ;
2021-06-03 03:07:56 +08:00
if ( cfg! ( any (
feature = " bundled_bindings " ,
feature = " bundled " ,
feature = " bundled-sqlcipher "
) ) | | ( win_target ( ) & & cfg! ( feature = " bundled-windows " ) ) )
2021-05-28 15:00:39 +08:00
& & ! cfg! ( feature = " buildtime_bindgen " )
2019-06-26 02:40:28 +08:00
{
2021-06-03 03:07:56 +08:00
// Generally means the `bundled_bindings` feature is enabled.
// Most users are better off with turning
2020-01-15 00:11:36 +08:00
// on buildtime_bindgen instead, but this is still supported as we
// have runtime version checks and there are good reasons to not
// want to run bindgen.
2021-06-03 03:07:56 +08:00
std ::fs ::copy (
format! ( " {} /bindgen_bundled_version.rs " , lib_name ( ) ) ,
out_path ,
)
. expect ( " Could not copy bindings to output directory " ) ;
2019-04-20 01:22:03 +08:00
} else {
bindings ::write_to_out_dir ( header , out_path ) ;
}
2017-02-08 09:37:52 +08:00
}
2018-12-15 09:12:31 +08:00
fn find_link_mode ( ) -> & 'static str {
2020-06-25 01:53:45 +08:00
// If the user specifies SQLITE3_STATIC (or SQLCIPHER_STATIC), do static
2018-12-15 09:12:31 +08:00
// linking, unless it's explicitly set to 0.
match & env ::var ( format! ( " {} _STATIC " , env_prefix ( ) ) ) {
Ok ( v ) if v ! = " 0 " = > " static " ,
_ = > " dylib " ,
}
}
2017-03-04 03:57:40 +08:00
// Prints the necessary cargo link commands and returns the path to the header.
2017-03-04 04:16:49 +08:00
fn find_sqlite ( ) -> HeaderLocation {
2021-06-03 03:07:56 +08:00
let link_lib = lib_name ( ) ;
2017-10-24 16:54:48 +08:00
2018-04-07 04:27:07 +08:00
println! ( " cargo:rerun-if-env-changed= {} _INCLUDE_DIR " , env_prefix ( ) ) ;
println! ( " cargo:rerun-if-env-changed= {} _LIB_DIR " , env_prefix ( ) ) ;
2018-12-15 09:12:31 +08:00
println! ( " cargo:rerun-if-env-changed= {} _STATIC " , env_prefix ( ) ) ;
2021-05-28 15:00:39 +08:00
if cfg! ( feature = " vcpkg " ) & & is_compiler ( " msvc " ) {
2019-03-25 04:21:13 +08:00
println! ( " cargo:rerun-if-env-changed=VCPKGRS_DYNAMIC " ) ;
}
2020-01-08 15:48:19 +08:00
// dependents can access `DEP_SQLITE3_LINK_TARGET` (`sqlite3` being the
// `links=` value in our Cargo.toml) to get this value. This might be
// useful if you need to ensure whatever crypto library sqlcipher relies
// on is available, for example.
println! ( " cargo:link-target= {} " , link_lib ) ;
2021-05-28 15:00:39 +08:00
if win_target ( ) & & cfg! ( feature = " winsqlite3 " ) {
2020-08-18 06:33:50 +08:00
println! ( " cargo:rustc-link-lib=dylib= {} " , link_lib ) ;
return HeaderLocation ::Wrapper ;
}
2017-03-04 03:57:40 +08:00
// Allow users to specify where to find SQLite.
2017-10-24 16:54:48 +08:00
if let Ok ( dir ) = env ::var ( format! ( " {} _LIB_DIR " , env_prefix ( ) ) ) {
2019-02-05 12:53:57 +08:00
// Try to use pkg-config to determine link commands
let pkgconfig_path = Path ::new ( & dir ) . join ( " pkgconfig " ) ;
env ::set_var ( " PKG_CONFIG_PATH " , pkgconfig_path ) ;
2019-12-20 03:08:04 +08:00
if pkg_config ::Config ::new ( ) . probe ( link_lib ) . is_err ( ) {
2019-02-05 12:53:57 +08:00
// Otherwise just emit the bare minimum link commands.
println! ( " cargo:rustc-link-lib= {} = {} " , find_link_mode ( ) , link_lib ) ;
println! ( " cargo:rustc-link-search= {} " , dir ) ;
}
2017-03-04 04:16:49 +08:00
return HeaderLocation ::FromEnvironment ;
2017-03-04 03:57:40 +08:00
}
2017-05-28 11:35:46 +08:00
if let Some ( header ) = try_vcpkg ( ) {
return header ;
}
2017-03-04 03:57:40 +08:00
// See if pkg-config can do everything for us.
2018-08-11 18:48:21 +08:00
match pkg_config ::Config ::new ( )
. print_system_libs ( false )
. probe ( link_lib )
{
2017-03-04 03:57:40 +08:00
Ok ( mut lib ) = > {
if let Some ( mut header ) = lib . include_paths . pop ( ) {
header . push ( " sqlite3.h " ) ;
2017-03-04 04:16:49 +08:00
HeaderLocation ::FromPath ( header . to_string_lossy ( ) . into ( ) )
2017-03-04 03:57:40 +08:00
} else {
2017-03-04 04:16:49 +08:00
HeaderLocation ::Wrapper
2017-03-04 03:57:40 +08:00
}
}
Err ( _ ) = > {
// No env var set and pkg-config couldn't help; just output the link-lib
// request and hope that the library exists on the system paths. We used to
2018-10-29 01:16:48 +08:00
// output /usr/lib explicitly, but that can introduce other linking problems;
2020-04-16 12:07:23 +08:00
// see https://github.com/rusqlite/rusqlite/issues/207.
2018-12-15 09:12:31 +08:00
println! ( " cargo:rustc-link-lib= {} = {} " , find_link_mode ( ) , link_lib ) ;
2017-03-04 04:16:49 +08:00
HeaderLocation ::Wrapper
2017-02-08 09:37:52 +08:00
}
2017-01-24 09:17:14 +08:00
}
2017-03-04 03:57:40 +08:00
}
2017-05-28 11:35:46 +08:00
fn try_vcpkg ( ) -> Option < HeaderLocation > {
2021-05-28 15:00:39 +08:00
if cfg! ( feature = " vcpkg " ) & & is_compiler ( " msvc " ) {
// See if vcpkg can find it.
2021-06-03 03:07:56 +08:00
if let Ok ( mut lib ) = vcpkg ::Config ::new ( ) . probe ( lib_name ( ) ) {
2021-05-28 15:00:39 +08:00
if let Some ( mut header ) = lib . include_paths . pop ( ) {
header . push ( " sqlite3.h " ) ;
return Some ( HeaderLocation ::FromPath ( header . to_string_lossy ( ) . into ( ) ) ) ;
}
2017-05-28 11:35:46 +08:00
}
2021-05-28 15:00:39 +08:00
None
} else {
None
2017-05-28 11:35:46 +08:00
}
}
2018-10-29 01:16:48 +08:00
}
2017-10-24 16:54:48 +08:00
2019-04-20 01:22:03 +08:00
#[ cfg(not(feature = " buildtime_bindgen " )) ]
2018-10-29 01:16:48 +08:00
mod bindings {
2021-06-03 03:07:56 +08:00
#![ allow(dead_code) ]
2018-10-29 01:16:48 +08:00
use super ::HeaderLocation ;
use std ::fs ;
use std ::path ::Path ;
2020-03-14 14:41:57 +08:00
static PREBUILT_BINDGEN_PATHS : & [ & str ] = & [
2018-10-29 01:16:48 +08:00
" bindgen-bindings/bindgen_3.6.8.rs " ,
#[ cfg(feature = " min_sqlite_version_3_6_23 " ) ]
" bindgen-bindings/bindgen_3.6.23.rs " ,
#[ cfg(feature = " min_sqlite_version_3_7_7 " ) ]
" bindgen-bindings/bindgen_3.7.7.rs " ,
2019-01-06 16:50:35 +08:00
#[ cfg(feature = " min_sqlite_version_3_7_16 " ) ]
" bindgen-bindings/bindgen_3.7.16.rs " ,
2018-10-29 01:16:48 +08:00
] ;
pub fn write_to_out_dir ( _header : HeaderLocation , out_path : & Path ) {
let in_path = PREBUILT_BINDGEN_PATHS [ PREBUILT_BINDGEN_PATHS . len ( ) - 1 ] ;
fs ::copy ( in_path , out_path ) . expect ( " Could not copy bindings to output directory " ) ;
2017-02-08 09:37:52 +08:00
}
2018-10-29 01:16:48 +08:00
}
2016-06-15 22:34:13 +08:00
2018-10-29 01:16:48 +08:00
#[ cfg(feature = " buildtime_bindgen " ) ]
mod bindings {
use super ::HeaderLocation ;
2019-08-17 14:18:37 +08:00
use bindgen ::callbacks ::{ IntKind , ParseCallbacks } ;
2017-03-04 03:57:40 +08:00
2018-10-29 01:16:48 +08:00
use std ::fs ::OpenOptions ;
use std ::io ::Write ;
use std ::path ::Path ;
2017-03-04 03:57:40 +08:00
2021-05-28 15:00:39 +08:00
use super ::win_target ;
2018-10-29 01:16:48 +08:00
#[ derive(Debug) ]
struct SqliteTypeChooser ;
2017-03-04 03:57:40 +08:00
2018-10-29 01:16:48 +08:00
impl ParseCallbacks for SqliteTypeChooser {
fn int_macro ( & self , _name : & str , value : i64 ) -> Option < IntKind > {
if value > = i32 ::min_value ( ) as i64 & & value < = i32 ::max_value ( ) as i64 {
Some ( IntKind ::I32 )
} else {
None
2017-03-04 03:57:40 +08:00
}
}
2018-10-29 01:16:48 +08:00
}
2017-03-04 03:57:40 +08:00
2020-04-10 16:38:55 +08:00
// Are we generating the bundled bindings? Used to avoid emitting things
// that would be problematic in bundled builds. This env var is set by
// `upgrade.sh`.
fn generating_bundled_bindings ( ) -> bool {
// Hacky way to know if we're generating the bundled bindings
println! ( " cargo:rerun-if-env-changed=LIBSQLITE3_SYS_BUNDLING " ) ;
2021-05-06 00:29:16 +08:00
match std ::env ::var ( " LIBSQLITE3_SYS_BUNDLING " ) {
Ok ( v ) = > v ! = " 0 " ,
Err ( _ ) = > false ,
}
2020-04-10 16:38:55 +08:00
}
2018-10-29 01:16:48 +08:00
pub fn write_to_out_dir ( header : HeaderLocation , out_path : & Path ) {
let header : String = header . into ( ) ;
let mut output = Vec ::new ( ) ;
2019-01-13 19:46:19 +08:00
let mut bindings = bindgen ::builder ( )
2021-06-03 03:07:56 +08:00
. trust_clang_mangling ( false )
2018-10-29 01:16:48 +08:00
. header ( header . clone ( ) )
. parse_callbacks ( Box ::new ( SqliteTypeChooser ) )
2019-01-13 19:46:19 +08:00
. rustfmt_bindings ( true ) ;
2021-06-03 03:07:56 +08:00
if cfg! ( any ( feature = " sqlcipher " , feature = " bundled-sqlcipher " ) ) {
bindings = bindings . clang_arg ( " -DSQLITE_HAS_CODEC " ) ;
}
2019-01-13 19:46:19 +08:00
if cfg! ( feature = " unlock_notify " ) {
bindings = bindings . clang_arg ( " -DSQLITE_ENABLE_UNLOCK_NOTIFY " ) ;
}
if cfg! ( feature = " preupdate_hook " ) {
bindings = bindings . clang_arg ( " -DSQLITE_ENABLE_PREUPDATE_HOOK " ) ;
}
if cfg! ( feature = " session " ) {
bindings = bindings . clang_arg ( " -DSQLITE_ENABLE_SESSION " ) ;
}
2021-05-28 15:00:39 +08:00
if win_target ( ) & & cfg! ( feature = " winsqlite3 " ) {
2020-08-18 06:33:50 +08:00
bindings = bindings
. clang_arg ( " -DBINDGEN_USE_WINSQLITE3 " )
2021-04-05 23:35:23 +08:00
. blocklist_item ( " NTDDI_.+ " )
. blocklist_item ( " WINAPI_FAMILY.* " )
. blocklist_item ( " _WIN32_.+ " )
. blocklist_item ( " _VCRT_COMPILER_PREPROCESSOR " )
. blocklist_item ( " _SAL_VERSION " )
. blocklist_item ( " __SAL_H_VERSION " )
. blocklist_item ( " _USE_DECLSPECS_FOR_SAL " )
. blocklist_item ( " _USE_ATTRIBUTES_FOR_SAL " )
. blocklist_item ( " _CRT_PACKING " )
. blocklist_item ( " _HAS_EXCEPTIONS " )
. blocklist_item ( " _STL_LANG " )
. blocklist_item ( " _HAS_CXX17 " )
. blocklist_item ( " _HAS_CXX20 " )
. blocklist_item ( " _HAS_NODISCARD " )
. blocklist_item ( " WDK_NTDDI_VERSION " )
. blocklist_item ( " OSVERSION_MASK " )
. blocklist_item ( " SPVERSION_MASK " )
. blocklist_item ( " SUBVERSION_MASK " )
. blocklist_item ( " WINVER " )
. blocklist_item ( " __security_cookie " )
. blocklist_type ( " size_t " )
. blocklist_type ( " __vcrt_bool " )
. blocklist_type ( " wchar_t " )
. blocklist_function ( " __security_init_cookie " )
. blocklist_function ( " __report_gsfailure " )
. blocklist_function ( " __va_start " ) ;
2020-08-18 06:33:50 +08:00
}
2019-01-13 19:46:19 +08:00
2020-04-10 16:38:55 +08:00
// When cross compiling unless effort is taken to fix the issue, bindgen
// will find the wrong headers. There's only one header included by the
// amalgamated `sqlite.h`: `stdarg.h`.
//
// Thankfully, there's almost no case where rust code needs to use
// functions taking `va_list` (It's nearly impossible to get a `va_list`
// in Rust unless you get passed it by C code for some reason).
//
// Arguably, we should never be including these, but we include them for
// the cases where they aren't totally broken...
let target_arch = std ::env ::var ( " TARGET " ) . unwrap ( ) ;
let host_arch = std ::env ::var ( " HOST " ) . unwrap ( ) ;
let is_cross_compiling = target_arch ! = host_arch ;
// Note that when generating the bundled file, we're essentially always
// cross compiling.
if generating_bundled_bindings ( ) | | is_cross_compiling {
// Get rid of va_list, as it's not
bindings = bindings
2021-04-05 23:35:23 +08:00
. blocklist_function ( " sqlite3_vmprintf " )
. blocklist_function ( " sqlite3_vsnprintf " )
. blocklist_function ( " sqlite3_str_vappendf " )
. blocklist_type ( " va_list " )
. blocklist_type ( " __builtin_va_list " )
. blocklist_type ( " __gnuc_va_list " )
. blocklist_type ( " __va_list_tag " )
. blocklist_item ( " __GNUC_VA_LIST " ) ;
2020-04-10 16:38:55 +08:00
}
2019-01-13 19:46:19 +08:00
bindings
2018-10-29 01:16:48 +08:00
. generate ( )
2019-12-20 03:08:04 +08:00
. unwrap_or_else ( | _ | panic! ( " could not run bindgen on header {} " , header ) )
2018-10-29 01:16:48 +08:00
. write ( Box ::new ( & mut output ) )
. expect ( " could not write output of bindgen " ) ;
let mut output = String ::from_utf8 ( output ) . expect ( " bindgen output was not UTF-8?! " ) ;
// rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it
// can. This flag was added in SQLite 3.8.3, but oring it in in prior
// versions of SQLite is harmless. We don't want to not build just
// because this flag is missing (e.g., if we're linking against
// SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's
// output.
if ! output . contains ( " pub const SQLITE_DETERMINISTIC " ) {
output . push_str ( " \n pub const SQLITE_DETERMINISTIC: i32 = 2048; \n " ) ;
}
2017-03-04 03:57:40 +08:00
2018-10-29 01:16:48 +08:00
let mut file = OpenOptions ::new ( )
. write ( true )
. truncate ( true )
. create ( true )
2019-12-20 03:08:04 +08:00
. open ( out_path )
. unwrap_or_else ( | _ | panic! ( " Could not write to {:?} " , out_path ) ) ;
2017-03-04 03:57:40 +08:00
2018-10-29 01:16:48 +08:00
file . write_all ( output . as_bytes ( ) )
2019-12-20 03:08:04 +08:00
. unwrap_or_else ( | _ | panic! ( " Could not write to {:?} " , out_path ) ) ;
2017-03-04 03:57:40 +08:00
}
2016-06-15 22:34:13 +08:00
}