Motivation
We already have features, which allow for additional code to be compiled, only if the user needs it. In a case, where two libraries depend on such a library, one library might need a feature the other library does not need. The solution is to compile all requested features, which is only guaranteed to work if every feature is purely additive. However, suppose you want to write a graphics library with support for different backends. The most common solution is to use traits and type parameters in order to allow this, which leads to over-generalization (who wants to use multiple backends at the same time) and often, a dependent library uses type definitions (like type Window = graphics::Window<GlBackend>
). What would be helpful here, is an option to select a backend in the Cargo.toml
. This is what flavors
are about.
Design
Note: Just some rough ideas to start the discussion
- Add a new table to
Cargo.toml
,[flavors]
- Every flavor is another table
- If flavors conflict, link to the library twice (like cargo is already doing for two incompatible versions)
Drawbacks
Not yet resolved / depending on design choices
- Bigger executable size if incompatible flavors are used
- Are flavors mostly used in libraries with just a single dependent library?
- Can we minimize code duplication if a library has multiple flavors, all with structs / functions they have in common?
- Should the a library
foo
offering flavors provide all common items in a dependent library,foo-core
?
Alternatives
- In some situations, traits & type parameters
- not possible to provide different functionality
- eventually more complex code
- Code duplication:
GlWindow
,VkWindow
,DxWindow
…- may be macro-provided
- features, not keeping their promises
- one library per flavor
Unresolved question
- Which guarantees does a library make about flavors? Should another flavor always provide the same items (checked by the compiler)?
- -> you cannot forget anything
- more limited, flavors cannot offer different functionality
- Should there be just one set of flavors or multiple flavors like this:
[flavors.backend]
flavors = ["opengl", "vulkan"]
[flavors.threadpool]
flavors = ["rayon", "rust-threadpool"]
- How do flavors work together with features? How to specify dependencies of a flavor?
- What drawbacks are there?
- Many, many more
Thanks for reading this, feel free to make suggestions on how to improve this.