Repository: bytecodealliance/wasmtime
Pull request #8732 (2024-06-02 01:00:37)

Refactor wasmtime::Func to "unsplat" arguments for the async API
Related issue: #5066 


ssnover: @pchickey tagging you as well per your request in the issue; I don't have permission to edit reviewers.

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f75d78128..3f3df368e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -300,7 +300,11 @@ jobs:
           --exclude wasi-http-tests \
           --exclude cranelift-codegen-meta \
           --features component-model
+      env:
+        RUSTDOCFLAGS: --cfg=docsrs
     - run: cargo doc --package cranelift-codegen-meta --document-private-items
+      env:
+        RUSTDOCFLAGS: --cfg=docsrs
 
     # Assemble the documentation, and always upload it as an artifact for
     # inspection on PRs and such.
diff --git a/Cargo.lock b/Cargo.lock
index 8041eb4e6..e9b9f6e29 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -781,7 +781,7 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-module",
  "log",
- "object 0.33.0",
+ "object 0.36.0",
  "target-lexicon",
 ]
 
@@ -1862,7 +1862,7 @@ version = "22.0.0"
 dependencies = [
  "anyhow",
  "libloading",
- "object 0.33.0",
+ "object 0.36.0",
  "wasmtime",
 ]
 
@@ -1932,9 +1932,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.33.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8dd6c0cdf9429bce006e1362bfce61fa1bfd8c898a643ed8d2b471934701d3d"
+checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
 dependencies = [
  "crc32fast",
  "hashbrown 0.14.3",
@@ -3184,7 +3184,7 @@ version = "22.0.0"
 dependencies = [
  "bitflags 2.4.1",
  "byte-array-literals",
- "object 0.33.0",
+ "object 0.36.0",
  "wasi",
  "wasm-encoder",
  "wit-bindgen-rust-macro",
@@ -3392,7 +3392,7 @@ dependencies = [
  "mach2",
  "memfd",
  "memoffset",
- "object 0.33.0",
+ "object 0.36.0",
  "once_cell",
  "paste",
  "postcard",
@@ -3537,7 +3537,7 @@ dependencies = [
  "log",
  "memchr",
  "num_cpus",
- "object 0.33.0",
+ "object 0.36.0",
  "once_cell",
  "rayon",
  "rustix",
@@ -3624,7 +3624,7 @@ dependencies = [
  "cranelift-wasm",
  "gimli",
  "log",
- "object 0.33.0",
+ "object 0.36.0",
  "target-lexicon",
  "thiserror",
  "wasmparser",
@@ -3644,7 +3644,7 @@ dependencies = [
  "gimli",
  "indexmap 2.2.6",
  "log",
- "object 0.33.0",
+ "object 0.36.0",
  "postcard",
  "rustc-demangle",
  "serde",
@@ -3761,7 +3761,7 @@ dependencies = [
 name = "wasmtime-jit-debug"
 version = "22.0.0"
 dependencies = [
- "object 0.33.0",
+ "object 0.36.0",
  "once_cell",
  "rustix",
  "wasmtime-versioned-export-macros",
@@ -3916,7 +3916,7 @@ dependencies = [
  "anyhow",
  "cranelift-codegen",
  "gimli",
- "object 0.33.0",
+ "object 0.36.0",
  "target-lexicon",
  "wasmparser",
  "wasmtime-cranelift",
diff --git a/Cargo.toml b/Cargo.toml
index be1e8c067..ac53b9223 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -265,7 +265,7 @@ wit-component = "0.209.1"
 # Non-Bytecode Alliance maintained dependencies:
 # --------------------------
 cc = "1.0"
-object = { version = "0.33", default-features = false, features = ['read_core', 'elf'] }
+object = { version = "0.36", default-features = false, features = ['read_core', 'elf'] }
 gimli = { version = "0.28.0", default-features = false, features = ['read'] }
 addr2line = { version = "0.21.0", default-features = false }
 anyhow = { version = "1.0.22", default-features = false }
diff --git a/benches/call.rs b/benches/call.rs
index aef4421b0..a25cbb8fe 100644
--- a/benches/call.rs
+++ b/benches/call.rs
@@ -367,20 +367,24 @@ fn wasm_to_host(c: &mut Criterion) {
 
         let mut typed = Linker::new(&engine);
         typed
-            .func_wrap0_async("", "nop", |caller| {
+            .func_wrap_async("", "nop", |caller, _: ()| {
                 Box::new(async {
                     drop(caller);
                 })
             })
             .unwrap();
         typed
-            .func_wrap2_async("", "nop-params-and-results", |_caller, x: i32, y: i64| {
-                Box::new(async move {
-                    assert_eq!(x, 0);
-                    assert_eq!(y, 0);
-                    0.0f32
-                })
-            })
+            .func_wrap_async(
+                "",
+                "nop-params-and-results",
+                |_caller, (x, y): (i32, i64)| {
+                    Box::new(async move {
+                        assert_eq!(x, 0);
+                        assert_eq!(y, 0);
+                        0.0f32
+                    })
+                },
+            )
             .unwrap();
         let instance = run_await(typed.instantiate_async(&mut *store, &module)).unwrap();
         bench_instance(group, store, &instance, "async-typed", is_async);
diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs
index af51c5602..2d48e9b61 100644
--- a/cranelift/object/src/backend.rs
+++ b/cranelift/object/src/backend.rs
@@ -154,6 +154,7 @@ impl ObjectModule {
     pub fn new(builder: ObjectBuilder) -> Self {
         let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian);
         object.flags = builder.flags;
+        object.set_subsections_via_symbols();
         object.add_file_symbol(builder.name);
         Self {
             isa: builder.isa,
@@ -368,19 +369,14 @@ impl Module for ObjectModule {
         let align = alignment
             .max(self.isa.function_alignment().minimum.into())
             .max(self.isa.symbol_alignment());
-        let (section, offset) = if self.per_function_section {
+        let section = if self.per_function_section {
             let symbol_name = self.object.symbol(symbol).name.clone();
-            let (section, offset) =
-                self.object
-                    .add_subsection(StandardSection::Text, &symbol_name, bytes, align);
-            self.object.symbol_mut(symbol).section = SymbolSection::Section(section);
-            self.object.symbol_mut(symbol).value = offset;
-            (section, offset)
+            self.object
+                .add_subsection(StandardSection::Text, &symbol_name)
         } else {
-            let section = self.object.section_id(StandardSection::Text);
-            let offset = self.object.add_symbol_data(symbol, section, bytes, align);
-            (section, offset)
+            self.object.section_id(StandardSection::Text)
         };
+        let offset = self.object.add_symbol_data(symbol, section, bytes, align);
 
         if !relocs.is_empty() {
             let relocs = relocs
diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs
index e5113a5e1..828f4f926 100644
--- a/crates/component-macro/src/bindgen.rs
+++ b/crates/component-macro/src/bindgen.rs
@@ -2,6 +2,7 @@ use proc_macro2::{Span, TokenStream};
 use quote::ToTokens;
 use std::collections::HashMap;
 use std::collections::HashSet;
+use std::env;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
 use syn::parse::{Error, Parse, ParseStream, Result};
@@ -15,6 +16,7 @@ pub struct Config {
     resolve: Resolve,
     world: WorldId,
     files: Vec<PathBuf>,
+    include_generated_code_from_file: bool,
 }
 
 pub fn expand(input: &Config) -> Result<TokenStream> {
@@ -38,7 +40,7 @@ pub fn expand(input: &Config) -> Result<TokenStream> {
     // place a formatted version of the expanded code into a file. This file
     // will then show up in rustc error messages for any codegen issues and can
     // be inspected manually.
-    if std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() {
+    if input.include_generated_code_from_file || std::env::var("WASMTIME_DEBUG_BINDGEN").is_ok() {
         static INVOCATION: AtomicUsize = AtomicUsize::new(0);
         let root = Path::new(env!("DEBUG_OUTPUT_DIR"));
         let world_name = &input.resolve.worlds[input.world].name;
@@ -81,6 +83,7 @@ impl Parse for Config {
         let mut path = None;
         let mut async_configured = false;
         let mut features = Vec::new();
+        let mut include_generated_code_from_file = false;
 
         if input.peek(token::Brace) {
             let content;
@@ -155,6 +158,10 @@ impl Parse for Config {
                         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())
+                    }
+                    Opt::IncludeGeneratedCodeFromFile(i) => include_generated_code_from_file = i,
                 }
             }
         } else {
@@ -174,6 +181,7 @@ impl Parse for Config {
             resolve,
             world,
             files,
+            include_generated_code_from_file,
         })
     }
 }
@@ -230,6 +238,8 @@ mod kw {
     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);
 }
 
 enum Opt {
@@ -248,6 +258,8 @@ enum Opt {
     SkipMutForwardingImpls(bool),
     Features(Vec<syn::LitStr>),
     RequireStoreDataSend(bool),
+    WasmtimeCrate(syn::Path),
+    IncludeGeneratedCodeFromFile(bool),
 }
 
 impl Parse for Opt {
@@ -411,6 +423,16 @@ impl Parse for Opt {
             Ok(Opt::RequireStoreDataSend(
                 input.parse::<syn::LitBool>()?.value,
             ))
+        } else if l.peek(kw::wasmtime_crate) {
+            input.parse::<kw::wasmtime_crate>()?;
+            input.parse::<Token![:]>()?;
+            Ok(Opt::WasmtimeCrate(input.parse()?))
+        } else if l.peek(kw::include_generated_code_from_file) {
+            input.parse::<kw::include_generated_code_from_file>()?;
+            input.parse::<Token![:]>()?;
+            Ok(Opt::IncludeGeneratedCodeFromFile(
+                input.parse::<syn::LitBool>()?.value,
+            ))
         } else {
             Err(l.error())
         }
diff --git a/crates/component-macro/src/component.rs b/crates/component-macro/src/component.rs
index 9f7ef47bd..f41181f83 100644
--- a/crates/component-macro/src/component.rs
+++ b/crates/component-macro/src/component.rs
@@ -1,10 +1,10 @@
-use proc_macro2::TokenStream;
+use proc_macro2::{Span, TokenStream};
 use quote::{format_ident, quote};
 use std::collections::HashSet;
 use std::fmt;
 use syn::parse::{Parse, ParseStream};
 use syn::punctuated::Punctuated;
-use syn::{braced, parse_quote, Data, DeriveInput, Error, Result, Token};
+use syn::{braced, parse_quote, Data, DeriveInput, Error, Ident, Result, Token};
 use wasmtime_component_util::{DiscriminantSize, FlagsSize};
 
 mod kw {
@@ -12,6 +12,7 @@ mod kw {
     syn::custom_keyword!(variant);
     syn::custom_keyword!(flags);
     syn::custom_keyword!(name);
+    syn::custom_keyword!(wasmtime_crate);
 }
 
 #[derive(Debug, Copy, Clone)]
@@ -35,39 +36,28 @@ enum Style {
     Variant(VariantStyle),
 }
 
-fn find_style(input: &DeriveInput) -> Result<Style> {
-    let mut style = None;
-
-    for attribute in &input.attrs {
-        if !attribute.path().is_ident("component") {
-            continue;
-        }
-        let attr_style = attribute.parse_args()?;
-
-        if style.is_some() {
-            return Err(Error::new_spanned(
-                attribute,
-                "duplicate `component` attribute",
-            ));
-        }
-        style = Some(attr_style);
-    }
-
-    style.ok_or_else(|| Error::new_spanned(input, "missing `component` attribute"))
+#[derive(Debug, Clone)]
+enum ComponentAttr {
+    Style(Style),
+    WasmtimeCrate(syn::Path),
 }
 
-impl Parse for Style {
+impl Parse for ComponentAttr {
     fn parse(input: ParseStream) -> Result<Self> {
         let lookahead = input.lookahead1();
         if lookahead.peek(kw::record) {
             input.parse::<kw::record>()?;
-            Ok(Style::Record)
+            Ok(ComponentAttr::Style(Style::Record))
         } else if lookahead.peek(kw::variant) {
             input.parse::<kw::variant>()?;
-            Ok(Style::Variant(VariantStyle::Variant))
+            Ok(ComponentAttr::Style(Style::Variant(VariantStyle::Variant)))
         } else if lookahead.peek(Token![enum]) {
             input.parse::<Token![enum]>()?;
-            Ok(Style::Variant(VariantStyle::Enum))
+            Ok(ComponentAttr::Style(Style::Variant(VariantStyle::Enum)))
+        } else if lookahead.peek(kw::wasmtime_crate) {
+            input.parse::<kw::wasmtime_crate>()?;
+            input.parse::<Token![=]>()?;
+            Ok(ComponentAttr::WasmtimeCrate(input.parse()?))
         } else if input.peek(kw::flags) {
             Err(input.error(
                 "`flags` not allowed here; \
@@ -127,6 +117,7 @@ pub trait Expander {
         name: &syn::Ident,
         generics: &syn::Generics,
         fields: &[&syn::Field],
+        wasmtime_crate: &syn::Path,
     ) -> Result<TokenStream>;
 
     fn expand_variant(
@@ -136,17 +127,49 @@ pub trait Expander {
         discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
+        wasmtime_crate: &syn::Path,
     ) -> Result<TokenStream>;
 }
 
 pub fn expand(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenStream> {
-    match find_style(input)? {
-        Style::Record => expand_record(expander, input),
-        Style::Variant(style) => expand_variant(expander, input, style),
+    let mut wasmtime_crate = None;
+    let mut style = None;
+
+    for attribute in &input.attrs {
+        if !attribute.path().is_ident("component") {
+            continue;
+        }
+        match attribute.parse_args()? {
+            ComponentAttr::WasmtimeCrate(c) => wasmtime_crate = Some(c),
+            ComponentAttr::Style(attr_style) => {
+                if style.is_some() {
+                    return Err(Error::new_spanned(
+                        attribute,
+                        "duplicate `component` attribute",
+                    ));
+                }
+                style = Some(attr_style);
+            }
+        }
     }
+
+    let style = style.ok_or_else(|| Error::new_spanned(input, "missing `component` attribute"))?;
+    let wasmtime_crate = wasmtime_crate.unwrap_or_else(default_wasmtime_crate);
+    match style {
+        Style::Record => expand_record(expander, input, &wasmtime_crate),
+        Style::Variant(style) => expand_variant(expander, input, style, &wasmtime_crate),
+    }
+}
+
+fn default_wasmtime_crate() -> syn::Path {
+    Ident::new("wasmtime", Span::call_site()).into()
 }
 
-fn expand_record(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenStream> {
+fn expand_record(
+    expander: &dyn Expander,
+    input: &DeriveInput,
+    wasmtime_crate: &syn::Path,
+) -> Result<TokenStream> {
     let name = &input.ident;
 
     let body = if let Data::Struct(body) = &input.data {
@@ -163,6 +186,7 @@ fn expand_record(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenSt
             &input.ident,
             &input.generics,
             &fields.named.iter().collect::<Vec<_>>(),
+            wasmtime_crate,
         ),
 
         syn::Fields::Unnamed(_) | syn::Fields::Unit => Err(Error::new(
@@ -176,6 +200,7 @@ fn expand_variant(
     expander: &dyn Expander,
     input: &DeriveInput,
     style: VariantStyle,
+    wasmtime_crate: &syn::Path,
 ) -> Result<TokenStream> {
     let name = &input.ident;
 
@@ -249,6 +274,7 @@ fn expand_variant(
         discriminant_size,
         &cases,
         style,
+        wasmtime_crate,
     )
 }
 
@@ -258,8 +284,9 @@ fn expand_record_for_component_type(
     fields: &[&syn::Field],
     typecheck: TokenStream,
     typecheck_argument: TokenStream,
+    wt: &syn::Path,
 ) -> Result<TokenStream> {
-    let internal = quote!(wasmtime::component::__internal);
+    let internal = quote!(#wt::component::__internal);
 
     let mut lower_generic_params = TokenStream::new();
     let mut lower_generic_args = TokenStream::new();
@@ -271,18 +298,18 @@ fn expand_record_for_component_type(
         let generic = format_ident!("T{}", index);
 
         lower_generic_params.extend(quote!(#generic: Copy,));
-        lower_generic_args.extend(quote!(<#ty as wasmtime::component::ComponentType>::Lower,));
+        lower_generic_args.extend(quote!(<#ty as #wt::component::ComponentType>::Lower,));
 
         lower_field_declarations.extend(quote!(#ident: #generic,));
 
         abi_list.extend(quote!(
-            <#ty as wasmtime::component::ComponentType>::ABI,
+            <#ty as #wt::component::ComponentType>::ABI,
         ));
 
         unique_types.insert(ty);
     }
 
-    let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType));
+    let generics = add_trait_bounds(generics, parse_quote!(#wt::component::ComponentType));
     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
     let lower = format_ident!("Lower{}", name);
 
@@ -307,10 +334,10 @@ fn expand_record_for_component_type(
         #[repr(C)]
         pub struct #lower <#lower_generic_params> {
             #lower_field_declarations
-            _align: [wasmtime::ValRaw; 0],
+            _align: [#wt::ValRaw; 0],
         }
 
-        unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause {
+        unsafe impl #impl_generics #wt::component::ComponentType for #name #ty_generics #where_clause {
             type Lower = #lower <#lower_generic_args>;
 
             const ABI: #internal::CanonicalAbiInfo =
@@ -354,27 +381,28 @@ impl Expander for LiftExpander {
         name: &syn::Ident,
         generics: &syn::Generics,
         fields: &[&syn::Field],
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
-        let internal = quote!(wasmtime::component::__internal);
+        let internal = quote!(#wt::component::__internal);
 
         let mut lifts = TokenStream::new();
         let mut loads = TokenStream::new();
 
         for (i, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
             let field_ty = quote!(ty.fields[#i].ty);
-            lifts.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::lift(
+            lifts.extend(quote!(#ident: <#ty as #wt::component::Lift>::lift(
                 cx, #field_ty, &src.#ident
             )?,));
 
-            loads.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::load(
+            loads.extend(quote!(#ident: <#ty as #wt::component::Lift>::load(
                 cx, #field_ty,
                 &bytes
-                    [<#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset)..]
-                    [..<#ty as wasmtime::component::ComponentType>::SIZE32]
+                    [<#ty as #wt::component::ComponentType>::ABI.next_field32_size(&mut offset)..]
+                    [..<#ty as #wt::component::ComponentType>::SIZE32]
             )?,));
         }
 
-        let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift));
+        let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lift));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
         let extract_ty = quote! {
@@ -385,7 +413,7 @@ impl Expander for LiftExpander {
         };
 
         let expanded = quote! {
-            unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause {
+            unsafe impl #impl_generics #wt::component::Lift for #name #ty_generics #where_clause {
                 #[inline]
                 fn lift(
                     cx: &mut #internal::LiftContext<'_>,
@@ -407,7 +435,7 @@ impl Expander for LiftExpander {
                     #extract_ty
                     debug_assert!(
                         (bytes.as_ptr() as usize)
-                            % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize)
+                            % (<Self as #wt::component::ComponentType>::ALIGN32 as usize)
                             == 0
                     );
                     let mut offset = 0;
@@ -428,8 +456,9 @@ impl Expander for LiftExpander {
         discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
-        let internal = quote!(wasmtime::component::__internal);
+        let internal = quote!(#wt::component::__internal);
 
         let mut lifts = TokenStream::new();
         let mut loads = TokenStream::new();
@@ -452,14 +481,14 @@ impl Expander for LiftExpander {
                     VariantStyle::Enum => unreachable!(),
                 };
                 lifts.extend(
-                    quote!(#index_u32 => Self::#ident(<#ty as wasmtime::component::Lift>::lift(
+                    quote!(#index_u32 => Self::#ident(<#ty as #wt::component::Lift>::lift(
                         cx, #payload_ty, unsafe { &src.payload.#ident }
                     )?),),
                 );
 
                 loads.extend(
-                    quote!(#index_quoted => Self::#ident(<#ty as wasmtime::component::Lift>::load(
-                        cx, #payload_ty, &payload[..<#ty as wasmtime::component::ComponentType>::SIZE32]
+                    quote!(#index_quoted => Self::#ident(<#ty as #wt::component::Lift>::load(
+                        cx, #payload_ty, &payload[..<#ty as #wt::component::ComponentType>::SIZE32]
                     )?),),
                 );
             } else {
@@ -469,7 +498,7 @@ impl Expander for LiftExpander {
             }
         }
 
-        let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift));
+        let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lift));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
         let from_bytes = match discriminant_size {
@@ -486,7 +515,7 @@ impl Expander for LiftExpander {
         };
 
         let expanded = quote! {
-            unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause {
+            unsafe impl #impl_generics #wt::component::Lift for #name #ty_generics #where_clause {
                 #[inline]
                 fn lift(
                     cx: &mut #internal::LiftContext<'_>,
@@ -506,7 +535,7 @@ impl Expander for LiftExpander {
                     ty: #internal::InterfaceType,
                     bytes: &[u8],
                 ) -> #internal::anyhow::Result<Self> {
-                    let align = <Self as wasmtime::component::ComponentType>::ALIGN32;
+                    let align = <Self as #wt::component::ComponentType>::ALIGN32;
                     debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0);
                     let discrim = #from_bytes;
                     let payload_offset = <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32;
@@ -532,27 +561,28 @@ impl Expander for LowerExpander {
         name: &syn::Ident,
         generics: &syn::Generics,
         fields: &[&syn::Field],
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
-        let internal = quote!(wasmtime::component::__internal);
+        let internal = quote!(#wt::component::__internal);
 
         let mut lowers = TokenStream::new();
         let mut stores = TokenStream::new();
 
         for (i, syn::Field { ident, ty, .. }) in fields.iter().enumerate() {
             let field_ty = quote!(ty.fields[#i].ty);
-            lowers.extend(quote!(wasmtime::component::Lower::lower(
+            lowers.extend(quote!(#wt::component::Lower::lower(
                 &self.#ident, cx, #field_ty, #internal::map_maybe_uninit!(dst.#ident)
             )?;));
 
-            stores.extend(quote!(wasmtime::component::Lower::store(
+            stores.extend(quote!(#wt::component::Lower::store(
                 &self.#ident,
                 cx,
                 #field_ty,
-                <#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset),
+                <#ty as #wt::component::ComponentType>::ABI.next_field32_size(&mut offset),
             )?;));
         }
 
-        let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower));
+        let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lower));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
         let extract_ty = quote! {
@@ -563,7 +593,7 @@ impl Expander for LowerExpander {
         };
 
         let expanded = quote! {
-            unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause {
+            unsafe impl #impl_generics #wt::component::Lower for #name #ty_generics #where_clause {
                 #[inline]
                 fn lower<T>(
                     &self,
@@ -583,7 +613,7 @@ impl Expander for LowerExpander {
                     ty: #internal::InterfaceType,
                     mut offset: usize
                 ) -> #internal::anyhow::Result<()> {
-                    debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0);
+                    debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
                     #extract_ty
                     #stores
                     Ok(())
@@ -601,8 +631,9 @@ impl Expander for LowerExpander {
         discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
-        let internal = quote!(wasmtime::component::__internal);
+        let internal = quote!(#wt::component::__internal);
 
         let mut lowers = TokenStream::new();
         let mut stores = TokenStream::new();
@@ -644,7 +675,7 @@ impl Expander for LowerExpander {
             }
 
             lowers.extend(quote!(#pattern => {
-                #internal::map_maybe_uninit!(dst.tag).write(wasmtime::ValRaw::u32(#index_u32));
+                #internal::map_maybe_uninit!(dst.tag).write(#wt::ValRaw::u32(#index_u32));
                 unsafe {
                     #internal::lower_payload(
                         #internal::map_maybe_uninit!(dst.payload),
@@ -660,7 +691,7 @@ impl Expander for LowerExpander {
             }));
         }
 
-        let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower));
+        let generics = add_trait_bounds(generics, parse_quote!(#wt::component::Lower));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
         let extract_ty = quote! {
@@ -671,7 +702,7 @@ impl Expander for LowerExpander {
         };
 
         let expanded = quote! {
-            unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause {
+            unsafe impl #impl_generics #wt::component::Lower for #name #ty_generics #where_clause {
                 #[inline]
                 fn lower<T>(
                     &self,
@@ -693,7 +724,7 @@ impl Expander for LowerExpander {
                     mut offset: usize
                 ) -> #internal::anyhow::Result<()> {
                     #extract_ty
-                    debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0);
+                    debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
                     match self {
                         #stores
                     }
@@ -713,6 +744,7 @@ impl Expander for ComponentTypeExpander {
         name: &syn::Ident,
         generics: &syn::Generics,
         fields: &[&syn::Field],
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
         expand_record_for_component_type(
             name,
@@ -730,10 +762,11 @@ impl Expander for ComponentTypeExpander {
                             syn::LitStr::new(&ident.to_string(), ident.span())
                         });
 
-                        Ok(quote!((#name, <#ty as wasmtime::component::ComponentType>::typecheck),))
+                        Ok(quote!((#name, <#ty as #wt::component::ComponentType>::typecheck),))
                     },
                 )
                 .collect::<Result<_>>()?,
+            wt,
         )
     }
 
@@ -744,8 +777,9 @@ impl Expander for ComponentTypeExpander {
         _discriminant_size: DiscriminantSize,
         cases: &[VariantCase],
         style: VariantStyle,
+        wt: &syn::Path,
     ) -> Result<TokenStream> {
-        let internal = quote!(wasmtime::component::__internal);
+        let internal = quote!(#wt::component::__internal);
 
         let mut case_names_and_checks = TokenStream::new();
         let mut lower_payload_generic_params = TokenStream::new();
@@ -761,11 +795,11 @@ impl Expander for ComponentTypeExpander {
             let name = rename.unwrap_or_else(|| syn::LitStr::new(&ident.to_string(), ident.span()));
 
             if let Some(ty) = ty {
-                abi_list.extend(quote!(Some(<#ty as wasmtime::component::ComponentType>::ABI),));
+                abi_list.extend(quote!(Some(<#ty as #wt::component::ComponentType>::ABI),));
 
                 case_names_and_checks.extend(match style {
                     VariantStyle::Variant => {
-                        quote!((#name, Some(<#ty as wasmtime::component::ComponentType>::typecheck)),)
+                        quote!((#name, Some(<#ty as #wt::component::ComponentType>::typecheck)),)
                     }
                     VariantStyle::Enum => {
                         return Err(Error::new(
@@ -780,8 +814,7 @@ impl Expander for ComponentTypeExpander {
                 lower_payload_generic_params.extend(quote!(#generic: Copy,));
                 lower_payload_generic_args.extend(quote!(#generic,));
                 lower_payload_case_declarations.extend(quote!(#ident: #generic,));
-                lower_generic_args
-                    .extend(quote!(<#ty as wasmtime::component::ComponentType>::Lower,));
+                lower_generic_args.extend(quote!(<#ty as #wt::component::ComponentType>::Lower,));
 
                 unique_types.insert(ty);
             } else {
@@ -792,7 +825,7 @@ impl Expander for ComponentTypeExpander {
                     }
                     VariantStyle::Enum => quote!(#name,),
                 });
-                lower_payload_case_declarations.extend(quote!(#ident: [wasmtime::ValRaw; 0],));
+                lower_payload_case_declarations.extend(quote!(#ident: [#wt::ValRaw; 0],));
             }
         }
 
@@ -801,7 +834,7 @@ impl Expander for ComponentTypeExpander {
             VariantStyle::Enum => quote!(typecheck_enum),
         };
 
-        let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType));
+        let generics = add_trait_bounds(generics, parse_quote!(#wt::component::ComponentType));
         let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
         let lower = format_ident!("Lower{}", name);
         let lower_payload = format_ident!("LowerPayload{}", name);
@@ -819,7 +852,7 @@ impl Expander for ComponentTypeExpander {
             #[derive(Clone, Copy)]
             #[repr(C)]
             pub struct #lower<#lower_payload_generic_params> {
-                tag: wasmtime::ValRaw,
+                tag: #wt::ValRaw,
                 payload: #lower_payload<#lower_payload_generic_args>
             }
 
@@ -831,7 +864,7 @@ impl Expander for ComponentTypeExpander {
                 #lower_payload_case_declarations
             }
 
-            unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause {
+            unsafe impl #impl_generics #wt::component::ComponentType for #name #ty_generics #where_clause {
                 type Lower = #lower<#lower_generic_args>;
 
                 #[inline]
@@ -897,6 +930,7 @@ impl Parse for Flags {
 }
 
 pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
+    let wt = default_wasmtime_crate();
     let size = FlagsSize::from_count(flags.flags.len());
 
     let ty;
@@ -1099,9 +1133,10 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
         &fields,
         quote!(typecheck_flags),
         component_names,
+        &wt,
     )?;
 
-    let internal = quote!(wasmtime::component::__internal);
+    let internal = quote!(#wt::component::__internal);
 
     let field_names = fields
         .iter()
@@ -1215,7 +1250,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
 
         #component_type_impl
 
-        unsafe impl wasmtime::component::Lower for #name {
+        unsafe impl #wt::component::Lower for #name {
             fn lower<T>(
                 &self,
                 cx: &mut #internal::LowerContext<'_, T>,
@@ -1238,7 +1273,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
                 _ty: #internal::InterfaceType,
                 mut offset: usize
             ) -> #internal::anyhow::Result<()> {
-                debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0);
+                debug_assert!(offset % (<Self as #wt::component::ComponentType>::ALIGN32 as usize) == 0);
                 #(
                     self.#field_names.store(
                         cx,
@@ -1251,7 +1286,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
             }
         }
 
-        unsafe impl wasmtime::component::Lift for #name {
+        unsafe impl #wt::component::Lift for #name {
             fn lift(
                 cx: &mut #internal::LiftContext<'_>,
                 _ty: #internal::InterfaceType,
@@ -1259,7 +1294,7 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
             ) -> #internal::anyhow::Result<Self> {
                 Ok(Self {
                     #(
-                        #field_names: wasmtime::component::Lift::lift(
+                        #field_names: #wt::component::Lift::lift(
                             cx,
                             #field_interface_type,
                             &src.#field_names,
@@ -1275,12 +1310,12 @@ pub fn expand_flags(flags: &Flags) -> Result<TokenStream> {
             ) -> #internal::anyhow::Result<Self> {
                 debug_assert!(
                     (bytes.as_ptr() as usize)
-                        % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize)
+                        % (<Self as #wt::component::ComponentType>::ALIGN32 as usize)
                         == 0
                 );
                 #(
                     let (field, bytes) = bytes.split_at(#field_size);
-                    let #field_names = wasmtime::component::Lift::load(
+                    let #field_names = #wt::component::Lift::load(
                         cx,
                         #field_interface_type,
                         field,
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_0_hello_world.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_0_hello_world.rs
new file mode 100644
index 000000000..fcc566e89
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_0_hello_world.rs
@@ -0,0 +1,9 @@
+bindgen!({
+  inline: r#"
+      package my:project;
+      world hello-world {
+          import name: func() -> string;
+          export greet: func();
+      }
+  "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_1_world_imports.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_1_world_imports.rs
new file mode 100644
index 000000000..deb8c94bd
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_1_world_imports.rs
@@ -0,0 +1,17 @@
+bindgen!({
+    inline: r#"
+        package example:imports;
+
+        world my-world {
+            /// Fetch a greeting to present.
+            import greet: func() -> string;
+
+            /// Log a message to the host.
+            import log: func(msg: string);
+
+            import my-custom-host: interface {
+                tick: func();
+            }
+        }
+    "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_2_world_exports.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_2_world_exports.rs
new file mode 100644
index 000000000..2ee5181da
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_2_world_exports.rs
@@ -0,0 +1,18 @@
+bindgen!({
+    inline: r#"
+        package my:project;
+
+        interface host {
+            gen-random-integer: func() -> u32;
+            sha256: func(bytes: list<u8>) -> string;
+        }
+
+        world hello-world {
+            import host;
+
+            export demo: interface {
+                run: func();
+            }
+        }
+    "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_3_interface_imports.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_3_interface_imports.rs
new file mode 100644
index 000000000..de899279b
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_3_interface_imports.rs
@@ -0,0 +1,20 @@
+bindgen!({
+    inline: r#"
+        package example:interface-imports;
+
+        interface logging {
+            enum level {
+                debug,
+                info,
+                warn,
+                error,
+            }
+
+            log: func(level: level, msg: string);
+        }
+
+        world with-imports {
+            import logging;
+        }
+    "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_4_imported_resources.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_4_imported_resources.rs
new file mode 100644
index 000000000..5540c19ba
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_4_imported_resources.rs
@@ -0,0 +1,45 @@
+bindgen!({
+    inline: r#"
+        package example:imported-resources;
+
+        interface logging {
+            enum level {
+                debug,
+                info,
+                warn,
+                error,
+            }
+
+            resource logger {
+                constructor(max-level: level);
+
+                get-max-level: func() -> level;
+                set-max-level: func(level: level);
+
+                log: func(level: level, msg: string);
+            }
+        }
+
+        world import-some-resources {
+            import logging;
+        }
+    "#,
+
+    with: {
+        // Specify that our host resource is going to point to the `MyLogger`
+        // which is defined just below this macro.
+        "example:imported-resources/logging/logger": MyLogger,
+    },
+
+    // Interactions with `ResourceTable` can possibly trap so enable the ability
+    // to return traps from generated functions.
+    trappable_imports: true,
+});
+
+/// A sample host-defined type which contains arbitrary host-defined data.
+///
+/// In this case this is relatively simple but there's no restrictions on what
+/// this type can hold other than that it must be `'static + Send`.
+pub struct MyLogger {
+    pub max_level: example::imported_resources::logging::Level,
+}
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_5_all_world_export_kinds.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_5_all_world_export_kinds.rs
new file mode 100644
index 000000000..d138f17e8
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_5_all_world_export_kinds.rs
@@ -0,0 +1,29 @@
+bindgen!({
+    inline: r#"
+        package example:world-exports;
+
+        world with-exports {
+            import log: func(msg: string);
+
+            export run: func();
+
+            /// An example of exporting an interface inline and naming it
+            /// directly.
+            export environment: interface {
+                get: func(var: string) -> string;
+                set: func(var: string, val: string);
+            }
+
+            /// An example of exporting an interface.
+            export units;
+        }
+
+        interface units {
+            /// Renders the number of bytes as a human readable string.
+            bytes-to-string: func(bytes: u64) -> string;
+
+            /// Renders the provided duration as a human readable string.
+            duration-to-string: func(seconds: u64, ns: u32) -> string;
+        }
+    "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/_6_exported_resources.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/_6_exported_resources.rs
new file mode 100644
index 000000000..576450cc6
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/_6_exported_resources.rs
@@ -0,0 +1,26 @@
+bindgen!({
+    inline: r#"
+        package example:exported-resources;
+
+        world export-some-resources {
+            export logging;
+        }
+
+        interface logging {
+            enum level {
+                debug,
+                info,
+                warn,
+                error,
+            }
+            resource logger {
+                constructor(max-level: level);
+
+                get-max-level: func() -> level;
+                set-max-level: func(level: level);
+
+                log: func(level: level, msg: string);
+            }
+        }
+    "#,
+});
diff --git a/crates/wasmtime/src/runtime/component/bindgen_examples/mod.rs b/crates/wasmtime/src/runtime/component/bindgen_examples/mod.rs
new file mode 100644
index 000000000..aac9ab36b
--- /dev/null
+++ b/crates/wasmtime/src/runtime/component/bindgen_examples/mod.rs
@@ -0,0 +1,489 @@
+//! Examples of output of the [`bindgen!`] macro.
+//!
+//! This module is only included in docs.rs documentation and is not present in
+//! the actual crate when compiling from crates.io. The purpose of this module
+//! is to showcase what the output of the [`bindgen!`] macro looks like and some
+//! examples of how to use it.
+//!
+//! If you're confused or lost in [`bindgen!`] feel free to [open an issue]
+//! with a description of your issue and it can hopefully lead to a new example
+//! being added here for others to use as reference.
+//!
+//! ## Including `*.wit` files in your project
+//!
+//! Note that most of the examples in this module will use the `inline` key of
+//! the [`bindgen!`] macro. This is done as it's easy to show the example and
+//! WIT all in one self-contained snippet of Rust code. Typically though a
+//! project will have a `wit` directory next to `Cargo.toml` which contains WIT
+//! files.
+//!
+//! The general layout of a `wit` directory is that:
+//!
+//! * All `*.wit` files at `wit/*.wit` are parsed and included in the same
+//!   package.
+//! * If the `wit/deps` folder is present then it can either contain:
+//!   * Subdirectories with a package-per-directory. For example
+//!     `wit/deps/wasi-http` and `wit/deps/wasi-cli`.
+//!   * WIT files that are a single-file rendering of a package, for example
+//!     `wit/deps/wasi-http.wit`
+//!   * WIT packages encoded as WebAssembly binaries for a package, for example
+//!     `wit/deps/wasi-http.wasm`
+//!
+//! This means that at this time you'll need to copy around `*.wit` files or
+//! WIT packages encoded as `*.wasm` and check them in to your project's `wit`
+//! directory. The hope is that in the future it will be easier to manage these
+//! files with registry tooling and they won't have to be copied manually.
+//! For reference documentation on the layout of the `wit` directory see
+//! [`wit_parser::Resolve::push_dir`].
+//!
+//! [`bindgen!`]: crate::component::bindgen
+//! [`wit_parser::Resolve::push_dir`]: https://docs.rs/wit-parser/latest/wit_parser/struct.Resolve.html#method.push_dir
+//! [open an issue]: https://github.com/bytecodealliance/wasmtime/issues/new
+
+#![allow(missing_docs)]
+
+// This "hack" will shadow the `bindgen` macro in general and be inherited to
+// following modules by default. This enables documenting sources as-is while
+// additionally customizing them to working within the wasmtime crate itself by
+// injecting a configuration option to change how the `wasmtime` crate is
+// referenced in the generated output.
+//
+// Note that this has an additional "hack" such that when docs.rs is documenting
+// this crate (or CI) then `include_generated_code_from_file` is unconditionally
+// turned on. This makes `[source]` links on documentation show the actual
+// generated code rather than just the `bindgen!` macro invocation, which can be
+// helpful when exploring code.
+#[cfg(docsrs)]
+macro_rules! bindgen {
+    ({$($t:tt)*}) => (crate::component::bindgen!({
+        $($t)*
+        wasmtime_crate: crate,
+        include_generated_code_from_file: true,
+    }););
+}
+#[cfg(not(docsrs))]
+macro_rules! bindgen {
+    ({$($t:tt)*}) => (crate::component::bindgen!({
+        $($t)*
+        wasmtime_crate: crate,
+    }););
+}
+
+/// A "hello world" style example.
+///
+/// This example loads a component which has access to a single host function.
+/// The exported function is called on an instantiation of the component.
+///
+/// ```rust
+/// use wasmtime::component::*;
+/// use wasmtime::{Engine, Store};
+///
+#[doc = include_str!("./_0_hello_world.rs")]
+///
+/// struct MyState {
+///     name: String,
+/// }
+///
+/// // Imports into the world, like the `name` import for this world, are
+/// // satisfied through traits.
+/// impl HelloWorldImports for MyState {
+///     fn name(&mut self) -> String {
+///         self.name.clone()
+///     }
+/// }
+///
+/// fn main() -> wasmtime::Result<()> {
+/// #   if true { return Ok(()) }
+///     // Compile the `Component` that is being run for the application.
+///     let engine = Engine::default();
+///     let component = Component::from_file(&engine, "./your-component.wasm")?;
+///
+///     // Instantiation of bindings always happens through a `Linker`.
+///     // Configuration of the linker is done through a generated `add_to_linker`
+///     // method on the bindings structure.
+///     //
+///     // Note that the closure provided here is a projection from `T` in
+///     // `Store<T>` to `&mut U` where `U` implements the `HelloWorldImports`
+///     // trait. In this case the `T`, `MyState`, is stored directly in the
+///     // structure so no projection is necessary here.
+///     let mut linker = Linker::new(&engine);
+///     HelloWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
+///
+///     // As with the core wasm API of Wasmtime instantiation occurs within a
+///     // `Store`. The bindings structure contains an `instantiate` method which
+///     // takes the store, component, and linker. This returns the `bindings`
+///     // structure which is an instance of `HelloWorld` and supports typed access
+///     // to the exports of the component.
+///     let mut store = Store::new(
+///         &engine,
+///         MyState {
+///             name: "me".to_string(),
+///         },
+///     );
+///     let (bindings, _) = HelloWorld::instantiate(&mut store, &component, &linker)?;
+///
+///     // Here our `greet` function doesn't take any parameters for the component,
+///     // but in the Wasmtime embedding API the first argument is always a `Store`.
+///     bindings.call_greet(&mut store)?;
+///     Ok(())
+/// }
+/// ```
+pub mod _0_hello_world;
+
+/// An example of generated bindings for top-level imported functions and
+/// interfaces into a world.
+///
+/// The code used to generate this module is:
+///
+/// ```rust
+/// use wasmtime::component::*;
+/// use wasmtime::{Engine, Store};
+///
+#[doc = include_str!("./_1_world_imports.rs")]
+///
+/// struct MyState {
+///     // ...
+/// }
+///
+/// impl my_custom_host::Host for MyState {
+///     fn tick(&mut self) {
+///         todo!()
+///     }
+/// }
+///
+/// impl MyWorldImports for MyState {
+///     fn greet(&mut self) -> String {
+///         todo!()
+///     }
+///
+///     fn log(&mut self, msg: String) {
+///         println!("{msg}");
+///     }
+/// }
+///
+/// fn main() -> wasmtime::Result<()> {
+/// #   if true { return Ok(()) }
+///     let engine = Engine::default();
+///     let component = Component::from_file(&engine, "./your-component.wasm")?;
+///
+///     let mut linker = Linker::new(&engine);
+///     MyWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
+///
+///     let mut store = Store::new(
+///         &engine,
+///         MyState { /* ... */ },
+///     );
+///     let (bindings, _) = MyWorld::instantiate(&mut store, &component, &linker)?;
+///
+///     // ... NB: this world has no exports just yet so not much can be done
+///     // with `bindings`.
+///
+///     Ok(())
+/// }
+/// ```
+pub mod _1_world_imports;
+
+/// An example of generated bindings for top-level exported functions for a
+/// world.
+///
+/// Some notable generated items here are:
+///
+/// * [`my::project::host::Host`](_2_world_exports::my::project::host::Host) -
+///   the generated trait for the `interface host` import.
+/// * [`exports::demo::Guest`](_2_world_exports::exports::demo::Guest) -
+///   the generated structured used to invoke exports on the returned instance.
+/// * [`HelloWorld`](_2_world_exports::HelloWorld) -
+///   the overall generated structure representing our `world`.
+///
+/// ```rust
+/// use wasmtime::component::*;
+/// use wasmtime::{Engine, Store};
+///
+#[doc = include_str!("./_2_world_exports.rs")]
+///
+/// struct MyState {
+///     // ...
+/// }
+///
+/// // Note that the trait here is per-interface and within a submodule now.
+/// impl my::project::host::Host for MyState {
+///     fn gen_random_integer(&mut self) -> u32 {
+/// #       panic!();
+/// #       #[cfg(FALSE)]
+///         rand::thread_rng().gen()
+///     }
+///
+///     fn sha256(&mut self, bytes: Vec<u8>) -> String {
+///         // ...
+/// #       panic!()
+///     }
+/// }
+///
+/// fn main() -> wasmtime::Result<()> {
+/// #   if true { return Ok(()) }
+///     let engine = Engine::default();
+///     let component = Component::from_file(&engine, "./your-component.wasm")?;
+///
+///     let mut linker = Linker::new(&engine);
+///     HelloWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
+///
+///     let mut store = Store::new(
+///         &engine,
+///         MyState { /* ... */ },
+///     );
+///     let (bindings, _) = HelloWorld::instantiate(&mut store, &component, &linker)?;
+///
+///     // Note that the `demo` method returns a `&exports::Demo::Guest`
+///     // through which we can run the methods on that interface.
+///     bindings.demo().call_run(&mut store)?;
+///     Ok(())
+/// }
+/// ```
+pub mod _2_world_exports;
+
+/// Example of generating bindings for imported interfaces in a world.
+///
+/// Notable parts of this example are:
+///
+/// * Imported interfaces use the Rust module system to encapsulate themselves.
+///   The interface imported here is `example:interface-imports/logging` so the
+///   generated trait and types are located in
+///   [`example::interface_imports::logging`][module].
+/// * Types in the `logging` interface are generated in the `logging` module,
+///   for example [`Level`].
+/// * Generated types have implementations of [`ComponentType`], [`Lift`], and
+///   [`Lower`] derived.
+/// * The generated trait that host's must implement is always called [`Host`]
+///   and is located in the generated module.
+///
+/// [module]: _3_interface_imports::example::interface_imports::logging
+/// [`Level`]: _3_interface_imports::example::interface_imports::logging::Level
+/// [`Host`]: _3_interface_imports::example::interface_imports::logging::Host
+/// [`ComponentType`]: crate::component::ComponentType
+/// [`Lift`]: crate::component::Lift
+/// [`Lower`]: crate::component::Lower
+///
+/// ```rust
+/// use wasmtime::component::bindgen;
+/// use example::interface_imports::logging::Level;
+///
+#[doc = include_str!("./_3_interface_imports.rs")]
+///
+/// struct MyState {
+///     // ...
+/// }
+///
+/// impl example::interface_imports::logging::Host for MyState {
+///     fn log(&mut self, level: Level, msg: String) {
+///         // ...
+///     }
+/// }
+/// ```
+pub mod _3_interface_imports;
+
+/// Example of generating bindings for imported resources in a world.
+///
+/// Notable parts of this example are:
+///
+/// * Imported resources from the host are represented as traits, in this case
+///   [`HostLogger`].
+/// * The per-interface [`Host`] trait still exists but has a supertrait of
+///   [`HostLogger`].
+/// * Resources are represented as [`Resource<T>`] and it's recommended to
+///   specify a `with` key to indicate what host type you'd like to use for
+///   each resource.
+/// * A [`ResourceTable`] can be used to manage resources when working with
+///   guests.
+///
+/// [`Host`]: _4_imported_resources::example::imported_resources::logging::Host
+/// [`HostLogger`]: _4_imported_resources::example::imported_resources::logging::HostLogger
+/// [`Resource<T>`]: crate::component::Resource
+/// [`ResourceTable`]: crate::component::ResourceTable
+///
+/// ```rust
+/// use wasmtime::Result;
+/// use wasmtime::component::{bindgen, ResourceTable, Resource};
+/// use example::imported_resources::logging::{Level, Host, HostLogger};
+///
+#[doc = include_str!("./_4_imported_resources.rs")]
+///
+/// #[derive(Default)]
+/// struct MyState {
+///     // Manages the mapping of `MyLogger` structures to `Resource<MyLogger>`.
+///     table: ResourceTable,
+/// }
+///
+/// // There are no free-functions on `interface logging`, so this is an empty
+/// // impl.
+/// impl Host for MyState {}
+///
+/// // This separate `HostLogger` trait serves to act as a namespace for just
+/// // the `logger`-related resource methods.
+/// impl HostLogger for MyState {
+///     // A `constructor` in WIT maps to a `new` function in Rust.
+///     fn new(&mut self, max_level: Level) -> Result<Resource<MyLogger>> {
+///         let id = self.table.push(MyLogger { max_level })?;
+///         Ok(id)
+///     }
+///
+///     fn get_max_level(&mut self, logger: Resource<MyLogger>) -> Result<Level> {
+///         debug_assert!(!logger.owned());
+///         let logger = self.table.get(&logger)?;
+///         Ok(logger.max_level)
+///     }
+///
+///     fn set_max_level(&mut self, logger: Resource<MyLogger>, level: Level) -> Result<()> {
+///         debug_assert!(!logger.owned());
+///         let logger = self.table.get_mut(&logger)?;
+///         logger.max_level = level;
+///         Ok(())
+///     }
+///
+///     fn log(&mut self, logger: Resource<MyLogger>, level: Level, msg: String) -> Result<()> {
+///         debug_assert!(!logger.owned());
+///         let logger = self.table.get_mut(&logger)?;
+///         if (level as u32) <= (logger.max_level as u32) {
+///             println!("{msg}");
+///         }
+///         Ok(())
+///     }
+///
+///     fn drop(&mut self, logger: Resource<MyLogger>) -> Result<()> {
+///         debug_assert!(logger.owned());
+///         let _logger: MyLogger = self.table.delete(logger)?;
+///         // ... custom destruction logic here if necessary, otherwise
+///         // a `Drop for MyLogger` would also work.
+///         Ok(())
+///     }
+/// }
+///
+/// # fn main() {}
+/// ```
+pub mod _4_imported_resources;
+
+/// Example of all kinds of structures of exports from a world.
+///
+/// * Top-level functions in a `world` are exported directly on the generated
+///   structure such as [`call_run`].
+/// * All other exports are otherwise scoped with generated traits/types
+///   in a top level [`exports`] module.
+/// * Exported named interfaces are located at the root of the [`exports`]
+///   module, such as [`exports::environment`].
+/// * Interfaces are all bound with a structure called `Guest` which has typed
+///   functions for each export that can be called. For example
+///   [`exports::environment::Guest`][guest1] and
+///   [`exports::example::world_exports::units::Guest`][guest2].
+/// * Interfaces exported by their id are modeled with multiple namespacing
+///   modules, such as [`exports::example::world_exports::units`][units].
+///
+/// [`call_run`]: _5_all_world_export_kinds::WithExports::call_run
+/// [`exports`]: _5_all_world_export_kinds::exports
+/// [`exports::environment`]: _5_all_world_export_kinds::exports::environment
+/// [guest1]: _5_all_world_export_kinds::exports::environment::Guest
+/// [guest2]: _5_all_world_export_kinds::exports::example::world_exports::units::Guest
+/// [units]: _5_all_world_export_kinds::exports::example::world_exports::units
+///
+/// ```rust
+/// use wasmtime::{Result, Engine, Store};
+/// use wasmtime::component::{bindgen, Component, Linker};
+///
+#[doc = include_str!("./_5_all_world_export_kinds.rs")]
+///
+/// struct MyState;
+///
+/// impl WithExportsImports for MyState {
+///     fn log(&mut self, msg: String) {
+///         println!("{msg}");
+///     }
+/// }
+///
+/// fn main() -> Result<()> {
+/// #   if true { return Ok(()) }
+///     let engine = Engine::default();
+///     let component = Component::from_file(&engine, "./your-component.wasm")?;
+///
+///     let mut linker = Linker::new(&engine);
+///     WithExports::add_to_linker(&mut linker, |state: &mut MyState| state)?;
+///
+///     let mut store = Store::new(&engine, MyState);
+///     let (bindings, _) = WithExports::instantiate(&mut store, &component, &linker)?;
+///
+///     // top-level functions are exported directly on `WithExports` and are
+///     // all prefixed with `call_*`.
+///     bindings.call_run(&mut store)?;
+///
+///     // exported named interfaces are named directly after their export name
+///     // and the `&Guest` return value has `call_*` functions on it.
+///     bindings.environment().call_set(&mut store, "key", "value")?;
+///     let value = bindings.environment().call_get(&mut store, "key")?;
+///     assert_eq!(value, "value");
+///
+///     // exported interfaces by id are similar to export-by-name except that
+///     // the exported name is modeled after the full id, not just the name.
+///     let units = bindings.example_world_exports_units();
+///     let bytes = 1 << 30 + 1 << 20;
+///     let s = units.call_bytes_to_string(&mut store, bytes)?;
+///     println!("{bytes} = {s}");
+///
+///     let (seconds, ns) = (1 << 20, 12345);
+///     let s = units.call_duration_to_string(&mut store, seconds, ns)?;
+///     println!("{seconds}s + {ns}ns = {s}");
+///     Ok(())
+/// }
+/// ```
+pub mod _5_all_world_export_kinds;
+
+/// Example of a world which exports a resource.
+///
+/// * Guest resources are modeled as [`ResourceAny`]. Note that this type is not
+///   specialized per-resource at this time so care must be taken to not mix
+///   them up.
+/// * Resource-related methods are a projection from a [`Guest`] structure, for
+///   example to [`GuestLogger`] here.
+/// * Resource-related methods all take a [`ResourceAny`] as an argument or
+///   a return value.
+/// * The [`ResourceAny`] must be explicitly dropped.
+///
+/// [`ResourceAny`]: crate::component::ResourceAny
+/// [`Guest`]: _6_exported_resources::exports::example::exported_resources::logging::Guest
+/// [`GuestLogger`]: _6_exported_resources::exports::example::exported_resources::logging::GuestLogger
+///
+/// ```rust
+/// use wasmtime::{Result, Engine, Store};
+/// use wasmtime::component::{bindgen, Component, Linker};
+/// use self::exports::example::exported_resources::logging::Level;
+///
+#[doc = include_str!("./_6_exported_resources.rs")]
+///
+/// struct MyState;
+///
+/// fn main() -> Result<()> {
+/// #   if true { return Ok(()) }
+///     let engine = Engine::default();
+///     let component = Component::from_file(&engine, "./your-component.wasm")?;
+///
+///     let linker = Linker::new(&engine);
+///     // ... this small example has no imports so nothing is added here, but
+///     // if you had imports this is where they'd go.
+///
+///     let mut store = Store::new(&engine, MyState);
+///     let (bindings, _) = ExportSomeResources::instantiate(&mut store, &component, &linker)?;
+///     let guest = bindings.example_exported_resources_logging();
+///     let logger = guest.logger();
+///
+///     // Resource methods are all attached to `logger` and take the
+///     // `ResourceAny` parameter explicitly.
+///     let my_logger = logger.call_constructor(&mut store, Level::Warn)?;
+///     assert_eq!(logger.call_get_max_level(&mut store, my_logger)?, Level::Warn);
+///     logger.call_set_max_level(&mut store, my_logger, Level::Info)?;
+///
+///     logger.call_log(&mut store, my_logger, Level::Debug, "hello!")?;
+///
+///     // The `ResourceAny` type has no destructor but when the host is done
+///     // with it it needs to invoke the guest-level destructor.
+///     my_logger.resource_drop(&mut store)?;
+///
+///     Ok(())
+/// }
+/// ```
+pub mod _6_exported_resources;
diff --git a/crates/wasmtime/src/runtime/component/linker.rs b/crates/wasmtime/src/runtime/component/linker.rs
index 6abe76045..b36785f35 100644
--- a/crates/wasmtime/src/runtime/component/linker.rs
+++ b/crates/wasmtime/src/runtime/component/linker.rs
@@ -649,9 +649,9 @@ impl<T> LinkerInstance<'_, T> {
         ty: ResourceType,
         dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static,
     ) -> Result<()> {
-        let dtor = Arc::new(crate::func::HostFunc::wrap(
+        let dtor = Arc::new(crate::func::HostFunc::wrap_inner(
             &self.engine,
-            move |mut cx: crate::Caller<'_, T>, param: u32| dtor(cx.as_context_mut(), param),
+            move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param),
         ));
         self.insert(name, Definition::Resource(ty, dtor))?;
         Ok(())
diff --git a/crates/wasmtime/src/runtime/component/mod.rs b/crates/wasmtime/src/runtime/component/mod.rs
index feb1d9827..01ad8df32 100644
--- a/crates/wasmtime/src/runtime/component/mod.rs
+++ b/crates/wasmtime/src/runtime/component/mod.rs
@@ -160,198 +160,25 @@ pub(crate) use self::store::ComponentStoreData;
 /// raw [`Instance`] type which must be manually-type-checked and manually have
 /// its imports provided via the [`Linker`] type.
 ///
-/// The most basic usage of this macro is:
+/// # Examples
 ///
-/// ```rust,ignore
-/// wasmtime::component::bindgen!();
-/// ```
-///
-/// This will parse your project's [WIT package] in a `wit` directory adjacent
-/// to your crate's `Cargo.toml`. All of the `*.wit` files in that directory are
-/// parsed and then the single `world` found will be used for bindings.
-///
-/// For example if your project contained:
-///
-/// ```text,ignore
-/// // wit/my-component.wit
-///
-/// package my:project;
-///
-/// world hello-world {
-///     import name: func() -> string;
-///     export greet: func();
-/// }
-/// ```
-///
-/// Then you can interact with the generated bindings like so:
-///
-/// ```rust
-/// use wasmtime::component::*;
-/// use wasmtime::{Config, Engine, Store};
-///
-/// # const _: () = { macro_rules! bindgen { () => () }
-/// bindgen!();
-/// # };
-/// # bindgen!({
-/// #   inline: r#"
-/// #       package my:project;
-/// #       world hello-world {
-/// #           import name: func() -> string;
-/// #           export greet: func();
-/// #       }
-/// #   "#,
-/// # });
-///
-/// struct MyState {
-///     name: String,
-/// }
-///
-/// // Imports into the world, like the `name` import for this world, are
-/// // satisfied through traits.
-/// impl HelloWorldImports for MyState {
-///     fn name(&mut self) -> String {
-///         self.name.clone()
-///     }
-/// }
-///
-/// fn main() -> wasmtime::Result<()> {
-/// #   if true { return Ok(()) }
-///     // Configure an `Engine` and compile the `Component` that is being run for
-///     // the application.
-///     let mut config = Config::new();
-///     config.wasm_component_model(true);
-///     let engine = Engine::new(&config)?;
-///     let component = Component::from_file(&engine, "./your-component.wasm")?;
-///
-///     // Instantiation of bindings always happens through a `Linker`.
-///     // Configuration of the linker is done through a generated `add_to_linker`
-///     // method on the bindings structure.
-///     //
-///     // Note that the closure provided here is a projection from `T` in
-///     // `Store<T>` to `&mut U` where `U` implements the `HelloWorldImports`
-///     // trait. In this case the `T`, `MyState`, is stored directly in the
-///     // structure so no projection is necessary here.
-///     let mut linker = Linker::new(&engine);
-///     HelloWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
-///
-///     // As with the core wasm API of Wasmtime instantiation occurs within a
-///     // `Store`. The bindings structure contains an `instantiate` method which
-///     // takes the store, component, and linker. This returns the `bindings`
-///     // structure which is an instance of `HelloWorld` and supports typed access
-///     // to the exports of the component.
-///     let mut store = Store::new(
-///         &engine,
-///         MyState {
-///             name: "me".to_string(),
-///         },
-///     );
-///     let (bindings, _) = HelloWorld::instantiate(&mut store, &component, &linker)?;
-///
-///     // Here our `greet` function doesn't take any parameters for the component,
-///     // but in the Wasmtime embedding API the first argument is always a `Store`.
-///     bindings.call_greet(&mut store)?;
-///     Ok(())
-/// }
-/// ```
-///
-/// The function signatures within generated traits and on generated exports
-/// match the component-model signatures as specified in the WIT `world` item.
-/// Note that WIT also has support for importing and exports interfaces within
-/// worlds, which can be bound here as well:
-///
-/// For example this WIT input
-///
-/// ```text,ignore
-/// // wit/my-component.wit
-///
-/// package my:project;
-///
-/// interface host {
-///     gen-random-integer: func() -> u32;
-///     sha256: func(bytes: list<u8>) -> string;
-/// }
-///
-/// world hello-world {
-///     import host;
-///
-///     export demo: interface {
-///         run: func();
-///     }
-/// }
-/// ```
-///
-/// Then you can interact with the generated bindings like so:
+/// Examples for this macro can be found in the [`bindgen_examples`] module
+/// documentation. That module has a submodule-per-example which includes the
+/// source code, with WIT, used to generate the structures along with the
+/// generated code itself in documentation.
 ///
-/// ```rust
-/// use wasmtime::component::*;
-/// use wasmtime::{Config, Engine, Store};
-/// use my::project::host::Host;
+/// # Debugging and Exploring
 ///
-/// # const _: () = { macro_rules! bindgen { () => () }
-/// bindgen!();
-/// # };
-/// # bindgen!({
-/// #   inline: r#"
-/// # package my:project;
-/// #
-/// # interface host {
-/// #     gen-random-integer: func() -> u32;
-/// #     sha256: func(bytes: list<u8>) -> string;
-/// # }
-/// #
-/// # world hello-world {
-/// #     import host;
-/// #
-/// #     export demo: interface {
-/// #         run: func();
-/// #     }
-/// # }
-/// #   "#,
-/// # });
-///
-/// struct MyState {
-///     // ...
-/// }
+/// If you need to debug the output of `bindgen!` you can try using the
+/// `WASMTIME_DEBUG_BINDGEN=1` environment variable. This will write the
+/// generated code to a file on disk so rustc can produce better error messages
+/// against the actual generated source instead of the macro invocation itself.
+/// This additionally can enable opening up the generated code in an editor and
+/// exploring it (through an error message).
 ///
-/// // Note that the trait here is per-interface and within a submodule now.
-/// impl Host for MyState {
-///     fn gen_random_integer(&mut self) -> u32 {
-/// #       panic!();
-/// #       #[cfg(FALSE)]
-///         rand::thread_rng().gen()
-///     }
-///
-///     fn sha256(&mut self, bytes: Vec<u8>) -> String {
-///         // ...
-/// #       panic!()
-///     }
-/// }
-///
-/// fn main() -> wasmtime::Result<()> {
-/// #   if true { return Ok(()) }
-///     let mut config = Config::new();
-///     config.wasm_component_model(true);
-///     let engine = Engine::new(&config)?;
-///     let component = Component::from_file(&engine, "./your-component.wasm")?;
-///
-///     let mut linker = Linker::new(&engine);
-///     HelloWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
-///
-///     let mut store = Store::new(
-///         &engine,
-///         MyState { /* ... */ },
-///     );
-///     let (bindings, _) = HelloWorld::instantiate(&mut store, &component, &linker)?;
-///
-///     // Note that the `demo` method returns a `&Demo` through which we can
-///     // run the methods on that interface.
-///     bindings.demo().call_run(&mut store)?;
-///     Ok(())
-/// }
-/// ```
-///
-/// The generated bindings can additionally be explored more fully with `cargo
-/// doc` to see what types and traits and such are generated.
+/// The generated bindings can additionally be explored with `cargo doc` to see
+/// what's generated. It's also recommended to browse the [`bindgen_examples`]
+/// for example generated structures and example generated code.
 ///
 /// # Syntax
 ///
@@ -380,11 +207,22 @@ pub(crate) use self::store::ComponentStoreData;
 /// // Parse the file `foo.wit` as a single-file WIT package with no
 /// // dependencies.
 /// bindgen!("foo" in "foo.wit");
+///
+/// // Specify a suite of options to the bindings generation, documented below
+/// bindgen!({
+///     world: "foo",
+///     path: "other/path/to/wit",
+///     // ...
+/// });
 /// ```
 ///
-/// A more configured version of invoking this macro looks like:
+/// # Options Reference
+///
+/// This is an example listing of all options that this macro supports along
+/// with documentation for each option and example syntax for each option.
 ///
-/// ```rust,ignore
+/// ```rust
+/// # macro_rules! bindgen { ($($t:tt)*) => () }
 /// bindgen!({
 ///     world: "foo", // not needed if `path` has one `world`
 ///
@@ -534,6 +372,27 @@ pub(crate) use self::store::ComponentStoreData;
 ///     // but if synchronous bindings depend on asynchronous bindings using
 ///     // the `with` key then this may be required.
 ///     require_store_data_send: false,
+///
+///     // If the `wasmtime` crate is depended on at a nonstandard location
+///     // or is renamed then this is the path to the root of the `wasmtime`
+///     // crate. Much of the generated code needs to refer to `wasmtime` so
+///     // this should be used if the `wasmtime` name is not wasmtime itself.
+///     //
+///     // By default this is `wasmtime`.
+///     wasmtime_crate: path::to::wasmtime,
+///
+///     // This is an in-source alternative to using `WASMTIME_DEBUG_BINDGEN`.
+///     //
+///     // Note that if this option is specified then the compiler will always
+///     // recompile your bindings. Cargo records the start time of when rustc
+///     // is spawned by this will write a file during compilation. To Cargo
+///     // that looks like a file was modified after `rustc` was spawned,
+///     // so Cargo will always think your project is "dirty" and thus always
+///     // recompile it. Recompiling will then overwrite the file again,
+///     // starting the cycle anew. This is only recommended for debugging.
+///     //
+///     // This option defaults to false.
+///     include_generated_code_from_file: false,
 /// });
 /// ```
 pub use wasmtime_component_macro::bindgen;
@@ -793,3 +652,6 @@ pub use wasmtime_component_macro::Lower;
 /// [`BitXorAssign`]: std::ops::BitXorAssign
 /// [`Not`]: std::ops::Not
 pub use wasmtime_component_macro::flags;
+
+#[cfg(any(docsrs, test, doctest))]
+pub mod bindgen_examples;
diff --git a/crates/wasmtime/src/runtime/debug.rs b/crates/wasmtime/src/runtime/debug.rs
index 1585c0674..bb98b48bd 100644
--- a/crates/wasmtime/src/runtime/debug.rs
+++ b/crates/wasmtime/src/runtime/debug.rs
@@ -127,7 +127,7 @@ fn convert_object_elf_to_loadable_file<E: Endian>(
     let text_range = match sections.section_by_name(e, b".text") {
         Some((i, text)) => {
             let range = text.file_range(e);
-            let off = header.e_shoff.get(e) as usize + i * header.e_shentsize.get(e) as usize;
+            let off = header.e_shoff.get(e) as usize + i.0 * header.e_shentsize.get(e) as usize;
 
             let section: &mut SectionHeader64<E> =
                 object::from_bytes_mut(&mut bytes[off..]).unwrap().0;
diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs
index 19e0b90b1..54a8975e8 100644
--- a/crates/wasmtime/src/runtime/func.rs
+++ b/crates/wasmtime/src/runtime/func.rs
@@ -361,38 +361,6 @@ macro_rules! for_each_function_signature {
 mod typed;
 pub use typed::*;
 
-macro_rules! generate_wrap_async_func {
-    ($num:tt $($args:ident)*) => (paste::paste!{
-        /// Same as [`Func::wrap`], except the closure asynchronously produces
-        /// its result. For more information see the [`Func`] documentation.
-        ///
-        /// # Panics
-        ///
-        /// This function will panic if called with a non-asynchronous store.
-        #[allow(non_snake_case)]
-        #[cfg(feature = "async")]
-        pub fn [<wrap $num _async>]<T, $($args,)* R>(
-            store: impl AsContextMut<Data = T>,
-            func: impl for<'a> Fn(Caller<'a, T>, $($args),*) -> Box<dyn Future<Output = R> + Send + 'a> + Send + Sync + 'static,
-        ) -> Func
-        where
-            $($args: WasmTy,)*
-            R: WasmRet,
-        {
-            assert!(store.as_context().async_support(), concat!("cannot use `wrap", $num, "_async` without enabling async support on the config"));
-            Func::wrap(store, move |mut caller: Caller<'_, T>, $($args: $args),*| {
-                let async_cx = caller.store.as_context_mut().0.async_cx().expect("Attempt to start async function on dying fiber");
-                let mut future = Pin::from(func(caller, $($args),*));
-
-                match unsafe { async_cx.block_on(future.as_mut()) } {
-                    Ok(ret) => ret.into_fallible(),
-                    Err(e) => R::fallible_from_error(e),
-                }
-            })
-        }
-    })
-}
-
 impl Func {
     /// Creates a new `Func` with the given arguments, typically to create a
     /// host-defined function to pass as an import to a module.
@@ -860,7 +828,57 @@ impl Func {
         }
     }
 
-    for_each_function_signature!(generate_wrap_async_func);
+    fn wrap_inner<F, T, Params, Results>(mut store: impl AsContextMut<Data = T>, func: F) -> Func
+    where
+        F: Fn(Caller<'_, T>, Params) -> Results + Send + Sync + 'static,
+        Params: WasmTyList,
+        Results: WasmRet,
+    {
+        let store = store.as_context_mut().0;
+        // part of this unsafety is about matching the `T` to a `Store<T>`,
+        // which is done through the `AsContextMut` bound above.
+        unsafe {
+            let host = HostFunc::wrap_inner(store.engine(), func);
+            host.into_func(store)
+        }
+    }
+
+    /// Same as [`Func::wrap`], except the closure asynchronously produces the
+    /// result and the arguments are passed within a tuple. For more information
+    /// see the [`Func`] documentation.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if called with a non-asynchronous store.
+    #[cfg(feature = "async")]
+    pub fn wrap_async<T, F, P, R>(store: impl AsContextMut<Data = T>, func: F) -> Func
+    where
+        F: for<'a> Fn(Caller<'a, T>, P) -> Box<dyn Future<Output = R> + Send + 'a>
+            + Send
+            + Sync
+            + 'static,
+        P: WasmTyList,
+        R: WasmRet,
+    {
+        assert!(
+            store.as_context().async_support(),
+            concat!("cannot use `wrap_async` without enabling async support on the config")
+        );
+        Func::wrap_inner(store, move |mut caller: Caller<'_, T>, args| {
+            let async_cx = caller
+                .store
+                .as_context_mut()
+                .0
+                .async_cx()
+                .expect("Attempt to start async function on dying fiber");
+            let mut future = Pin::from(func(caller, args));
+
+            match unsafe { async_cx.block_on(future.as_mut()) } {
+                Ok(ret) => ret.into_fallible(),
+                Err(e) => R::fallible_from_error(e),
+            }
+        })
+    }
 
     /// Returns the underlying wasm type that this `Func` has.
     ///
@@ -1832,6 +1850,122 @@ pub trait IntoFunc<T, Params, Results>: Send + Sync + 'static {
     fn into_func(self, engine: &Engine) -> HostContext;
 }
 
+macro_rules! impl_into_func {
+    ($num:tt $arg:ident) => {
+        // Implement for functions without a leading `&Caller` parameter,
+        // delegating to the implementation below which does have the leading
+        // `Caller` parameter.
+        #[allow(non_snake_case)]
+        impl<T, F, $arg, R> IntoFunc<T, $arg, R> for F
+        where
+            F: Fn($arg) -> R + Send + Sync + 'static,
+            $arg: WasmTy,
+            R: WasmRet,
+        {
+            fn into_func(self, engine: &Engine) -> HostContext {
+                let f = move |_: Caller<'_, T>, $arg: $arg| {
+                    self($arg)
+                };
+
+                f.into_func(engine)
+            }
+        }
+
+        #[allow(non_snake_case)]
+        impl<T, F, $arg, R> IntoFunc<T, (Caller<'_, T>, $arg), R> for F
+        where
+            F: Fn(Caller<'_, T>, $arg) -> R + Send + Sync + 'static,
+            $arg: WasmTy,
+            R: WasmRet,
+        {
+            fn into_func(self, engine: &Engine) -> HostContext {
+                HostContext::from_closure(engine, move |caller: Caller<'_, T>, ($arg,)| {
+                    self(caller, $arg)
+                })
+            }
+        }
+    };
+    ($num:tt $($args:ident)*) => {
+        // Implement for functions without a leading `&Caller` parameter,
+        // delegating to the implementation below which does have the leading
+        // `Caller` parameter.
+        #[allow(non_snake_case)]
+        impl<T, F, $($args,)* R> IntoFunc<T, ($($args,)*), R> for F
+        where
+            F: Fn($($args),*) -> R + Send + Sync + 'static,
+            $($args: WasmTy,)*
+            R: WasmRet,
+        {
+            fn into_func(self, engine: &Engine) -> HostContext {
+                let f = move |_: Caller<'_, T>, $($args:$args),*| {
+                    self($($args),*)
+                };
+
+                f.into_func(engine)
+            }
+        }
+
+        #[allow(non_snake_case)]
+        impl<T, F, $($args,)* R> IntoFunc<T, (Caller<'_, T>, $($args,)*), R> for F
+        where
+            F: Fn(Caller<'_, T>, $($args),*) -> R + Send + Sync + 'static,
+            $($args: WasmTy,)*
+            R: WasmRet,
+        {
+            fn into_func(self, engine: &Engine) -> HostContext {
+                HostContext::from_closure(engine, move |caller: Caller<'_, T>, ( $( $args ),* )| {
+                    self(caller, $( $args ),* )
+                })
+            }
+        }
+    }
+}
+
+for_each_function_signature!(impl_into_func);
+
+/// Trait implemented for various tuples made up of types which implement
+/// [`WasmTy`] that can be passed to [`Func::wrap_inner`] and
+/// [`HostContext::from_closure`].
+pub unsafe trait WasmTyList {
+    /// Get the value type that each Type in the list represents.
+    fn valtypes() -> impl Iterator<Item = ValType>;
+
+    // Load a version of `Self` from the `values` provided.
+    //
+    // # Safety
+    //
+    // This function is unsafe as it's up to the caller to ensure that `values` are
+    // valid for this given type.
+    #[doc(hidden)]
+    unsafe fn load(store: &mut AutoAssertNoGc<'_>, values: &mut [MaybeUninit<ValRaw>]) -> Self;
+}
+
+macro_rules! impl_wasm_ty_list {
+    ($num:tt $($args:ident)*) => (paste::paste!{
+        #[allow(non_snake_case)]
+        unsafe impl<$($args),*> WasmTyList for ($($args,)*)
+        where
+            $($args: WasmTy,)*
+        {
+            fn valtypes() -> impl Iterator<Item = ValType> {
+                IntoIterator::into_iter([$($args::valtype(),)*])
+            }
+
+            unsafe fn load(_store: &mut AutoAssertNoGc<'_>, _values: &mut [MaybeUninit<ValRaw>]) -> Self {
+                let mut _cur = 0;
+                ($({
+                    debug_assert!(_cur < _values.len());
+                    let ptr = _values.get_unchecked(_cur).assume_init_ref();
+                    _cur += 1;
+                    $args::load(_store, ptr)
+                },)*)
+            }
+        }
+    });
+}
+
+for_each_function_signature!(impl_wasm_ty_list);
+
 /// A structure representing the caller's context when creating a function
 /// via [`Func::wrap`].
 ///
@@ -2012,155 +2146,6 @@ struct HostFuncState<F> {
     ty: RegisteredType,
 }
 
-macro_rules! impl_into_func {
-    ($num:tt $($args:ident)*) => {
-        // Implement for functions without a leading `&Caller` parameter,
-        // delegating to the implementation below which does have the leading
-        // `Caller` parameter.
-        #[allow(non_snake_case)]
-        impl<T, F, $($args,)* R> IntoFunc<T, ($($args,)*), R> for F
-        where
-            F: Fn($($args),*) -> R + Send + Sync + 'static,
-            $($args: WasmTy,)*
-            R: WasmRet,
-        {
-            fn into_func(self, engine: &Engine) -> HostContext {
-                let f = move |_: Caller<'_, T>, $($args:$args),*| {
-                    self($($args),*)
-                };
-
-                f.into_func(engine)
-            }
-        }
-
-        #[allow(non_snake_case)]
-        impl<T, F, $($args,)* R> IntoFunc<T, (Caller<'_, T>, $($args,)*), R> for F
-        where
-            F: Fn(Caller<'_, T>, $($args),*) -> R + Send + Sync + 'static,
-            $($args: WasmTy,)*
-            R: WasmRet,
-        {
-            fn into_func(self, engine: &Engine) -> HostContext {
-                /// This shim is a regular, non-closure function we can stuff
-                /// inside `VMFuncRef::array_call`.
-                ///
-                /// It reads the actual callee closure out of
-                /// `VMArrayCallHostFuncContext::host_state`, forwards
-                /// arguments to that function, and finally forwards the
-                /// results back out to the caller. It also handles traps and
-                /// panics along the way.
-                unsafe extern "C" fn array_call_trampoline<T, F, $($args,)* R>(
-                    callee_vmctx: *mut VMOpaqueContext,
-                    caller_vmctx: *mut VMOpaqueContext,
-                    args: *mut ValRaw,
-                    args_len: usize
-                )
-                where
-                    F: Fn(Caller<'_, T>, $( $args ),*) -> R + 'static,
-                    $($args: WasmTy,)*
-                    R: WasmRet,
-                {
-                    // Note that this function is intentionally scoped into a
-                    // separate closure. Handling traps and panics will involve
-                    // longjmp-ing from this function which means we won't run
-                    // destructors. As a result anything requiring a destructor
-                    // should be part of this closure, and the long-jmp-ing
-                    // happens after the closure in handling the result.
-                    let run = move |mut caller: Caller<'_, T>| {
-                        let args = core::slice::from_raw_parts_mut(
-                            args.cast::<MaybeUninit<ValRaw>>(),
-                            args_len,
-                        );
-                        let vmctx = VMArrayCallHostFuncContext::from_opaque(callee_vmctx);
-                        let state = (*vmctx).host_state();
-
-                        // Double-check ourselves in debug mode, but we control
-                        // the `Any` here so an unsafe downcast should also
-                        // work.
-                        debug_assert!(state.is::<HostFuncState<F>>());
-                        let state = &*(state as *const _ as *const HostFuncState<F>);
-                        let func = &state.func;
-
-                        let ret = 'ret: {
-                            if let Err(trap) = caller.store.0.call_hook(CallHook::CallingHost) {
-                                break 'ret R::fallible_from_error(trap);
-                            }
-
-                            let mut store = AutoAssertNoGc::new(caller.store.0);
-                            let mut _cur = 0;
-                            $(let $args = {
-                                debug_assert!(_cur < args.len());
-                                let ptr = args.get_unchecked(_cur).assume_init_ref();
-                                _cur += 1;
-                                $args::load(&mut store, ptr)
-                            };)*
-                            let _ = &mut store;
-                            drop(store);
-
-                            let r = func(
-                                caller.sub_caller(),
-                                $( $args, )*
-                            );
-                            if let Err(trap) = caller.store.0.call_hook(CallHook::ReturningFromHost) {
-                                break 'ret R::fallible_from_error(trap);
-                            }
-                            r.into_fallible()
-                        };
-
-                        if !ret.compatible_with_store(caller.store.0) {
-                            bail!("host function attempted to return cross-`Store` value to Wasm")
-                        } else {
-                            let mut store = AutoAssertNoGc::new(&mut **caller.store.0);
-                            let ret = ret.store(&mut store, args)?;
-                            Ok(ret)
-                        }
-                    };
-
-                    // With nothing else on the stack move `run` into this
-                    // closure and then run it as part of `Caller::with`.
-                    let result = crate::runtime::vm::catch_unwind_and_longjmp(move || {
-                        let caller_vmctx = VMContext::from_opaque(caller_vmctx);
-                        Caller::with(caller_vmctx, run)
-                    });
-
-                    match result {
-                        Ok(val) => val,
-                        Err(err) => crate::trap::raise(err),
-                    }
-                }
-
-                let ty = R::func_type(
-                    engine,
-                    None::<ValType>.into_iter()
-                        $(.chain(Some($args::valtype())))*
-                );
-                let type_index = ty.type_index();
-
-                let array_call = array_call_trampoline::<T, F, $($args,)* R>;
-
-                let ctx = unsafe {
-                    VMArrayCallHostFuncContext::new(
-                        VMFuncRef {
-                            array_call,
-                            wasm_call: None,
-                            type_index,
-                            vmctx: ptr::null_mut(),
-                        },
-                        Box::new(HostFuncState {
-                            func: self,
-                            ty: ty.into_registered_type(),
-                        }),
-                    )
-                };
-
-                ctx.into()
-            }
-        }
-    }
-}
-
-for_each_function_signature!(impl_into_func);
-
 #[doc(hidden)]
 pub enum HostContext {
     Array(StoreBox<VMArrayCallHostFuncContext>),
@@ -2172,6 +2157,105 @@ impl From<StoreBox<VMArrayCallHostFuncContext>> for HostContext {
     }
 }
 
+impl HostContext {
+    fn from_closure<F, T, P, R>(engine: &Engine, func: F) -> Self
+    where
+        F: Fn(Caller<'_, T>, P) -> R + Send + Sync + 'static,
+        P: WasmTyList,
+        R: WasmRet,
+    {
+        let ty = R::func_type(engine, None::<ValType>.into_iter().chain(P::valtypes()));
+        let type_index = ty.type_index();
+
+        let array_call = Self::array_call_trampoline::<T, F, P, R>;
+
+        let ctx = unsafe {
+            VMArrayCallHostFuncContext::new(
+                VMFuncRef {
+                    array_call,
+                    wasm_call: None,
+                    type_index,
+                    vmctx: ptr::null_mut(),
+                },
+                Box::new(HostFuncState {
+                    func,
+                    ty: ty.into_registered_type(),
+                }),
+            )
+        };
+
+        ctx.into()
+    }
+
+    unsafe extern "C" fn array_call_trampoline<T, F, P, R>(
+        callee_vmctx: *mut VMOpaqueContext,
+        caller_vmctx: *mut VMOpaqueContext,
+        args: *mut ValRaw,
+        args_len: usize,
+    ) where
+        F: Fn(Caller<'_, T>, P) -> R + 'static,
+        P: WasmTyList,
+        R: WasmRet,
+    {
+        // Note that this function is intentionally scoped into a
+        // separate closure. Handling traps and panics will involve
+        // longjmp-ing from this function which means we won't run
+        // destructors. As a result anything requiring a destructor
+        // should be part of this closure, and the long-jmp-ing
+        // happens after the closure in handling the result.
+        let run = move |mut caller: Caller<'_, T>| {
+            let args =
+                core::slice::from_raw_parts_mut(args.cast::<MaybeUninit<ValRaw>>(), args_len);
+            let vmctx = VMArrayCallHostFuncContext::from_opaque(callee_vmctx);
+            let state = (*vmctx).host_state();
+
+            // Double-check ourselves in debug mode, but we control
+            // the `Any` here so an unsafe downcast should also
+            // work.
+            debug_assert!(state.is::<HostFuncState<F>>());
+            let state = &*(state as *const _ as *const HostFuncState<F>);
+            let func = &state.func;
+
+            let ret = 'ret: {
+                if let Err(trap) = caller.store.0.call_hook(CallHook::CallingHost) {
+                    break 'ret R::fallible_from_error(trap);
+                }
+
+                let mut store = AutoAssertNoGc::new(caller.store.0);
+                let params = P::load(&mut store, args);
+                let _ = &mut store;
+                drop(store);
+
+                let r = func(caller.sub_caller(), params);
+                if let Err(trap) = caller.store.0.call_hook(CallHook::ReturningFromHost) {
+                    break 'ret R::fallible_from_error(trap);
+                }
+                r.into_fallible()
+            };
+
+            if !ret.compatible_with_store(caller.store.0) {
+                bail!("host function attempted to return cross-`Store` value to Wasm")
+            } else {
+                let mut store = AutoAssertNoGc::new(&mut **caller.store.0);
+                let ret = ret.store(&mut store, args)?;
+                Ok(ret)
+            }
+        };
+
+        // With nothing else on the stack move `run` into this
+        // closure and then run it as part of `Caller::with`.
+        let result = crate::runtime::vm::catch_unwind_and_longjmp(move || {
+            let caller_vmctx = VMContext::from_opaque(caller_vmctx);
+            Caller::with(caller_vmctx, run)
+        });
+
+        match result {
+            Ok(val) => val,
+            Err(err) => crate::trap::raise(err),
+        }
+    }
+}
+
 /// Representation of a host-defined function.
 ///
 /// This is used for `Func::new` but also for `Linker`-defined functions. For
@@ -2236,6 +2320,17 @@ impl HostFunc {
         HostFunc::_new(engine, ctx.into())
     }
 
+    /// Analog of [`Func::wrap_inner`]
+    pub fn wrap_inner<F, T, Params, Results>(engine: &Engine, func: F) -> Self
+    where
+        F: Fn(Caller<'_, T>, Params) -> Results + Send + Sync + 'static,
+        Params: WasmTyList,
+        Results: WasmRet,
+    {
+        let ctx = HostContext::from_closure(engine, func);
+        HostFunc::_new(engine, ctx)
+    }
+
     /// Analog of [`Func::wrap`]
     pub fn wrap<T, Params, Results>(
         engine: &Engine,
diff --git a/crates/wasmtime/src/runtime/linker.rs b/crates/wasmtime/src/runtime/linker.rs
index f02c969b8..ed9001d12 100644
--- a/crates/wasmtime/src/runtime/linker.rs
+++ b/crates/wasmtime/src/runtime/linker.rs
@@ -1,10 +1,10 @@
 use crate::func::HostFunc;
 use crate::instance::InstancePre;
-use crate::prelude::*;
 use crate::store::StoreOpaque;
+use crate::{prelude::*, IntoFunc};
 use crate::{
     AsContext, AsContextMut, Caller, Engine, Extern, ExternType, Func, FuncType, ImportType,
-    Instance, IntoFunc, Module, StoreContextMut, Val, ValRaw, ValType,
+    Instance, Module, StoreContextMut, Val, ValRaw, ValType, WasmTyList,
 };
 use alloc::sync::Arc;
 use anyhow::{bail, Context, Result};
@@ -134,44 +134,6 @@ pub(crate) enum DefinitionType {
     Memory(wasmtime_environ::Memory, u64),
 }
 
-macro_rules! generate_wrap_async_func {
-    ($num:tt $($args:ident)*) => (paste::paste!{
-        /// Asynchronous analog of [`Linker::func_wrap`].
-        ///
-        /// For more information also see
-        /// [`Func::wrapN_async`](crate::Func::wrap1_async).
-        #[allow(non_snake_case)]
-        #[cfg(feature = "async")]
-        pub fn [<func_wrap $num _async>]<$($args,)* R>(
-            &mut self,
-            module: &str,
-            name: &str,
-            func: impl for<'a> Fn(Caller<'a, T>, $($args),*) -> Box<dyn Future<Output = R> + Send + 'a> + Send + Sync + 'static,
-        ) -> Result<&mut Self>
-        where
-            $($args: crate::WasmTy,)*
-            R: crate::WasmRet,
-        {
-            assert!(
-                self.engine.config().async_support,
-                concat!(
-                    "cannot use `func_wrap",
-                    $num,
-                    "_async` without enabling async support on the config",
-                ),
-            );
-            self.func_wrap(module, name, move |mut caller: Caller<'_, T>, $($args: $args),*| {
-                let async_cx = caller.store.as_context_mut().0.async_cx().expect("Attempt to start async function on dying fiber");
-                let mut future = Pin::from(func(caller, $($args),*));
-                match unsafe { async_cx.block_on(future.as_mut()) } {
-                    Ok(ret) => ret.into_fallible(),
-                    Err(e) => R::fallible_from_error(e),
-                }
-            })
-        }
-    })
-}
-
 impl<T> Linker<T> {
     /// Creates a new [`Linker`].
     ///
@@ -580,7 +542,44 @@ impl<T> Linker<T> {
         Ok(self)
     }
 
-    for_each_function_signature!(generate_wrap_async_func);
+    /// Asynchronous analog of [`Linker::func_wrap`].
+    #[cfg(feature = "async")]
+    pub fn func_wrap_async<F, Params: WasmTyList, Args: crate::WasmRet>(
+        &mut self,
+        module: &str,
+        name: &str,
+        func: F,
+    ) -> Result<&mut Self>
+    where
+        F: for<'a> Fn(Caller<'a, T>, Params) -> Box<dyn Future<Output = Args> + Send + 'a>
+            + Send
+            + Sync
+            + 'static,
+    {
+        assert!(
+            self.engine.config().async_support,
+            "cannot use `func_wrap_async` without enabling async support on the config",
+        );
+        let func = HostFunc::wrap_inner(
+            &self.engine,
+            move |mut caller: Caller<'_, T>, args: Params| {
+                let async_cx = caller
+                    .store
+                    .as_context_mut()
+                    .0
+                    .async_cx()
+                    .expect("Attempt to start async function on dying fiber");
+                let mut future = Pin::from(func(caller, args));
+                match unsafe { async_cx.block_on(future.as_mut()) } {
+                    Ok(ret) => ret.into_fallible(),
+                    Err(e) => Args::fallible_from_error(e),
+                }
+            },
+        );
+        let key = self.import_key(module, Some(name));
+        self.insert(key, Definition::HostFunc(Arc::new(func)))?;
+        Ok(self)
+    }
 
     /// Convenience wrapper to define an entire [`Instance`] in this linker.
     ///
diff --git a/crates/wiggle/generate/src/wasmtime.rs b/crates/wiggle/generate/src/wasmtime.rs
index 46158a224..e3a8ca729 100644
--- a/crates/wiggle/generate/src/wasmtime.rs
+++ b/crates/wiggle/generate/src/wasmtime.rs
@@ -83,13 +83,15 @@ fn generate_func(
     let arg_names = (0..params.len())
         .map(|i| Ident::new(&format!("arg{}", i), Span::call_site()))
         .collect::<Vec<_>>();
-    let arg_decls = params
+    let arg_tys = params
         .iter()
-        .enumerate()
-        .map(|(i, ty)| {
-            let name = &arg_names[i];
-            let wasm = names::wasm_type(*ty);
-            quote! { #name: #wasm }
+        .map(|ty| names::wasm_type(*ty))
+        .collect::<Vec<_>>();
+    let arg_decls = arg_names
+        .iter()
+        .zip(arg_tys.iter())
+        .map(|(name, ty)| {
+            quote! { #name: #ty }
         })
         .collect::<Vec<_>>();
 
@@ -130,12 +132,12 @@ fn generate_func(
 
     match asyncness {
         Asyncness::Async => {
-            let wrapper = format_ident!("func_wrap{}_async", params.len());
+            let arg_decls = quote! { ( #(#arg_names,)* ) : ( #(#arg_tys,)* ) };
             quote! {
-                linker.#wrapper(
+                linker.func_wrap_async(
                     #module_str,
                     #field_str,
-                    move |mut caller: wiggle::wasmtime_crate::Caller<'_, T> #(, #arg_decls)*| {
+                    move |mut caller: wiggle::wasmtime_crate::Caller<'_, T>, #arg_decls| {
                         Box::new(async move { #body })
                     },
                 )?;
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 7b5c449db..dfe4f9523 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -156,6 +156,9 @@ pub struct Opts {
     /// This is helpful when sync bindings depend on generated functions from
     /// async bindings as is the case with WASI in-tree.
     pub require_store_data_send: bool,
+
+    /// Path to the `wasmtime` crate if it's not the default path.
+    pub wasmtime_crate: Option<String>,
 }
 
 #[derive(Debug, Clone)]
@@ -420,13 +423,14 @@ impl Wasmtime {
                     gen.generate_add_to_linker(*id, &key_name);
 
                     let module = &gen.src[..];
+                    let wt = gen.gen.wasmtime_path();
 
                     format!(
                         "
                             #[allow(clippy::all)]
                             pub mod {snake} {{
                                 #[allow(unused_imports)]
-                                use wasmtime::component::__internal::anyhow;
+                                use {wt}::component::__internal::anyhow;
 
                                 {module}
                             }}
@@ -449,6 +453,7 @@ impl Wasmtime {
     }
 
     fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) {
+        let wt = self.wasmtime_path();
         let mut gen = InterfaceGenerator::new(self, resolve);
         let (field, ty, getter) = match item {
             WorldItem::Function(func) => {
@@ -459,7 +464,7 @@ impl Wasmtime {
                 self.exports.funcs.push(body);
                 (
                     func_field_name(resolve, func),
-                    "wasmtime::component::Func".to_string(),
+                    format!("{wt}::component::Func"),
                     getter,
                 )
             }
@@ -479,7 +484,7 @@ impl Wasmtime {
                 for (_, func) in iface.functions.iter() {
                     uwriteln!(
                         gen.src,
-                        "{}: wasmtime::component::Func,",
+                        "{}: {wt}::component::Func,",
                         func_field_name(resolve, func)
                     );
                 }
@@ -490,8 +495,8 @@ impl Wasmtime {
                     gen.src,
                     "
                         pub fn new(
-                            __exports: &mut wasmtime::component::ExportInstance<'_, '_>,
-                        ) -> wasmtime::Result<{struct_name}> {{
+                            __exports: &mut {wt}::component::ExportInstance<'_, '_>,
+                        ) -> {wt}::Result<{struct_name}> {{
                     "
                 );
                 let mut fields = Vec::new();
@@ -554,7 +559,7 @@ impl Wasmtime {
                         #[allow(clippy::all)]
                         pub mod {snake} {{
                             #[allow(unused_imports)]
-                            use wasmtime::component::__internal::anyhow;
+                            use {wt}::component::__internal::anyhow;
 
                             {module}
                         }}
@@ -610,6 +615,7 @@ impl Wasmtime {
     }
 
     fn build_world_struct(&mut self, resolve: &Resolve, world: WorldId) {
+        let wt = self.wasmtime_path();
         let camel = to_rust_upper_camel_case(&resolve.worlds[world].name);
         uwriteln!(self.src, "pub struct {camel} {{");
         for (name, (ty, _)) in self.exports.fields.iter() {
@@ -624,7 +630,7 @@ impl Wasmtime {
             self.src,
             "
                 #[allow(unused_imports)]
-                use wasmtime::component::__internal::anyhow;
+                use {wt}::component::__internal::anyhow;
             "
         );
 
@@ -643,10 +649,10 @@ impl Wasmtime {
                 /// parameters, wrapping up the result in a structure that
                 /// translates between wasm and the host.
                 pub {async_} fn instantiate{async__}<T {send}>(
-                    mut store: impl wasmtime::AsContextMut<Data = T>,
-                    component: &wasmtime::component::Component,
-                    linker: &wasmtime::component::Linker<T>,
-                ) -> wasmtime::Result<(Self, wasmtime::component::Instance)> {{
+                    mut store: impl {wt}::AsContextMut<Data = T>,
+                    component: &{wt}::component::Component,
+                    linker: &{wt}::component::Linker<T>,
+                ) -> {wt}::Result<(Self, {wt}::component::Instance)> {{
                     let instance = linker.instantiate{async__}(&mut store, component){await_}?;
                     Ok((Self::new(store, &instance)?, instance))
                 }}
@@ -655,9 +661,9 @@ impl Wasmtime {
                 /// parameters, wrapping up the result in a structure that
                 /// translates between wasm and the host.
                 pub {async_} fn instantiate_pre<T {send}>(
-                    mut store: impl wasmtime::AsContextMut<Data = T>,
-                    instance_pre: &wasmtime::component::InstancePre<T>,
-                ) -> wasmtime::Result<(Self, wasmtime::component::Instance)> {{
+                    mut store: impl {wt}::AsContextMut<Data = T>,
+                    instance_pre: &{wt}::component::InstancePre<T>,
+                ) -> {wt}::Result<(Self, {wt}::component::Instance)> {{
                     let instance = instance_pre.instantiate{async__}(&mut store){await_}?;
                     Ok((Self::new(store, &instance)?, instance))
                 }}
@@ -671,9 +677,9 @@ impl Wasmtime {
                 /// returned structure which can be used to interact with
                 /// the wasm module.
                 pub fn new(
-                    mut store: impl wasmtime::AsContextMut,
-                    instance: &wasmtime::component::Instance,
-                ) -> wasmtime::Result<Self> {{
+                    mut store: impl {wt}::AsContextMut,
+                    instance: &{wt}::component::Instance,
+                ) -> {wt}::Result<Self> {{
                     let mut store = store.as_context_mut();
                     let mut exports = instance.exports(&mut store);
                     let mut __exports = exports.root();
@@ -930,6 +936,13 @@ impl Wasmtime {
             }
         }
     }
+
+    fn wasmtime_path(&self) -> String {
+        self.opts
+            .wasmtime_crate
+            .clone()
+            .unwrap_or("wasmtime".to_string())
+    }
 }
 
 impl Wasmtime {
@@ -942,9 +955,10 @@ impl Wasmtime {
             return;
         }
 
+        let wt = self.wasmtime_path();
         let world_camel = to_rust_upper_camel_case(&resolve.worlds[world].name);
         if self.opts.async_.maybe_async() {
-            uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
+            uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]")
         }
         uwrite!(self.src, "pub trait {world_camel}Imports");
         let mut supertraits = vec![];
@@ -992,11 +1006,11 @@ impl Wasmtime {
         // Generate impl WorldImports for &mut WorldImports
         let (async_trait, maybe_send) = if self.opts.async_.maybe_async() {
             (
-                "#[wasmtime::component::__internal::async_trait]\n",
+                format!("#[{wt}::component::__internal::async_trait]\n"),
                 "+ Send",
             )
         } else {
-            ("", "")
+            (String::new(), "")
         };
         if !self.opts.skip_mut_forwarding_impls {
             uwriteln!(
@@ -1064,14 +1078,15 @@ impl Wasmtime {
         } else {
             ""
         };
+        let wt = self.wasmtime_path();
         if has_world_imports_trait {
             uwrite!(
                 self.src,
                 "
                     pub fn add_to_linker_imports_get_host<T>(
-                        linker: &mut wasmtime::component::Linker<T>,
+                        linker: &mut {wt}::component::Linker<T>,
                         host_getter: impl for<'a> {camel}ImportsGetHost<&'a mut T>,
-                    ) -> wasmtime::Result<()>
+                    ) -> {wt}::Result<()>
                         where {data_bounds}
                     {{
                         let mut linker = linker.root();
@@ -1084,9 +1099,9 @@ impl Wasmtime {
                     "
                         linker.resource(
                             \"{name}\",
-                            wasmtime::component::ResourceType::host::<{camel}>(),
-                            move |mut store, rep| -> wasmtime::Result<()> {{
-                                Host{camel}::drop(&mut host_getter(store.data_mut()), wasmtime::component::Resource::new_own(rep))
+                            {wt}::component::ResourceType::host::<{camel}>(),
+                            move |mut store, rep| -> {wt}::Result<()> {{
+                                Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep))
                             }},
                         )?;"
                 );
@@ -1105,9 +1120,9 @@ impl Wasmtime {
                 self.src,
                 "
                     pub fn add_to_linker<T, U>(
-                        linker: &mut wasmtime::component::Linker<T>,
+                        linker: &mut {wt}::component::Linker<T>,
                         get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
-                    ) -> wasmtime::Result<()>
+                    ) -> {wt}::Result<()>
                         where
                             {data_bounds}
                             {host_bounds}
@@ -1260,6 +1275,7 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn type_resource(&mut self, id: TypeId, name: &str, resource: &TypeDef, docs: &Docs) {
         let camel = name.to_upper_camel_case();
+        let wt = self.gen.wasmtime_path();
 
         if self.types_imported() {
             self.rustdoc(docs);
@@ -1286,7 +1302,7 @@ impl<'a> InterfaceGenerator<'a> {
 
             // Generate resource trait
             if self.gen.opts.async_.maybe_async() {
-                uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
+                uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]")
             }
             uwriteln!(self.src, "pub trait Host{camel} {{");
 
@@ -1322,7 +1338,8 @@ impl<'a> InterfaceGenerator<'a> {
 
             uwrite!(
                 self.src,
-                "fn drop(&mut self, rep: wasmtime::component::Resource<{camel}>) -> wasmtime::Result<()>;");
+                "fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()>;"
+            );
 
             uwriteln!(self.src, "}}");
 
@@ -1330,11 +1347,11 @@ impl<'a> InterfaceGenerator<'a> {
             if !self.gen.opts.skip_mut_forwarding_impls {
                 let (async_trait, maybe_send) = if self.gen.opts.async_.maybe_async() {
                     (
-                        "#[wasmtime::component::__internal::async_trait]\n",
+                        format!("#[{wt}::component::__internal::async_trait]\n"),
                         "+ Send",
                     )
                 } else {
-                    ("", "")
+                    (String::new(), "")
                 };
                 uwriteln!(
                     self.src,
@@ -1357,7 +1374,7 @@ impl<'a> InterfaceGenerator<'a> {
                     uwriteln!(self.src, "}}");
                 }
                 uwriteln!(self.src, "
-                    fn drop(&mut self, rep: wasmtime::component::Resource<{camel}>) -> wasmtime::Result<()> {{
+                    fn drop(&mut self, rep: {wt}::component::Resource<{camel}>) -> {wt}::Result<()> {{
                         Host{camel}::drop(*self, rep)
                     }}",
                 );
@@ -1368,7 +1385,7 @@ impl<'a> InterfaceGenerator<'a> {
             uwriteln!(
                 self.src,
                 "
-                    pub type {camel} = wasmtime::component::ResourceAny;
+                    pub type {camel} = {wt}::component::ResourceAny;
 
                     pub struct Guest{camel}<'a> {{
                         funcs: &'a Guest,
@@ -1380,6 +1397,7 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn type_record(&mut self, id: TypeId, _name: &str, record: &Record, docs: &Docs) {
         let info = self.info(id);
+        let wt = self.gen.wasmtime_path();
 
         // We use a BTree set to make sure we don't have any duplicates and we have a stable order
         let additional_derives: BTreeSet<String> = self
@@ -1396,12 +1414,15 @@ impl<'a> InterfaceGenerator<'a> {
 
             let mut derives = additional_derives.clone();
 
-            self.push_str("#[derive(wasmtime::component::ComponentType)]\n");
+            uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
             if lt.is_none() {
-                self.push_str("#[derive(wasmtime::component::Lift)]\n");
+                uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
             }
-            self.push_str("#[derive(wasmtime::component::Lower)]\n");
+            uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
             self.push_str("#[component(record)]\n");
+            if let Some(path) = &self.gen.opts.wasmtime_crate {
+                uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
+            }
 
             if info.is_copy() {
                 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
@@ -1493,8 +1514,9 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
         self.rustdoc(docs);
+        let wt = self.gen.wasmtime_path();
         let rust_name = to_rust_upper_camel_case(name);
-        self.src.push_str("wasmtime::component::flags!(\n");
+        uwriteln!(self.src, "{wt}::component::flags!(\n");
         self.src.push_str(&format!("{rust_name} {{\n"));
         for flag in flags.flags.iter() {
             // TODO wasmtime-component-macro doesn't support docs for flags rn
@@ -1545,14 +1567,15 @@ impl<'a> InterfaceGenerator<'a> {
     // with the Wasmtime-understood size of a type.
     fn assert_type(&mut self, id: TypeId, name: &str) {
         self.push_str("const _: () = {\n");
+        let wt = self.gen.wasmtime_path();
         uwriteln!(
             self.src,
-            "assert!({} == <{name} as wasmtime::component::ComponentType>::SIZE32);",
+            "assert!({} == <{name} as {wt}::component::ComponentType>::SIZE32);",
             self.gen.sizes.size(&Type::Id(id)),
         );
         uwriteln!(
             self.src,
-            "assert!({} == <{name} as wasmtime::component::ComponentType>::ALIGN32);",
+            "assert!({} == <{name} as {wt}::component::ComponentType>::ALIGN32);",
             self.gen.sizes.align(&Type::Id(id)),
         );
         self.push_str("};\n");
@@ -1568,6 +1591,7 @@ impl<'a> InterfaceGenerator<'a> {
         Self: Sized,
     {
         let info = self.info(id);
+        let wt = self.gen.wasmtime_path();
 
         // We use a BTree set to make sure we don't have any duplicates and we have a stable order
         let additional_derives: BTreeSet<String> = self
@@ -1585,12 +1609,15 @@ impl<'a> InterfaceGenerator<'a> {
 
             self.rustdoc(docs);
             let lt = self.lifetime_for(&info, mode);
-            self.push_str("#[derive(wasmtime::component::ComponentType)]\n");
+            uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
             if lt.is_none() {
-                self.push_str("#[derive(wasmtime::component::Lift)]\n");
+                uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
             }
-            self.push_str("#[derive(wasmtime::component::Lower)]\n");
+            uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
             self.push_str(&format!("#[component({})]\n", derive_component));
+            if let Some(path) = &self.gen.opts.wasmtime_crate {
+                uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
+            }
             if info.is_copy() {
                 derives.extend(["Copy", "Clone"].into_iter().map(|s| s.to_string()));
             } else if info.is_clone() {
@@ -1718,6 +1745,7 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn type_enum(&mut self, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
         let info = self.info(id);
+        let wt = self.gen.wasmtime_path();
 
         // We use a BTree set to make sure we don't have any duplicates and have a stable order
         let mut derives: BTreeSet<String> = self
@@ -1736,10 +1764,13 @@ impl<'a> InterfaceGenerator<'a> {
 
         let name = to_rust_upper_camel_case(name);
         self.rustdoc(docs);
-        self.push_str("#[derive(wasmtime::component::ComponentType)]\n");
-        self.push_str("#[derive(wasmtime::component::Lift)]\n");
-        self.push_str("#[derive(wasmtime::component::Lower)]\n");
+        uwriteln!(self.src, "#[derive({wt}::component::ComponentType)]");
+        uwriteln!(self.src, "#[derive({wt}::component::Lift)]");
+        uwriteln!(self.src, "#[derive({wt}::component::Lower)]");
         self.push_str("#[component(enum)]\n");
+        if let Some(path) = &self.gen.opts.wasmtime_crate {
+            uwriteln!(self.src, "#[component(wasmtime_crate = {path})]\n");
+        }
 
         self.push_str("#[derive(");
         self.push_str(&derives.into_iter().collect::<Vec<_>>().join(", "));
@@ -1919,10 +1950,11 @@ impl<'a> InterfaceGenerator<'a> {
     fn generate_add_to_linker(&mut self, id: InterfaceId, name: &str) {
         let iface = &self.resolve.interfaces[id];
         let owner = TypeOwner::Interface(id);
+        let wt = self.gen.wasmtime_path();
 
         let is_maybe_async = self.gen.opts.async_.maybe_async();
         if is_maybe_async {
-            uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]")
+            uwriteln!(self.src, "#[{wt}::component::__internal::async_trait]")
         }
         // Generate the `pub trait` which represents the host functionality for
         // this import which additionally inherits from all resource traits
@@ -1981,7 +2013,7 @@ impl<'a> InterfaceGenerator<'a> {
                     if errors_converted.insert(err_name, err_id).is_none() {
                         uwriteln!(
                             self.src,
-                            "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> wasmtime::Result<{err_camel}>;"
+                            "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}>;"
                         );
                     }
                 }
@@ -2020,9 +2052,9 @@ impl<'a> InterfaceGenerator<'a> {
                 }}
 
                 pub fn add_to_linker_get_host<T>(
-                    linker: &mut wasmtime::component::Linker<T>,
+                    linker: &mut {wt}::component::Linker<T>,
                     host_getter: impl for<'a> GetHost<&'a mut T>,
-                ) -> wasmtime::Result<()>
+                ) -> {wt}::Result<()>
                     where {data_bounds}
                 {{
             "
@@ -2035,9 +2067,9 @@ impl<'a> InterfaceGenerator<'a> {
                 self.src,
                 "inst.resource(
                     \"{name}\",
-                    wasmtime::component::ResourceType::host::<{camel}>(),
-                    move |mut store, rep| -> wasmtime::Result<()> {{
-                        Host{camel}::drop(&mut host_getter(store.data_mut()), wasmtime::component::Resource::new_own(rep))
+                    {wt}::component::ResourceType::host::<{camel}>(),
+                    move |mut store, rep| -> {wt}::Result<()> {{
+                        Host{camel}::drop(&mut host_getter(store.data_mut()), {wt}::component::Resource::new_own(rep))
                     }},
                 )?;"
             )
@@ -2055,9 +2087,9 @@ impl<'a> InterfaceGenerator<'a> {
                 self.src,
                 "
                 pub fn add_to_linker<T, U>(
-                    linker: &mut wasmtime::component::Linker<T>,
+                    linker: &mut {wt}::component::Linker<T>,
                     get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
-                ) -> wasmtime::Result<()>
+                ) -> {wt}::Result<()>
                     where
                         U: {host_bounds}, {data_bounds}
                 {{
@@ -2069,11 +2101,11 @@ impl<'a> InterfaceGenerator<'a> {
             // Generate impl Host for &mut Host
             let (async_trait, maybe_send) = if is_maybe_async {
                 (
-                    "#[wasmtime::component::__internal::async_trait]\n",
+                    format!("#[{wt}::component::__internal::async_trait]"),
                     "+ Send",
                 )
             } else {
-                ("", "")
+                (String::new(), "")
             };
 
             uwriteln!(
@@ -2100,7 +2132,7 @@ impl<'a> InterfaceGenerator<'a> {
             for (err_name, err_id) in errors_converted {
                 uwriteln!(
                     self.src,
-                    "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> wasmtime::Result<{err_camel}> {{
+                    "fn convert_{err_snake}(&mut self, err: {root}{custom_name}) -> {wt}::Result<{err_camel}> {{
                         Host::convert_{err_snake}(*self, err)
                     }}",
                     custom_name = self.gen.trappable_errors[&err_id],
@@ -2131,8 +2163,11 @@ impl<'a> InterfaceGenerator<'a> {
         // Generate the closure that's passed to a `Linker`, the final piece of
         // codegen here.
 
-        self.src
-            .push_str("move |mut caller: wasmtime::StoreContextMut<'_, T>, (");
+        let wt = self.gen.wasmtime_path();
+        uwrite!(
+            self.src,
+            "move |mut caller: {wt}::StoreContextMut<'_, T>, ("
+        );
         for (i, _param) in func.params.iter().enumerate() {
             uwrite!(self.src, "arg{},", i);
         }
@@ -2146,8 +2181,10 @@ impl<'a> InterfaceGenerator<'a> {
         }
         self.src.push_str(") |");
         if self.gen.opts.async_.is_import_async(&func.name) {
-            self.src
-                .push_str(" wasmtime::component::__internal::Box::new(async move { \n");
+            uwriteln!(
+                self.src,
+                " {wt}::component::__internal::Box::new(async move {{ "
+            );
         } else {
             self.src.push_str(" { \n");
         }
@@ -2269,6 +2306,7 @@ impl<'a> InterfaceGenerator<'a> {
     }
 
     fn generate_function_trait_sig(&mut self, func: &Function) {
+        let wt = self.gen.wasmtime_path();
         self.rustdoc(&func.docs);
 
         if self.gen.opts.async_.is_import_async(&func.name) {
@@ -2307,7 +2345,7 @@ impl<'a> InterfaceGenerator<'a> {
         } else {
             // All other functions get their return values wrapped in an wasmtime::Result.
             // Returning the anyhow::Error case can be used to trap.
-            self.push_str("wasmtime::Result<");
+            uwrite!(self.src, "{wt}::Result<");
             self.print_result_ty(&func.results, TypeMode::Owned);
             self.push_str(">");
         }
@@ -2352,10 +2390,11 @@ impl<'a> InterfaceGenerator<'a> {
         };
 
         self.rustdoc(&func.docs);
+        let wt = self.gen.wasmtime_path();
 
         uwrite!(
             self.src,
-            "pub {async_} fn call_{}<S: wasmtime::AsContextMut>(&self, mut store: S, ",
+            "pub {async_} fn call_{}<S: {wt}::AsContextMut>(&self, mut store: S, ",
             func.item_name().to_snake_case(),
         );
 
@@ -2365,12 +2404,11 @@ impl<'a> InterfaceGenerator<'a> {
             self.push_str(",");
         }
 
-        self.src.push_str(") -> wasmtime::Result<");
+        uwrite!(self.src, ") -> {wt}::Result<");
         self.print_result_ty(&func.results, TypeMode::Owned);
 
         if is_async {
-            self.src
-                .push_str("> where <S as wasmtime::AsContext>::Data: Send {\n");
+            uwriteln!(self.src, "> where <S as {wt}::AsContext>::Data: Send {{");
         } else {
             self.src.push_str("> {\n");
         }
@@ -2395,7 +2433,7 @@ impl<'a> InterfaceGenerator<'a> {
         }
 
         self.src.push_str("let callee = unsafe {\n");
-        self.src.push_str("wasmtime::component::TypedFunc::<(");
+        uwrite!(self.src, "{wt}::component::TypedFunc::<(");
         for (_, ty) in func.params.iter() {
             self.print_ty(ty, TypeMode::AllBorrowed("'_"));
             self.push_str(", ");
@@ -2521,6 +2559,10 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
     fn is_imported_interface(&self, interface: InterfaceId) -> bool {
         self.gen.interface_last_seen_as_import[&interface]
     }
+
+    fn wasmtime_path(&self) -> String {
+        self.gen.wasmtime_path()
+    }
 }
 
 /// When an interface `use`s a type from another interface, it creates a new TypeId
diff --git a/crates/wit-bindgen/src/rust.rs b/crates/wit-bindgen/src/rust.rs
index 13b3967be..fc564c41b 100644
--- a/crates/wit-bindgen/src/rust.rs
+++ b/crates/wit-bindgen/src/rust.rs
@@ -15,6 +15,7 @@ pub trait RustGenerator<'a> {
     fn info(&self, ty: TypeId) -> TypeInfo;
     fn path_to_interface(&self, interface: InterfaceId) -> Option<String>;
     fn is_imported_interface(&self, interface: InterfaceId) -> bool;
+    fn wasmtime_path(&self) -> String;
 
     /// This determines whether we generate owning types or (where appropriate)
     /// borrowing types.
@@ -51,7 +52,10 @@ pub trait RustGenerator<'a> {
                     }
                     self.push_str("str");
                 }
-                TypeMode::Owned => self.push_str("wasmtime::component::__internal::String"),
+                TypeMode::Owned => {
+                    let wt = self.wasmtime_path();
+                    self.push_str(&format!("{wt}::component::__internal::String"))
+                }
             },
         }
     }
@@ -212,7 +216,8 @@ pub trait RustGenerator<'a> {
                 self.push_str("]");
             }
             TypeMode::Owned => {
-                self.push_str("wasmtime::component::__internal::Vec<");
+                let wt = self.wasmtime_path();
+                self.push_str(&format!("{wt}::component::__internal::Vec<"));
                 self.print_ty(ty, next_mode);
                 self.push_str(">");
             }
@@ -242,15 +247,16 @@ pub trait RustGenerator<'a> {
             TypeOwner::Interface(i) => self.is_imported_interface(i),
             _ => true,
         };
+        let wt = self.wasmtime_path();
         if is_host_defined {
-            self.push_str("wasmtime::component::Resource<");
+            self.push_str(&format!("{wt}::component::Resource<"));
             self.print_type_name_in_interface(
                 ty.owner,
                 &ty.name.as_ref().unwrap().to_upper_camel_case(),
             );
             self.push_str(">");
         } else {
-            self.push_str("wasmtime::component::ResourceAny");
+            self.push_str(&format!("{wt}::component::ResourceAny"));
         }
     }
 
diff --git a/examples/min-platform/src/main.rs b/examples/min-platform/src/main.rs
index d8adeeb93..8fd6c063d 100644
--- a/examples/min-platform/src/main.rs
+++ b/examples/min-platform/src/main.rs
@@ -10,7 +10,7 @@ fn main() -> Result<()> {
 fn main() -> Result<()> {
     use anyhow::{anyhow, Context};
     use libloading::os::unix::{Library, Symbol, RTLD_GLOBAL, RTLD_NOW};
-    use object::{Object, ObjectSymbol, SymbolKind};
+    use object::{Object, ObjectSymbol};
     use std::io::Write;
     use wasmtime::{Config, Engine};
 
@@ -44,7 +44,7 @@ fn main() -> Result<()> {
     // running `libembedding.so` in this case requires only minimal
     // dependencies.
     for sym in object.symbols() {
-        if !sym.is_undefined() || sym.is_weak() || sym.kind() == SymbolKind::Null {
+        if !sym.is_undefined() || sym.is_weak() {
             continue;
         }
 
diff --git a/supply-chain/config.toml b/supply-chain/config.toml
index 0d7a87568..115ac2c4b 100644
--- a/supply-chain/config.toml
+++ b/supply-chain/config.toml
@@ -405,7 +405,11 @@ version = "0.3.0"
 criteria = "safe-to-deploy"
 
 [[exemptions.object]]
-version = "0.29.0"
+version = "0.32.0"
+criteria = "safe-to-deploy"
+
+[[exemptions.object]]
+version = "0.36.0"
 criteria = "safe-to-deploy"
 
 [[exemptions.ocaml-boxroot-sys]]


Test patch:
diff --git a/tests/all/async_functions.rs b/tests/all/async_functions.rs
index 7579085ea..c94dc4e3b 100644
--- a/tests/all/async_functions.rs
+++ b/tests/all/async_functions.rs
@@ -32,7 +32,7 @@ async fn smoke() {
     run_smoke_test(&mut store, func).await;
     run_smoke_typed_test(&mut store, func).await;
 
-    let func = Func::wrap0_async(&mut store, move |_caller| Box::new(async { Ok(()) }));
+    let func = Func::wrap_async(&mut store, move |_caller, _: ()| Box::new(async { Ok(()) }));
     run_smoke_test(&mut store, func).await;
     run_smoke_typed_test(&mut store, func).await;
 }
@@ -49,7 +49,9 @@ async fn smoke_host_func() -> Result<()> {
         move |_caller, _params, _results| Box::new(async { Ok(()) }),
     )?;
 
-    linker.func_wrap0_async("", "second", move |_caller| Box::new(async { Ok(()) }))?;
+    linker.func_wrap_async("", "second", move |_caller, _: ()| {
+        Box::new(async { Ok(()) })
+    })?;
 
     let func = linker
         .get(&mut store, "", "first")
@@ -83,7 +85,7 @@ async fn smoke_with_suspension() {
     run_smoke_test(&mut store, func).await;
     run_smoke_typed_test(&mut store, func).await;
 
-    let func = Func::wrap0_async(&mut store, move |_caller| {
+    let func = Func::wrap_async(&mut store, move |_caller, _: ()| {
         Box::new(async {
             tokio::task::yield_now().await;
             Ok(())
@@ -110,7 +112,7 @@ async fn smoke_host_func_with_suspension() -> Result<()> {
         },
     )?;
 
-    linker.func_wrap0_async("", "second", move |_caller| {
+    linker.func_wrap_async("", "second", move |_caller, _: ()| {
         Box::new(async {
             tokio::task::yield_now().await;
             Ok(())
@@ -509,7 +511,7 @@ async fn resume_separate_thread() {
             ",
         )
         .unwrap();
-        let func = Func::wrap0_async(&mut store, |_| {
+        let func = Func::wrap_async(&mut store, |_, _: ()| {
             Box::new(async {
                 tokio::task::yield_now().await;
                 Err::<(), _>(anyhow!("test"))
@@ -541,7 +543,7 @@ async fn resume_separate_thread2() {
             ",
         )
         .unwrap();
-        let func = Func::wrap0_async(&mut store, |_| {
+        let func = Func::wrap_async(&mut store, |_, _: ()| {
             Box::new(async {
                 tokio::task::yield_now().await;
             })
@@ -582,7 +584,7 @@ async fn resume_separate_thread3() {
                 ",
             )
             .unwrap();
-            let func = Func::wrap0_async(&mut store, |_| {
+            let func = Func::wrap_async(&mut store, |_, _: ()| {
                 Box::new(async {
                     tokio::task::yield_now().await;
                 })
@@ -627,7 +629,7 @@ async fn recursive_async() -> Result<()> {
     let i = Instance::new_async(&mut store, &m, &[]).await?;
     let overflow = i.get_typed_func::<(), ()>(&mut store, "overflow")?;
     let normal = i.get_typed_func::<(), ()>(&mut store, "normal")?;
-    let f2 = Func::wrap0_async(&mut store, move |mut caller| {
+    let f2 = Func::wrap_async(&mut store, move |mut caller, _: ()| {
         let normal = normal.clone();
         let overflow = overflow.clone();
         Box::new(async move {
@@ -831,17 +833,17 @@ async fn non_stacky_async_activations() -> Result<()> {
         stacks.push(wasmtime::WasmBacktrace::force_capture(store));
     }
 
-    linker1.func_wrap0_async("", "host_capture_stack", {
+    linker1.func_wrap_async("", "host_capture_stack", {
         let stacks = stacks.clone();
-        move |caller| {
+        move |caller, _: ()| {
             capture_stack(&stacks, &caller);
             Box::new(async { Ok(()) })
         }
     })?;
 
-    linker1.func_wrap0_async("", "start_async_instance", {
+    linker1.func_wrap_async("", "start_async_instance", {
         let stacks = stacks.clone();
-        move |mut caller| {
+        move |mut caller, _: ()| {
             let stacks = stacks.clone();
             capture_stack(&stacks, &caller);
 
@@ -849,9 +851,9 @@ async fn non_stacky_async_activations() -> Result<()> {
             let mut store2 = Store::new(caller.engine(), ());
             let mut linker2 = Linker::new(caller.engine());
             linker2
-                .func_wrap0_async("", "yield", {
+                .func_wrap_async("", "yield", {
                     let stacks = stacks.clone();
-                    move |caller| {
+                    move |caller, _: ()| {
                         let stacks = stacks.clone();
                         Box::new(async move {
                             capture_stack(&stacks, &caller);
@@ -972,13 +974,17 @@ async fn gc_preserves_externref_on_historical_async_stacks() -> Result<()> {
             Ok(())
         },
     )?;
-    linker.func_wrap1_async("", "recurse", |mut cx: Caller<'_, Option<F>>, val: i32| {
-        let func = cx.data().clone().unwrap();
-        Box::new(async move {
-            let r = Some(ExternRef::new(&mut cx, val)?);
-            Ok(func.call_async(&mut cx, (val, r)).await)
-        })
-    })?;
+    linker.func_wrap_async(
+        "",
+        "recurse",
+        |mut cx: Caller<'_, Option<F>>, (val,): (i32,)| {
+            let func = cx.data().clone().unwrap();
+            Box::new(async move {
+                let r = Some(ExternRef::new(&mut cx, val)?);
+                Ok(func.call_async(&mut cx, (val, r)).await)
+            })
+        },
+    )?;
     let instance = linker.instantiate_async(&mut store, &module).await?;
     let func: F = instance.get_typed_func(&mut store, "run")?;
     *store.data_mut() = Some(func.clone());
diff --git a/tests/all/call_hook.rs b/tests/all/call_hook.rs
index fad0bfb8d..5b7bc60da 100644
--- a/tests/all/call_hook.rs
+++ b/tests/all/call_hook.rs
@@ -121,9 +121,9 @@ async fn call_wrapped_async_func() -> Result<(), Error> {
     let engine = Engine::new(&config)?;
     let mut store = Store::new(&engine, State::default());
     store.call_hook(State::call_hook);
-    let f = Func::wrap4_async(
+    let f = Func::wrap_async(
         &mut store,
-        |caller: Caller<State>, a: i32, b: i64, c: f32, d: f64| {
+        |caller: Caller<State>, (a, b, c, d): (i32, i64, f32, f64)| {
             Box::new(async move {
                 // Calling this func will switch context into wasm, then back to host:
                 assert_eq!(caller.data().context, vec![Context::Wasm, Context::Host]);
@@ -245,9 +245,9 @@ async fn call_linked_func_async() -> Result<(), Error> {
     let mut store = Store::new(&engine, State::default());
     store.call_hook(State::call_hook);
 
-    let f = Func::wrap4_async(
+    let f = Func::wrap_async(
         &mut store,
-        |caller: Caller<State>, a: i32, b: i64, c: f32, d: f64| {
+        |caller: Caller<State>, (a, b, c, d): (i32, i64, f32, f64)| {
             Box::new(async move {
                 // Calling this func will switch context into wasm, then back to host:
                 assert_eq!(caller.data().context, vec![Context::Wasm, Context::Host]);
@@ -728,7 +728,7 @@ async fn drop_suspended_async_hook() -> Result<(), Error> {
     let mut linker = Linker::new(&engine);
 
     // Simulate a host function that has lots of yields with an infinite loop.
-    linker.func_wrap0_async("host", "f", |mut cx| {
+    linker.func_wrap_async("host", "f", |mut cx, _: ()| {
         Box::new(async move {
             let state = cx.data_mut();
             assert_eq!(*state, 0);
diff --git a/tests/all/component_model/async.rs b/tests/all/component_model/async.rs
index cbb398fdd..6b995657c 100644
--- a/tests/all/component_model/async.rs
+++ b/tests/all/component_model/async.rs
@@ -219,7 +219,7 @@ async fn poll_through_wasm_activation() -> Result<()> {
 
     execute_across_threads(async move {
         let mut store = Store::new(&engine, Some(Box::pin(invoke_component)));
-        let poll_once = wasmtime::Func::wrap0_async(&mut store, |mut cx| {
+        let poll_once = wasmtime::Func::wrap_async(&mut store, |mut cx, _: ()| {
             let invoke_component = cx.data_mut().take().unwrap();
             Box::new(async move {
                 match PollOnce::new(invoke_component).await {
diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs
index 77e4eb08e..955c90cf3 100644
--- a/tests/host_segfault.rs
+++ b/tests/host_segfault.rs
@@ -138,7 +138,7 @@ fn main() {
                 config.async_support(true);
                 let engine = Engine::new(&config).unwrap();
                 let mut store = Store::new(&engine, ());
-                let f = Func::wrap0_async(&mut store, |_| {
+                let f = Func::wrap_async(&mut store, |_, _: ()| {
                     Box::new(async {
                         overrun_the_stack();
                     })
@@ -170,7 +170,7 @@ fn main() {
                 config.allocation_strategy(InstanceAllocationStrategy::pooling());
                 let engine = Engine::new(&config).unwrap();
                 let mut store = Store::new(&engine, ());
-                let f = Func::wrap0_async(&mut store, |_| {
+                let f = Func::wrap_async(&mut store, |_, _: ()| {
                     Box::new(async {
                         overrun_the_stack();
                     })