/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! This shouldn't exist, but does because if something isn't going to link //! against `nss` but has an `nss`-enabled `sqlcipher` turned on (for example, //! by a `cargo` feature activated by something else in the workspace). //! it might need to issue link commands for NSS. use std::{ env, ffi::OsString, path::{Path, PathBuf}, }; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum LinkingKind { Dynamic { folded_libs: bool }, Static, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct NoNssDir; pub fn link_nss() -> Result<(), NoNssDir> { let is_gecko = env::var_os("MOZ_TOPOBJDIR").is_some(); if !is_gecko { let (lib_dir, include_dir) = get_nss()?; println!( "cargo:rustc-link-search=native={}", lib_dir.to_string_lossy() ); println!("cargo:include={}", include_dir.to_string_lossy()); let kind = determine_kind(); link_nss_libs(kind); } else { let libs = match env::var("CARGO_CFG_TARGET_OS") .as_ref() .map(std::string::String::as_str) { Ok("android") | Ok("macos") => vec!["nss3"], _ => vec!["nssutil3", "nss3", "plds4", "plc4", "nspr4"], }; for lib in &libs { println!("cargo:rustc-link-lib=dylib={}", lib); } } Ok(()) } fn get_nss() -> Result<(PathBuf, PathBuf), NoNssDir> { let nss_dir = env("NSS_DIR").ok_or(NoNssDir)?; let nss_dir = Path::new(&nss_dir); if !nss_dir.exists() { println!( "NSS_DIR path (obtained via `env`) does not exist: {}", nss_dir.display() ); panic!("It looks like NSS is not built. Please run `libs/verify-[platform]-environment.sh` first!"); } let lib_dir = nss_dir.join("lib"); let include_dir = nss_dir.join("include"); Ok((lib_dir, include_dir)) } fn determine_kind() -> LinkingKind { if env_flag("NSS_STATIC") { LinkingKind::Static } else { let folded_libs = env_flag("NSS_USE_FOLDED_LIBS"); LinkingKind::Dynamic { folded_libs } } } fn link_nss_libs(kind: LinkingKind) { let libs = get_nss_libs(kind); // Emit -L flags let kind_str = match kind { LinkingKind::Dynamic { .. } => "dylib", LinkingKind::Static => "static", }; for lib in libs { println!("cargo:rustc-link-lib={}={}", kind_str, lib); } // Link against C++ stdlib (for mozpkix) let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); if target_os == "android" || target_os == "linux" { println!("cargo:rustc-link-lib=stdc++"); } else { println!("cargo:rustc-link-lib=c++"); } } fn get_nss_libs(kind: LinkingKind) -> Vec<&'static str> { match kind { LinkingKind::Static => { let mut static_libs = vec![ "certdb", "certhi", "cryptohi", "freebl_static", "mozpkix", "nspr4", "nss_static", "nssb", "nssdev", "nsspki", "nssutil", "pk11wrap_static", "plc4", "plds4", "softokn_static", ]; // Hardware specific libs. let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); // https://searchfox.org/nss/rev/0d5696b3edce5124353f03159d2aa15549db8306/lib/freebl/freebl.gyp#508-542 if target_arch == "arm" || target_arch == "aarch64" { static_libs.push("armv8_c_lib"); } if target_arch == "x86_64" || target_arch == "x86" { static_libs.push("gcm-aes-x86_c_lib"); static_libs.push("sha-x86_c_lib"); } if target_arch == "arm" { static_libs.push("gcm-aes-arm32-neon_c_lib") } if target_arch == "aarch64" { static_libs.push("gcm-aes-aarch64_c_lib"); } if target_arch == "x86_64" { static_libs.push("hw-acc-crypto-avx"); static_libs.push("hw-acc-crypto-avx2"); } // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#315-324 if ((target_os == "android" || target_os == "linux") && target_arch == "x86_64") || target_os == "windows" { static_libs.push("intel-gcm-wrap_c_lib"); // https://searchfox.org/nss/rev/08c4d05078d00089f8d7540651b0717a9d66f87e/lib/freebl/freebl.gyp#43-47 if (target_os == "android" || target_os == "linux") && target_arch == "x86_64" { static_libs.push("intel-gcm-s_lib"); } } static_libs } LinkingKind::Dynamic { folded_libs } => { let mut dylibs = vec!["freebl3", "nss3", "nssckbi", "softokn3"]; if !folded_libs { dylibs.append(&mut vec!["nspr4", "nssutil3", "plc4", "plds4"]); } dylibs } } } pub fn env(name: &str) -> Option { println!("cargo:rerun-if-env-changed={}", name); env::var_os(name) } pub fn env_str(name: &str) -> Option { println!("cargo:rerun-if-env-changed={}", name); env::var(name).ok() } pub fn env_flag(name: &str) -> bool { match env_str(name).as_ref().map(String::as_ref) { Some("1") => true, Some("0") => false, Some(s) => { println!( "cargo:warning=unknown value for environment var {:?}: {:?}. Ignoring", name, s ); false } None => false, } }