From c48a0f3e6d70c3e9beb0473c8181dfd57adc9c59 Mon Sep 17 00:00:00 2001 From: chertov Date: Mon, 13 Oct 2025 12:58:50 +0700 Subject: [PATCH 1/3] Allow generating hidden visibility functions --- bindgen/ir/function.rs | 6 +++++- bindgen/options/mod.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 6f8c00fa89..d17f803d6f 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -730,7 +730,11 @@ impl ClangSubItemParser for Function { debug!("Function::parse({cursor:?}, {:?})", cursor.cur_type()); let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { + let allow_hidden = context.options().generate_hidden_functions && + (visibility == CXVisibility_Hidden || + visibility == CXVisibility_Protected); + + if visibility != CXVisibility_Default && !allow_hidden { return Err(ParseError::Continue); } if cursor.access_specifier() == CX_CXXPrivate && diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index b9b33a850b..a1915d85c2 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -2329,4 +2329,16 @@ options! { }, as_args: "--generate-private-functions", }, + /// Whether to allow generating functions that are marked with hidden or protected visibility. + generate_hidden_functions: bool { + methods: { + /// Set whether to generate functions that are not externally visible according to clang. + pub fn generate_hidden_functions(mut self, doit: bool) -> Self { + self.options.generate_hidden_functions = doit; + self + } + + }, + as_args: "--generate-hidden-functions", + }, } From 0d28b509debf51a69de7b0e99021fc3ef1aef4f7 Mon Sep 17 00:00:00 2001 From: chertov Date: Tue, 14 Oct 2025 23:33:59 +0700 Subject: [PATCH 2/3] Add regression tests for generate_hidden_functions option --- bindgen-tests/tests/tests.rs | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 6e3c358d3e..bfd56f1cc3 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -427,6 +427,54 @@ fn test_header_contents() { assert_eq!(expected, actual); } +const HIDDEN_FUNCTIONS_HEADER: &str = r#" +__attribute__((visibility("hidden"))) int hidden_fn(void); +__attribute__((visibility("protected"))) int protected_fn(void); +int visible_fn(void); +"#; + +fn hidden_functions_builder() -> Builder { + builder() + .allowlist_function("visible_fn") + .allowlist_function("hidden_fn") + .allowlist_function("protected_fn") + .header_contents("hidden.h", HIDDEN_FUNCTIONS_HEADER) +} + +#[test] +fn hidden_functions_are_skipped_by_default() { + let bindings = hidden_functions_builder() + .generate() + .unwrap() + .to_string(); + + assert!(bindings.contains("pub fn visible_fn")); + assert!(!bindings.contains("pub fn hidden_fn")); +} + +#[test] +fn hidden_functions_can_be_generated_when_enabled() { + let default_bindings = hidden_functions_builder() + .generate() + .unwrap() + .to_string(); + + let hidden_enabled = hidden_functions_builder() + .generate_hidden_functions(true) + .generate() + .unwrap() + .to_string(); + + assert!(hidden_enabled.contains("pub fn hidden_fn")); + assert!(!default_bindings.contains("pub fn hidden_fn")); + + // Clang on Mach-O downgrades `protected` visibility to `default`, + // so the symbol might already be present without the new option. + if !default_bindings.contains("pub fn protected_fn") { + assert!(hidden_enabled.contains("pub fn protected_fn")); + } +} + #[test] fn test_multiple_header_calls_in_builder() { let actual = builder() From 5c6e371e6c2194c147d2d1855acc5b71bce792e4 Mon Sep 17 00:00:00 2001 From: chertov Date: Tue, 14 Oct 2025 23:33:59 +0700 Subject: [PATCH 3/3] Add regression tests for generate_hidden_functions option # Conflicts: # bindgen-tests/tests/tests.rs --- bindgen-tests/tests/tests.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index bfd56f1cc3..cd21f5f9ba 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -443,10 +443,7 @@ fn hidden_functions_builder() -> Builder { #[test] fn hidden_functions_are_skipped_by_default() { - let bindings = hidden_functions_builder() - .generate() - .unwrap() - .to_string(); + let bindings = hidden_functions_builder().generate().unwrap().to_string(); assert!(bindings.contains("pub fn visible_fn")); assert!(!bindings.contains("pub fn hidden_fn")); @@ -454,10 +451,8 @@ fn hidden_functions_are_skipped_by_default() { #[test] fn hidden_functions_can_be_generated_when_enabled() { - let default_bindings = hidden_functions_builder() - .generate() - .unwrap() - .to_string(); + let default_bindings = + hidden_functions_builder().generate().unwrap().to_string(); let hidden_enabled = hidden_functions_builder() .generate_hidden_functions(true)