diff --git a/libsqlite3-sys/build.rs b/libsqlite3-sys/build.rs index 8766566..a98662c 100644 --- a/libsqlite3-sys/build.rs +++ b/libsqlite3-sys/build.rs @@ -1,22 +1,34 @@ +use std::env; +use std::path::Path; + fn main() { - build::main(); + let out_dir = env::var("OUT_DIR").unwrap(); + let out_path = Path::new(&out_dir).join("bindgen.rs"); + build::main(&out_dir, &out_path); } #[cfg(feature = "bundled")] mod build { extern crate cc; use std::path::Path; - use std::{env, fs}; - pub fn main() { + pub fn main(out_dir: &str, out_path: &Path) { if cfg!(feature = "sqlcipher") { panic!("Builds with bundled SQLCipher are not supported"); } - let out_dir = env::var("OUT_DIR").unwrap(); - let out_path = Path::new(&out_dir).join("bindgen.rs"); - fs::copy("sqlite3/bindgen_bundled_version.rs", out_path) - .expect("Could not copy bindings to output directory"); + #[cfg(feature = "buildtime_bindgen")] + { + use super::{bindings, HeaderLocation}; + let header = HeaderLocation::FromPath("sqlite3/sqlite3.h".to_owned()); + bindings::write_to_out_dir(header, out_path); + } + #[cfg(not(feature = "buildtime_bindgen"))] + { + use std::fs; + fs::copy("sqlite3/bindgen_bundled_version.rs", out_path) + .expect("Could not copy bindings to output directory"); + } let mut cfg = cc::Build::new(); cfg.file("sqlite3/sqlite3.c") @@ -48,6 +60,38 @@ mod build { } } +fn env_prefix() -> &'static str { + if cfg!(feature = "sqlcipher") { + "SQLCIPHER" + } else { + "SQLITE3" + } +} + +pub enum HeaderLocation { + FromEnvironment, + Wrapper, + FromPath(String), +} + +impl From for String { + fn from(header: HeaderLocation) -> String { + match header { + HeaderLocation::FromEnvironment => { + let prefix = env_prefix(); + let mut header = env::var(format!("{}_INCLUDE_DIR", prefix)).expect(&format!( + "{}_INCLUDE_DIR must be set if {}_LIB_DIR is set", + prefix, prefix + )); + header.push_str("/sqlite3.h"); + header + } + HeaderLocation::Wrapper => "wrapper.h".into(), + HeaderLocation::FromPath(path) => path, + } + } +} + #[cfg(not(feature = "bundled"))] mod build { extern crate pkg_config; @@ -55,35 +99,13 @@ mod build { #[cfg(all(feature = "vcpkg", target_env = "msvc"))] extern crate vcpkg; + use super::{bindings, env_prefix, HeaderLocation}; use std::env; + use std::path::Path; - pub enum HeaderLocation { - FromEnvironment, - Wrapper, - FromPath(String), - } - - impl From for String { - fn from(header: HeaderLocation) -> String { - match header { - HeaderLocation::FromEnvironment => { - let prefix = env_prefix(); - let mut header = env::var(format!("{}_INCLUDE_DIR", prefix)).expect(&format!( - "{}_INCLUDE_DIR must be set if {}_LIB_DIR is set", - prefix, prefix - )); - header.push_str("/sqlite3.h"); - header - } - HeaderLocation::Wrapper => "wrapper.h".into(), - HeaderLocation::FromPath(path) => path, - } - } - } - - pub fn main() { + pub fn main(_out_dir: &str, out_path: &Path) { let header = find_sqlite(); - bindings::write_to_out_dir(header); + bindings::write_to_out_dir(header, out_path); } // Prints the necessary cargo link commands and returns the path to the header. @@ -122,8 +144,8 @@ mod build { 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 - // output /usr/lib explicitly, but that can introduce other linking problems; see - // https://github.com/jgallagher/rusqlite/issues/207. + // output /usr/lib explicitly, but that can introduce other linking problems; + // see https://github.com/jgallagher/rusqlite/issues/207. println!("cargo:rustc-link-lib={}", link_lib); HeaderLocation::Wrapper } @@ -147,14 +169,6 @@ mod build { None } - fn env_prefix() -> &'static str { - if cfg!(feature = "sqlcipher") { - "SQLCIPHER" - } else { - "SQLITE3" - } - } - fn link_lib() -> &'static str { if cfg!(feature = "sqlcipher") { "sqlcipher" @@ -162,88 +176,84 @@ mod build { "sqlite3" } } +} - #[cfg(not(feature = "buildtime_bindgen"))] - mod bindings { - use super::HeaderLocation; +#[cfg(all(not(feature = "buildtime_bindgen"), not(feature = "bundled")))] +mod bindings { + use super::HeaderLocation; - use std::path::Path; - use std::{env, fs}; + use std::fs; + use std::path::Path; - static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[ - "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", - ]; + static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[ + "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", + ]; - pub fn write_to_out_dir(_header: HeaderLocation) { - let out_dir = env::var("OUT_DIR").unwrap(); - let out_path = Path::new(&out_dir).join("bindgen.rs"); - 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"); - } - } - - #[cfg(feature = "buildtime_bindgen")] - mod bindings { - extern crate bindgen; - - use self::bindgen::callbacks::{IntKind, ParseCallbacks}; - use super::HeaderLocation; - - use std::env; - use std::fs::OpenOptions; - use std::io::Write; - use std::path::Path; - - #[derive(Debug)] - struct SqliteTypeChooser; - - impl ParseCallbacks for SqliteTypeChooser { - fn int_macro(&self, _name: &str, value: i64) -> Option { - if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 { - Some(IntKind::I32) - } else { - None - } - } - } - - pub fn write_to_out_dir(header: HeaderLocation) { - let header: String = header.into(); - let out_dir = env::var("OUT_DIR").unwrap(); - let mut output = Vec::new(); - bindgen::builder() - .header(header.clone()) - .parse_callbacks(Box::new(SqliteTypeChooser)) - .rustfmt_bindings(true) - .generate() - .expect(&format!("could not run bindgen on header {}", header)) - .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("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n"); - } - - let path = Path::new(&out_dir).join("bindgen.rs"); - - let mut file = OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(path.clone()) - .expect(&format!("Could not write to {:?}", path)); - - file.write_all(output.as_bytes()) - .expect(&format!("Could not write to {:?}", path)); - } + 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"); + } +} + +#[cfg(feature = "buildtime_bindgen")] +mod bindings { + extern crate bindgen; + + use self::bindgen::callbacks::{IntKind, ParseCallbacks}; + use super::HeaderLocation; + + use std::fs::OpenOptions; + use std::io::Write; + use std::path::Path; + + #[derive(Debug)] + struct SqliteTypeChooser; + + impl ParseCallbacks for SqliteTypeChooser { + fn int_macro(&self, _name: &str, value: i64) -> Option { + if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 { + Some(IntKind::I32) + } else { + None + } + } + } + + pub fn write_to_out_dir(header: HeaderLocation, out_path: &Path) { + let header: String = header.into(); + let mut output = Vec::new(); + bindgen::builder() + .header(header.clone()) + .parse_callbacks(Box::new(SqliteTypeChooser)) + .rustfmt_bindings(true) + .generate() + .expect(&format!("could not run bindgen on header {}", header)) + .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("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n"); + } + + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(out_path.clone()) + .expect(&format!("Could not write to {:?}", out_path)); + + file.write_all(output.as_bytes()) + .expect(&format!("Could not write to {:?}", out_path)); } }