diff --git a/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-many.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-many.rs new file mode 100644 index 0000000000..5aa9e45ec2 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-many.rs @@ -0,0 +1,6 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[allow(dead_code)] +#[cfg_attr(not(windows), link(wasm_import_module = "test-module"))] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs new file mode 100644 index 0000000000..388594b27e --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs @@ -0,0 +1,6 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[link(wasm_import_module = "test-module")] +#[allow(dead_code)] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs new file mode 100644 index 0000000000..657cec106a --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs @@ -0,0 +1,5 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[allow(dead_code)] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h b/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h new file mode 100644 index 0000000000..0de6eebb36 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' --extern-fn-block-attrs '#[cfg_attr(not(windows), link(wasm_import_module = "test-module"))]' + +void test_function(); \ No newline at end of file diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h b/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h new file mode 100644 index 0000000000..2f475f1ed1 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' --wasm-import-module-name test-module + +void test_function(); \ No newline at end of file diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs.h b/bindgen-tests/tests/headers/extern-fn-block-attrs.h new file mode 100644 index 0000000000..26480e2ef0 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' + +void test_function(); \ No newline at end of file diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 88a5416ea4..eee4f46121 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4665,13 +4665,19 @@ impl CodeGenerator for Function { } } - // Unfortunately this can't piggyback on the `attributes` list because - // the #[link(wasm_import_module)] needs to happen before the `extern - // "C"` block. It doesn't get picked up properly otherwise - let wasm_link_attribute = - ctx.options().wasm_import_module_name.as_ref().map(|name| { - quote! { #[link(wasm_import_module = #name)] } + let mut block_attributes = quote! {}; + for attr in &ctx.options().extern_fn_block_attrs { + let parsed_attr = proc_macro2::TokenStream::from_str(attr).unwrap_or_else( + |err| { + panic!( + "Error parsing extern fn block attribute `{attr}`: {err}" + ) + }, + ); + block_attributes.extend(quote! { + #parsed_attr }); + } let should_wrap = is_internal && ctx.options().wrap_static_fns && @@ -4725,7 +4731,7 @@ impl CodeGenerator for Function { .then(|| quote!(unsafe)); let tokens = quote! { - #wasm_link_attribute + #block_attributes #safety extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index 4334e9c239..972b487c25 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -423,6 +423,9 @@ struct BindgenCommand { /// The NAME to be used in a #[link(wasm_import_module = ...)] statement #[arg(long, value_name = "NAME")] wasm_import_module_name: Option, + /// Attributes to apply to the extern function block. + #[arg(long, value_name = "ATTRS")] + extern_fn_block_attrs: Vec, /// Use dynamic loading mode with the given library NAME. #[arg(long, value_name = "NAME")] dynamic_loading: Option, @@ -647,6 +650,7 @@ where enable_function_attribute_detection, use_array_pointers_in_arguments, wasm_import_module_name, + extern_fn_block_attrs, dynamic_loading, dynamic_link_require_all, prefix_link_name, @@ -907,6 +911,7 @@ where time_phases, use_array_pointers_in_arguments => Builder::array_pointers_in_arguments, wasm_import_module_name, + extern_fn_block_attrs => Builder::extern_fn_block_attrs, ctypes_prefix, anon_fields_prefix, generate => Builder::with_codegen_config, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index edc979e01f..b9b33a850b 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -1916,6 +1916,25 @@ options! { }, as_args: "--use-array-pointers-in-arguments", }, + /// Attributes to add to all `extern` blocks. + extern_fn_block_attrs: Vec { + methods: { + /// Add an attribute to all the `extern` blocks generated by `bindgen`. + /// + /// This can be used to add attributes such as `#[link(...)]` to all + /// the `extern` blocks. + pub fn extern_fn_block_attrs>(mut self, attr: T) -> Self { + self.options.extern_fn_block_attrs.push(attr.into()); + self + } + }, + as_args: |attrs, args| { + for attr in attrs { + args.push("--extern-fn-block-attrs".to_owned()); + args.push(attr.clone()); + } + }, + }, /// The name of the `wasm_import_module`. wasm_import_module_name: Option { methods: { @@ -1927,7 +1946,9 @@ options! { mut self, import_name: T, ) -> Self { - self.options.wasm_import_module_name = Some(import_name.into()); + self.options.extern_fn_block_attrs.push(format!( + "#[link(wasm_import_module = \"{}\")]", import_name.into() + )); self } },