Skip to content

[WIP] reexport the static inline functions and TLS variables with C/CPP wrapper #1460

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

Closed
wants to merge 7 commits into from

Conversation

flier
Copy link
Contributor

@flier flier commented Dec 4, 2018

According the discussion of #1090, I doubt we hard to ask user to provide a customized build library (with -fkeep-inline-functions or other options) for FFI binding, we may reexport those static inline functions with auto generated C/CPP wrapper functions base on the rust-c and cpp crates (it's also easy to implement it in bindgen itself).

For example, the c code from generate-c-inline.h

inline static int foo(const int x, const int y) { return x + y; }
inline static void nop() { return; }

could be translate to Rust code

c! { # include "generate-c-inline.h" }
extern "C" {
    #[link_name = "\u{1}_foo"]
    pub fn foo(x: ::std::os::raw::c_int, y: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
}
c! { int _foo ( const int x , const int y ) { return foo ( x , y ) ; } }
extern "C" {
    #[link_name = "\u{1}_nop"]
    pub fn nop();
}
c! { void _nop ( ) { nop ( ) ; } }

and the C++ code from generate-inline.hpp

inline int foo() {
  return 42;
}
inline static int bar(const int x, const int y) { return x + y; }

could be translate to Rust code

cpp! { # include "generate-inline.hpp" }
extern "C" {
    #[link_name = "\u{1}_Z3foov"]
    pub fn foo() -> ::std::os::raw::c_int;
}
extern "C" {
    #[link_name = "\u{1}_ZL3barii"]
    pub fn bar(x: ::std::os::raw::c_int, y: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
}
cpp! { int _ZL3barii ( const int x , const int y ) { return bar ( x , y ) ; } }

non_upper_case_globals
)]

c! { # include "generate-c-inline.h" }
Copy link
Contributor

Choose a reason for hiding this comment

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

Where do these macros come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

rust-c has a simple c! {} implementation for C, and rust-cpp also provides cpp! {}macro for C++

if you think the way is right, I could add a special implementation to bindgen, it need add some code to build.rs, generate some .c/.cpp file on building.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it may be ok to depend on external crates, but then it should be documented and obviously not on-by-default.

Copy link
Contributor Author

@flier flier Dec 6, 2018

Choose a reason for hiding this comment

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

After read the rust_c and rust-cpp crates, I believe we only need a very simple implementation like

macro_rules! c {
    () => {};

    (#include $filename:tt $($rest:tt)*) => {
        c!{ $($rest)* }
    };

    ({ $body:tt } $($rest:tt)*) => {
        c!{ $($rest)* }
    };
}

and a bindgen-build crate be added to support extract and build C/C++ code in the build script.

You can check a real example that includes hundreds of static inline functions with some build script, like

    bindgen_build::build(binding_file, "rte", |build| {
        build
            .flag("-march=native")
            .include("src")
            .include(rte_sdk_dir.join("include"));

        for (name, value) in &cpu_features {
            build.define(name, value.as_ref().map(|s| s.as_str()));
        }
    }).unwrap();

besides, I added some code to handle the deprecated functions, like

extern "C" {
    #[deprecated]
    #[link_name = "\u{1}_rte_bsf64"]
    pub fn rte_bsf64(slab: u64, pos: *mut u32) -> ::std::os::raw::c_int;
}
c ! { { int _rte_bsf64 ( uint64_t slab , uint32_t * pos ) { return rte_bsf64 ( slab , pos ) ; } } }

and the generated C/C++ file like

// generated by bindgen; DO NOT EDIT

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# include "rte.h"
...
int _rte_bsf64_safe ( uint64_t v , uint32_t * pos ) { return rte_bsf64_safe ( v , pos ) ; }
...
#pragma GCC diagnostic pop

What's your opinion?

Copy link
Contributor Author

@flier flier Dec 6, 2018

Choose a reason for hiding this comment

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

besides, with the C/C++ wrapper, we could reexport the thread local variable to solve #1187

__thread int i;
extern __thread struct state s;
static __thread char *p;

could generate the getter/setter functions

extern "C" {
    pub fn i() -> ::std::os::raw::c_int;
    pub fn set_i(v: ::std::os::raw::c_int);
}
c! { { int i ( ) { return i ; } } }
c! { { void set_i ( int v ) { i = v ; } } }
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct state {
    _unused: [u8; 0],
}
extern "C" {
    pub fn s() -> state;
    pub fn set_s(v: state);
}
c! { { struct state s ( ) { return s ; } } }
c! { { void set_s ( struct state v ) { s = v ; } } }
extern "C" {
    pub fn p() -> *mut ::std::os::raw::c_char;
    pub fn set_p(v: *mut ::std::os::raw::c_char);
}
c! { { char * p ( ) { return p ; } } }
c! { { void set_p ( char * v ) { p = v ; } } }

Copy link
Contributor

Choose a reason for hiding this comment

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

This approach works, but there's a lot of unanswered questions related to mangling and such...

I'm sorry for having missed this, btw :(

Maybe a better approach would be to instead add a ParseCallback when we see a thread-local variable, in order to let the caller to do whatever they want with it, since this seems like a pretty opinionated solution to the problem.

That would allow us not to depend on c! / cpp! in any way.

@flier flier changed the title [WIP] reexport the static inline functions with C/CPP wrapper [WIP] reexport the static inline functions and TLS variables with C/CPP wrapper Dec 6, 2018
@bors-servo
Copy link

☔ The latest upstream changes (presumably #1525) made this pull request unmergeable. Please resolve the merge conflicts.

@pvdrz
Copy link
Contributor

pvdrz commented Apr 13, 2023

I'm closing this PR as the --wrap-static-fns feature already handles most of the functionality exposed here.

@pvdrz pvdrz closed this Apr 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants