wrap_static_fns is missing from bindgen::Builder
Hi, I think I'm going crazy, I have been trying to use an external C library in my Rust program without success.
The C library is uhubctl, source code is here https://github.com/mvp/uhubctl/tree/master
As you can see most of the important functions are declared as static functions, for instance
static int usb_find_hubs(void)
And I need to expose them to my Rust program.
After struggling for a while, I realise that the bindings.rs file generated by Bindgen doesn't contain anything, and I also realised that I need the wrap_static_fns flag. Allegedly it should be a method in bindgen::Builder.
However, my VSCode keeps saying that the method is not found, and cargo build gives the same result.
error[E0599]: no method named `wrap_static_fns` found for struct `bindgen::Builder` in the current scope
If I run the command line version
bindgen libs/uhubctl.h -o src/bindings.rs -- -I//opt/homebrew/Cellar/libusb/1.0.27/include/libusb-1.0 -DPROGRAM_VERSION=\"2.6.0\" --wrap-static-fns
I get
panicked at /Users/hoang.bui/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-cli-0.70.1/main.rs:45:36:
Unable to generate bindings: ClangDiagnostic("error: unsupported option '--wrap-static-fns'\n")
I am also a total beginner in Rust so I'm completely lost.
I am on macOS Sonoma 14.6.1, rustc 1.82.0 bindgen 0.70.1
Here is my build.rs
/* File: build.rs */
extern crate bindgen;
extern crate cc;
use std::path::PathBuf;
fn main() {
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=libs/uhubctl.c");
let libusb_header_path_flag = "-I/opt/homebrew/Cellar/libusb/1.0.27/include/libusb-1.0";
let uhubctl_version_flag = "-DPROGRAM_VERSION=\"2.6.0\"";
let bindings = bindgen::Builder::default()
// The input header we would like to generate bindings for.
.header("libs/uhubctl.h")
.wrap_static_fns(true)
.clang_arg(libusb_header_path_flag)
.clang_arg(uhubctl_version_flag)
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// Finish the builder and generate the bindings.
.generate()
.expect("Unable to generate bindings");
// Write the bindings to the src/bindings.rs file.
let out_path = PathBuf::from("src");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
// Build static library
cc::Build::new()
.file("libs/uhubctl.c")
.flag(libusb_header_path_flag)
.flag(uhubctl_version_flag)
.compile("uhubctl.a");
}
Any help would be much appreciated!
My first bet is that you're not actually using 0.70.1 as the released crate clearly has this method: https://docs.rs/bindgen/0.70.1/bindgen/struct.Builder.html#method.wrap_static_fns
The command line version is also wrong as you're passing --wrap-static-fns after the -- which means it is being passed as a CLI argument to clang:
Usage: bindgen <FLAGS> <OPTIONS> <HEADER> -- <CLANG_ARGS>...
Arguments:
[HEADER] C or C++ header file
[CLANG_ARGS]... Arguments to be passed straight through to clang
That means that you must pass --wrap-static-fns before the --.
@pvdrz you are right about the command line, I changed it to
bindgen libs/uhubctl.h -o src/bindings.rs --experimental --wrap-static-fns -- -I//opt/homebrew/Cellar/libusb/1.0.27/include/libusb-1.0 -DPROGRAM_VERSION=\"2.6.0\"
and it worked.
However I'm not sure about the crate, I believe I am on 0.70.1.
Here's my Cargo.toml
[package]
name = "android-charge-limiter-rust"
version = "0.1.0"
edition = "2021"
[build-dependencies]
bindgen = "0.70.1"
cc = "1.0"
[dependencies]
and my Cargo.lock also says 0.70.1
[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
I tried deleting Cargo.lock and target/ folder and rebuild, the same result as before
I shift-click on bindgen::Builder to see the underlying code, it takes me to a path in ~/.cargo/ that looks like the right version 0.70.1, but the wrap_static_fns function is nowhere to be found
Here is the content of the ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.70.1 folder if it helps bindgen-0.70.1.zip
And here is my project's source code, maybe someone can try to reproduce android-charge-limiter-rust.zip
I think that's because you're missing the experimental feature on your bindgen dependency.
@pvdrz could you point to an example or tutorial? The tutorial at https://rust-lang.github.io/rust-bindgen/introduction.html as well as https://github.com/rust-lang/rust-bindgen/discussions/2405 does not have anything on this
Edit: After some Googling, I followed this guide roughly to add a feature, as a shot in the dark https://doc.rust-lang.org/cargo/reference/features.html I changed the bindgen line in Cargo.toml to
bindgen = { version = "0.70.1", features = ["experimental"] }
and it worked.
I think these things need to be mentioned in the pages that talk about wrap_static_fns or anything that requires this feature
yeah this might have been an oversight. But the next version of bindgen won't require the experimental to use the feature.