Skip to content

Commit f2ddae4

Browse files
feat(rust) make link_native_symbols default
1 parent 8fa3f37 commit f2ddae4

5 files changed

Lines changed: 147 additions & 257 deletions

File tree

crates/guest-rust/macro/src/lib.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,6 @@ impl Parse for Config {
175175
Opt::MergeStructurallyEqualTypes(enable) => {
176176
opts.merge_structurally_equal_types = Some(Some(enable.value()))
177177
}
178-
Opt::LinkNativeSymbols(enable) => {
179-
opts.link_native_symbols = enable.value();
180-
}
181178
}
182179
}
183180
} else {
@@ -335,7 +332,6 @@ mod kw {
335332
syn::custom_keyword!(debug);
336333
syn::custom_keyword!(enable_method_chaining);
337334
syn::custom_keyword!(merge_structurally_equal_types);
338-
syn::custom_keyword!(link_native_symbols);
339335
}
340336

341337
#[derive(Clone)]
@@ -420,7 +416,6 @@ enum Opt {
420416
Debug(syn::LitBool),
421417
EnableMethodChaining(syn::LitBool),
422418
MergeStructurallyEqualTypes(syn::LitBool),
423-
LinkNativeSymbols(syn::LitBool),
424419
}
425420

426421
impl Parse for Opt {
@@ -628,10 +623,6 @@ impl Parse for Opt {
628623
input.parse::<kw::merge_structurally_equal_types>()?;
629624
input.parse::<Token![:]>()?;
630625
Ok(Opt::MergeStructurallyEqualTypes(input.parse()?))
631-
} else if l.peek(kw::link_native_symbols) {
632-
input.parse::<kw::link_native_symbols>()?;
633-
input.parse::<Token![:]>()?;
634-
Ok(Opt::LinkNativeSymbols(input.parse()?))
635626
} else {
636627
Err(l.error())
637628
}

crates/guest-rust/src/lib.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -891,27 +891,42 @@ extern crate std;
891891
/// // structurally equal, which is useful when import and export the same
892892
/// // interface.
893893
/// merge_structurally_equal_types: true,
894-
///
895-
/// // Make the same generated bindings usable on a native (non-wasm)
896-
/// // target as well as on wasm32.
897-
/// //
898-
/// // Imports normally compile to `unreachable!()` off wasm32. With this
899-
/// // enabled each one instead calls through a function pointer that a host
900-
/// // installs at load time via a generated
901-
/// // `__wit_bindgen_register_*` symbol, and exports additionally get a
902-
/// // native symbol whose name encodes the characters a linker cannot
903-
/// // accept. Both targets still build from one source.
904-
/// //
905-
/// // The registration symbols are prefixed with a hex-encoded
906-
/// // `<package>/<world>` so that two `generate!` invocations in one crate
907-
/// // don't collide. Binding the *same* world twice in one linkage unit
908-
/// // still does; use `type_section_suffix` to tell them apart. See
909-
/// // `wit_bindgen_rust::Opts::link_native_symbols` for the full list of
910-
/// // symbols a host can expect.
911-
/// link_native_symbols: true,
912894
/// });
913895
/// ```
914896
///
897+
/// ## Native (non-WebAssembly) targets
898+
///
899+
/// Generated bindings also compile for native targets, which is useful for
900+
/// testing component code without a wasm runtime or for building it as a
901+
/// `cdylib` plugin. Native linkers don't accept the `:`, `/`, `#`, `[` and
902+
/// `]` characters that canonical ABI symbol names use, so on native targets
903+
/// symbols are hex-encoded with the scheme in
904+
/// `wit_bindgen_core::symbol_name` (the same one the C++ generator uses).
905+
///
906+
/// Imports are not resolved by the native linker. Each import calls through
907+
/// a function pointer that starts out null, and a host provides an
908+
/// implementation at load time by calling the generated
909+
/// `__wit_bindgen_register_<world><import>` function with a function pointer
910+
/// of the import's core signature (`<import>` here is
911+
/// `make_external_symbol(module, name, GuestImport)`). This means everything
912+
/// links whether or not a host is present: a host only needs to register the
913+
/// imports it actually implements, and calling an import that was never
914+
/// registered aborts with a message naming the import and its registration
915+
/// function.
916+
///
917+
/// Exports, including post-return functions, async callbacks, and resource
918+
/// destructors, are exported under their hex-encoded core export names. A
919+
/// `__wit_bindgen_cabi_realloc_<world>` function is also exported so hosts
920+
/// can allocate guest-owned memory when lowering arguments, as the canonical
921+
/// ABI requires.
922+
///
923+
/// The `<world>` prefix above is a hex-encoded
924+
/// `<package>/<world><type_section_suffix>`, which keeps two `generate!`
925+
/// invocations in one binary from defining the same symbols. Note that
926+
/// binding the same world twice in one native binary will fail to link with
927+
/// duplicate symbols unless `type_section_suffix` is used to tell the two
928+
/// apart.
929+
///
915930
/// [WIT package]: https://component-model.bytecodealliance.org/design/packages.html
916931
#[cfg(feature = "macros")]
917932
pub use wit_bindgen_rust_macro::generate;

crates/rust/src/interface.rs

Lines changed: 66 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -357,25 +357,23 @@ macro_rules! {macro_name} {{
357357
}
358358
};
359359
let camel = name.to_upper_camel_case();
360-
for (cfg, symbol) in self.core_export_symbols(&format!("{module}#[dtor]{name}")) {
361-
uwriteln!(
362-
self.src,
363-
r#"
364-
const _: () = {{
365-
#[doc(hidden)]
366-
{cfg}#[unsafe(export_name = "{symbol}")]
367-
#[allow(non_snake_case)]
368-
unsafe extern "C" fn dtor(rep: *mut u8) {{
369-
unsafe {{
370-
$($path_to_types)*::{camel}::dtor::<
371-
<$ty as $($path_to_types)*::Guest>::{camel}
372-
>(rep)
373-
}}
360+
let attrs = self.core_export_attrs(&format!("{module}#[dtor]{name}"));
361+
uwriteln!(
362+
self.src,
363+
r#"
364+
const _: () = {{
365+
#[doc(hidden)]
366+
{attrs}#[allow(non_snake_case)]
367+
unsafe extern "C" fn dtor(rep: *mut u8) {{
368+
unsafe {{
369+
$($path_to_types)*::{camel}::dtor::<
370+
<$ty as $($path_to_types)*::Guest>::{camel}
371+
>(rep)
374372
}}
375-
}};
376-
"#
377-
);
378-
}
373+
}}
374+
}};
375+
"#
376+
);
379377
}
380378
uwriteln!(self.src, "}};);");
381379
uwriteln!(self.src, "}}");
@@ -1292,86 +1290,69 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8)
12921290
export_name.to_string()
12931291
};
12941292

1295-
for (cfg, symbol) in self.core_export_symbols(&export_name) {
1293+
let attrs = self.core_export_attrs(&export_name);
1294+
uwrite!(
1295+
self.src,
1296+
"\
1297+
{attrs}unsafe extern \"C\" fn export_{name_snake}\
1298+
",
1299+
);
1300+
let params = self.print_export_sig(func, async_);
1301+
self.push_str(" {\n");
1302+
uwriteln!(
1303+
self.src,
1304+
"unsafe {{ {path_to_self}::_export_{name_snake}_cabi::<{ty}>({}) }}",
1305+
params.join(", ")
1306+
);
1307+
self.push_str("}\n");
1308+
1309+
if async_ {
1310+
let attrs = self.core_export_attrs(&format!("[callback]{export_name}"));
12961311
uwrite!(
12971312
self.src,
12981313
"\
1299-
{cfg}#[unsafe(export_name = \"{symbol}\")]
1300-
unsafe extern \"C\" fn export_{name_snake}\
1301-
",
1314+
{attrs}unsafe extern \"C\" fn _callback_{name_snake}(event0: u32, event1: u32, event2: u32) -> u32 {{
1315+
unsafe {{
1316+
{path_to_self}::__callback_{name_snake}(event0, event1, event2)
1317+
}}
1318+
}}
1319+
"
13021320
);
1303-
let params = self.print_export_sig(func, async_);
1304-
self.push_str(" {\n");
1321+
} else if abi::guest_export_needs_post_return(self.resolve, func) {
1322+
let attrs = self.core_export_attrs(&format!("cabi_post_{export_name}"));
1323+
uwrite!(
1324+
self.src,
1325+
"\
1326+
{attrs}unsafe extern \"C\" fn _post_return_{name_snake}\
1327+
"
1328+
);
1329+
let params = self.print_post_return_sig(func);
1330+
self.src.push_str("{\n");
13051331
uwriteln!(
13061332
self.src,
1307-
"unsafe {{ {path_to_self}::_export_{name_snake}_cabi::<{ty}>({}) }}",
1333+
"unsafe {{ {path_to_self}::__post_return_{name_snake}::<{ty}>({}) }}",
13081334
params.join(", ")
13091335
);
1310-
self.push_str("}\n");
1311-
}
1312-
1313-
if async_ {
1314-
for (cfg, symbol) in self.core_export_symbols(&format!("[callback]{export_name}")) {
1315-
uwrite!(
1316-
self.src,
1317-
"\
1318-
{cfg}#[unsafe(export_name = \"{symbol}\")]
1319-
unsafe extern \"C\" fn _callback_{name_snake}(event0: u32, event1: u32, event2: u32) -> u32 {{
1320-
unsafe {{
1321-
{path_to_self}::__callback_{name_snake}(event0, event1, event2)
1322-
}}
1323-
}}
1324-
"
1325-
);
1326-
}
1327-
} else if abi::guest_export_needs_post_return(self.resolve, func) {
1328-
for (cfg, symbol) in self.core_export_symbols(&format!("cabi_post_{export_name}")) {
1329-
uwrite!(
1330-
self.src,
1331-
"\
1332-
{cfg}#[unsafe(export_name = \"{symbol}\")]
1333-
unsafe extern \"C\" fn _post_return_{name_snake}\
1334-
"
1335-
);
1336-
let params = self.print_post_return_sig(func);
1337-
self.src.push_str("{\n");
1338-
uwriteln!(
1339-
self.src,
1340-
"unsafe {{ {path_to_self}::__post_return_{name_snake}::<{ty}>({}) }}",
1341-
params.join(", ")
1342-
);
1343-
self.src.push_str("}\n");
1344-
}
1336+
self.src.push_str("}\n");
13451337
}
13461338
}
13471339

