Skip to content

Commit

Permalink
Configure WIT feature gates at runtime & implement wasi-cli `exit-wit…
Browse files Browse the repository at this point in the history
…h-code` (#9381)

* Remove `features` configuration from component::bindgen! and always emit all unstable members. These features will be gated at runtime.

* Implement wasi-cli's unstable `exit-with-code`

* Add codegen test for unstable features

* Add LinkOptions type and add a parameter to all add_to_linker functions in for worlds/interfaces that use any unstable feature.

* More descriptive test feature names.

* Generate feature gate `if` checks

* Expose `cli-exit-with-code` as CLI option

* Generate bespoke option types per interface and world.

* Add unit test

* Remove exit code restriction on Windows

* Add cli_exit_with_code test

* Use BTreeSet to generate the options in consistent order

* Change wasmtime-wasi's `add_to_linker_(a)sync` signature back to how it was and add new variants that take the option parameters.

* Lift Windows exit code restriction in tests

* Lift Windows exit code restriction
  • Loading branch information
badeend authored Oct 7, 2024
1 parent 2772d2b commit c230353
Show file tree
Hide file tree
Showing 19 changed files with 2,069 additions and 89 deletions.
2 changes: 2 additions & 0 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ wasmtime_option_group! {
pub struct WasiOptions {
/// Enable support for WASI CLI APIs, including filesystems, sockets, clocks, and random.
pub cli: Option<bool>,
/// Enable WASI APIs marked as: @unstable(feature = cli-exit-with-code)
pub cli_exit_with_code: Option<bool>,
/// Deprecated alias for `cli`
pub common: Option<bool>,
/// Enable support for WASI neural network API (experimental)
Expand Down
18 changes: 2 additions & 16 deletions crates/component-macro/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ impl Parse for Config {
let mut inline = None;
let mut paths = Vec::new();
let mut async_configured = false;
let mut features = Vec::new();
let mut include_generated_code_from_file = false;

if input.peek(token::Brace) {
Expand Down Expand Up @@ -152,9 +151,6 @@ impl Parse for Config {
}
Opt::Stringify(val) => opts.stringify = val,
Opt::SkipMutForwardingImpls(val) => opts.skip_mut_forwarding_impls = val,
Opt::Features(f) => {
features.extend(f.into_iter().map(|f| f.value()));
}
Opt::RequireStoreDataSend(val) => opts.require_store_data_send = val,
Opt::WasmtimeCrate(f) => {
opts.wasmtime_crate = Some(f.into_token_stream().to_string())
Expand All @@ -168,7 +164,7 @@ impl Parse for Config {
paths.push(input.parse::<syn::LitStr>()?.value());
}
}
let (resolve, pkgs, files) = parse_source(&paths, &inline, &features)
let (resolve, pkgs, files) = parse_source(&paths, &inline)
.map_err(|err| Error::new(call_site, format!("{err:?}")))?;

let world = select_world(&resolve, &pkgs, world.as_deref())
Expand All @@ -186,10 +182,9 @@ impl Parse for Config {
fn parse_source(
paths: &Vec<String>,
inline: &Option<String>,
features: &[String],
) -> anyhow::Result<(Resolve, Vec<PackageId>, Vec<PathBuf>)> {
let mut resolve = Resolve::default();
resolve.features.extend(features.iter().cloned());
resolve.all_features = true;
let mut files = Vec::new();
let mut pkgs = Vec::new();
let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
Expand Down Expand Up @@ -283,7 +278,6 @@ mod kw {
syn::custom_keyword!(additional_derives);
syn::custom_keyword!(stringify);
syn::custom_keyword!(skip_mut_forwarding_impls);
syn::custom_keyword!(features);
syn::custom_keyword!(require_store_data_send);
syn::custom_keyword!(wasmtime_crate);
syn::custom_keyword!(include_generated_code_from_file);
Expand All @@ -304,7 +298,6 @@ enum Opt {
AdditionalDerives(Vec<syn::Path>),
Stringify(bool),
SkipMutForwardingImpls(bool),
Features(Vec<syn::LitStr>),
RequireStoreDataSend(bool),
WasmtimeCrate(syn::Path),
IncludeGeneratedCodeFromFile(bool),
Expand Down Expand Up @@ -478,13 +471,6 @@ impl Parse for Opt {
Ok(Opt::SkipMutForwardingImpls(
input.parse::<syn::LitBool>()?.value,
))
} else if l.peek(kw::features) {
input.parse::<kw::features>()?;
input.parse::<Token![:]>()?;
let contents;
syn::bracketed!(contents in input);
let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
Ok(Opt::Features(list.into_iter().collect()))
} else if l.peek(kw::require_store_data_send) {
input.parse::<kw::require_store_data_send>()?;
input.parse::<Token![:]>()?;
Expand Down
28 changes: 28 additions & 0 deletions crates/component-macro/tests/codegen/unstable-features.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package foo:foo;

@unstable(feature = experimental-interface)
interface the-interface {
@unstable(feature = experimental-interface-function)
foo: func();

@unstable(feature = experimental-interface-resource)
resource bar {
@unstable(feature = experimental-interface-resource-method)
foo: func();
}
}

@unstable(feature = experimental-world)
world the-world {
@unstable(feature = experimental-world-interface-import)
import the-interface;

@unstable(feature = experimental-world-function-import)
import foo: func();

@unstable(feature = experimental-world-resource)
resource baz {
@unstable(feature = experimental-world-resource-method)
foo: func();
}
}
Loading

0 comments on commit c230353

Please sign in to comment.