I am trying to compile bindings for the SEAL C++ library. Here is my repo.
// Generate the bindings
let bindings = bindgen::Builder::default()
.generate_inline_functions(true)
.derive_default(true)
.header("./seal/src/seal/seal.h")
.clang_arg("-I./seal/src/")
.clang_arg("-std=c++17")
.clang_arg("-x")
.clang_arg("c++")
.opaque_type("std::.*")
.whitelist_type("seal::.*")
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from("./src/");
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
bindings.rs does not have anything from defaultparams.h
What do I have to add to the Builder object to include defaultparams.h's functions in the generated bindings? I need coeff_modulus_128() for example.
I tried whitelisting the std::vector but it did not have any impact on the generated bindings.
Solved by adding .whitelist_function("seal::.*") to the build.rs file. Since the inline functions weren't enclosed in a type, they were not whitelisted by the current config.
Related
I am trying to find a macro like cfg (let's call it my_cfg) that would conditionally compile based on a custom configuration file (like Toml or Yaml) instead of definitions from Cargo.toml of a package. My use case is that I have a bunch of packages with workspace, and I would like to have one place, e.g. config package, that can be referenced by other packages. And my_cfg would use values in this fashion:
#[my_cfg(config1)]
const CONST1: usize = 10;
#[my_cfg(config2)]
const CONST1: usize = 100;
The values config1 and config2 are defined in a package called config.
I am trying to use syn::parse_file function from syn crate.
But, I unable to use it and found a function in the crate with feature attribute:
#[cfg(all(feature = "parsing", feature = "full"))]
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
pub fn parse_file(mut content: &str) -> Result<File> {
// other code
}
Unable to find any discription of this feature.
How do I enable these features in my project?
And use this function.
You can enable a certain crate feature in the Cargo.toml config file - where you specify the crate itself and its version.
For the syn crate, the parsing feature is enabled by default but full is not, as described in the docs.
Here you can read more about how to enable features for your crates (dependencies).
I have a header file lets say greetings.h:
include <hello.h>;
include <bye.h>;
include <hola.h>;
...
Im using bindgen in rust to generate those file from c header to rust.
But I want to ignore generating the include <hola.h> header and generate the greeting.h only with helllo.h and bye.h.
I have searched it in docs.rs bindgen documentation but not found any hint on that.
or is there any option to do that with clang
I was able to solve this by guessing that my library that Im trying to bind from c to rust are "namespaced", in C language there is no actually namespaces but people that write open source code tend to prefix their code with "some_prefix*".
So if the h file that I want to bind looks like:
mylib.h:
include <hello.h>;
include <bye.h>;
include <hola.h>;
...
mylib_add_value(...);
mylib_remove_value(...);
mylib_display_value(...);
...
and I don't want the hola.h to be generated,
i can filter the output with allow and block functionality of bingden like:
build.rs:
fn main() {
// Tell cargo to tell rustc to link the system nvpair of zfs
// shared library.
println!("cargo:rustc-link-lib=mylib");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
.allowlist_var(r#"(\w*mylib\w*)"#)
.allowlist_type(r#"(\w*mylib\w*)"#)
.allowlist_function(r#"(\w*mylib\w*)"#)
.blocklist_item(r#"(\w*hola\w*)"#)
.blocklist_type(r#"(\w*hola\w*)"#)
.blocklist_function(r#"(\w*hola\w*)"#)
.clang_args(vec!["-I/usr/include/mylib"])
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: (true),
})
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
//.write_to_file(out_path)
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
Bindgen will bring all dependencies of allowlist firstly and if some of the dependencies include *hola* it won't generate it.
I'm currently trying to learn Rust (for embedded specifically), coming from a background of C for embedded systems and Python.
So far, I've been reading Rust Programming Language and Rust for Embedded, and read a few blog posts on the web.
I want my first project to be a simple "Blinky", where an LED blinks infinitely. I've got an STM32L152CDISCOVERY board with an STM32L152 chip in it (basically same as STM32L151), which is a Cortex M3.
Instead of implementing everything from scratch, I want to leverage existing crates and HALs. I've found two that seem promising: stm32l1 and stm32l1xx-hal. I've tried to read the documentation of each of them and also part of the source code, but I still can't figure out how to use them correctly.
Got a few questions about Rust and about the crates:
I see that stm32l1xx-hal has a dependency on stm32l1. Do I need to add both as a dependency in my Cargo.toml file? Or will that create problems related to ownership?
Is this the correct way to add them? Why is the second one added like that [dependencies.stm32l1]?
[dependencies]
cortex-m-rt = "0.6.10"
cortex-m-semihosting = "0.3.3"
panic-halt = "0.2.0"
stm32l1xx-hal = "0.1.0"
[dependencies.stm32l1]
version = "0.13.0"
features = ["stm32l151", "rt"]
To blink the LD4 (which is connected to PB4 PB6), I've got to enable the GPIOB in the RCC register and then configure the pin to push pull output. By inspecting the documentation of stm32l1xx-hal, I see that there is an RCC struct and a PB4 struct with the method into_push_pull_output. However, I still don't understand how to use these structs: how to import them or how to get an instance of them.
I've seen code examples for stm32l1 but not for stm32l1xx-hal. I know that I can do this:
use stm32l1::{stm32l151};
...
let p = stm32l151::Peripherals::take().unwrap();
p.RCC.ahbenr.modify(|_,w| w.gpiopben().set_bit());
But in the source code of stm32l1xx-hal I see that the RCC part is already done in impl GpioExt for $GPIOX, but I don't know how to get to this "Parts" functionality.
Any help that points me in the right direction is appreciated.
I got some help from a Discord community. The answers were (modified a bit by me):
stm32l1xx-hal already depends on stm32l1 as seen here. There's no need to import it twice. It is enough to add to Cargo.toml:
[dependencies.stm32l1xx-hal]
version = "0.1.0"
default-features = false
features = ["stm32l151", "rt"]
Note that the default-features = false is optional, but without it the compiler was giving me an error.
The syntaxes are equivalent, but as I said above, I only need to add the HAL one. You can add curly braces {} in the first style to add the options, such as:
stm32l1xx-hal = { version = "0.1.0", features = ["stm32l151", "rt"]}
The right code for doing the blinky (which was on PB6, not PB4, sigh) was:
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32l1xx_hal::delay::Delay;
use stm32l1xx_hal::gpio::GpioExt;
use stm32l1xx_hal::hal::digital::v2::OutputPin;
use stm32l1xx_hal::rcc::{Config, RccExt};
use stm32l1xx_hal::stm32::Peripherals;
use stm32l1xx_hal::stm32::CorePeripherals;
use stm32l1xx_hal::time::MicroSeconds;
#[entry]
fn main() -> ! {
let p = Peripherals::take().unwrap();
let cp = CorePeripherals::take().unwrap();
// Get LED pin PB6
let gpiob = p.GPIOB.split();
let mut led = gpiob.pb6.into_push_pull_output();
// Set up a delay
let rcc = p.RCC.freeze(Config::default());
let mut delay = Delay::new(cp.SYST, rcc.clocks);
loop {
// Turn LED On
led.set_high().unwrap();
delay.delay(MicroSeconds(1_000_000_u32));
// Turn LED Off
led.set_low().unwrap();
delay.delay(MicroSeconds(1_000_000_u32));
}
}
For me, the key was to understand that the split method can be called from the Peripherals because stm32l1xx-hal implemented split for a struct defined in stm32l1. In other words, the HAL crate is not only defining new structs, but also extending functionality for existing structs. I need to wrap my head around trait design patterns.
I know how to say that a dependancy is only needed on windows but how do I say (as a crate writer) that a feature is only available on windows.
I tried (based on the depends way)
[target.'cfg(windows)'.features]
windbg = []
but this doesn't work.
cargo build says
warning: unused manifest key: target.cfg(windows).features
and a client app using the crate fails saying that the feature doesn't exist
Currently Cargo is not able to specify feature's target platform, but you can add target_os to your code as an extra attribute to let compiler know that your feature will only be available on the target you set.
Let's say you have defined your feature like below.
#[cfg(feature = "windbg")]
mod windbg {
//...
}
You'll need to replace it with:
#[cfg(all(target_os = "windows", feature = "windbg"))]
mod windbg {
//...
}