Skip to content

Support no_std where possible (specifically for wasm32v1-none) #6826

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

Open
Dinnerbone opened this issue Dec 25, 2024 · 18 comments
Open

Support no_std where possible (specifically for wasm32v1-none) #6826

Dinnerbone opened this issue Dec 25, 2024 · 18 comments
Labels
help required We need community help to make this happen. platform: wasm Issues with webassembly type: enhancement New feature or request

Comments

@Dinnerbone
Copy link
Contributor

Is your feature request related to a problem? Please describe.
naga, wgpu and related crates should have std as a (default) feature, specifically for wasm32v1-none support.

Describe the solution you'd like
There's a hope to get the wasm ecosystem slowly shifting from wasm32-unknown-unknown to wasm32v1-none, which is hopefully stabilizing in rust 1.84. This is primarily because wasm32-unknown-unknown is something of a moving target and can change the browser requirements at will, which we recently discovered when older Safari stopped working 😅

The main differences between wasm32v1-none and wasm32-unknown-unknown are:

  • It does not enable any wasm features by default (which means it won't arbitrarily break browser compatibility with rust updates)
  • It has no std (as opposed to a stubbed pseudo-std)

Unfortunately, no_std is both a blessing and a curse: it's neat to get things using core/alloc where possible, but it sucks that the majority of the ecosystem needs churn to make this viable.

I've done a quick investigation and I think it's plausible to get at least web working in no_std, but potentially other platforms too. wgpu-types is the easiest to get no_std, it only needs it for one specific dx12 config. naga is possibly the second easiest crate, but it requires some work in dependencies. wgpu-core and wgpu-hal will need more work mostly surrounding the use of mutexes.

Describe alternatives you've considered
We could just not, but that means it's impossible to allow users of wgpu to have any control over which browsers they support.
We can also limit this to a specific set of features, there's no real need today for DX12 and no_std, for example.

@bushrat011899
Copy link
Contributor

I think there's value in having even just a subset of wgpu be no_std compatible. For context, I'm working on making Bevy no_std compatible, and a big line in the sand right now is anything related to our rendering crates, since they're built around wgpu and would be almost impossible to make independent of wgpu for the sake of an std feature.

@rdrpenguin04
Copy link

This would also be useful for porting to game consoles, particularly console homebrew.

@cwfitzgerald cwfitzgerald added the help required We need community help to make this happen. label Jan 10, 2025
@cwfitzgerald
Copy link
Member

We're definitely interested in having this, but will need to be from an outside contributor, so PR's welcome!

I think that it is important that when the first PR comes in to partially support no-std, we have a CI job to make sure we don't break it in the future. That could be as simple as adding this wasm target to CI.

@brody4hire
Copy link
Contributor

@bushrat011899 wrote in #6892 (comment):

Thanks for the assistance in getting it over the line! I'm planning on looking into no_std for naga next, but I suspect that'll be a much longer process.

@bushrat011899 I am working on this update for wgpu-core, hope to have a PR ready with this soon. I am taking a slightly different approach and would appreciate your feedback on this. I have also raised a couple more PRs to help prepare for these updates (see recent references above).

I may consider hacking on wgpu-hal as well, if you are not already working on this.

Hope I am not stepping on any toes.

@bushrat011899
Copy link
Contributor

Hope I am not stepping on any toes.

Not at all! Just happy to have more people working on no_std support!

@brody4hire
Copy link
Contributor

brody4hire commented Jan 16, 2025

FYI I have now got no-std build working with naga in my workarea, with really ugly hacking - unfortunately I need to take rest after a very long day, hope to raise a PR for this before the weekend. I have ended up learning quite a bit from this :)


P.S. Here is the branch I pushed to backup my workarea: https://github.com/brodycj/wgpu/tree/wipsave34asdf

This is based on PR #6926 for wgpu-core, only recommended for the super-brave!

@kpreid
Copy link
Collaborator

kpreid commented Feb 21, 2025

I’d like to recommend a change to the problem statement here:

naga, wgpu and related crates should have std as a (default) feature,

While having a feature named std makes sense for some cases, like libraries which provide a trait and implement it for std types, I think that it is not a good pattern in general, because it is not clear when dependents should enable them. Instead, as much as possible, libraries should have features named for the actual functionality they enable, and document which of those features require std.

