Skip to content
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

Cargo features user experience #627

Closed
AlexanderEkdahl opened this issue Jun 9, 2024 · 9 comments
Closed

Cargo features user experience #627

AlexanderEkdahl opened this issue Jun 9, 2024 · 9 comments
Labels
A-framework Affects the framework crates and the translator for them bug Something isn't working documentation Improvements or additions to documentation

Comments

@AlexanderEkdahl
Copy link
Contributor

AlexanderEkdahl commented Jun 9, 2024

As I mentioned earlier, excellent work on these libraries and generators!

That said, I find it frustrating to have to specify the feature for every class I want to use (objc2-metal has 61 features). Should features be enabled by default and libraries that want to reduce code only specify the functionality they need?

I understand that this might be necessary when one crate extends the functionality of another.

Is there a Cargo feature to enable every feature of a crate?

@madsmtm madsmtm added question Further information is requested A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates labels Jun 9, 2024
@madsmtm
Copy link
Owner

madsmtm commented Jun 9, 2024

That said, I find it frustrating to have to specify the feature for every class I want to use (objc2-metal has 61 features). Should features be enabled by default and libraries that want to reduce code only specify the functionality they need?

Hmm, I guess they could all be enabled by default, though it really is a lot of code that's being compiled (objc2-foundation takes 4.5s and objc2-app-kit 9s on my fairly new Mac, a lot more on my older machine),

Is there a Cargo feature to enable every feature of a crate?

