192f3ab15Sopenharmony_ci#[cfg(feature = "bindgen")]
292f3ab15Sopenharmony_ciextern crate bindgen;
392f3ab15Sopenharmony_ciextern crate cc;
492f3ab15Sopenharmony_ci#[cfg(feature = "vendored")]
592f3ab15Sopenharmony_ciextern crate openssl_src;
692f3ab15Sopenharmony_ciextern crate pkg_config;
792f3ab15Sopenharmony_ciextern crate vcpkg;
892f3ab15Sopenharmony_ci
992f3ab15Sopenharmony_ciuse std::collections::HashSet;
1092f3ab15Sopenharmony_ciuse std::env;
1192f3ab15Sopenharmony_ciuse std::ffi::OsString;
1292f3ab15Sopenharmony_ciuse std::path::{Path, PathBuf};
1392f3ab15Sopenharmony_cimod cfgs;
1492f3ab15Sopenharmony_ci
1592f3ab15Sopenharmony_cimod find_normal;
1692f3ab15Sopenharmony_ci#[cfg(feature = "vendored")]
1792f3ab15Sopenharmony_cimod find_vendored;
1892f3ab15Sopenharmony_cimod run_bindgen;
1992f3ab15Sopenharmony_ci
2092f3ab15Sopenharmony_ci#[derive(PartialEq)]
2192f3ab15Sopenharmony_cienum Version {
2292f3ab15Sopenharmony_ci    Openssl3xx,
2392f3ab15Sopenharmony_ci    Openssl11x,
2492f3ab15Sopenharmony_ci    Openssl10x,
2592f3ab15Sopenharmony_ci    Libressl,
2692f3ab15Sopenharmony_ci    Boringssl,
2792f3ab15Sopenharmony_ci}
2892f3ab15Sopenharmony_ci
2992f3ab15Sopenharmony_cifn env_inner(name: &str) -> Option<OsString> {
3092f3ab15Sopenharmony_ci    let var = env::var_os(name);
3192f3ab15Sopenharmony_ci    println!("cargo:rerun-if-env-changed={}", name);
3292f3ab15Sopenharmony_ci
3392f3ab15Sopenharmony_ci    match var {
3492f3ab15Sopenharmony_ci        Some(ref v) => println!("{} = {}", name, v.to_string_lossy()),
3592f3ab15Sopenharmony_ci        None => println!("{} unset", name),
3692f3ab15Sopenharmony_ci    }
3792f3ab15Sopenharmony_ci
3892f3ab15Sopenharmony_ci    var
3992f3ab15Sopenharmony_ci}
4092f3ab15Sopenharmony_ci
4192f3ab15Sopenharmony_cifn env(name: &str) -> Option<OsString> {
4292f3ab15Sopenharmony_ci    let prefix = env::var("TARGET").unwrap().to_uppercase().replace('-', "_");
4392f3ab15Sopenharmony_ci    let prefixed = format!("{}_{}", prefix, name);
4492f3ab15Sopenharmony_ci    env_inner(&prefixed).or_else(|| env_inner(name))
4592f3ab15Sopenharmony_ci}
4692f3ab15Sopenharmony_ci
4792f3ab15Sopenharmony_cifn find_openssl(target: &str) -> (Vec<PathBuf>, PathBuf) {
4892f3ab15Sopenharmony_ci    #[cfg(feature = "vendored")]
4992f3ab15Sopenharmony_ci    {
5092f3ab15Sopenharmony_ci        // vendor if the feature is present, unless
5192f3ab15Sopenharmony_ci        // OPENSSL_NO_VENDOR exists and isn't `0`
5292f3ab15Sopenharmony_ci        if env("OPENSSL_NO_VENDOR").map_or(true, |s| s == "0") {
5392f3ab15Sopenharmony_ci            return find_vendored::get_openssl(target);
5492f3ab15Sopenharmony_ci        }
5592f3ab15Sopenharmony_ci    }
5692f3ab15Sopenharmony_ci    find_normal::get_openssl(target)
5792f3ab15Sopenharmony_ci}
5892f3ab15Sopenharmony_ci
5992f3ab15Sopenharmony_cifn check_ssl_kind() {
6092f3ab15Sopenharmony_ci    if cfg!(feature = "unstable_boringssl") {
6192f3ab15Sopenharmony_ci        println!("cargo:rustc-cfg=boringssl");
6292f3ab15Sopenharmony_ci        println!("cargo:boringssl=true");
6392f3ab15Sopenharmony_ci        // BoringSSL does not have any build logic, exit early
6492f3ab15Sopenharmony_ci        std::process::exit(0);
6592f3ab15Sopenharmony_ci    }
6692f3ab15Sopenharmony_ci}
6792f3ab15Sopenharmony_ci
6892f3ab15Sopenharmony_cifn main() {
6992f3ab15Sopenharmony_ci    check_ssl_kind();
7092f3ab15Sopenharmony_ci
7192f3ab15Sopenharmony_ci    let target = env::var("TARGET").unwrap();
7292f3ab15Sopenharmony_ci
7392f3ab15Sopenharmony_ci    let (lib_dirs, include_dir) = find_openssl(&target);
7492f3ab15Sopenharmony_ci
7592f3ab15Sopenharmony_ci    if !lib_dirs.iter().all(|p| Path::new(p).exists()) {
7692f3ab15Sopenharmony_ci        panic!("OpenSSL library directory does not exist: {:?}", lib_dirs);
7792f3ab15Sopenharmony_ci    }
7892f3ab15Sopenharmony_ci    if !Path::new(&include_dir).exists() {
7992f3ab15Sopenharmony_ci        panic!(
8092f3ab15Sopenharmony_ci            "OpenSSL include directory does not exist: {}",
8192f3ab15Sopenharmony_ci            include_dir.to_string_lossy()
8292f3ab15Sopenharmony_ci        );
8392f3ab15Sopenharmony_ci    }
8492f3ab15Sopenharmony_ci
8592f3ab15Sopenharmony_ci    for lib_dir in lib_dirs.iter() {
8692f3ab15Sopenharmony_ci        println!(
8792f3ab15Sopenharmony_ci            "cargo:rustc-link-search=native={}",
8892f3ab15Sopenharmony_ci            lib_dir.to_string_lossy()
8992f3ab15Sopenharmony_ci        );
9092f3ab15Sopenharmony_ci    }
9192f3ab15Sopenharmony_ci    println!("cargo:include={}", include_dir.to_string_lossy());
9292f3ab15Sopenharmony_ci
9392f3ab15Sopenharmony_ci    let version = postprocess(&[include_dir]);
9492f3ab15Sopenharmony_ci
9592f3ab15Sopenharmony_ci    let libs_env = env("OPENSSL_LIBS");
9692f3ab15Sopenharmony_ci    let libs = match libs_env.as_ref().and_then(|s| s.to_str()) {
9792f3ab15Sopenharmony_ci        Some(v) => {
9892f3ab15Sopenharmony_ci            if v.is_empty() {
9992f3ab15Sopenharmony_ci                vec![]
10092f3ab15Sopenharmony_ci            } else {
10192f3ab15Sopenharmony_ci                v.split(':').collect()
10292f3ab15Sopenharmony_ci            }
10392f3ab15Sopenharmony_ci        }
10492f3ab15Sopenharmony_ci        None => match version {
10592f3ab15Sopenharmony_ci            Version::Openssl10x if target.contains("windows") => vec!["ssleay32", "libeay32"],
10692f3ab15Sopenharmony_ci            Version::Openssl3xx | Version::Openssl11x if target.contains("windows-msvc") => {
10792f3ab15Sopenharmony_ci                vec!["libssl", "libcrypto"]
10892f3ab15Sopenharmony_ci            }
10992f3ab15Sopenharmony_ci            _ => vec!["ssl", "crypto"],
11092f3ab15Sopenharmony_ci        },
11192f3ab15Sopenharmony_ci    };
11292f3ab15Sopenharmony_ci
11392f3ab15Sopenharmony_ci    let kind = determine_mode(&lib_dirs, &libs);
11492f3ab15Sopenharmony_ci    for lib in libs.into_iter() {
11592f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib={}={}", kind, lib);
11692f3ab15Sopenharmony_ci    }
11792f3ab15Sopenharmony_ci
11892f3ab15Sopenharmony_ci    if kind == "static" && target.contains("windows") {
11992f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib=dylib=gdi32");
12092f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib=dylib=user32");
12192f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib=dylib=crypt32");
12292f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib=dylib=ws2_32");
12392f3ab15Sopenharmony_ci        println!("cargo:rustc-link-lib=dylib=advapi32");
12492f3ab15Sopenharmony_ci    }
12592f3ab15Sopenharmony_ci}
12692f3ab15Sopenharmony_ci
12792f3ab15Sopenharmony_cifn postprocess(include_dirs: &[PathBuf]) -> Version {
12892f3ab15Sopenharmony_ci    let version = validate_headers(include_dirs);
12992f3ab15Sopenharmony_ci
13092f3ab15Sopenharmony_ci    // Never run bindgen for BoringSSL, if it was needed we already ran it.
13192f3ab15Sopenharmony_ci    if version != Version::Boringssl {
13292f3ab15Sopenharmony_ci        #[cfg(feature = "bindgen")]
13392f3ab15Sopenharmony_ci        run_bindgen::run(&include_dirs);
13492f3ab15Sopenharmony_ci    }
13592f3ab15Sopenharmony_ci
13692f3ab15Sopenharmony_ci    version
13792f3ab15Sopenharmony_ci}
13892f3ab15Sopenharmony_ci
13992f3ab15Sopenharmony_ci/// Validates the header files found in `include_dir` and then returns the
14092f3ab15Sopenharmony_ci/// version string of OpenSSL.
14192f3ab15Sopenharmony_ci#[allow(clippy::unusual_byte_groupings)]
14292f3ab15Sopenharmony_cifn validate_headers(include_dirs: &[PathBuf]) -> Version {
14392f3ab15Sopenharmony_ci    // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, 1.1.0, 1.1.1 and 3.0.0.
14492f3ab15Sopenharmony_ci    // To correctly expose the right API from this crate, take a look at
14592f3ab15Sopenharmony_ci    // `opensslv.h` to see what version OpenSSL claims to be.
14692f3ab15Sopenharmony_ci    //
14792f3ab15Sopenharmony_ci    // OpenSSL has a number of build-time configuration options which affect
14892f3ab15Sopenharmony_ci    // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem
14992f3ab15Sopenharmony_ci    // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem.
15092f3ab15Sopenharmony_ci    //
15192f3ab15Sopenharmony_ci    // To handle all this conditional compilation we slurp up the configuration
15292f3ab15Sopenharmony_ci    // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines
15392f3ab15Sopenharmony_ci    // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can
15492f3ab15Sopenharmony_ci    // account for compile differences and such.
15592f3ab15Sopenharmony_ci    println!("cargo:rerun-if-changed=build/expando.c");
15692f3ab15Sopenharmony_ci    let mut gcc = cc::Build::new();
15792f3ab15Sopenharmony_ci    gcc.includes(include_dirs);
15892f3ab15Sopenharmony_ci    let expanded = match gcc.file("build/expando.c").try_expand() {
15992f3ab15Sopenharmony_ci        Ok(expanded) => expanded,
16092f3ab15Sopenharmony_ci        Err(e) => {
16192f3ab15Sopenharmony_ci            panic!(
16292f3ab15Sopenharmony_ci                "
16392f3ab15Sopenharmony_ciHeader expansion error:
16492f3ab15Sopenharmony_ci{:?}
16592f3ab15Sopenharmony_ci
16692f3ab15Sopenharmony_ciFailed to find OpenSSL development headers.
16792f3ab15Sopenharmony_ci
16892f3ab15Sopenharmony_ciYou can try fixing this setting the `OPENSSL_DIR` environment variable
16992f3ab15Sopenharmony_cipointing to your OpenSSL installation or installing OpenSSL headers package
17092f3ab15Sopenharmony_cispecific to your distribution:
17192f3ab15Sopenharmony_ci
17292f3ab15Sopenharmony_ci    # On Ubuntu
17392f3ab15Sopenharmony_ci    sudo apt-get install libssl-dev
17492f3ab15Sopenharmony_ci    # On Arch Linux
17592f3ab15Sopenharmony_ci    sudo pacman -S openssl
17692f3ab15Sopenharmony_ci    # On Fedora
17792f3ab15Sopenharmony_ci    sudo dnf install openssl-devel
17892f3ab15Sopenharmony_ci    # On Alpine Linux
17992f3ab15Sopenharmony_ci    apk add openssl-dev
18092f3ab15Sopenharmony_ci
18192f3ab15Sopenharmony_ciSee rust-openssl documentation for more information:
18292f3ab15Sopenharmony_ci
18392f3ab15Sopenharmony_ci    https://docs.rs/openssl
18492f3ab15Sopenharmony_ci",
18592f3ab15Sopenharmony_ci                e
18692f3ab15Sopenharmony_ci            );
18792f3ab15Sopenharmony_ci        }
18892f3ab15Sopenharmony_ci    };
18992f3ab15Sopenharmony_ci    let expanded = String::from_utf8(expanded).unwrap();
19092f3ab15Sopenharmony_ci
19192f3ab15Sopenharmony_ci    let mut enabled = vec![];
19292f3ab15Sopenharmony_ci    let mut openssl_version = None;
19392f3ab15Sopenharmony_ci    let mut libressl_version = None;
19492f3ab15Sopenharmony_ci    let mut is_boringssl = false;
19592f3ab15Sopenharmony_ci    for line in expanded.lines() {
19692f3ab15Sopenharmony_ci        let line = line.trim();
19792f3ab15Sopenharmony_ci
19892f3ab15Sopenharmony_ci        let openssl_prefix = "RUST_VERSION_OPENSSL_";
19992f3ab15Sopenharmony_ci        let new_openssl_prefix = "RUST_VERSION_NEW_OPENSSL_";
20092f3ab15Sopenharmony_ci        let libressl_prefix = "RUST_VERSION_LIBRESSL_";
20192f3ab15Sopenharmony_ci        let boringsl_prefix = "RUST_OPENSSL_IS_BORINGSSL";
20292f3ab15Sopenharmony_ci        let conf_prefix = "RUST_CONF_";
20392f3ab15Sopenharmony_ci        if let Some(version) = line.strip_prefix(openssl_prefix) {
20492f3ab15Sopenharmony_ci            openssl_version = Some(parse_version(version));
20592f3ab15Sopenharmony_ci        } else if let Some(version) = line.strip_prefix(new_openssl_prefix) {
20692f3ab15Sopenharmony_ci            openssl_version = Some(parse_new_version(version));
20792f3ab15Sopenharmony_ci        } else if let Some(version) = line.strip_prefix(libressl_prefix) {
20892f3ab15Sopenharmony_ci            libressl_version = Some(parse_version(version));
20992f3ab15Sopenharmony_ci        } else if let Some(conf) = line.strip_prefix(conf_prefix) {
21092f3ab15Sopenharmony_ci            enabled.push(conf);
21192f3ab15Sopenharmony_ci        } else if line.starts_with(boringsl_prefix) {
21292f3ab15Sopenharmony_ci            is_boringssl = true;
21392f3ab15Sopenharmony_ci        }
21492f3ab15Sopenharmony_ci    }
21592f3ab15Sopenharmony_ci
21692f3ab15Sopenharmony_ci    if is_boringssl {
21792f3ab15Sopenharmony_ci        println!("cargo:rustc-cfg=boringssl");
21892f3ab15Sopenharmony_ci        println!("cargo:boringssl=true");
21992f3ab15Sopenharmony_ci        run_bindgen::run_boringssl(include_dirs);
22092f3ab15Sopenharmony_ci        return Version::Boringssl;
22192f3ab15Sopenharmony_ci    }
22292f3ab15Sopenharmony_ci
22392f3ab15Sopenharmony_ci    // We set this for any non-BoringSSL lib.
22492f3ab15Sopenharmony_ci    println!("cargo:rustc-cfg=openssl");
22592f3ab15Sopenharmony_ci
22692f3ab15Sopenharmony_ci    for enabled in &enabled {
22792f3ab15Sopenharmony_ci        println!("cargo:rustc-cfg=osslconf=\"{}\"", enabled);
22892f3ab15Sopenharmony_ci    }
22992f3ab15Sopenharmony_ci    println!("cargo:conf={}", enabled.join(","));
23092f3ab15Sopenharmony_ci
23192f3ab15Sopenharmony_ci    for cfg in cfgs::get(openssl_version, libressl_version) {
23292f3ab15Sopenharmony_ci        println!("cargo:rustc-cfg={}", cfg);
23392f3ab15Sopenharmony_ci    }
23492f3ab15Sopenharmony_ci
23592f3ab15Sopenharmony_ci    if let Some(libressl_version) = libressl_version {
23692f3ab15Sopenharmony_ci        println!("cargo:libressl_version_number={:x}", libressl_version);
23792f3ab15Sopenharmony_ci
23892f3ab15Sopenharmony_ci        let major = (libressl_version >> 28) as u8;
23992f3ab15Sopenharmony_ci        let minor = (libressl_version >> 20) as u8;
24092f3ab15Sopenharmony_ci        let fix = (libressl_version >> 12) as u8;
24192f3ab15Sopenharmony_ci        let (major, minor, fix) = match (major, minor, fix) {
24292f3ab15Sopenharmony_ci            (2, 5, 0) => ('2', '5', '0'),
24392f3ab15Sopenharmony_ci            (2, 5, 1) => ('2', '5', '1'),
24492f3ab15Sopenharmony_ci            (2, 5, 2) => ('2', '5', '2'),
24592f3ab15Sopenharmony_ci            (2, 5, _) => ('2', '5', 'x'),
24692f3ab15Sopenharmony_ci            (2, 6, 0) => ('2', '6', '0'),
24792f3ab15Sopenharmony_ci            (2, 6, 1) => ('2', '6', '1'),
24892f3ab15Sopenharmony_ci            (2, 6, 2) => ('2', '6', '2'),
24992f3ab15Sopenharmony_ci            (2, 6, _) => ('2', '6', 'x'),
25092f3ab15Sopenharmony_ci            (2, 7, _) => ('2', '7', 'x'),
25192f3ab15Sopenharmony_ci            (2, 8, 0) => ('2', '8', '0'),
25292f3ab15Sopenharmony_ci            (2, 8, 1) => ('2', '8', '1'),
25392f3ab15Sopenharmony_ci            (2, 8, _) => ('2', '8', 'x'),
25492f3ab15Sopenharmony_ci            (2, 9, 0) => ('2', '9', '0'),
25592f3ab15Sopenharmony_ci            (2, 9, _) => ('2', '9', 'x'),
25692f3ab15Sopenharmony_ci            (3, 0, 0) => ('3', '0', '0'),
25792f3ab15Sopenharmony_ci            (3, 0, 1) => ('3', '0', '1'),
25892f3ab15Sopenharmony_ci            (3, 0, _) => ('3', '0', 'x'),
25992f3ab15Sopenharmony_ci            (3, 1, 0) => ('3', '1', '0'),
26092f3ab15Sopenharmony_ci            (3, 1, _) => ('3', '1', 'x'),
26192f3ab15Sopenharmony_ci            (3, 2, 0) => ('3', '2', '0'),
26292f3ab15Sopenharmony_ci            (3, 2, 1) => ('3', '2', '1'),
26392f3ab15Sopenharmony_ci            (3, 2, _) => ('3', '2', 'x'),
26492f3ab15Sopenharmony_ci            (3, 3, 0) => ('3', '3', '0'),
26592f3ab15Sopenharmony_ci            (3, 3, 1) => ('3', '3', '1'),
26692f3ab15Sopenharmony_ci            (3, 3, _) => ('3', '3', 'x'),
26792f3ab15Sopenharmony_ci            (3, 4, 0) => ('3', '4', '0'),
26892f3ab15Sopenharmony_ci            (3, 4, _) => ('3', '4', 'x'),
26992f3ab15Sopenharmony_ci            (3, 5, _) => ('3', '5', 'x'),
27092f3ab15Sopenharmony_ci            (3, 6, 0) => ('3', '6', '0'),
27192f3ab15Sopenharmony_ci            (3, 6, _) => ('3', '6', 'x'),
27292f3ab15Sopenharmony_ci            (3, 7, 0) => ('3', '7', '0'),
27392f3ab15Sopenharmony_ci            (3, 7, 1) => ('3', '7', '1'),
27492f3ab15Sopenharmony_ci            (3, 7, _) => ('3', '7', 'x'),
27592f3ab15Sopenharmony_ci            (3, 8, 0) => ('3', '8', '0'),
27692f3ab15Sopenharmony_ci            _ => version_error(),
27792f3ab15Sopenharmony_ci        };
27892f3ab15Sopenharmony_ci
27992f3ab15Sopenharmony_ci        println!("cargo:libressl=true");
28092f3ab15Sopenharmony_ci        println!("cargo:libressl_version={}{}{}", major, minor, fix);
28192f3ab15Sopenharmony_ci        println!("cargo:version=101");
28292f3ab15Sopenharmony_ci        Version::Libressl
28392f3ab15Sopenharmony_ci    } else {
28492f3ab15Sopenharmony_ci        let openssl_version = openssl_version.unwrap();
28592f3ab15Sopenharmony_ci        println!("cargo:version_number={:x}", openssl_version);
28692f3ab15Sopenharmony_ci
28792f3ab15Sopenharmony_ci        if openssl_version >= 0x4_00_00_00_0 {
28892f3ab15Sopenharmony_ci            version_error()
28992f3ab15Sopenharmony_ci        } else if openssl_version >= 0x3_00_00_00_0 {
29092f3ab15Sopenharmony_ci            Version::Openssl3xx
29192f3ab15Sopenharmony_ci        } else if openssl_version >= 0x1_01_01_00_0 {
29292f3ab15Sopenharmony_ci            println!("cargo:version=111");
29392f3ab15Sopenharmony_ci            Version::Openssl11x
29492f3ab15Sopenharmony_ci        } else if openssl_version >= 0x1_01_00_06_0 {
29592f3ab15Sopenharmony_ci            println!("cargo:version=110");
29692f3ab15Sopenharmony_ci            println!("cargo:patch=f");
29792f3ab15Sopenharmony_ci            Version::Openssl11x
29892f3ab15Sopenharmony_ci        } else if openssl_version >= 0x1_01_00_00_0 {
29992f3ab15Sopenharmony_ci            println!("cargo:version=110");
30092f3ab15Sopenharmony_ci            Version::Openssl11x
30192f3ab15Sopenharmony_ci        } else if openssl_version >= 0x1_00_02_00_0 {
30292f3ab15Sopenharmony_ci            println!("cargo:version=102");
30392f3ab15Sopenharmony_ci            Version::Openssl10x
30492f3ab15Sopenharmony_ci        } else if openssl_version >= 0x1_00_01_00_0 {
30592f3ab15Sopenharmony_ci            println!("cargo:version=101");
30692f3ab15Sopenharmony_ci            Version::Openssl10x
30792f3ab15Sopenharmony_ci        } else {
30892f3ab15Sopenharmony_ci            version_error()
30992f3ab15Sopenharmony_ci        }
31092f3ab15Sopenharmony_ci    }
31192f3ab15Sopenharmony_ci}
31292f3ab15Sopenharmony_ci
31392f3ab15Sopenharmony_cifn version_error() -> ! {
31492f3ab15Sopenharmony_ci    panic!(
31592f3ab15Sopenharmony_ci        "
31692f3ab15Sopenharmony_ci
31792f3ab15Sopenharmony_ciThis crate is only compatible with OpenSSL (version 1.0.1 through 1.1.1, or 3.0.0), or LibreSSL 2.5
31892f3ab15Sopenharmony_cithrough 3.8.0, but a different version of OpenSSL was found. The build is now aborting
31992f3ab15Sopenharmony_cidue to this version mismatch.
32092f3ab15Sopenharmony_ci
32192f3ab15Sopenharmony_ci"
32292f3ab15Sopenharmony_ci    );
32392f3ab15Sopenharmony_ci}
32492f3ab15Sopenharmony_ci
32592f3ab15Sopenharmony_ci// parses a string that looks like "0x100020cfL"
32692f3ab15Sopenharmony_cifn parse_version(version: &str) -> u64 {
32792f3ab15Sopenharmony_ci    // cut off the 0x prefix
32892f3ab15Sopenharmony_ci    assert!(version.starts_with("0x"));
32992f3ab15Sopenharmony_ci    let version = &version[2..];
33092f3ab15Sopenharmony_ci
33192f3ab15Sopenharmony_ci    // and the type specifier suffix
33292f3ab15Sopenharmony_ci    let version = version.trim_end_matches(|c: char| !c.is_ascii_hexdigit());
33392f3ab15Sopenharmony_ci
33492f3ab15Sopenharmony_ci    u64::from_str_radix(version, 16).unwrap()
33592f3ab15Sopenharmony_ci}
33692f3ab15Sopenharmony_ci
33792f3ab15Sopenharmony_ci// parses a string that looks like 3_0_0
33892f3ab15Sopenharmony_cifn parse_new_version(version: &str) -> u64 {
33992f3ab15Sopenharmony_ci    println!("version: {}", version);
34092f3ab15Sopenharmony_ci    let mut it = version.split('_');
34192f3ab15Sopenharmony_ci    let major = it.next().unwrap().parse::<u64>().unwrap();
34292f3ab15Sopenharmony_ci    let minor = it.next().unwrap().parse::<u64>().unwrap();
34392f3ab15Sopenharmony_ci    let patch = it.next().unwrap().parse::<u64>().unwrap();
34492f3ab15Sopenharmony_ci
34592f3ab15Sopenharmony_ci    (major << 28) | (minor << 20) | (patch << 4)
34692f3ab15Sopenharmony_ci}
34792f3ab15Sopenharmony_ci
34892f3ab15Sopenharmony_ci/// Given a libdir for OpenSSL (where artifacts are located) as well as the name
34992f3ab15Sopenharmony_ci/// of the libraries we're linking to, figure out whether we should link them
35092f3ab15Sopenharmony_ci/// statically or dynamically.
35192f3ab15Sopenharmony_cifn determine_mode(libdirs: &[PathBuf], libs: &[&str]) -> &'static str {
35292f3ab15Sopenharmony_ci    // First see if a mode was explicitly requested
35392f3ab15Sopenharmony_ci    let kind = env("OPENSSL_STATIC");
35492f3ab15Sopenharmony_ci    match kind.as_ref().and_then(|s| s.to_str()) {
35592f3ab15Sopenharmony_ci        Some("0") => return "dylib",
35692f3ab15Sopenharmony_ci        Some(_) => return "static",
35792f3ab15Sopenharmony_ci        None => {}
35892f3ab15Sopenharmony_ci    }
35992f3ab15Sopenharmony_ci
36092f3ab15Sopenharmony_ci    // Next, see what files we actually have to link against, and see what our
36192f3ab15Sopenharmony_ci    // possibilities even are.
36292f3ab15Sopenharmony_ci    let mut files = HashSet::new();
36392f3ab15Sopenharmony_ci    for dir in libdirs {
36492f3ab15Sopenharmony_ci        for path in dir
36592f3ab15Sopenharmony_ci            .read_dir()
36692f3ab15Sopenharmony_ci            .unwrap()
36792f3ab15Sopenharmony_ci            .map(|e| e.unwrap())
36892f3ab15Sopenharmony_ci            .map(|e| e.file_name())
36992f3ab15Sopenharmony_ci            .filter_map(|e| e.into_string().ok())
37092f3ab15Sopenharmony_ci        {
37192f3ab15Sopenharmony_ci            files.insert(path);
37292f3ab15Sopenharmony_ci        }
37392f3ab15Sopenharmony_ci    }
37492f3ab15Sopenharmony_ci    let can_static = libs
37592f3ab15Sopenharmony_ci        .iter()
37692f3ab15Sopenharmony_ci        .all(|l| files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l)));
37792f3ab15Sopenharmony_ci    let can_dylib = libs.iter().all(|l| {
37892f3ab15Sopenharmony_ci        files.contains(&format!("lib{}.so", l))
37992f3ab15Sopenharmony_ci            || files.contains(&format!("{}.dll", l))
38092f3ab15Sopenharmony_ci            || files.contains(&format!("lib{}.dylib", l))
38192f3ab15Sopenharmony_ci    });
38292f3ab15Sopenharmony_ci    match (can_static, can_dylib) {
38392f3ab15Sopenharmony_ci        (true, false) => return "static",
38492f3ab15Sopenharmony_ci        (false, true) => return "dylib",
38592f3ab15Sopenharmony_ci        (false, false) => {
38692f3ab15Sopenharmony_ci            panic!(
38792f3ab15Sopenharmony_ci                "OpenSSL libdir at `{:?}` does not contain the required files \
38892f3ab15Sopenharmony_ci                 to either statically or dynamically link OpenSSL",
38992f3ab15Sopenharmony_ci                libdirs
39092f3ab15Sopenharmony_ci            );
39192f3ab15Sopenharmony_ci        }
39292f3ab15Sopenharmony_ci        (true, true) => {}
39392f3ab15Sopenharmony_ci    }
39492f3ab15Sopenharmony_ci
39592f3ab15Sopenharmony_ci    // Ok, we've got not explicit preference and can *either* link statically or
39692f3ab15Sopenharmony_ci    // link dynamically. In the interest of "security upgrades" and/or "best
39792f3ab15Sopenharmony_ci    // practices with security libs", let's link dynamically.
39892f3ab15Sopenharmony_ci    "dylib"
39992f3ab15Sopenharmony_ci}
400