@cwfitzgerald
Copy link
Member

cwfitzgerald commented Feb 21, 2025

Seems reasonable to me - we also have things like backends which can't be no-std (dx12 will always have std, for example)

@bushrat011899
Copy link
Contributor

bushrat011899 commented Feb 25, 2025

Instead, as much as possible, libraries should have features named for the actual functionality they enable, and document which of those features require std.

Agreed, but I would definitely recommend doing this from the Cargo.toml through features. Using the DX12 backend as an example:

[features]
std = ["foo"]
dx12 = ["std", "bar"]

This clearly communicates that the dx12 feature requires std, and also keeps the lib.rs file clean:

#![no_std]

#[cfg(feature = "std")]
extern crate std;

This does mean users can see the std feature and have the option of enabling it even when it might not give them functionality, but I think that's a reasonable compromise. Like any crate feature though, libraries should activate the bare minimum they need, and gate functionality where reasonable to avoid activating too many features.

@kpreid
Copy link
Collaborator

kpreid commented Feb 25, 2025

keeps the lib.rs file clean

wgpu already solves much more complex cfg problems by using the build script to create cfg aliases that do not appear in the [features] table.

This clearly communicates that the dx12 feature requires std

I agree that this is useful documentation to have, but I do not think a feature should be added solely in order to achieve it.

@bushrat011899
Copy link
Contributor

Perfectly reasonable opinion, I do appreciate reducing the quantity of features. I recently merged a change to Bevy which completely hides the portable-atomic feature, relying exclusively on cfg(has_atomic_feature = "...") to bring in (and use) the dependency only when it's needed.

@ErichDonGubler
Copy link
Member

Some progress was claimed to be made in #7232, which was subsumed by #7043. I'm not sure if this is done yet, so calling out my immediate inability to determine what scope is left here.

@bushrat011899
Copy link
Contributor

Opened a PR to add no_std support to codespan-reporting, which would greatly simplify no_std in Naga itself. Noting it here so people interested in this issue are able to review the changes there if they wish.

@bushrat011899
Copy link
Contributor

The no_std PR I opened for codespan-reporting has been successfully merged, with a plan to release a new version in a week or so. Once that's done, no_std support for naga can make further progress.

github-merge-queue bot pushed a commit to petgraph/petgraph that referenced this issue Mar 21, 2025
# Objective

- Alternative to #238
- Alternative to #370
- Implements Item 6 from #551

## Solution

- Promoted `hashbrown` to a direct dependency (currently transient
through `indexmap`)
- Added a new `std` feature, and included it in all features which rely
on `std` for documentation purposes.
- Added new CI task to ensure `no_std` support works (using
`wasm32v1-none` as an example `no_std` target)
- Added several lints which help minimise `std` usage
- Adjusted certain public APIs to allow passing a `S: BuildHasher`
instead of implicitly relying on `std::hash::RandomState` when the `std`
feature is disabled

---

## Notes

