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
|
# ARM-bit version compat
|
||||||
- env: >
|
- env: >
|
||||||
TARGET=arm-unknown-linux-gnueabihf
|
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
|
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||||
RUST_TEST_THREADS=1
|
RUST_TEST_THREADS=1
|
||||||
|
|
@ -32,7 +32,7 @@ matrix:
|
||||||
- binfmt-support
|
- binfmt-support
|
||||||
- env: >
|
- env: >
|
||||||
TARGET=arm-unknown-linux-gnueabihf
|
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
|
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||||
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf
|
||||||
RUST_TEST_THREADS=1
|
RUST_TEST_THREADS=1
|
||||||
|
|
@ -52,8 +52,8 @@ matrix:
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
|
|
||||||
# 64-bit version compat
|
# 64-bit version compat
|
||||||
- env: BUILD_OPENSSL_VERSION=1.0.2h
|
- env: BUILD_OPENSSL_VERSION=1.0.2k
|
||||||
- env: BUILD_OPENSSL_VERSION=1.1.0c
|
- env: BUILD_OPENSSL_VERSION=1.1.0d
|
||||||
|
|
||||||
# 32-bit version compat
|
# 32-bit version compat
|
||||||
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u
|
- env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u
|
||||||
|
|
@ -61,12 +61,12 @@ matrix:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- gcc-multilib
|
- 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:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- gcc-multilib
|
- 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:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,20 @@ environment:
|
||||||
- TARGET: i686-pc-windows-gnu
|
- TARGET: i686-pc-windows-gnu
|
||||||
BITS: 32
|
BITS: 32
|
||||||
MSYS2: 1
|
MSYS2: 1
|
||||||
OPENSSL_VERSION: 1_1_0c
|
OPENSSL_VERSION: 1_1_0d
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
BITS: 64
|
BITS: 64
|
||||||
OPENSSL_VERSION: 1_1_0c
|
OPENSSL_VERSION: 1_1_0d
|
||||||
OPENSSL_DIR: C:\OpenSSL
|
OPENSSL_DIR: C:\OpenSSL
|
||||||
|
|
||||||
# 1.0.2, 64/32 bit
|
# 1.0.2, 64/32 bit
|
||||||
- TARGET: x86_64-pc-windows-gnu
|
- TARGET: x86_64-pc-windows-gnu
|
||||||
BITS: 64
|
BITS: 64
|
||||||
MSYS2: 1
|
MSYS2: 1
|
||||||
OPENSSL_VERSION: 1_0_2j
|
OPENSSL_VERSION: 1_0_2k
|
||||||
- TARGET: i686-pc-windows-msvc
|
- TARGET: i686-pc-windows-msvc
|
||||||
BITS: 32
|
BITS: 32
|
||||||
OPENSSL_VERSION: 1_0_2j
|
OPENSSL_VERSION: 1_0_2k
|
||||||
OPENSSL_DIR: C:\OpenSSL
|
OPENSSL_DIR: C:\OpenSSL
|
||||||
install:
|
install:
|
||||||
# install OpenSSL
|
# install OpenSSL
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,12 @@ libc = "0.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pkg-config = "0.3.9"
|
pkg-config = "0.3.9"
|
||||||
|
gcc = "0.3.42"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
user32-sys = "0.2"
|
user32-sys = "0.2"
|
||||||
gdi32-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]
|
[package.metadata.pkg-config]
|
||||||
openssl = "1.0.1"
|
openssl = "1.0.1"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,37 @@
|
||||||
extern crate pkg_config;
|
extern crate pkg_config;
|
||||||
|
extern crate gcc;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::{BufWriter, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
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() {
|
fn main() {
|
||||||
let target = env::var("TARGET").unwrap();
|
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:rustc-link-search=native={}", lib_dir.to_string_lossy());
|
||||||
println!("cargo:include={}", include_dir.to_string_lossy());
|
println!("cargo:include={}", include_dir.to_string_lossy());
|
||||||
|
|
||||||
let version = validate_headers(&[include_dir.clone().into()],
|
let version = validate_headers(&[include_dir.clone().into()]);
|
||||||
&[lib_dir.clone().into()]);
|
|
||||||
|
|
||||||
let libs = if (version.contains("0x10001") ||
|
let libs = match version {
|
||||||
version.contains("0x10002")) &&
|
Version::Openssl101 | Version::Openssl102 if target.contains("windows") => {
|
||||||
target.contains("windows") {
|
["ssleay32", "libeay32"]
|
||||||
["ssleay32", "libeay32"]
|
}
|
||||||
} else if target.contains("windows") {
|
Version::Openssl110 if target.contains("windows") => ["libssl", "libcrypto"],
|
||||||
["libssl", "libcrypto"]
|
_ => ["ssl", "crypto"],
|
||||||
} else {
|
|
||||||
["ssl", "crypto"]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = determine_mode(Path::new(&lib_dir), &libs);
|
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() {
|
for include in lib.include_paths.iter() {
|
||||||
println!("cargo:include={}", include.display());
|
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
|
/// Validates the header files found in `include_dir` and then returns the
|
||||||
/// version string of OpenSSL.
|
/// version string of OpenSSL.
|
||||||
fn validate_headers(include_dirs: &[PathBuf],
|
fn validate_headers(include_dirs: &[PathBuf]) -> Version {
|
||||||
libdirs: &[PathBuf]) -> String {
|
|
||||||
// This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To
|
// 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
|
// correctly expose the right API from this crate, take a look at
|
||||||
// `opensslv.h` to see what version OpenSSL claims to be.
|
// `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
|
// 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
|
// 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.
|
// 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
|
// file of OpenSSL, `opensslconf.h`, and then dump out everything it defines
|
||||||
// as our own #[cfg] directives. That way the `ossl10x.rs` bindings can
|
// as our own #[cfg] directives. That way the `ossl10x.rs` bindings can
|
||||||
// account for compile differences and such.
|
// account for compile differences and such.
|
||||||
let mut conf_header = String::new();
|
let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
let mut include = include_dirs.iter()
|
path.push("expando.c");
|
||||||
.map(|p| p.join("openssl/opensslconf.h"))
|
let mut file = BufWriter::new(File::create(&path).unwrap());
|
||||||
.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();
|
|
||||||
|
|
||||||
// Look for `#define OPENSSL_FOO`, print out everything as our own
|
write!(file, "\
|
||||||
// #[cfg] flag.
|
#include <openssl/opensslv.h>
|
||||||
let mut vars = vec![];
|
#include <openssl/opensslconf.h>
|
||||||
for line in conf_header.lines() {
|
|
||||||
let i = match line.find("define ") {
|
#ifdef LIBRESSL_VERSION_NUMBER
|
||||||
Some(i) => i,
|
RUST_LIBRESSL
|
||||||
None => continue,
|
#elif OPENSSL_VERSION_NUMBER >= 0x10200000
|
||||||
};
|
RUST_OPENSSL_NEW
|
||||||
let var = line[i + "define ".len()..].trim();
|
#elif OPENSSL_VERSION_NUMBER >= 0x10100000
|
||||||
if var.starts_with("OPENSSL") && !var.contains(" ") {
|
RUST_OPENSSL_110
|
||||||
println!("cargo:rustc-cfg=osslconf=\"{}\"", var);
|
#elif OPENSSL_VERSION_NUMBER >= 0x10002000
|
||||||
vars.push(var);
|
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
|
/// Given a libdir for OpenSSL (where artifacts are located) as well as the name
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue