Wasmtime: cranelift-codegen no longer builds with no_std

Created on 1 Dec 2019  路  8Comments  路  Source: bytecodealliance/wasmtime

I've tracked down a few things that are preventing this from happening.

  1. packed_struct requires std by default
  2. There are a few uses of std in cranelift-codegen and cranelift-codegen-shared that can be replaced with core or alloc.
  3. thiserror requires std, because the Error trait doesn't exist in core or alloc.

The first two are trivial to fix, and I'll create a PR with those changes in a second.

However, there are 11 uses of the Display and Into<result::CodegenError> traits that prevent me from placing thiserror behind a feature gate, and I'm not sure what to do about them.


Here are the 11 things that rely on those traits, as reported by rustc (click to expand)

$ cargo build --no-default-features --features core
Compiling cranelift-codegen v0.51.0 (/home/icydefiance/Documents/code/cranelift/cranelift-codegen)
error[E0599]: no method named `to_string` found for type `verifier::VerifierError` in the current scope
--> cranelift-codegen/src/print_errors.rs:218:36
    |
218 |     writeln!(w, "; error: {}", err.to_string())?;
    |                                    ^^^^^^^^^ method not found in `verifier::VerifierError`
    | 
::: cranelift-codegen/src/verifier/mod.rs:138:1
    |
138 | pub struct VerifierError {
    | ------------------------ method `to_string` not found for this
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `to_string`, perhaps you need to implement it:
            candidate bytecodealliance/cranelift#1: `alloc::string::ToString`

error[E0599]: no method named `to_string` found for type `result::CodegenError` in the current scope
--> cranelift-codegen/src/print_errors.rs:227:13
    |
227 |         err.to_string()
    |             ^^^^^^^^^ method not found in `result::CodegenError`
    | 
::: cranelift-codegen/src/result.rs:12:1
    |
12  | pub enum CodegenError {
    | --------------------- method `to_string` not found for this
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `to_string`, perhaps you need to implement it:
            candidate bytecodealliance/cranelift#1: `alloc::string::ToString`

error[E0277]: `verifier::VerifierError` doesn't implement `core::fmt::Display`
--> cranelift-codegen/src/verifier/mod.rs:235:33
    |
235 |             writeln!(f, "- {}", err)?;
    |                                 ^^^ `verifier::VerifierError` cannot be formatted with the default formatter
    |
    = help: the trait `core::fmt::Display` is not implemented for `verifier::VerifierError`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
    = note: required because of the requirements on the impl of `core::fmt::Display` for `&verifier::VerifierError`
    = note: required by `core::fmt::Display::fmt`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/context.rs:224:30
    |
224 |             self.verify(fisa)?;
    |                              ^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required by `core::convert::From::from`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/context.rs:244:39
    |
244 |             self.verify_locations(isa)?;
    |                                       ^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required by `core::convert::From::from`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:111:28
    |
111 |                 return Err(errors.into());
    |                            ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:139:28
    |
139 |                 return Err(errors.into());
    |                            ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:168:28
    |
168 |                 return Err(errors.into());
    |                            ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:196:28
    |
196 |                 return Err(errors.into());
    |                            ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:239:28
    |
239 |                 return Err(errors.into());
    |                            ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error[E0277]: the trait bound `result::CodegenError: core::convert::From<verifier::VerifierErrors>` is not satisfied
--> cranelift-codegen/src/regalloc/context.rs:248:17
    |
248 |             Err(errors.into())
    |                 ^^^^^^^^^^^^^ the trait `core::convert::From<verifier::VerifierErrors>` is not implemented for `result::CodegenError`
    |
    = note: required because of the requirements on the impl of `core::convert::Into<result::CodegenError>` for `verifier::VerifierErrors`

error: aborting due to 11 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `cranelift-codegen`.

To learn more, run the command again with --verbose.

Additional info:

  • The author of thiserror doesn't want to add a feature-gate for just the Error trait, but it's possible to provide another implementation of Display (and presumably Into). dtolnay/thiserror#43
  • There was some discussion of moving Error to alloc, and a PR was even created to do so, but it was closed because RFC 2504 will add backtrace functionality that requires std.
bug cranelift

Most helpful comment

It's nice to be able to experiment on a smaller crate like wasmparser (since we're the same authors), to have a precise idea of what the code would look like in the end, what's the best strategy to implement this (use no-std-compat or something else). Once that's done, we agreed we could also port the whole Cranelift crate to no-std support, using the methods learned during the port of wasmparser. Hope this makes sense!

All 8 comments

In addition to that PR, I started addressing point 3 on the no_std-thiserror branch on my fork. (diff) Building that branch will give you the same errors that I pasted in the above post.

I got cranelift-wasm and its dependencies (including cranelift-codegen) to compile with no_std in my fork. To do so, I had to fork thiserror and v0.48.2 of wasmparser (there have been breaking changes since then).

I also copied the extern crate alloc as std; line from cranelift-wasm to cranelift-codegen, and eliminated all direct use of alloc there. (It also reduced the changes I had to make to thiserror.) Unfortunately I don't think there's a way to do the same thing with core.

Considering the current lack of interest in supporting no_std, as expressed in my PR, I won't bother making any new PRs. However, they're good enough for the project I'm playing with, so they may also be useful to someone else, and they may be informative if there is any future interest in supporting no_std.

I happen to know of at least one project where building cranelift-wasm as no_std is really helpful, so I just want to say I appreciate this work.

Sorry we didn't get back to you earlier, things have been a bit hectic lately, and no-std support is not checked in automation, so it's definitely something we may break a lot. The main issue here was finding a proper core reviewer for your work; if there's someone who could chime in and review such changes, it would be definitely helpful. And then, we could reopen your PR here and in other places and take your changes, if you were so inclined.

(Of course, that also depends on the thiserror changes being properly integrated upstream, which might be another hill to climb.)

By "lack of interest" I was referring to Alex's comment in my PR, but if that's not the case then I can make some new PRs later today. I'll start with thiserror and wasmparser and see how it goes.

It's nice to be able to experiment on a smaller crate like wasmparser (since we're the same authors), to have a precise idea of what the code would look like in the end, what's the best strategy to implement this (use no-std-compat or something else). Once that's done, we agreed we could also port the whole Cranelift crate to no-std support, using the methods learned during the port of wasmparser. Hope this makes sense!

It's nice to be able to experiment on a smaller crate like wasmparser

Opened https://github.com/bytecodealliance/wasmparser/issues/198 . I'm proposing not depend on structures that require memory allocations (this means no hashbrown )

... using the methods learned during the port of wasmparser

These ideas might not be applied here

Was this page helpful?
0 / 5 - 0 ratings