Skip to content

Commit cda52bb

Browse files
authored
Merge pull request #36 from HunkBenny/main
Add `def.h` to bindgen + solved deprecation warning
2 parents 932454f + 29bc346 commit cda52bb

File tree

3 files changed

+88
-10
lines changed

3 files changed

+88
-10
lines changed

build.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod bundled;
2+
mod callback;
23
mod from_source;
34

45
#[cfg(any(feature = "bundled", feature = "from-source"))]
@@ -13,6 +14,7 @@ use std::path::PathBuf;
1314

1415
use crate::from_source::{compile_scip, download_scip_source, is_from_source_feature_enabled};
1516
use bundled::*;
17+
use callback::DeriveCastedConstant;
1618

1719
#[cfg(not(feature = "bundled"))]
1820
pub fn is_bundled_feature_enabled() -> bool {
@@ -60,11 +62,19 @@ fn _build_from_scip_dir(path: &str) -> bindgen::Builder {
6062
.to_str()
6163
.unwrap()
6264
.to_owned();
65+
let scipdef_file = PathBuf::from(&path)
66+
.join("include")
67+
.join("scip")
68+
.join("def.h")
69+
.to_str()
70+
.unwrap()
71+
.to_owned();
6372

6473
bindgen::Builder::default()
6574
.header(scip_header_file)
6675
.header(scipdefplugins_header_file)
67-
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
76+
.header(scipdef_file)
77+
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
6878
.clang_arg(format!("-I{}", include_dir_path))
6979
}
7080

@@ -90,7 +100,7 @@ fn look_in_scipoptdir_and_conda_env() -> Option<bindgen::Builder> {
90100
}
91101
}
92102

93-
return None;
103+
None
94104
}
95105

96106
fn try_system_include_paths() -> Option<bindgen::Builder> {
@@ -100,25 +110,27 @@ fn try_system_include_paths() -> Option<bindgen::Builder> {
100110
let search_paths = vec![
101111
"/usr/include",
102112
"/usr/local/include",
103-
"/opt/local/include", // MacPorts
104-
"/opt/homebrew/include", // Homebrew ARM Mac
105-
"/usr/local/opt/scip/include", // Homebrew Intel Mac
113+
"/opt/local/include", // MacPorts
114+
"/opt/homebrew/include", // Homebrew ARM Mac
115+
"/usr/local/opt/scip/include", // Homebrew Intel Mac
106116
];
107117

108118
for base_path in search_paths {
109119
let base = PathBuf::from(base_path);
110120
let scip_h = base.join("scip").join("scip.h");
111121
let scipdefplugins_h = base.join("scip").join("scipdefplugins.h");
122+
let def_h = base.join("scip").join("def.h");
112123

113-
if scip_h.exists() && scipdefplugins_h.exists() {
124+
if scip_h.exists() && scipdefplugins_h.exists() && def_h.exists() {
114125
println!("cargo:warning=Found SCIP headers in {}", base_path);
115126

116127
return Some(
117128
bindgen::Builder::default()
118129
.header(scip_h.to_str().unwrap())
119130
.header(scipdefplugins_h.to_str().unwrap())
120-
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
121-
.clang_arg(format!("-I{}", base_path))
131+
.header(def_h.to_str().unwrap())
132+
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
133+
.clang_arg(format!("-I{}", base_path)),
122134
);
123135
}
124136
}
@@ -188,14 +200,17 @@ fn main() -> Result<(), Box<dyn Error>> {
188200
println!("cargo:rustc-link-lib=soplex");
189201
}
190202
}
203+
// Setup the DeriveCastedConstant callback to target SCIP_INVALID
204+
let derive_casted_constant = DeriveCastedConstant::new().target("SCIP_INVALID");
191205

192206
let builder = builder
193207
.blocklist_item("FP_NAN")
194208
.blocklist_item("FP_INFINITE")
195209
.blocklist_item("FP_ZERO")
196210
.blocklist_item("FP_SUBNORMAL")
197211
.blocklist_item("FP_NORMAL")
198-
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
212+
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
213+
.parse_callbacks(Box::new(derive_casted_constant));
199214

200215
let bindings = builder.generate()?;
201216
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

callback.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! This file contains some custom callbacks for bindgen.
2+
3+
use bindgen::callbacks::{Token, TokenKind};
4+
use std::collections::HashSet;
5+
6+
/// This callback will be used to remove the type casts.
7+
/// bindgen has a hard time parsing constants with type casts like
8+
/// ```rust
9+
/// #define SCIP_INVALID (double)1e99
10+
/// ```
11+
///
12+
/// ### Note;
13+
/// Maybe we should be careful on which macros we use this? I can see a situation where Rust and C
14+
/// would have different opinions on what the macro should look like.
15+
#[derive(Debug)]
16+
pub struct DeriveCastedConstant {
17+
/// Set of macros to target for removing type casts
18+
targets: HashSet<String>,
19+
}
20+
21+
impl DeriveCastedConstant {
22+
pub fn new() -> Self {
23+
DeriveCastedConstant {
24+
targets: HashSet::new(),
25+
}
26+
}
27+
28+
pub fn target(mut self, name: &str) -> Self {
29+
self.targets.insert(name.to_string());
30+
self
31+
}
32+
}
33+
34+
/// Implement the ParseCallbacks trait for DeriveCastedConstant
35+
impl bindgen::callbacks::ParseCallbacks for DeriveCastedConstant {
36+
fn modify_macro(&self, _name: &str, _tokens: &mut Vec<Token>) {
37+
// modify SCIP_INVALID
38+
if self.targets.contains(_name) {
39+
// So here we are looking for a pattern like ['(', type, ')']
40+
let position_cast = _tokens.windows(3).position(|window| match window {
41+
[Token {
42+
kind: TokenKind::Punctuation,
43+
raw: left_parenthesis,
44+
}, Token {
45+
// this will not go off on a cast like (SCIP_Real) as SCIP_Real is not a
46+
// Clang-keyword
47+
kind: TokenKind::Keyword,
48+
..
49+
}, Token {
50+
kind: TokenKind::Punctuation,
51+
raw: right_parenthesis,
52+
}] => **left_parenthesis == *b"(" && **right_parenthesis == *b")",
53+
_ => false,
54+
});
55+
if let Some(pos) = position_cast {
56+
// position found! So a macro with a type cast exists. We remove the typecast.
57+
*_tokens = [&_tokens[..pos], &_tokens[pos + 3..]].concat();
58+
}
59+
}
60+
}
61+
}

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
1010

1111
#[cfg(test)]
1212
mod tests {
13-
use std::ffi::CString;
1413
use super::*;
14+
use std::ffi::CString;
1515
use std::mem::MaybeUninit;
1616

1717
#[test]
@@ -68,5 +68,7 @@ mod tests {
6868
unsafe { SCIPreleaseVar(scip_ptr, &mut var_ptr) };
6969
unsafe { SCIPreleaseCons(scip_ptr, &mut cons_ptr) };
7070
unsafe { SCIPfree(&mut scip_ptr) };
71+
// Get some constants defined in def.h
72+
println!("Found SCIP_INVALID: {}", SCIP_INVALID);
7173
}
7274
}

0 commit comments

Comments
 (0)