Merge pull request #569 from sfackler/expando
Macro-expand OpenSSL headers for feature checks
This commit is contained in:
commit
a27bc0a3ca
12
.travis.yml
12
.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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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_<FOO>`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") {
|
||||
let libs = match version {
|
||||
Version::Openssl101 | Version::Openssl102 if target.contains("windows") => {
|
||||
["ssleay32", "libeay32"]
|
||||
} else if target.contains("windows") {
|
||||
["libssl", "libcrypto"]
|
||||
} else {
|
||||
["ssl", "crypto"]
|
||||
}
|
||||
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::<PathBuf>()
|
||||
}).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);
|
||||
}
|
||||
}
|
||||
println!("cargo:conf={}", vars.join(","));
|
||||
write!(file, "\
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
return version_text.to_string()
|
||||
#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={}", enabled.join(","));
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue