Repository: rust-lang/rust-bindgen
Pull request #2743 (2024-02-02 04:41:12)

feat: add `headers` option
Problem: It's cumbersome to define multiple input headers using the existing `header` API. It's difficult for the user to configure the `Builder` with a list of input headers.

Solution: Add `headers` method that permits adding multiple headers via an iterable of Strings.

Testing: Added `test_headers_call_in_builder`. Ran `cargo test` in `bindgen-tests/tests/expectations`.

Issue: https://github.com/rust-lang/rust-bindgen/issues/2738


Patch:
diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs
index 1fc22416..d6e7ad51 100644
--- a/bindgen/options/mod.rs
+++ b/bindgen/options/mod.rs
@@ -1179,6 +1179,35 @@ options! {
                 self.options.input_headers.push(header.into().into_boxed_str());
                 self
             }
+
+            /// Add input C/C++ header(s) to generate bindings for.
+            ///
+            /// This can be used to generate bindings for a single header:
+            ///
+            /// ```ignore
+            /// let bindings = bindgen::Builder::default()
+            ///     .headers(["input.h"])
+            ///     .generate()
+            ///     .unwrap();
+            /// ```
+            ///
+            /// Or for multiple headers:
+            ///
+            /// ```ignore
+            /// let bindings = bindgen::Builder::default()
+            ///     .headers(["first.h", "second.h", "third.h"])
+            ///     .generate()
+            ///     .unwrap();
+            /// ```
+            pub fn headers<I: IntoIterator>(mut self, headers: I) -> Builder
+            where
+                I::Item: Into<String>,
+            {
+                self.options
+                    .input_headers
+                    .extend(headers.into_iter().map(Into::into).map(Into::into));
+                self
+            }
         },
         // This field is handled specially inside the macro.
         as_args: ignore,


Test patch:
diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs
index 9df45c3b..0e15155d 100644
--- a/bindgen-tests/tests/tests.rs
+++ b/bindgen-tests/tests/tests.rs
@@ -472,6 +472,42 @@ fn test_multiple_header_calls_in_builder() {
     }
 }
 
+#[test]
+fn test_headers_call_in_builder() {
+    let actual = builder()
+        .headers([
+            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h"),
+            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"),
+        ])
+        .clang_arg("--target=x86_64-unknown-linux")
+        .generate()
+        .unwrap()
+        .to_string();
+
+    let actual = format_code(actual).unwrap();
+
+    let expected_filename = concat!(
+        env!("CARGO_MANIFEST_DIR"),
+        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
+    );
+    let expected = include_str!(concat!(
+        env!("CARGO_MANIFEST_DIR"),
+        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
+    ));
+    let expected = format_code(expected).unwrap();
+
+    if actual != expected {
+        println!("Generated bindings differ from expected!");
+        error_diff_mismatch(
+            &actual,
+            &expected,
+            None,
+            Path::new(expected_filename),
+        )
+        .unwrap();
+    }
+}
+
 #[test]
 fn test_multiple_header_contents() {
     let actual = builder()