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

Generating headers for other platforms – Support for #[cfg(target…)]-dependent signatures #73

Open
Michael-F-Bryan opened this issue Jul 7, 2021 · 4 comments
Labels
K-feature Kind: proposed new code to implement new behaviour

Comments

@Michael-F-Bryan
Copy link

Is there a way to generate header files for bindings which get cross-compiled? Currently, headers are generated by running a test on the host machine, but that assumes your test suite is executable.

I could bodge things together using a virtualisation layer like qemu and having the VM print the generated header to stdout, but that isn't ideal.

My use case is:

  • Create a bindings library which wraps your Rust crate
  • Generate pre-compiled libraries and headers for that library
  • Cross-compile from a Linux host (CI runner) to things like Android, iOS, or bare metal ARM
  • Conditional compilation is used to selectively enable functionality which is valid for the particular platform
@Michael-F-Bryan
Copy link
Author

As an aside, I've been using safer_ffi for generating bindings to our library at work and so far I'm really liking it! I've done a fair amount of FFI with Rust, and having proc macros and the ReprC trait makes it so much nicer to write good quality bindings.

@danielhenrymantilla
Copy link
Collaborator

Thanks, very glad to hear that 😊


Regarding the OP:

Conditional compilation is used to selectively enable functionality which is valid for the particular platform

Yeah, sadly supporting that one is surprisingly hard: the whole idea of safer-ffi is to embed the "C repr information" into types, which, without compiler hacking / plugin / custom linter, can only be achieved through traits (ReprC (and CType)). The traits express this information by featuring "reflection" capabilities: any ReprC type is able to write into an impl Write the C header code representing its definition (and same applies for #[ffi_export]-ed functions, which are "collected" into an inventory (and thus, ctor)-backed collection, which is accessed by the unit test).

This means that, technically, I have been unable to feature any place to "collect and emit" the header code other than a unit test (alas, not even an integration or an example binary work!).

I've been been kind of at peace with that thanks to the emitted C code using the type aliases to be as platform agnostic as possible (e.g., size_t and/or uint32_t instead of uint). But if the very Rust-exported API is #[cfg(target…)]-gated, then indeed safer-ffi is currently unable to feature that, sadly 😢

I am, in parallel, learning about compiler lints and other stuff, so that I may be able to, eventually, go and try the compiler plugin approach, but that won't be achieved within the current year.

In the interim, I suggest the following workaround:

  • instead of:

    #[cfg(target…)]
    #[ffi_export]
    fn foo() -> … {
  • do:

    #[cfg(feature = "target…")]
    #[ffi_export]
    fn foo() -> … {
        #[cfg(not(target…))] unimplemented! {}
        #[cfg(target…)] {
            /* function body using `return` */
        }
    }

    that is, replicate the target…s as Cargo features, cfg-gate the function signatures based on that (the body can still be cfg-gated based on the actual targets and actual functions being available), and then run the targeted unit test with the Cargo features to indicate which "target profile" to use 😬

    Otherwise, this might be the one place where cbindgen is still better than safer-ffi 😞

@danielhenrymantilla danielhenrymantilla added K-feature Kind: proposed new code to implement new behaviour M-long-term Marker: this is not planned to be done right away labels Jul 8, 2021
@danielhenrymantilla danielhenrymantilla changed the title Generating headers for other platforms Generating headers for other platforms – Support for #[cfg(target…)]-dependent signatures Jul 8, 2021
@Michael-F-Bryan
Copy link
Author

This means that, technically, I have been unable to feature any place to "collect and emit" the header code other than a unit test (alas, not even an integration or an example binary work!).

Hmm, what did you try? I remember experimenting with inventory ages ago for Advent of Code problems. My project worked by pulling each question out into its own crate and using a custom proc macro to register my implementation.

I distinctly remember wondering why my "runner" executable wasn't able to detect any questions and figured out you need to make sure Rust links in any crates containing ctor initializers in order for them to be included in the final binary (and hence run).

The way I've done this in the past is to do either an explicit extern crate foo or use something... Maybe that'll work for you?

Otherwise, this might be the one place where cbindgen is still better than safer-ffi 😞

Wait, there is hope!

When troubleshooting an unrelated cross-compilation issue (TensorFlow's build system is... less than ideal) I started using cross to make sure the correct compiler toolchain gets installed.

One of the nice things about cross is it also includes an install of qemu which gets used to run cargo test on the target architecture. Cross doesn't support running unit tests for every target, but at the moment it works on every platform I need. I'm not quite sure what I'll do for bare metal platforms where cargo test doesn't work and ctor doesn't exist, but that's future Michael's problem.

My PR's CI is currently failing because of TensorFlow, but this was my solution.

@danielhenrymantilla danielhenrymantilla removed the M-long-term Marker: this is not planned to be done right away label Jul 8, 2021
@danielhenrymantilla
Copy link
Collaborator

Interesting leads; I'll investigate them soon and see what it gives (if they work, I'll add them to the documentation / future FAQ, so as to consider this as "solved", hence my removing the long-term label 🙂), thanks for the pointers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
K-feature Kind: proposed new code to implement new behaviour
Projects
None yet
Development

No branches or pull requests

2 participants