Skip to content

Commit bc1054f

Browse files
committed
feat(sys): import types from openssl-sys
The change introduces an optional feature nginx-sys/openssl-sys that replaces some generated types with corresponding imports from "libc".
1 parent 26515b9 commit bc1054f

File tree

4 files changed

+202
-4
lines changed

4 files changed

+202
-4
lines changed

Cargo.lock

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nginx-sys/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,21 @@ default-target = "x86_64-unknown-linux-gnu"
2020
targets = []
2121

2222
[dependencies]
23+
openssl-sys = { version = "0.9.109", optional = true }
2324

2425
[target.'cfg(not(windows))'.dependencies]
2526
errno = { version = "0.3", default-features = false }
2627

2728
[build-dependencies]
2829
bindgen = "0.71"
30+
bitflags = "2.9.1"
2931
cc = "1.2.0"
3032
dunce = "1.0.5"
3133
regex = "1.11.1"
3234
nginx-src = { version = "~1.28.0", optional = true, path = "../nginx-src" }
3335

3436
[features]
37+
# Reexport types from "openssl-sys" instead of generating our own bindings.
38+
# Note that openssl-sys depends on "std".
39+
openssl-sys = ["dep:openssl-sys"]
3540
vendored = ["dep:nginx-src"]
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
use std::collections::HashMap;
2+
3+
use bindgen::callbacks::{DeriveTrait, ImplementsTrait};
4+
use bitflags::bitflags;
5+
6+
bitflags! {
7+
/// Efficient encoding for bindgen type information enums
8+
#[derive(Clone, Debug)]
9+
pub struct TypeFlags: u8 {
10+
const COPY = 1;
11+
const DEBUG = 1 << 1;
12+
const DEFAULT = 1 << 2;
13+
const HASH = 1 << 3;
14+
const PARTIAL_ORD_OR_PARTIAL_EQ = 1 << 4;
15+
}
16+
}
17+
18+
impl TypeFlags {
19+
pub fn implements(&self, t: DeriveTrait) -> bool {
20+
match t {
21+
DeriveTrait::Copy => self.contains(Self::COPY),
22+
DeriveTrait::Debug => self.contains(Self::DEBUG),
23+
DeriveTrait::Default => self.contains(Self::DEFAULT),
24+
DeriveTrait::Hash => self.contains(Self::HASH),
25+
DeriveTrait::PartialEqOrPartialOrd => self.contains(Self::PARTIAL_ORD_OR_PARTIAL_EQ),
26+
}
27+
}
28+
}
29+
30+
#[derive(Debug)]
31+
struct Crate<'a> {
32+
name: &'a str,
33+
types: HashMap<&'a str, TypeFlags>,
34+
}
35+
36+
impl<'a> Crate<'a> {
37+
pub fn new(name: &'a str, types: impl IntoIterator<Item = (&'a str, TypeFlags)>) -> Self {
38+
Self {
39+
name,
40+
types: HashMap::from_iter(types),
41+
}
42+
}
43+
44+
pub fn type_names(&self) -> impl Iterator<Item = &str> {
45+
self.types.keys().cloned()
46+
}
47+
48+
pub fn uses(&self) -> Option<String> {
49+
if self.types.is_empty() {
50+
return None;
51+
}
52+
53+
Some(format!(
54+
r#"
55+
#[allow(unused_imports)]
56+
pub use {}::{{{}}};
57+
"#,
58+
self.name,
59+
self.type_names().collect::<Vec<_>>().join(",")
60+
))
61+
}
62+
}
63+
64+
#[derive(Debug, Default)]
65+
pub struct NgxBindgenCallbacks<'a>(Vec<Crate<'a>>);
66+
67+
impl<'a> NgxBindgenCallbacks<'a> {
68+
pub fn new() -> Self {
69+
Self::default()
70+
}
71+
72+
pub fn add_external_types(
73+
&mut self,
74+
source: &'a str,
75+
types: impl IntoIterator<Item = (&'a str, TypeFlags)>,
76+
) {
77+
if let Some(c) = self.0.iter_mut().find(|c| c.name == source) {
78+
c.types.extend(types)
79+
} else {
80+
self.0.push(Crate::new(source, types));
81+
}
82+
}
83+
84+
fn find(&self, name: &str) -> Option<(&Crate, &str, &TypeFlags)> {
85+
for c in &self.0[..] {
86+
for (key, value) in c.types.iter() {
87+
if *key == name {
88+
return Some((c, *key, value));
89+
}
90+
}
91+
}
92+
None
93+
}
94+
95+
fn blocklist(&self) -> String {
96+
self.0
97+
.iter()
98+
.flat_map(Crate::type_names)
99+
.collect::<Vec<_>>()
100+
.join("|")
101+
}
102+
103+
fn uses(&self) -> String {
104+
self.0
105+
.iter()
106+
.flat_map(Crate::uses)
107+
.collect::<Vec<_>>()
108+
.join("\n")
109+
}
110+
111+
pub fn add_to_builder(self, mut builder: bindgen::Builder) -> bindgen::Builder
112+
where
113+
'a: 'static,
114+
{
115+
let blocklist = self.blocklist();
116+
if !blocklist.is_empty() {
117+
builder = builder.blocklist_type(blocklist);
118+
}
119+
120+
let uses = self.uses();
121+
if !uses.is_empty() {
122+
builder = builder.raw_line(uses);
123+
}
124+
125+
builder.parse_callbacks(Box::new(self))
126+
}
127+
}
128+
129+
impl<'a> bindgen::callbacks::ParseCallbacks for NgxBindgenCallbacks<'a> {
130+
fn blocklisted_type_implements_trait(
131+
&self,
132+
name: &str,
133+
derive_trait: DeriveTrait,
134+
) -> Option<ImplementsTrait> {
135+
let parts = name.split_ascii_whitespace().collect::<Vec<_>>();
136+
let type_name = match &parts[..] {
137+
["const", "struct", n] => n,
138+
["const", n] => n,
139+
["struct", n] => n,
140+
[n] => n,
141+
_ => panic!("unhandled blocklisted type: {name}"),
142+
};
143+
144+
if self.find(type_name)?.2.implements(derive_trait) {
145+
return Some(ImplementsTrait::Yes);
146+
}
147+
None
148+
}
149+
}

nginx-sys/build/main.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use std::fs::{read_to_string, File};
66
use std::io::Write;
77
use std::path::{Path, PathBuf};
88

9+
mod bindgen_callbacks;
10+
911
const ENV_VARS_TRIGGERING_RECOMPILE: &[&str] = &["OUT_DIR", "NGINX_BUILD_DIR", "NGINX_SOURCE_DIR"];
1012

1113
/// The feature flags set by the nginx configuration script.
@@ -228,7 +230,7 @@ fn generate_binding(nginx: &NginxSource) {
228230
#[cfg(not(windows))]
229231
let macro_dependencies = ["random", "sched_yield", "usleep"];
230232

231-
let bindings = bindgen::Builder::default()
233+
let mut bindings = bindgen::Builder::default()
232234
// Allow all the NGINX symbols,
233235
.allowlist_function("ngx_.*")
234236
.allowlist_type("ngx_.*")
@@ -246,9 +248,25 @@ fn generate_binding(nginx: &NginxSource) {
246248
.clang_args(clang_args)
247249
.layout_tests(false)
248250
.rust_target(rust_target)
249-
.use_core()
250-
.generate()
251-
.expect("Unable to generate bindings");
251+
.use_core();
252+
253+
if cfg!(feature = "openssl-sys") {
254+
use bindgen_callbacks::TypeFlags as TF;
255+
256+
let mut callbacks = bindgen_callbacks::NgxBindgenCallbacks::new();
257+
callbacks.add_external_types(
258+
"openssl_sys",
259+
[
260+
("SSL", TF::empty()),
261+
("SSL_CTX", TF::empty()),
262+
("SSL_SESSION", TF::empty()),
263+
],
264+
);
265+
266+
bindings = callbacks.add_to_builder(bindings);
267+
}
268+
269+
let bindings = bindings.generate().expect("Unable to generate bindings");
252270

253271
// Write the bindings to the $OUT_DIR/bindings.rs file.
254272
let out_dir_env =

0 commit comments

Comments
 (0)