-
Notifications
You must be signed in to change notification settings - Fork 270
fix: minimal build with no default features #731
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
fix: minimal build with no default features #731
Conversation
|
Argh. Thought about a quick fix, but the rabbit hole goes deeper. Compiling with just I see two options:
|
I want to draw your attention to this: #539 the tldr: compile features are a mess ATM and offer a lot of avenues for issues. I say if we start changing (and breaking some code that way) lets fix things properly and overhaul the entire feature set. |
Sure, I understand. What would you like to do for v0.21? Remove this “decoder” feature for now, until we sort everything out, and just duplicate the Or: accept that compiling without default features is broken? I’d rather not because it breaks projects that don’t use any part of the decoder. |
There is no rush to release v0.21 right? I can try and implement the changes proposed in #539 and then combine that with the transitive decoder feature you proposed. Then the theme for v0.21 will be: 'removing footguns'. Which I kinda like. |
Fine for me - I thought we were in a release train but totally fine. Just to check: so you’re taking over on that feature issue? Let me know if and what you’d like me to contribute. |
Yes your right there. This could be an easy change however, and if we do it now we probably no longer need to make breaking changes to features in the future.
I can allocate some time to take on #539. It seems like its own issue to me, on the other hand maybe changing the features should be one PR. I have no idea how to address it (539) yet. If you have ideas please, feel free to take on #539 and merge that with this :). |
Taken from 539:
Looking at it now the above seems overkill to me. Maybe we should have a feature for each container and none for codecs (they are all enabled when a container that can use them is enabled). I say we first propose what we want the features to be before implementing them. |
Enabling all codecs for a container leads to the question: the Symphonia ones or the others? When both are enabled ("they are all enabled") then the implementation in v0.20 as well as v0.21 will give "the others" (hound, lewton, claxon) precedence over Symphonia. Currently, default decoders are lewton, claxon, hound, and finally Symphonia only for MP3. Here's an opinion, I don't know how popular: how about changing the defaults all to Symphonia instead? Pros: more functionality, more consistent without hybrid Symphonia / other decoder mix All these variants should compile without warning then: # defaults: playback,flac,vorbis,wav,mp3
# all decoders Symphonia
# "vorbis" will also enable "ogg"
cargo build
# defaults plus aac
# "aac" will also enable "mp4"
cargo build --features aac
# whoever just wants to have the DSP modules
cargo build --no-default-features
# as a playback library with own sources
cargo build --no-default-features --features playback
# like the defaults but with some different Symphonia decoders
# "aac" will also enable "mp4"
# "vorbis" will also enable "ogg"
cargo build --no-default-features --features playback,vorbis,aac,aiff
# like the defaults but with alternative decoders
cargo build --no-default-features --features playback,claxon,lewton,hound,minimp3
# advanced usage: lots of stuff could be in a container
cargo build --no-default-features --features flac,mp4 This will probably still require an internal "decoder" feature flag. Feel free to improve. |
agreed! symphonia has proven great. And as you say if the license proves an issue (which it should not) users can fall back. The current situation is also a small footgun since symphonia implements more features (mainly seek). Having those missing while having enabled a feature for your format is confusing. I would also like to separate codecs and containers. Most users do not know the difference and that is yet another footgun. You enable ogg but you miss vorbis etc (not the best example). We could have three categories of codec/container features:
Examples would be:
Alternative and most user friendly would be to only have the container features. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for no-default features was added to accommodate a no-playback build option that some users requested. In particular, with that option the whole output stream's code could (and should) be excluded.
Because Cargo does not support a "negative" feature specification, the playback feature was marked as default only to avoid surprises in the usual case when users do want playback. This way only users who actually want no playback would have to deal with more complicated dependency requiring "no-default-features" flag.
I do not mind supporting even slimmer version of rodio as long as it is either required for some use-case or does not complicate things.
If you feel like this option is needed, see my other comments here.
Probably really late to this, but there is a third solution: #[allow(clippy::large_enum_variant)]
enum DecoderImpl<R: Read + Seek> {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
Wav(wav::WavDecoder<R>),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
Vorbis(vorbis::VorbisDecoder<R>),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
Flac(flac::FlacDecoder<R>),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
Mp3(mp3::Mp3Decoder<R>),
#[cfg(feature = "symphonia")]
Symphonia(symphonia::SymphoniaDecoder, PhantomData<R>),
#[allow(dead_code)]
None(Unreachable, PhantomData<R>),
}
enum Unreachable {} This requires adding an unreachable branch to all |
Not late at all! So that removes any need for an internal "decoder" feature right? Both are kinda hackish but yours seems the lesser of evils. |
It removes the need for the intermediate feature flag. I would not call either hackish:
Of the two, I see it as a choice between:
Anything that results in the least breaking changes for users is probably best in the short term. In the long run however, the notion of supporting many independent decoding backends with a single generic interface (mostly the
|
I will also add that if we consider the |
the "hope" is that the compiler will inline those calls, so having a consumer of Source that buffers should lead to the compiler unrolling 'some' loops.
Would be nice to see, you should know though there is a wider discussion regarding the |
@dvdsk Thanks, sent you an e-mail. |
I implemented a minimal best-case |
Sorry, was occupied with other things before I can jump on this. But indeed I’d vote to prevent going the I’m not sure what you mean with being too optimistic with the builder. I agree that it’s improbable that we’ll ever see more backends, let alone “lots more”. Honestly that also wasn’t the intent of the builder. It was there to expose some of Symphonia’s features, without tight coupling, and still allowing the other decoders to have their place. If it were me as a user, I would dispense with the other decoders and go full Symphonia. But me as a Rodio collaborator, I want to allow for other uses to use differently licensed decoders. |
I agree completely, I only tested the trivial The trouble is, I'm not certain that avoiding some kind of dynamic dispatch when fetching samples is always going to be possible. Any kind of dynamically-constructed (possibly end user-constructed, if we consider a DAW) graph is going to result in, for a standard headset setup, 44k*2 calls per second to So far, using |
My gut tells me we should go the buffer route even if we don't need |
Anyone against this for a v0.21 target? I like it best of the various options. |
I'm on board 👍 |
I find the compiler is quite good at vectorizing when it can guarantee contiguous data. Depends a lot on the task, but something common like averaging N channels down to mono gets vectorized out-of-the-box: https://godbolt.org/z/K5dcrTYbY. Granted, I haven't checked when it does/doesn't do this on the current So I support designing a buffer-based API in the long run. Also I think the |
b3d6fa4
to
76bfa36
Compare
Replaced my changes with cleaner proposal of @renski-dev
Just force pushed, replacing my previous take with the better proposal of @renski-dev. |
@PetrGlad do you have any further review comments? If not, I'd like to get this merged. It seems we're good to release v0.21 after that! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roderickvd I am sorry for not answering earlier.
I can build with --no-default-features but the test build fail (mostly in examples)
cargo test --no-default-features
Do you intent to clean that up here or is there another plan for these?
Make the minimal build on the CI absolutely minimal and add conditional compilation guards to examples and tests. All examples now show helpful messages when playback feature is disabled, and tests properly handle cases where no decoders are available.
No worries, I know how life goes. Thanks for responding now.
I agree that an absolutely minimal build should compile and test without error or warning. It turned out to be a bit more work than just in |
I figured out a way to get the examples to work without needing conditional compile statements 🥳 we need to put this in [[example]]
name = "basic"
required-features = ["playback"] Then is you run: cargo r --no-default-features --example basic you get a nice error from cargo:
|
Awesome I was looking for that. I'll refactor tomorrow or so. |
Replaces conditional compilation with Cargo's required-features to ensure examples and benchmarks only compile when necessary features are available. Removes redundant cfg guards and fallback main functions from example files.
Remove unnecessary feature gates from music examples and fix minor formatting inconsistencies across example files.
This should do it. |
@@ -1,6 +1,6 @@ | |||
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))] | |||
#[cfg(any(feature = "flac", feature = "symphonia-flac"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could handle these the same way as with the examples. I think this is fine though. Examples should be as simple as possible so not having conditional comp in there is nice. These tests are not meant to help users so having them look a little more daunting is fine.
thanks for all the hard work and patience everyone! |
This commit makes the decoder module and its exports conditional on the having at least one decoder format enabled. Also changes the CI to prevent regression.
Fixes #730