I am working on a *-sys crate (and a regular crate) for a CMake project. This project has several libraries all bundled into the same repo (Note these libraries depend on each other).
In principle, I should take each of these libraries and make a separate *-sys crate for each. However this means for each of these crates, I'd need to A) clone the source repo once per library (meaning when publishing, each crate will include the entirety of the source repo), B) duplicate a lot of the build script, C) keep the build scripts in sync, etc.
Alternatively, I can have a single sys crate for the entire project. I can then use feature flags to selectively build and create bindings for these all together. The problem is my Cargo manifest can only "links" against one of these libraries. This means another crate linking against one of my libraries may not be detected as incompatible.
Question 1: is the second approach reasonable? Or is it a terrible idea that I should avoid at the fairly significant cost?
Question 2: is it reasonable/common to have multiple copies of the source repo hanging around?
Question 3: is there another solution that works better in this situation?
in my opinion it is a valid solution to use feature flag to select individual libraries, and only have one single "-sys" crate. the
links attribute is there to "declare" what native library your crate would link against, the build script can emit as many linker directives as needed.
I tend to think the
links attribute as a logical library name, while the individual native libraries can be thought of components of the library. cargo uses this attributes to detect conflicting crates in the dependency graph, but the feature flags will be unified for a specific crate.
in case the foreign C/C++/whatever library resides in a huge mono repo, I would certainly want to avoid multiple copies, but for small foot print repos, multiple copies of the same repo might not be that bad. it all depends.
I personally prefer the single
-sys crate with feature flags approach. for example, suppose I have a BIG project called "beast", which consists of many smaller libraries like "memory", "thread", "process", "network", etc, I just create a single
beast-sys crate (
links = "beast") , with feature flags of
["memory", "thread", "process", "network"]; in
build.rs I configure cmake to build the required "component" based on
"network" component is later released as a standalone "beast-network" package, I just create a
beast-network-sys crate (
links = "beast-network"), and update the
beast-sys crate to use
beast-network-sys as an (optional) dependency, the
"network" feature flag is now not considered by
build.rs but instead enables the optional
however, I would strongly advice people to only use my higher level wrapper
"beast" crate as dependency instead of depends on the
-sys crates directly.
Feature flags are probably fine.
You shouldn't be cloning the repository in your build script, because this will prevent builds from working offline. Include a vendored copy of the sources in your crate.
You can make separate crates and deduplicate source code by putting it in a shared helper crate. This is the solution openssl-sys implemented.
Thank you for the notes! I am very glad this isn't a bad solution.
@kornel Yes I meant cloning the repo as a submodule in my sys crate. But when publishing this becomes a full copy of the submodule (from what I've read). Also that example is very helpful! it's an interesting approach!
I think I will stick to the one-sys-crate solution. The dedup-ing of the build script really sells it for me, and not having to separate out the src into its own crate is quite convenient.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.