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.
Related
I have several json files which contain objects that need to be exported from the module to be used(read only) in various places in the code base. Exporting a function that reads the files and parses them and invoking it every time the objects are needed seems very wasteful. In go I'd export a global variable and initialize it in init function. So how do I go about doing it in rust?
I guess you are using this for interface definitions between different system parts. This is a known and well understood problem and is usually solved with a build script, such as in the case of protobuf.
There is a very good tutorial about how to use the build script to generate files.
This is how this could look like in code.
(All files are relative to the crate root directory)
shared_data.json:
{
"example_data": 42
}
build.rs:
use std::{
env,
fs::File,
io::{Read, Write},
path::PathBuf,
};
fn main() {
// OUT_DIR is automatically set by cargo and contains the build directory path
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
// The path of the input file
let data_path_in = "shared_data.json";
// The path in the build directory that should contain the generated file
let data_path_out = out_path.join("generated_shared_data.rs");
// Tell cargo to re-run the build script whenever the input file changes
println!("cargo:rerun-if-changed={data_path_in}");
// The actual conversion
let mut data_in = String::new();
File::open(data_path_in)
.unwrap()
.read_to_string(&mut data_in)
.unwrap();
{
let mut out_file = File::create(data_path_out).unwrap();
writeln!(
out_file,
"::lazy_static::lazy_static! {{ static ref SHARED_DATA: ::serde_json::Value = ::serde_json::json!({}); }}",
data_in
)
.unwrap();
}
}
main.rs:
include!(concat!(env!("OUT_DIR"), "/generated_shared_data.rs"));
fn main() {
let example_data = SHARED_DATA
.as_object()
.unwrap()
.get("example_data")
.unwrap()
.as_u64()
.unwrap();
println!("{}", example_data);
}
Output:
42
Note that this still uses lazy_static, because I didn't realize that the json!() macro isn't const.
One could of course adjust the build script to work without lazy_static, but that would probably involve writing a custom serializer that serializes the json code inside the build script into executable Rust code.
EDIT: After further research, I came to the conclusion that it's impossible to create serde_json::Values in a const fashion. So I don't think there is a way around lazy_static.
And if you are using lazy_static, you might as well skip the entire build.rs step and use include_str!() instead:
use lazy_static::lazy_static;
lazy_static! {
static ref SHARED_DATA: serde_json::Value =
serde_json::from_str(include_str!("../shared_data.json")).unwrap();
}
fn main() {
let example_data = SHARED_DATA
.as_object()
.unwrap()
.get("example_data")
.unwrap()
.as_u64()
.unwrap();
println!("{}", example_data);
}
However, this will result in a runtime error if the json code is broken. With the build.rs and the json!(), this will result in a compile-time error.
The general way of solving this problem in Rust is to read the assets in a single place (main(), for example), and then pass a reference to the assets as needed. This pattern plays nicely with Rust's borrow checker and initialization rules.
However, if you insist on using global variables:
When we apply Rust's initialization and borrow checker rules to global variables one can see how the compiler might have a hard time proving (in general) that all accesses to a global variable are safe. In order to use global variables the unsafe keyword might need to be used when accessing the variable, in which case you are simply asserting that the programmer is responsible for manually verifying that all accesses to the global variable happen in safe way. Idiomatic Rust tries to build safe abstractions to minimize how often programmers need to do this. I wouldn't consider the lazy_static! macro as a hack, it is a abstraction (and a very commonly used one) that transfers the responsibility from the programmer to the language to prove that the global access is safe.
Let's assume I have the following feature defined in Cargo.toml:
[features]
my_feature = []
And the following code lives in src/lib.rs:
#[cfg(feature = "my_feature")]
fn f() { /* ... */ }
#[cfg(not(feature = "my_faeture"))] // <-- Mind the typo!
fn f() { /* ... */ }
How can I enforce, that the feature-strings are matched against the list of both explicitly defined and implicitly available features in Cargo.toml so that for instance typos could be avoided?
When RFC 3013, "Checking conditional compilation at compile time", is implemented, there will be warnings for a #[cfg] referring to a feature name that is not declared by Cargo, just as you're asking for. However, the implementation only just got started (Sep 28, 2021).
The means of operation described in the RFC is just as you suggested, ‘cargo would pass down the flags to rustc’.
It may be worth noting that this will not check all conditions appearing in the source text; as described in the RFC:
This lint will not be able to detect invalid #[cfg] tests that are within modules that are not compiled, presumably because an ancestor mod is disabled.
So, it will not confirm that all #[cfg(feature)] are valid on a single cargo check — you will need to test with your various features or combinations of features. But those are the same combinations that you would need anyway to check for compile errors in all of the regular source code that could be enabled; once you do that, the lint will assure you that you don't have any #[cfg(feature)] that are never enabled due to a typo.
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.
I am using assert_cli crate to test a command line application. While it is very helpful with simple use cases (see some examples in this article), sometimes I want to get the raw output of the command I am testing as a String to do more sophisticated checks (regex, json or just more complex logic in the output).
For that I need to get a copy of the command output verbatim. Here is an example:
extern crate assert_cli;
fn main() {
let a = assert_cli::Assert::command(&["echo", "foo-bar-foo"]);
a.execute();
println!("{:?}", a.expect_output);
}
Somewhat predictably it gives me the following error:
error[E0616]: field `expect_output` of struct `assert_cli::Assert` is private
--> src/main.rs:14:22
|
14 | println!("{:?}", a.expect_output);
| ^^^^^^^^^^^^^^^
It also has a .stdout() method, but that requires OutputAssertionBuilder and there it is also not obvious how to access the actual contents of stdout. You can only do some simple checks using predicates syntax.
assert_cli does internally get the full output of the command during execute as seen in the source code of assert.rs
let output = spawned.wait_with_output()?;
All the internal Command and output variables seem to be private and are never exposed to retrieve the raw stdout. This functionality seems to be too basic to be omitted from assert_cli library. I am probably missing something very obvious...
Q: Is there any way to get raw stdout back as contents of a variable?
This is what I want to achieve ideally:
extern crate assert_cli;
fn main() {
// do simple checkign with assert_cli
let a = assert_cli::Assert::command(&["echo", "foo-bar-foo"])
.stdout().contains("foo-bar-foo")
.unwrap();
// get raw stdout
let cmd_stdout = a.get_raw_stdout(); // how to do it?
// do some additional complex checking
assert_eq!(cmd_stdout, "foo-bar-foo");
}
P.S.: I know I can use std::process::Command separately to achieve this. I wonder if I can still stick to assert_cli since I do 80% of the testing with it.
The library defines only 3 types. None of which allow to access the output directly.
This functionality seems to be too basic to be omitted from assert_cli library. I am probably missing something very obvious...
The library is called assert* and it has all the functions you need to assert stuffs on the output of your command. Getting the actual output is outside the domain of "assertions".
Other people have opened an issue on the repository asking for this exact feature. I suggest you to go there, and tell the author that this feature interests you.
I encountered some problems reading the Rust documentation:
In this example, we have three modules again: client, network, and network::client. Following the same steps we did earlier for extracting modules into files, we would create src/client.rs for the client module. For the network module, we would create src/network.rs. But we wouldn’t be able to extract the network::client module into a src/client.rs file because that already exists for the top-level client module! If we could put the code for both the client and network::client modules in the src/client.rs file, Rust wouldn’t have any way to know whether the code was for client or for network::client
Why does Rust need to know the code in client.rs belongs to client or network::client? Can it belong to both?
The compiler has rules about where the source file for an external module can be. Those rules ensure that there aren't two modules that use the same source file.
If you really want to, you can override the rules with a #[path] attribute:
mod client; // defaults to client.rs relative to the current file
mod network {
#[path="client.rs"] // reads the same source as the outer `mod client;`
mod client;
}
However, doing so would lead to duplicate code, i.e. the code in client.rs would be compiled twice, and everything that's defined in client.rs would be defined twice, in two separate modules. It's as if you made network/client.rs an exact copy of client.rs and didn't write the #[path] attribute.
Another thing you can do is provide an alias for a module by reexporting it elsewhere. This can be useful when building a library: it enables you to present an external module hierarchy that is different from the internal module hierarchy.
mod client; // not accessible externally
pub mod network {
pub use client; // network::client::* will refer to the same definitions as client::*
}
For example, with the above, the client module is defined in client.rs, but clients use it through my_crate::network::client.