rust-bindgen
rust-bindgen copied to clipboard
Missing constants on macOS vs Linux
I get some #define constants from a C header missing in the generated bindings when building on Linux vs. macOS.
The constants in question, all starting with the TA_INTEGER prefix, are not behind any conditionals #if in the header but use other constants. See C Header section below.
Namely they use INT_MIN/INT_MAX which come from limits.h. The C lib I am wrapping builds fine and its code uses TA_INTEGER_MIN/TA_INTEGER_MAX/TA_INTEGER_DEFAULT; i.e. the constants from limits.h are 'seen' and used – on both platforms.
I am using Rust nighly and latest bindgen. Of note: clang is @ 5.0.1 on the Linux (CentOS) vs 12.0 on macOS.
Grepping on the bindings on macOS:
~/c/c/ta-lib-rs/tar/d/b/ta-lib-sys-9975acf6d6f5a59e
❯ rg TA_INTEGER_DEFAULT
out/bindings.rs
7:pub const TA_INTEGER_DEFAULT: i32 = -2147483648;
out/include/ta-lib/ta_defs.h
213:#define TA_INTEGER_DEFAULT (INT_MIN)
But on Linux:
~/c/c/ta-lib-rs/tar/d/b/ta-lib-sys-26bcdc06d91e3e82
❯ rg TA_INTEGER
out/include/ta-lib/ta_defs.h
213:#define TA_INTEGER_DEFAULT (INT_MIN)
If I run the above, grepping for TA_REAL instead, I get the same output on both platforms. I.e. constants starting with TA_REAL are there, constants starting with TA_INTEGER are missing on Linux.
It looks as if some stuff incoming from limits.h is just not recognized/omitted by bindgen which then leads to the TA_INTEGER prefixed constants missing in the generated binding. Just a guess ofc.
C Header
The actual offending header is this one, ta_defs.h, line 213 – #define TA_INTEGER_DEFAULT (INT_MIN).
/* min/max value for a TA_Integer */
#define TA_INTEGER_MIN (INT_MIN+1)
#define TA_INTEGER_MAX (INT_MAX)
/* min/max value for a TA_Real
*
* Use fix value making sense in the
* context of TA-Lib (avoid to use DBL_MIN
* and DBL_MAX standard macro because they
* are troublesome with some compiler).
*/
#define TA_REAL_MIN (-3e+37)
#define TA_REAL_MAX (3e+37)
/* A value outside of the min/max range
* indicates an undefined or default value.
*/
#define TA_INTEGER_DEFAULT (INT_MIN)
#define TA_REAL_DEFAULT (-4e+37)
Bindgen Invocation
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_arg(format!("-I{}", out_path.join("include").display()))
.allowlist_function("TA_.*")
.allowlist_type("TA_.*")
.allowlist_var("TA_.*")
.generate()
This then leads to a bunch of:
error[E0425]: cannot find value `TA_INTEGER_DEFAULT` in crate `ta`
--> ta-lib/src/macros.rs:170:29
|
170 | ta::TA_INTEGER_DEFAULT
| ^^^^^^^^^^^^^^^^^^ help: a constant with a similar name exists: `TA_REAL_DEFAULT`
I guess this is really an issue with whether INT_MIN is seen by bindgen on macOS, but maybe we can special-case and define them based on the target integer size.
Just to clarify: INT_MIN is seen on macOS but not seen on Linux/CentOS.
I worked around this for now in my wrapper crate but it's probably worth following up the root cause of this.
I have this problem on Linux as well. My clang version is Ubuntu clang version 14.0.0-1ubuntu1 and bindgen version is 0.63.0.