Yes there is, it's called all, and is documented in here. Please tell me how to improve the documentation such that you didn't have to ask this question (not that I mind, it's just unfortunate that you had to spend time doing so ;) ). Though now that I'm saying it, a tutorial that shows using "all" to begin with, and then narrows it down later on, would probably do the trick.

@AlexanderEkdahl
Copy link
Contributor Author

Oh, I had no idea about the "magic string" "all". That certainly solves the problem.

Personally I don't mind waiting 9 seconds for something to compile if it saves me 30 minutes of debugging/enabling features. However, I can see how having the capability to turn features on/off is beneficial (especially for libraries). I would expect the linker to remove the unused code but that may not be enabled by default?

Please tell me how to improve the documentation such that you didn't have to ask this question

I was copy-pasting the objc2-metal example to get up-and-running. I'm not sure where it would be natural to introduce the "all" feature as I do believe it is a good starting point for someone who wants to get up and running with an Apple library from Rust.

Maybe a new section in the main README.md that introduces the objc-* crates or in the minimal Readme found on the crates.io documentation?

@madsmtm
Copy link
Owner

madsmtm commented Sep 17, 2024

I've been thinking about this again, and perhaps it would indeed make sense to make all features be enabled by default, and allowing users to opt out with default-features = false. I find in the few projects that I use the libraries in myself, that I end up always enabling the "all" feature, it's only in winit that I tune it down.

@AlexanderEkdahl
Copy link
Contributor Author

With the "all" feature I find the developer experience to be perfectly acceptable.

I only wish it was more prominently visible in the README so that when I add a crate I can configure it correctly. I started a new project this morning and I had to find this thread 😃

I worry that if everything is enabled by default users (specifically users who depend on objc2-* transitively) will complain about long compile times.

@madsmtm
Copy link
Owner

madsmtm commented Sep 29, 2024

I only wish it was more prominently visible in the README so that when I add a crate I can configure it correctly. I started a new project this morning and I had to find this thread 😃

Yeah, that's part of why I've left this issue open, I still want to improve the docs on this!

I worry that if everything is enabled by default users (specifically users who depend on objc2-* transitively) will complain about long compile times.

That's also a worry of mine, and I know that some people reflexively use default-features = false everywhere for partly this reason. Idk., still have to think about it.

@madsmtm madsmtm added this to the objc2 v0.6 / frameworks v0.3 milestone Oct 27, 2024
madsmtm added a commit that referenced this issue Jan 16, 2025
Enable (almost) all framework crate features by default, to make the
user experience when developing binaries (not libraries) much easier.

Users that develop a library should use `default-features = false`, but
that's also probably something that they only want to do later in the
development process (and should be evaluated on a case-by-case basis).

Fixes #627

This also makes examples much nicer to run, it's just
`cargo run --example $name`, no need to configure all the required
features.
madsmtm added a commit that referenced this issue Jan 16, 2025
Enable (almost) all framework crate features by default, to make the
user experience when developing binaries (not libraries) much easier.

Users that develop a library should use `default-features = false`, but
that's also probably something that they only want to do later in the
development process (and should be evaluated on a case-by-case basis).

Fixes #627

This also makes examples much nicer to run, it's just
`cargo run --example $name`, no need to configure all the required
features.
madsmtm added a commit that referenced this issue Jan 16, 2025
Enable (almost) all framework crate features by default, to make the
user experience when developing binaries (not libraries) much easier.

Users that develop a library should use `default-features = false`, but
that's also probably something that they only want to do later in the
development process (and should be evaluated on a case-by-case basis).

Fixes #627

This also makes examples much nicer to run, it's just
`cargo run --example $name`, no need to configure all the required
features.
@madsmtm madsmtm added bug Something isn't working documentation Improvements or additions to documentation A-framework Affects the framework crates and the translator for them and removed question Further information is requested A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates labels Jan 16, 2025
madsmtm added a commit that referenced this issue Jan 16, 2025
Enable (almost) all framework crate features by default, to make the
user experience when developing binaries (not libraries) much easier.

Users that develop a library should use `default-features = false`, but
that's also probably something that they only want to do later in the
development process (and should be evaluated on a case-by-case basis).

Fixes #627

This also makes examples much nicer to run, it's just
`cargo run --example $name`, no need to configure all the required
features.
@madsmtm
Copy link
Owner

madsmtm commented Jan 16, 2025

I have moved the items in the "all" feature to the "default" feature in 9cb0268, with the motivation: Easy default for binary projects, though a bit harder for libraries that want to minimize compile-times.

It is somewhat unfortunate that I didn't do this originally, since once I do the release, I'll have to go file PRs to all the projects that currently use objc2 and add default-features = false, but such is life.

I'll also note that there was a slight complication here, namely that we don't want objc2-app-kit to implicitly enable objc2-uniform-type-identifiers, as the latter contains a #[link(name = "UniformTypeIdentifiers", kind = "framework")], and that would cause the dynamic linker to fail on versions lower than macOS 11.0 where UniformTypeIdentifiers was introduced. I fixed this by just not including such dependencies in the default features table.

@madsmtm
Copy link
Owner

madsmtm commented Jan 21, 2025

Okay, so I'm gonna file PRs against the popular crates that use objc2 (taken from #174), and make them use default-features = false. Tracking progress here (will tick the checkbox once a PR is filed, not necessarily merged):

Just to note, I'm not normally gonna fix other people's code like this, e.g. I'll expect them to figure out how to upgrade themselves, but I'm doing it now because I feel like it'll be my fault otherwise ;)

Crates where I will file a PR with the dependency upgrade itself (as well as using new framework crates):

@kchibisov
Copy link

Wouldn't it make sense to create a set of feature to enable functionality needed? Like if metal mandates 61 feature, maybe have a feature for that? Like enabling all will likely make them not being disabled in some dependency in the graph and blow up.

Like even for said metal, like all was also a fine solution.

I'd also said that win32 has a common problem, but doesn't try to enable everything by default.

@madsmtm
Copy link
Owner

madsmtm commented Jan 21, 2025

Yes, and we had that before, the all feature, but it's not very discoverable.

In my own use of the objc2 crates, including the porting work I've done to migrate other crates, I've found that in every single project, it makes sense to start out with enabling everything, since it can be really difficult to figure out from inside your editor (i.e. with rust-analyzer) what features to enable for a thing to be available (NSView requires both NSView and NSResponder, for example), and that massively hampers the development workflow (as you'd have to look it up on docs.rs instead).

Basically, enabling all features should be the default, since that's always what you want when starting out. Yes, this will cause some crates to enable too much, but that's a cost we'll have to live with.


If need be, I guess I could analyse crates.io for uses of default-features = true once in a while, to ensure that the most popular crates keep their compile-times low.

Python script to do so ```python import json import urllib.request import sys

API_URL = "https://crates.io/api/v1/crates"

crate_name = sys.argv[1]

page = 1
while True:
print(f"page {page}")
with urllib.request.urlopen(f"{API_URL}/{crate_name}/reverse_dependencies?per_page=100&page={page}") as f:
data = json.load(f)
page += 1

if len(data['versions']) == 0:
    break

versions = {x['id']: x for x in data['versions']}

for dep in data['dependencies']:
    crate = versions[dep['version_id']]
    if dep['default_features']:
        print(f"{crate['crate']} had `default-features = true`")
</details>

emilk pushed a commit to emilk/egui that referenced this issue Jan 22, 2025
The next version of the `objc2` framework crates will have a bunch of
default features enabled, see
madsmtm/objc2#627, so this PR pre-emptively
disables them, so that your compile times down blow up once you upgrade
to the next version (which is yet to be released, but will be soon).

* [x] I have followed the instructions in the PR template
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-framework Affects the framework crates and the translator for them bug Something isn't working documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

3 participants