rust-cookbook
rust-cookbook copied to clipboard
add "Compile and link dynamically to an external C library" example
| Crates | cc |
| Section | 8.3 Build Time Tooling |
Use cc crate to compile and link dynamically to an external/system C library from a build.rs file.
Please note that it will be important to mention that this is a build time crate. Most likely we will dedicate a separate (last) chapter like "build_time.md"
cc https://github.com/rust-lang-nursery/rust-cookbook/issues/236
I have a minimal working example here. I am currently verifying that the library produced is indeed dynamic.
I'm starting to get into the weeds on this and before I go too deep I thought I should get some clarification here... What is the overall goal of this issue? Are we trying to create library that is dynamically linked to or are we simply creating a dynamic object which is then statically compiled into the executable? Specifically, there is a subtle difference between a shared object and a shared library -- the former can be statically linked into an executable, while the latter is linked at runtime.
To expand upon this, the example from the cc crate docs would lead one to come up with the following code example:
cc::Build::new()
.file("src/foo.c")
.shared_flag(true)
.pic(true)
.compiler("gcc")
.compile("foo.so");
However, as far as I can tell, this does not actually produce a shared library. Instead, it produces foo.so.a, which does not appear to be a shared library. I'm guessing the object foo.o is created using the -shared flag, but a shared library is not actually created. Additionally, on macOS, where gcc is an alias for clang, the -shared flag is actually ignored.
To return to the original question, what do we want to do with this recipe? It seems we have two options. The more complex option:
- Create
libfoo.so - Link
libfoo.sowith our executable - It would be great if we could verify libfoo.so is a shared library. I am trying to get
_init()and_fini()to work with a standalone C shared lib but no luck so far...
The alternative:
- Create
libfoo.aas we have in prior examples, the only difference being we use.shared(true)and.pic(true)options
As an aside, is there an easy way to create an executable binary in rust? Cargo does not seem to offer this functionality so I imagine this is done via rustc -- I'll read the docs. Ideally I'd like to get option 1 working with a compiled binary, then delete the shared lib and watch the binary give me an error when it is subsequently run.
What is the overall goal of this issue? Are we trying to create library that is dynamically linked to or are we simply creating a dynamic object which is then statically compiled into the executable?
We would be interested in linking to a full blown external shared library (probably the title could be more descriptive). So we just assume existence of some *.so file with given symbols.
As you have noticed the cc crate does not seam to provide a way to create a *.so file (although we might drop a note about it in their bugtracker as the feature would be desirable and their docs are not perfectly clear on it imho)
As an aside, is there an easy way to create an executable binary in rust? Cargo does not seem to offer this functionality
Please see information under "Configuring a target" you are probably looking for [[bin]] clause. If you need more control (very unlikely) you can look into "The profile.* section"
Thanks for the links @budziq ! Very useful info. I'll follow-up with the cc team.
See this issue from the cc crate. Alex mentions it wasn't the intention of the cc crate to build shared libraries. Given this info, it seems we should close this issue and remove this as a recipe for the cookbook. What are your thoughts @budziq ?
Given this info, it seems we should close this issue and remove this as a recipe for the cookbook.
Not necessarily. We can still:
- build a static library whose only contents are link against *.so using
object- it might be a little contrived - link directly with *.so without cc crate, using only the facilities given by cargo
cargo:rustc-link-lib=dylib=foo
Then it still might an interesting example.
Great points. I think the latter might be more interesting. To that end, it might be worth having a separate section for cargo with various recipes that show what you can do with cargo (e.g., linking to a shared lib). The main takeaways I got from the book with regards to cargo were creating binary and library projects, and the commands cargo run, cargo build, and cargo test. Looking through the docs you linked there is obviously a lot more tooling available :smile:
@j-haj I feel that this example is stepping (possibly neck deep) into a FFI territory that is quite scattered in the rust landscape. For now I've marked this as "needs clarification" and created an issue to gather some opinions here before we proceed here.