nss_build_common/
lib.rs
1use std::{
11 env,
12 ffi::OsString,
13 path::{Path, PathBuf},
14};
15
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
17pub enum LinkingKind {
18 Dynamic { folded_libs: bool },
19 Static,
20}
21
22#[derive(Debug, PartialEq, Eq, Clone)]
23pub struct NoNssDir;
24
25pub fn link_nss() -> Result<(), NoNssDir> {
26 let is_gecko = env::var_os("MOZ_TOPOBJDIR").is_some();
27 if !is_gecko {
28 let (lib_dir, include_dir) = get_nss()?;
29 println!(
30 "cargo:rustc-link-search=native={}",
31 lib_dir.to_string_lossy()
32 );
33 println!("cargo:include={}", include_dir.to_string_lossy());
34 let kind = determine_kind();
35 link_nss_libs(kind);
36 } else {
37 let libs = match env::var("CARGO_CFG_TARGET_OS")
38 .as_ref()
39 .map(std::string::String::as_str)
40 {
41 Ok("android") | Ok("macos") => vec!["nss3"],
42 _ => vec!["nssutil3", "nss3", "plds4", "plc4", "nspr4"],
43 };
44 for lib in &libs {
45 println!("cargo:rustc-link-lib=dylib={}", lib);
46 }
47 }
48 Ok(())
49}
50
51fn get_nss() -> Result<(PathBuf, PathBuf), NoNssDir> {
52 let nss_dir = env("NSS_DIR").ok_or(NoNssDir)?;
53 let nss_dir = Path::new(&nss_dir);
54 if !nss_dir.exists() {
55 println!(
56 "NSS_DIR path (obtained via `env`) does not exist: {}",
57 nss_dir.display()
58 );
59 panic!("It looks like NSS is not built. Please run `libs/verify-[platform]-environment.sh` first!");
60 }
61 let lib_dir = nss_dir.join("lib");
62 let include_dir = nss_dir.join("include");
63 Ok((lib_dir, include_dir))
64}
65
66fn determine_kind() -> LinkingKind {
67 if env_flag("NSS_STATIC") {
68 LinkingKind::Static
69 } else {
70 let folded_libs = env_flag("NSS_USE_FOLDED_LIBS");
71 LinkingKind::Dynamic { folded_libs }
72 }
73}
74
75fn link_nss_libs(kind: LinkingKind) {
76 let libs = get_nss_libs(kind);
77 let kind_str = match kind {
79 LinkingKind::Dynamic { .. } => "dylib",
80 LinkingKind::Static => "static",
81 };
82 for lib in libs {
83 println!("cargo:rustc-link-lib={}={}", kind_str, lib);
84 }
85 let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
87 if target_os == "android" || target_os == "linux" {
88 println!("cargo:rustc-link-lib=stdc++");
89 } else {
90 println!("cargo:rustc-link-lib=c++");
91 }
92 let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
93 if target_arch == "x86_64" && target_os == "android" {
94 let android_home = env::var("ANDROID_HOME").expect("ANDROID_HOME not set");
95 const ANDROID_NDK_VERSION: &str = "28.1.13356709";
96 const DARWIN_X86_64_LIB_DIR: &str =
98 "/toolchains/llvm/prebuilt/darwin-x86_64/lib/clang/19/lib/linux/";
99 println!("cargo:rustc-link-search={android_home}/ndk/{ANDROID_NDK_VERSION}/{DARWIN_X86_64_LIB_DIR}");
100 const LINUX_X86_64_LIB_DIR: &str =
101 "/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/19/lib/linux/";
102 println!("cargo:rustc-link-search={android_home}/ndk/{ANDROID_NDK_VERSION}/{LINUX_X86_64_LIB_DIR}");
103 println!("cargo:rustc-link-lib=static=clang_rt.builtins-x86_64-android");
104 }
105}
106
107fn get_nss_libs(kind: LinkingKind) -> Vec<&'static str> {
108 match kind {
109 LinkingKind::Static => {
110 let mut static_libs = vec![
111 "certdb",
112 "certhi",
113 "cryptohi",
114 "freebl_static",
115 "mozpkix",
116 "nspr4",
117 "nss_static",
118 "nssb",
119 "nssdev",
120 "nsspki",
121 "nssutil",
122 "pk11wrap_static",
123 "plc4",
124 "plds4",
125 "softokn_static",
126 ];
127 let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
129 let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
130 if target_arch == "arm" || target_arch == "aarch64" {
132 static_libs.push("armv8_c_lib");
133 }
134 if target_arch == "x86_64" || target_arch == "x86" {
135 static_libs.push("gcm-aes-x86_c_lib");
136 static_libs.push("sha-x86_c_lib");
137 }
138 if target_arch == "arm" {
139 static_libs.push("gcm-aes-arm32-neon_c_lib")
140 }
141 if target_arch == "aarch64" {
142 static_libs.push("gcm-aes-aarch64_c_lib");
143 }
144 if target_arch == "x86_64" {
145 static_libs.push("hw-acc-crypto-avx");
146 static_libs.push("hw-acc-crypto-avx2");
147 }
148 if ((target_os == "android" || target_os == "linux") && target_arch == "x86_64")
150 || target_os == "windows"
151 {
152 static_libs.push("intel-gcm-wrap_c_lib");
153 if (target_os == "android" || target_os == "linux") && target_arch == "x86_64" {
155 static_libs.push("intel-gcm-s_lib");
156 }
157 }
158 static_libs
159 }
160 LinkingKind::Dynamic { folded_libs } => {
161 let mut dylibs = vec!["freebl3", "nss3", "nssckbi", "softokn3"];
162 if !folded_libs {
163 dylibs.append(&mut vec!["nspr4", "nssutil3", "plc4", "plds4"]);
164 }
165 dylibs
166 }
167 }
168}
169
170pub fn env(name: &str) -> Option<OsString> {
171 println!("cargo:rerun-if-env-changed={}", name);
172 env::var_os(name)
173}
174
175pub fn env_str(name: &str) -> Option<String> {
176 println!("cargo:rerun-if-env-changed={}", name);
177 env::var(name).ok()
178}
179
180pub fn env_flag(name: &str) -> bool {
181 match env_str(name).as_ref().map(String::as_ref) {
182 Some("1") => true,
183 Some("0") => false,
184 Some(s) => {
185 println!(
186 "cargo:warning=unknown value for environment var {:?}: {:?}. Ignoring",
187 name, s
188 );
189 false
190 }
191 None => false,
192 }
193}