1348-
/// Returns each copy of a core export named `export_name` that needs to be
1349-
/// emitted, as `(cfg, symbol)`: the `cfg` attribute to gate the copy with
1350-
/// and the symbol to export it as.
1340+
/// Returns the `export_name` attributes for a core export named
1341+
/// `export_name`.
13511342
///
1352-
/// Normally there's just one copy: the canonical ABI name with no `cfg`.
1353-
/// With `link_native_symbols` enabled a second, hex-encoded copy is emitted
1354-
/// for native targets as well, because native linkers reject the `:`, `/`,
1355-
/// `#`, `[` and `]` characters that canonical names contain. Names that
1356-
/// survive encoding unchanged (`$root` exports, for instance) are emitted
1357-
/// once with no `cfg` rather than twice.
1358-
fn core_export_symbols(&self, export_name: &str) -> Vec<(&'static str, String)> {
1343+
/// Has to exist due to the fact that native names cannot contain
1344+
/// special characters that wasm32 can like '/'.
1345+
///
1346+
/// `cfg_attr` conditions are mutually exclusive, so exactly one attribute
1347+
/// applies on any target (for names that survive encoding unchanged, such
1348+
/// as `$root` exports, both carry the same string).
1349+
fn core_export_attrs(&self, export_name: &str) -> String {
13591350
let prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or("");
1360-
let wasm = format!("{prefix}{export_name}");
1361-
if self.r#gen.native_symbols().is_none() {
1362-
return vec![("", wasm)];
1363-
}
1364-
let native = format!(
1365-
"{prefix}{}",
1366-
symbol_name::make_external_component(export_name)
1367-
);
1368-
if native == wasm {
1369-
return vec![("", wasm)];
1370-
}
1371-
vec![
1372-
("#[cfg(target_arch = \"wasm32\")]\n", wasm),
1373-
("#[cfg(not(target_arch = \"wasm32\"))]\n", native),
1374-
]
1351+
let native = symbol_name::make_external_component(export_name);
1352+
format!(
1353+
"#[cfg_attr(target_arch = \"wasm32\", unsafe(export_name = \"{prefix}{export_name}\"))]\n\
1354+
#[cfg_attr(not(target_arch = \"wasm32\"), unsafe(export_name = \"{prefix}{native}\"))]\n"
1355+
)
13751356
}
13761357

13771358
fn print_export_sig(&mut self, func: &Function, async_: bool) -> Vec<String> {

0 commit comments

Comments
 (0)