Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add custom export of c bindings #39

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

jpeeters
Copy link

@jpeeters jpeeters commented Dec 9, 2024

This commit provides a selective generation of bindings based on Kconfig
options. Then, only enabled features has exported bindings to Rust.

As a result, one developer can see early during the Rust application
build if the correct Kconfig options has been enabled.

Before this commit, most problems appeared during C and Rust linking
time.

This commit uses `expect` instead of `unwrap` on Result<_, _> in order
to provide better error information to developer.
This commit separates the implementation of Kconfig extraction from the
generation of cargo configuration at build time.

With this commit, the result of Kconfig extraction can be reused
anywhere else, providing a set of enabled Kconfig options.
This commit provides a selective generation of bindings based on Kconfig
options. Then, only enabled features has exported bindings to Rust.

As a result, one developer can see early during the Rust application
build if the correct Kconfig options has been enabled.

Before this commit, most problems appeared during C and Rust linking
time.
@jpeeters jpeeters changed the title Feat add custom export of c bindings add custom export of c bindings Dec 9, 2024
@jpeeters
Copy link
Author

Hi @d3zd3z 👋🏼 !

Sorry to ping you. This is my first PR and I don't know who to ask for review. Do you have time to check it out?

Copy link
Collaborator

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks for this contribution.

use std::env;
use std::fs::File;
use std::path::Path;

use regex::Regex;

/// Extract boolean Kconfig entries. This must happen in any crate that wishes to access the
/// configuration settings.
pub fn extract_kconfig_bool_options(path: &str) -> anyhow::Result<HashSet<String>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice you have also changed other Result to anyhow::Result. We should probably have a discussion/argument on discord as to which is better. I generally prefer the use in simple things like this.

/// Export boolean Kconfig entries. This must happen in any crate that wishes to access the
/// configuration settings.
pub fn export_bool_kconfig() {
pub fn export_kconfig_bool_options() {
let dotconfig = env::var("DOTCONFIG").expect("DOTCONFIG must be set by wrapper");

// Ensure the build script is rerun when the dotconfig changes.
println!("cargo:rerun-if-env-changed=DOTCONFIG");
println!("cargo-rerun-if-changed={}", dotconfig);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have seen some behavior that also suggests that this construct isn't working. Not really related to this change, but there have been times I have changed a kconfig but found that the values seen in rust didn't change.

@@ -11,14 +11,12 @@
// This builds a program that is run on the compilation host before the code is compiled. It can
// output configuration settings that affect the compilation.

use anyhow::Result;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I tend to prefer the use of anyhow::Result. Are there general guidelines on this?

Copy link
Author

@jpeeters jpeeters Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use anyhow::Result with the fully qualified path in return types in order to prevent confusion from using ::core::result::Result. This a practice I see several time in different project but we can change to what you think is better.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might have influenced me to be a bit more explicit. I'm not sure, though, about the zephyr crate itself, which defines an Error and Result type itself. I think it makes sense there to have Result be the Zephyr one, and then when a different one is needed, be explicit.

@@ -12,6 +12,6 @@
// output configuration settings that affect the compilation.

fn main() {
zephyr_build::export_bool_kconfig();
zephyr_build::export_kconfig_bool_options();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking API change to zephyr_build. This really makes me think we shouldn't be trying to match the crate version numbers with the zephyr numbers, as Zephyr doesn't do semantic versioning (at all). If our crates were all a "0.*" version, the API changes wouldn't matter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is definitely a breaking change. I suppose that the the project (i.e. zephyr-lang-rust) is young enough to allow with breakages at the moment.

I agree that if Zephyr is not using semver, we should not try to match the Zephyr version but have a compatibility table.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make a PR that reverses the Zephyr version number matching, going back to the 0.x versions, until we get some stability.

let flags: HashSet<String> =
BufReader::new(input)
.lines()
.fold(HashSet::new(), |mut set, line| {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fold with a mutable set feels, well, weird to me. Not strongly enough to ask you to change it. But, I would have just used a loop to make it clear the thing was mutating a single set.

Now, on the other hand:

.lines()
.filter(|line| config_y.is_match(line))
.collect()

is even more concise, well with the error handling fix. In general, I tend to find as things like this get more complicated, the comprehension versions can get a bit unwieldy.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. I think your proposal is more readable. I'll make the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants