-
Notifications
You must be signed in to change notification settings - Fork 39
/
build.rs
180 lines (157 loc) · 6.32 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use std::path::{Path, PathBuf};
fn generate_bindings(includedir: &Path, headerfile: &str, filter: &str) {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
bindgen::Builder::default()
.clang_arg(format!("-I{}", includedir.display()))
.header(
includedir
.join("oqs")
.join(format!("{headerfile}.h"))
.to_str()
.unwrap(),
)
// Options
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
.size_t_is_usize(true)
// Don't generate docs unless enabled
// Otherwise it breaks tests
.generate_comments(cfg!(feature = "docs"))
// Whitelist OQS stuff
.allowlist_recursively(false)
.allowlist_type(filter)
.allowlist_function(filter)
.allowlist_var(filter)
// Use core and libc
.use_core()
.ctypes_prefix("::libc")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings")
.write_to_file(out_path.join(format!("{headerfile}_bindings.rs")))
.expect("Couldn't write bindings!");
}
fn build_from_source() -> PathBuf {
let mut config = cmake::Config::new("liboqs");
config.profile("Release");
config.define("OQS_BUILD_ONLY_LIB", "Yes");
if cfg!(feature = "non_portable") {
// Build with CPU feature detection or just enable whatever is available for this CPU
config.define("OQS_DIST_BUILD", "No");
} else {
config.define("OQS_DIST_BUILD", "Yes");
}
macro_rules! algorithm_feature {
($typ:literal, $feat: literal) => {
let configflag = format!("OQS_ENABLE_{}_{}", $typ, $feat.to_ascii_uppercase());
let value = if cfg!(feature = $feat) { "Yes" } else { "No" };
config.define(&configflag, value);
};
}
// KEMs
// BIKE is not supported on Windows or Arm32, so if either is in the mix,
// have it be opt-in explicitly except through the default kems feature.
if cfg!(feature = "kems") && !(cfg!(windows) || cfg!(target_arch = "arm")) {
println!("cargo:rustc-cfg=feature=\"bike\"");
config.define("OQS_ENABLE_KEM_BIKE", "Yes");
} else {
algorithm_feature!("KEM", "bike");
}
algorithm_feature!("KEM", "classic_mceliece");
algorithm_feature!("KEM", "frodokem");
algorithm_feature!("KEM", "hqc");
algorithm_feature!("KEM", "kyber");
algorithm_feature!("KEM", "ntruprime");
// signature schemes
algorithm_feature!("SIG", "dilithium");
algorithm_feature!("SIG", "falcon");
algorithm_feature!("SIG", "sphincs");
if cfg!(windows) {
// Select the latest available Windows SDK
// SDK version 10.0.17763.0 seems broken
config.define("CMAKE_SYSTEM_VERSION", "10.0");
}
if cfg!(feature = "openssl") {
config.define("OQS_USE_OPENSSL", "Yes");
if cfg!(windows) {
// Windows doesn't prefix with lib
println!("cargo:rustc-link-lib=libcrypto");
} else {
println!("cargo:rustc-link-lib=crypto");
}
println!("cargo:rerun-if-env-changed=OPENSSL_ROOT_DIR");
if let Ok(dir) = std::env::var("OPENSSL_ROOT_DIR") {
let dir = Path::new(&dir).join("lib");
println!("cargo:rustc-link-search={}", dir.display());
} else if cfg!(target_os = "windows") || cfg!(target_os = "macos") {
println!("cargo:warning=You may need to specify OPENSSL_ROOT_DIR or disable the default `openssl` feature.");
}
} else {
config.define("OQS_USE_OPENSSL", "No");
}
let permit_unsupported = "OQS_PERMIT_UNSUPPORTED_ARCHITECTURE";
if let Ok(str) = std::env::var(permit_unsupported) {
config.define(permit_unsupported, str);
}
let outdir = config.build_target("oqs").build();
// lib is put into $outdir/build/lib
let mut libdir = outdir.join("build").join("lib");
if cfg!(windows) {
libdir.push("Release");
// Static linking doesn't work on Windows
println!("cargo:rustc-link-lib=oqs");
} else {
// Statically linking makes it easier to use the sys crate
println!("cargo:rustc-link-lib=static=oqs");
}
println!("cargo:rustc-link-search=native={}", libdir.display());
outdir
}
fn includedir_from_source() -> PathBuf {
let outdir = build_from_source();
outdir.join("build").join("include")
}
fn probe_includedir() -> PathBuf {
if cfg!(feature = "vendored") {
return includedir_from_source();
}
println!("cargo:rerun-if-env-changed=LIBOQS_NO_VENDOR");
let force_no_vendor = std::env::var_os("LIBOQS_NO_VENDOR").map_or(false, |v| v != "0");
let version = env!("CARGO_PKG_VERSION");
let (_, liboqs_version) = version.split_once("+liboqs-").unwrap();
let &[major_version, minor_version, _] =
liboqs_version.split('.').collect::<Vec<_>>().as_slice()
else {
panic!("Failed to parse target liboqs version");
};
let minor_num: usize = minor_version.parse().unwrap();
let upper_bound = format!("{}.{}.0", major_version, minor_num + 1);
let config = pkg_config::Config::new()
.range_version(liboqs_version..upper_bound.as_str())
.probe("liboqs");
match config {
Ok(lib) => lib.include_paths.first().cloned().unwrap(),
_ => {
if force_no_vendor {
panic!("The env variable LIBOQS_NO_VENDOR has been set but a suitable system liboqs could not be found.");
}
includedir_from_source()
}
}
}
fn main() {
// Check if clang is available before compiling anything.
bindgen::clang_version();
let includedir = probe_includedir();
let gen_bindings = |file, filter| generate_bindings(&includedir, file, filter);
gen_bindings("common", "OQS_.*");
gen_bindings("rand", "OQS_(randombytes|RAND)_.*");
gen_bindings("kem", "OQS_KEM.*");
gen_bindings("sig", "OQS_SIG.*");
// https://docs.rs/build-deps/0.1.4/build_deps/fn.rerun_if_changed_paths.html
build_deps::rerun_if_changed_paths("liboqs/src/**/*").unwrap();
build_deps::rerun_if_changed_paths("liboqs/src").unwrap();
build_deps::rerun_if_changed_paths("liboqs/src/*").unwrap();
}