I know this has been attempted several times before and delayed due to a
desire to refactor the crate _first_ before adding this functionality.
Delays in adding `no_std` support forced Bevy to drop `petgraph` from
its core crates, relying on a specialised alternative. We'd love to keep
using `petgraph`, but `no_std` support is now a requirement going
forward. This will also come up with `wgpu` which is _also_ pursuing
`no_std` support [here](gfx-rs/wgpu#6826).

---

BREAKING CHANGE:

Petgraph previously assumed the usage of `std::hash::RandomState` as the
hashing implementation across its codebase. In `no_std`, this is not
possible. To minimise friction for libraries supporting both `std` and
`no_std` with Petgraph, I have made the following changes to the public
API:

### `petgraph::algo::simple_paths::all_simple_paths`

This function now has a 3rd generic parameter `S` which controls the
hashing implementation used. Because `all_simple_paths` is a function it
cannot have default generic parameters, so users must specify the hasher
themselves.

```rust
// Before
let foo = all_simple_paths(/* ... */);

// After
let foo = all_simple_paths::<_, _, std::hash::RandomState>(/* ... */);
```

### Switched from `std::collections::{HashMap, HashSet}` to
`hashbrown::{HashMap, HashSet}`

To support `no_std`, we cannot use the standard library's
implementations of `HashMap` or `HashSet`. Methods and types previously
referencing those collections from `std` will now reference them from
`hashbrown`. Note that `hashbrown` was already a dependency of Petgraph,
so no change in audit requirements.

### Added Hashing Parameter

The following types have had a new generic parameter `S` added to
specify the hashing implementation. Note that when `std` is enabled,
these will all default to `std::hash::RandomState`, as before.

- `UnGraphMap`
- `DiGraphMap`
- `MatrixGraph`
- `DiMatrix`
- `UnMatrix`
- `NodeIdentifiers`
- `NodeReferences`

Note that for `MatrixGraph`, `DiMatrix`, `UnMatrix` the new `S`
parameter is in the 3rd position (all others have `S` in the last
position). The reason is `S` has a default parameter with `std` enabled,
but is required with `std` disabled. This means it must be the last
_required_ parameter.

```rust
// Before
let foo: MatrixGraph<Foo, Bar, Directed, Option<Bar>, DefaultIx>;

// After
let foo: MatrixGraph<Foo, Bar, std::hash::RandomState, Directed, Option<Bar>, DefaultIx>;
```

Also note that because `Default` can now be implemented for multiple
versions of the above types (generic over the hasher), you may need to
either specify the hasher, or explicitly declare it as default (with the
`std` feature enabled):

```rust
// Note that N and E are inferred by code below.
// Before
let foo = UnMatrix::default();

// After (Explicitly infer N and E, but use defaults otherwise)
let foo = UnMatrix::<_, _>::default();
```

### `default-features = false` MSRV is 1.81

If you don't enable the `std` feature, the MSRV increases to 1.81, when
`core::error::Error` was stabilised. To preserve the original MSRV of
1.64, just enable the `std` feature.
@bushrat011899
Copy link
Contributor

Working on a no_std PR for arbitrary so that it isn't a blocker for some of the naga features.

@bushrat011899
Copy link
Contributor

Have a no_std compatible implementation of round_ties_even in a PR for num-traits. If that PR is accepted that's the final blocker for no_std support in Naga. If not, the content of the PR could be easily used within Naga, but it would be nicer to solve this upstream.

@bushrat011899
Copy link
Contributor

All dependencies in Naga now have no_std PRs either opened or merged awaiting release. The SPIR-V features are the only ones with reliance on std once the above PRs are merged, due to DebugInfo::file_name, Options::block_ctx_dump_prefix, and the writing of block context dumps (I'm unfamiliar with SPIR-V so I don't understand whether that's required functionality).

emilk pushed a commit to emilk/egui that referenced this issue Apr 24, 2025
Prerequisite of #6744.
See: gfx-rs/wgpu#7218,
gfx-rs/wgpu#7425

Please be aware that Rust 1.84 enables some (more) WASM extensions by
default, and ships with an `std` built with them enabled:
https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features/
According to `rustc +1.84 --print=cfg --target wasm32-unknown-unknown`,
these are: `multivalue`, `mutable-globals`, `reference-types`, and
`sign-ext`.
(c.f. `rustc +1.84 --print=cfg --target wasm32-unknown-unknown -C
target-cpu=mvp` enabling none.)
For reference: https://webassembly.org/features/

----

If support is desired for ancient/esoteric browsers that don't have
these implemented, there are two ways to get around this:
- Target `wasm32v1-none` instead, but that's a `no-std` target, and I
suppose a lot of dependencies don't work that way (e.g.
gfx-rs/wgpu#6826)
- Using the `-Ctarget-cpu=mvp` and `-Zbuild-std=panic_abort,std` flags,
and the `RUSTC_BOOTSTRAP=1` escape hatch to allow using the latter with
non-`nightly` toolchains - until
https://github.com/rust-lang/wg-cargo-std-aware is stabilized. (For
reference:
https://github.com/ruffle-rs/ruffle/pull/18528/files#diff-fb2896d189d77b35ace9a079c1ba9b55777d16e0f11ce79f776475a451b1825a)

I don't think either of these is particularly advantageous, so I suggest
just accepting that browsers will have to have some extensions
implemented to run `egui`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help required We need community help to make this happen. platform: wasm Issues with webassembly type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants