diff --git a/.travis.yml b/.travis.yml index e8d89347..795c9370 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ matrix: # ARM-bit version compat - env: > TARGET=arm-unknown-linux-gnueabihf - BUILD_OPENSSL_VERSION=1.0.2h + BUILD_OPENSSL_VERSION=1.0.2k CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf RUST_TEST_THREADS=1 @@ -32,7 +32,7 @@ matrix: - binfmt-support - env: > TARGET=arm-unknown-linux-gnueabihf - BUILD_OPENSSL_VERSION=1.1.0c + BUILD_OPENSSL_VERSION=1.1.0d CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf RUST_TEST_THREADS=1 @@ -52,8 +52,8 @@ matrix: - rust: nightly # 64-bit version compat - - env: BUILD_OPENSSL_VERSION=1.0.2h - - env: BUILD_OPENSSL_VERSION=1.1.0c + - env: BUILD_OPENSSL_VERSION=1.0.2k + - env: BUILD_OPENSSL_VERSION=1.1.0d # 32-bit version compat - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u @@ -61,12 +61,12 @@ matrix: apt: packages: - gcc-multilib - - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2k addons: apt: packages: - gcc-multilib - - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0c + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0d addons: apt: packages: diff --git a/appveyor.yml b/appveyor.yml index 9b4a3f02..d396bd62 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,20 +5,20 @@ environment: - TARGET: i686-pc-windows-gnu BITS: 32 MSYS2: 1 - OPENSSL_VERSION: 1_1_0c + OPENSSL_VERSION: 1_1_0d - TARGET: x86_64-pc-windows-msvc BITS: 64 - OPENSSL_VERSION: 1_1_0c + OPENSSL_VERSION: 1_1_0d OPENSSL_DIR: C:\OpenSSL # 1.0.2, 64/32 bit - TARGET: x86_64-pc-windows-gnu BITS: 64 MSYS2: 1 - OPENSSL_VERSION: 1_0_2j + OPENSSL_VERSION: 1_0_2k - TARGET: i686-pc-windows-msvc BITS: 32 - OPENSSL_VERSION: 1_0_2j + OPENSSL_VERSION: 1_0_2k OPENSSL_DIR: C:\OpenSSL install: # install OpenSSL diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 1f1750dc..76bd9172 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -16,11 +16,12 @@ libc = "0.2" [build-dependencies] pkg-config = "0.3.9" +gcc = "0.3.42" [target.'cfg(windows)'.dependencies] user32-sys = "0.2" gdi32-sys = "0.2" -# We don't actually use metadeps for annoying reasons but this is still hear for tooling +# We don't actually use metadeps for annoying reasons but this is still here for tooling [package.metadata.pkg-config] openssl = "1.0.1" diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index 0e1cdc46..1b717693 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -1,13 +1,37 @@ extern crate pkg_config; +extern crate gcc; use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs::File; -use std::io::Read; +use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use std::process::Command; +// The set of `OPENSSL_NO_`s that we care about. +const DEFINES: &'static [&'static str] = &[ + "OPENSSL_NO_BUF_FREELISTS", + "OPENSSL_NO_COMP", + "OPENSSL_NO_EC", + "OPENSSL_NO_ENGINE", + "OPENSSL_NO_KRB5", + "OPENSSL_NO_NEXTPROTONEG", + "OPENSSL_NO_PSK", + "OPENSSL_NO_RFC3779", + "OPENSSL_NO_SHA", + "OPENSSL_NO_SRP", + "OPENSSL_NO_SSL3_METHOD", + "OPENSSL_NO_TLSEXT", +]; + +enum Version { + Openssl110, + Openssl102, + Openssl101, + Libressl, +} + fn main() { let target = env::var("TARGET").unwrap(); @@ -38,17 +62,14 @@ fn main() { println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy()); println!("cargo:include={}", include_dir.to_string_lossy()); - let version = validate_headers(&[include_dir.clone().into()], - &[lib_dir.clone().into()]); + let version = validate_headers(&[include_dir.clone().into()]); - let libs = if (version.contains("0x10001") || - version.contains("0x10002")) && - target.contains("windows") { - ["ssleay32", "libeay32"] - } else if target.contains("windows") { - ["libssl", "libcrypto"] - } else { - ["ssl", "crypto"] + let libs = match version { + Version::Openssl101 | Version::Openssl102 if target.contains("windows") => { + ["ssleay32", "libeay32"] + } + Version::Openssl110 if target.contains("windows") => ["libssl", "libcrypto"], + _ => ["ssl", "crypto"], }; let kind = determine_mode(Path::new(&lib_dir), &libs); @@ -209,7 +230,7 @@ See rust-openssl README for more information: "); } - validate_headers(&lib.include_paths, &lib.link_paths); + validate_headers(&lib.include_paths); for include in lib.include_paths.iter() { println!("cargo:include={}", include.display()); @@ -225,74 +246,11 @@ See rust-openssl README for more information: /// Validates the header files found in `include_dir` and then returns the /// version string of OpenSSL. -fn validate_headers(include_dirs: &[PathBuf], - libdirs: &[PathBuf]) -> String { +fn validate_headers(include_dirs: &[PathBuf]) -> Version { // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To // correctly expose the right API from this crate, take a look at // `opensslv.h` to see what version OpenSSL claims to be. - let mut version_header = String::new(); - let mut include = include_dirs.iter() - .map(|p| p.join("openssl/opensslv.h")) - .filter(|p| p.exists()); - let mut f = match include.next() { - Some(f) => File::open(f).unwrap(), - None => { - panic!("failed to open header file at `openssl/opensslv.h` to learn - about OpenSSL's version number, looked inside:\n\n{:#?}\n\n", - include_dirs); - } - }; - f.read_to_string(&mut version_header).unwrap(); - - // Do a bit of string parsing to find `#define OPENSSL_VERSION_NUMBER ...` - let version_line = version_header.lines().find(|l| { - l.contains("define ") && l.contains("OPENSSL_VERSION_NUMBER") - }).and_then(|line| { - let start = match line.find("0x") { - Some(start) => start, - None => return None, - }; - Some(line[start..].trim()) - }); - let version_text = match version_line { - Some(text) => text, - None => { - panic!("header file at `{}` did not include `OPENSSL_VERSION_NUMBER` \ - that this crate recognized, failed to learn about the \ - OpenSSL version number"); - } - }; - if version_text.contains("0x10001") { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:version=101"); - } else if version_text.contains("0x10002") { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:version=102"); - } else if version_text.contains("0x10100") { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:version=110"); - } else if version_text.contains("0x20000000L") { - // Check if it is really LibreSSL - if version_header.lines().any(|l| { - l.contains("define ") && l.contains("LIBRESSL_VERSION_NUMBER") - }) { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:libressl=true"); - println!("cargo:version=101"); - } - } else { - panic!(" - -This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, but a -different version of OpenSSL was found: - - {} - -The build is now aborting due to this version mismatch. - -", version_text); - } - + // // OpenSSL has a number of build-time configuration options which affect // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. @@ -301,56 +259,82 @@ The build is now aborting due to this version mismatch. // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can // account for compile differences and such. - let mut conf_header = String::new(); - let mut include = include_dirs.iter() - .map(|p| p.join("openssl/opensslconf.h")) - .filter(|p| p.exists()); - let mut f = match include.next() { - Some(f) => File::open(f).unwrap(), - None => { - // It's been seen that on linux the include dir printed out by - // `pkg-config` doesn't actually have opensslconf.h. Instead - // it's in an architecture-specific include directory. - // - // Try to detect that case to see if it exists. - let mut libdirs = libdirs.iter().map(|p| { - p.iter() - .map(|p| if p == "lib" {"include".as_ref()} else {p}) - .collect::() - }).map(|p| { - p.join("openssl/opensslconf.h") - }).filter(|p| p.exists()); - match libdirs.next() { - Some(f) => File::open(f).unwrap(), - None => { - panic!("failed to open header file at - `openssl/opensslconf.h` to learn about \ - OpenSSL's version number, looked \ - inside:\n\n{:#?}\n\n", - include_dirs); - } - } - } - }; - f.read_to_string(&mut conf_header).unwrap(); + let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + path.push("expando.c"); + let mut file = BufWriter::new(File::create(&path).unwrap()); - // Look for `#define OPENSSL_FOO`, print out everything as our own - // #[cfg] flag. - let mut vars = vec![]; - for line in conf_header.lines() { - let i = match line.find("define ") { - Some(i) => i, - None => continue, - }; - let var = line[i + "define ".len()..].trim(); - if var.starts_with("OPENSSL") && !var.contains(" ") { - println!("cargo:rustc-cfg=osslconf=\"{}\"", var); - vars.push(var); + write!(file, "\ +#include +#include + +#ifdef LIBRESSL_VERSION_NUMBER +RUST_LIBRESSL +#elif OPENSSL_VERSION_NUMBER >= 0x10200000 +RUST_OPENSSL_NEW +#elif OPENSSL_VERSION_NUMBER >= 0x10100000 +RUST_OPENSSL_110 +#elif OPENSSL_VERSION_NUMBER >= 0x10002000 +RUST_OPENSSL_102 +#elif OPENSSL_VERSION_NUMBER >= 0x10001000 +RUST_OPENSSL_101 +#else +RUST_OPENSSL_OLD +#endif +").unwrap(); + + for define in DEFINES { + write!(file, "\ +#ifdef {define} +RUST_{define} +#endif +", define = define).unwrap(); + } + + file.flush().unwrap(); + drop(file); + + let mut gcc = gcc::Config::new(); + for include_dir in include_dirs { + gcc.include(include_dir); + } + let expanded = gcc.file(&path).expand(); + let expanded = String::from_utf8(expanded).unwrap(); + + let mut enabled = vec![]; + for &define in DEFINES { + if expanded.contains(&format!("RUST_{}", define)) { + println!("cargo:rustc-cfg=osslconf=\"{}\"", define); + enabled.push(define); } } - println!("cargo:conf={}", vars.join(",")); + println!("cargo:conf={}", enabled.join(",")); - return version_text.to_string() + if expanded.contains("RUST_LIBRESSL") { + println!("cargo:rustc-cfg=libressl"); + println!("cargo:libressl=true"); + println!("cargo:version=101"); + Version::Libressl + } else if expanded.contains("RUST_OPENSSL_110") { + println!("cargo:rustc-cfg=ossl110"); + println!("cargo:version=110"); + Version::Openssl110 + } else if expanded.contains("RUST_OPENSSL_102") { + println!("cargo:rustc-cfg=ossl102"); + println!("cargo:version=102"); + Version::Openssl102 + } else if expanded.contains("RUST_OPENSSL_101") { + println!("cargo:rustc-cfg=ossl101"); + println!("cargo:version=101"); + Version::Openssl101 + } else { + panic!(" + +This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, or LibreSSL, +but a different version of OpenSSL was found. The build is now aborting due to +this version mismatch. + +"); + } } /// Given a libdir for OpenSSL (where artifacts are located) as well as the name