-
Notifications
You must be signed in to change notification settings - Fork 742
libloading support #1541
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
Comments
So, basically what you want, I assume, is something like bindgen, but generating something like: struct Lib {
foo: Option<extern "C" fn(i32) -> i32>,
bar: Option<extern "C" fn(*mut c_void) -> ()>,
} And such, instead of:
(and co, which is basically what bindgen does) Is that right? If so, I don't know what the best way to approach this would be. Tweaking bindgen to generate something like this wouldn't be hard, but it's not clear it'd be flexible enough for the general case... It should be possible to use If the API is stable (which it should if it's a dylib), then writing a rust program that processes bindgen's output and outputs the struct you want with some helpers and such should be pretty easy. We could even put it in the repo if it's useful for more people. I'd be happy to help if you want to give that a shot and get stuck or what not. |
I could also be convinced to add a special mode to bindgen that generates what you want, but I think adding it in a separate program would be easier. |
Hi! Having bindgen (or another program) do it would be fantastic! |
I think this generally needs a concrete proposal of what would be needed and what kind of inputs would bindgen get. I don't know the use case well enough. I'm not sure if my comments above reflect the use case given I got no reply from the reporter. In particular, how is bindgen supposed to know which functions are part of the dylib vs. part of some other imported header? |
I am also interested in this. At least in linux, I think the output of "nm -D" could be used by bindgen to know which functions are in the .so file. |
@emilio i have to apologize here, I read your reply in public transport In March 2018, but couldn't add a reply.
struct Lib {
foo: Option<extern "C" fn(i32) -> i32>,
bar: Option<extern "C" fn(*mut c_void) -> ()>,
} Indeed, that's what I'm looking for. let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header(XEN_HEADERS_WRAPPER)
// Run rustfmt on the bindings
.rustfmt_bindings(true)
// allow dynamic linking
.allow_dynamic_link(true)
// Finish the builder and generate the bindings.
.generate() And this would generate a struct
I think it could be integrated in bindgen, as it's one more option available for users ? But I'm still interested, more now than before ! Thanks @emilio |
When you are loading a library at runtime, your program has to know in advance which symbols it wants to load from this library. Also, you have to explicitely define the functions parameters. typedef struct {
void *handle;
/* Xen 4.1+ */
xc_interface* (*xc_interface_open)
(xentoollog_logger *logger, xentoollog_logger *dombuild_logger, unsigned open_flags);
int (*xc_interface_close)
(xc_interface *xch);
int (*xc_version)
(xc_interface *xch, int cmd, void *arg);
void* (*xc_map_foreign_range)
(xc_interface *xch, uint32_t domid, int size, int prot, unsigned long mfn ); So what we could have, is a |
Right, but this grows quite a dependency on bindgen, plus part of the point of using a dylib is that there can be functions that are not present in different versions of the library. Bindgen itself uses this quite a lot. For example, if you have libclang 9, you'll be able to use some functions that are not present in libclang 5. Just magically running Listing all the symbols looks fair enough. I think that should be reasonably straight-forward to implement. Also, btw, this wouldn't be that bad to implement as an input step to bindgen if you're allowed to use some C++. bindgen generates the right thing for this: extern "C" void my_function();
struct my_type_t {
int b;
};
extern "C" int my_other_function(struct my_type_t*);
// This could be generated from build.rs pretty easily and used as an input to
// bindgen.
struct Library {
decltype(my_function)* my_function;
decltype(my_other_function)* my_other_function;
}; |
Can it only care about the functions defined in the main header file as opposed to the ones that get imported from it? Concerning integration with libloading, as the get method returns a
I agree! A
|
hey @emilio , could you give us an update of the status of this issue so far ? are we still brainstorming on the interface, should we write some specifications, or maybe are you allocating this project for this year's GSoC ? Thanks. |
If this issue is still up for grabs, @joechrisellis will be looking at it around mid-july 😃 |
Hi guys, I have a proposal for what we might want to do in this case. I also have a prototype implementation that I can submit for review if you think this is the right approach. Let me know if you have any thoughts, or if anybody has a better suggestion. :) I agree with Emilio's comment:
This is not trivial to determine given the current architecture. For example, if you're including two libraries like so:
There is currently no way to determine whether a given symbol is from
Is non-trivial, because by the time we reach codegen the information about which function comes from which library is lost. We have no idea whether to put a given function into a library struct, or just treat it as we would normally. With that in mind, I am proposing two builder options
For a
I would expect this to generate bindings resembling:
With these bindings, you call the functions in the library like this:
By default, all of the symbols in the header file would be included. You could select specific symbols using the With this, whether or not we're generating libloading bindings is a global option for a single invocation of bindgen, which avoids requiring any ownership knowledge about which symbol comes from which header, and whether it is dynamically loaded or not. If the user wants multiple dynamically-loaded libraries, they'd do:
And then include them as needed in their code, like this:
There is a pitfall -- if you want to use two dynamically loaded libraries and they have a common include like
As I said, I have a small prototype implementation of this -- if you guys think this is the right path forwards, I'd be happy to submit it for review! :) |
The proposal looks very good for me, and would be helpful as one of our potential use-case, to generate Rust bindings to dynamically load a C library. Some header files also include other files which contains other unrelated functions. At the end of the pre-processing step, the header file might contain a lot of functions that are not needed from the Rust code but are in the " Happy to go ahead with this anyway! |
@joechrisellis If possible I would like to tryout your prototype (on Windows). |
Sorry for the lag replying here, but if people are fine with all functions from a set of bindings ending up in the same LibLoading thing then the proposal above seems sensible. If interested folks could give it a spin and see if it works for them it'd be awesome. Thanks! |
Hi guys, I've made a draft PR here that you might like to check out. There's more information inside the PR. 😄 |
It is not obvious to me how I can test the PR (how to get bindgen which includes the PR). Any hint would be great. |
@dergroncki, maybe the screenshot below will help. |
@dergroncki -- to test it, you can:
When building your project it should source bindgen locally. You should then be able to use the dynamic loading features as described above. 🙂 |
As an alternative to @joechrisellis's proposed solution, my solution was to make a wrapper that uses It's still in the proof-of-concept stage, but I've set up a suite of integration tests and my trivial hello world example ( |
If the
|
I agree with @hug-dev here, -- keeping this feature in-tree is probably a better idea for maintenance and avoiding bitrot, but @Michael-F-Bryan's has a lot of nice-to-haves!
Definitely -- I would be happy to change the implementation in the PR at the moment to reflect this, pending @Michael-F-Bryan's permission!
This is also useful -- I'll change the PR to do this, too. |
Hi,
I would like to rewrite a virtual machine introspection library in Rust:
https://github.com/libvmi/libvmi
This library is building a unified API accross hypervisor's VMI APIs.
I considered
bindgen
for the task, which would be perfect to generate akvm-sys
orxen-sys
crate, but I have a requirement that it should be able to load these libraries dynamically, at runtime, by locating alib.so
file, loading it withlibloading
. like a plugin.https://docs.rs/libloading/0.5.0/libloading/
I haven't found anything in the docs regarding dynamic loading.
Is it a use case that have already think about ?
How difficult would it be to implement ?
Thanks !
The text was updated successfully, but these errors were encountered: