1#![allow(clippy::uninlined_format_args)]
2
3use std::env;
4
5#[allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)]
6#[path = "../openssl-sys/build/cfgs.rs"]
7mod cfgs;
8
9fn main() {
10    let mut cfg = ctest2::TestGenerator::new();
11    let target = env::var("TARGET").unwrap();
12
13    if let Ok(out) = env::var("DEP_OPENSSL_INCLUDE") {
14        cfg.include(&out);
15    }
16
17    // Needed to get OpenSSL to correctly undef symbols that are already on
18    // Windows like X509_NAME
19    if target.contains("windows") {
20        cfg.header("windows.h");
21
22        // weird "different 'const' qualifiers" error on Windows, maybe a cl.exe
23        // thing?
24        if target.contains("msvc") {
25            cfg.flag("/wd4090");
26        }
27
28        // https://github.com/sfackler/rust-openssl/issues/889
29        cfg.define("WIN32_LEAN_AND_MEAN", None);
30    }
31
32    let openssl_version = env::var("DEP_OPENSSL_VERSION_NUMBER")
33        .ok()
34        .map(|v| u64::from_str_radix(&v, 16).unwrap());
35    let libressl_version = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER")
36        .ok()
37        .map(|v| u64::from_str_radix(&v, 16).unwrap());
38
39    cfg.cfg("openssl", None);
40
41    for c in cfgs::get(openssl_version, libressl_version) {
42        cfg.cfg(c, None);
43    }
44
45    if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
46        for var in vars.split(',') {
47            cfg.cfg("osslconf", Some(var));
48        }
49    }
50
51    cfg.header("openssl/comp.h")
52        .header("openssl/dh.h")
53        .header("openssl/ossl_typ.h")
54        .header("openssl/stack.h")
55        .header("openssl/x509.h")
56        .header("openssl/bio.h")
57        .header("openssl/x509v3.h")
58        .header("openssl/safestack.h")
59        .header("openssl/cmac.h")
60        .header("openssl/hmac.h")
61        .header("openssl/obj_mac.h")
62        .header("openssl/ssl.h")
63        .header("openssl/err.h")
64        .header("openssl/rand.h")
65        .header("openssl/pkcs12.h")
66        .header("openssl/bn.h")
67        .header("openssl/aes.h")
68        .header("openssl/ocsp.h")
69        .header("openssl/evp.h")
70        .header("openssl/x509_vfy.h");
71
72    if libressl_version.is_some() {
73        cfg.header("openssl/poly1305.h");
74    }
75
76    if let Some(version) = openssl_version {
77        cfg.header("openssl/cms.h");
78        if version >= 0x10100000 {
79            cfg.header("openssl/kdf.h");
80        }
81
82        if version >= 0x30000000 {
83            cfg.header("openssl/provider.h");
84        }
85    }
86
87    #[allow(clippy::if_same_then_else)]
88    cfg.type_name(|s, is_struct, _is_union| {
89        // Add some `*` on some callback parameters to get function pointer to
90        // typecheck in C, especially on MSVC.
91        if s == "PasswordCallback" {
92            "pem_password_cb*".to_string()
93        } else if s == "bio_info_cb" {
94            "bio_info_cb*".to_string()
95        } else if s == "_STACK" {
96            "struct stack_st".to_string()
97        // This logic should really be cleaned up
98        } else if is_struct
99            && s != "point_conversion_form_t"
100            && s.chars().next().unwrap().is_lowercase()
101        {
102            format!("struct {}", s)
103        } else if s.starts_with("stack_st_") {
104            format!("struct {}", s)
105        } else {
106            s.to_string()
107        }
108    });
109    cfg.skip_type(|s| {
110        // function pointers are declared without a `*` in openssl so their
111        // sizeof is 1 which isn't what we want.
112        s == "PasswordCallback"
113            || s == "pem_password_cb"
114            || s == "bio_info_cb"
115            || s.starts_with("CRYPTO_EX_")
116    });
117    cfg.skip_struct(|s| {
118        s == "ProbeResult" ||
119            s == "X509_OBJECT_data" || // inline union
120            s == "DIST_POINT_NAME_st_anon_union" || // inline union
121            s == "PKCS7_data" ||
122            s == "ASN1_TYPE_value"
123    });
124    cfg.skip_fn(move |s| {
125        s == "CRYPTO_memcmp" ||                 // uses volatile
126
127        // Skip some functions with function pointers on windows, not entirely
128        // sure how to get them to work out...
129        (target.contains("windows") && {
130            s.starts_with("PEM_read_bio_") ||
131            (s.starts_with("PEM_write_bio_") && s.ends_with("PrivateKey")) ||
132            s == "d2i_PKCS8PrivateKey_bio" ||
133            s == "i2d_PKCS8PrivateKey_bio" ||
134            s == "SSL_get_ex_new_index" ||
135            s == "SSL_CTX_get_ex_new_index" ||
136            s == "CRYPTO_get_ex_new_index"
137        })
138    });
139    cfg.skip_field_type(|s, field| {
140        (s == "EVP_PKEY" && field == "pkey") ||      // union
141            (s == "GENERAL_NAME" && field == "d") || // union
142            (s == "DIST_POINT_NAME" && field == "name") || // union
143            (s == "X509_OBJECT" && field == "data") || // union
144            (s == "PKCS7" && field == "d") || // union
145            (s == "ASN1_TYPE" && field == "value") // union
146    });
147    cfg.skip_signededness(|s| {
148        s.ends_with("_cb")
149            || s.ends_with("_CB")
150            || s.ends_with("_cb_fn")
151            || s.starts_with("CRYPTO_")
152            || s == "PasswordCallback"
153            || s.ends_with("_cb_func")
154            || s.ends_with("_cb_ex")
155    });
156    cfg.field_name(|_s, field| {
157        if field == "type_" {
158            "type".to_string()
159        } else {
160            field.to_string()
161        }
162    });
163    cfg.fn_cname(|rust, link_name| link_name.unwrap_or(rust).to_string());
164    cfg.generate("../openssl-sys/src/lib.rs", "all.rs");
165}
166