[libc-commits] [libc] [libc][hdrgen] Print __BEGIN_C_DECLS / __END_C_DECLS conditionally. (PR #188830)

Alexey Samsonov via libc-commits libc-commits at lists.llvm.org
Thu Mar 26 12:53:17 PDT 2026


https://github.com/vonosmas updated https://github.com/llvm/llvm-project/pull/188830

>From 5a05dbf4427f1be2ffc8ecc18d543056d1b0ccf5 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 26 Mar 2026 19:29:19 +0000
Subject: [PATCH 1/2] [libc][hdrgen] Print __BEGIN_C_DECLS / __END_C_DECLS
 conditionally.

Clean up the %public_api printer code slightly - get rid of explicit
`\n` and ensure we only print __BEGIN_C_DECLS and __END_C_DECLS if the
generated header actually contains functions or objects to declare.

I've noticed that after 27ba9e2a44c11f8123528c350227db2c9a707c8f
landed, generated errno.h header has two blocks of __BEGIN_C_DECLS /
__END_C_DECLS: an empty one was generated automatically from
%public_api section that was intended to only add the errno_t
type declaration.
---
 libc/utils/hdrgen/hdrgen/header.py               | 12 ++++++++++--
 .../hdrgen/tests/expected_output/macro_only.h    | 16 ++++++++++++++++
 libc/utils/hdrgen/tests/input/macro_only.yaml    |  6 ++++++
 libc/utils/hdrgen/tests/test_integration.py      |  9 ++++++++-
 4 files changed, 40 insertions(+), 3 deletions(-)
 create mode 100644 libc/utils/hdrgen/tests/expected_output/macro_only.h
 create mode 100644 libc/utils/hdrgen/tests/input/macro_only.yaml

diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py
index 1af741844bd01..e2ebbdb6e519a 100644
--- a/libc/utils/hdrgen/hdrgen/header.py
+++ b/libc/utils/hdrgen/hdrgen/header.py
@@ -280,9 +280,14 @@ def public_api(self):
             self.include_lines(self.template_file is None)
             + self.macro_lines()
             + self.enum_lines()
-            + ["\n__BEGIN_C_DECLS\n"]
         )
+        content.append("")
+        has_decls = self.functions or self.objects
+        if has_decls:
+            content.append("__BEGIN_C_DECLS")
+            content.append("")
 
+        # Emit function declarations.
         current_guard = None
         last_name = None
         for function in sorted(self.functions):
@@ -317,10 +322,13 @@ def public_api(self):
             content.append(f"#endif // {current_guard}")
             content.append("")
 
+        # Emit object declarations.
         content.extend(str(object) for object in self.objects)
         if self.objects:
             content.append("")
-        content.append("__END_C_DECLS")
+
+        if has_decls:
+            content.append("__END_C_DECLS")
 
         return "\n".join(content)
 
diff --git a/libc/utils/hdrgen/tests/expected_output/macro_only.h b/libc/utils/hdrgen/tests/expected_output/macro_only.h
new file mode 100644
index 0000000000000..dde3ca288016c
--- /dev/null
+++ b/libc/utils/hdrgen/tests/expected_output/macro_only.h
@@ -0,0 +1,16 @@
+//===-- Standard C header <macro_only.h> --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LLVM_LIBC_MACRO_ONLY_H
+#define _LLVM_LIBC_MACRO_ONLY_H
+
+#include "__llvm-libc-common.h"
+
+#define MACRO_A 1
+
+#endif // _LLVM_LIBC_MACRO_ONLY_H
diff --git a/libc/utils/hdrgen/tests/input/macro_only.yaml b/libc/utils/hdrgen/tests/input/macro_only.yaml
new file mode 100644
index 0000000000000..6e40738853ff0
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/macro_only.yaml
@@ -0,0 +1,6 @@
+header: macro_only.h
+standards:
+  - stdc
+macros:
+  - macro_name: MACRO_A
+    macro_value: 1
\ No newline at end of file
diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py
index 4ec3fa566c003..8848afe29d50f 100644
--- a/libc/utils/hdrgen/tests/test_integration.py
+++ b/libc/utils/hdrgen/tests/test_integration.py
@@ -82,13 +82,20 @@ def test_sorting(self):
         self.run_script(yaml_file, output_file)
         self.compare_files(output_file, expected_output_file)
 
-    def test_generate_header(self):
+    def test_generate_proxy_header(self):
         yaml_file = self.source_dir / "input/test_small.yaml"
         expected_output_file = self.source_dir / "expected_output/test_small_proxy.h"
         output_file = self.output_dir / "test_small.h"
         self.run_script(yaml_file, output_file, switches=["--proxy"])
         self.compare_files(output_file, expected_output_file)
 
+    def test_generate_macro_only_header(self):
+        yaml_file = self.source_dir / "input/macro_only.yaml"
+        expected_output_file = self.source_dir / "expected_output/macro_only.h"
+        output_file = self.output_dir / "macro_only.h"
+        self.run_script(yaml_file, output_file)
+        self.compare_files(output_file, expected_output_file)
+
 def main():
     parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments")
     parser.add_argument(

>From 5982b0700293a2edea706bda9198b403ffbfc8e5 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 26 Mar 2026 19:52:39 +0000
Subject: [PATCH 2/2] add newline

---
 libc/utils/hdrgen/tests/input/macro_only.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/utils/hdrgen/tests/input/macro_only.yaml b/libc/utils/hdrgen/tests/input/macro_only.yaml
index 6e40738853ff0..84c2b31781e8a 100644
--- a/libc/utils/hdrgen/tests/input/macro_only.yaml
+++ b/libc/utils/hdrgen/tests/input/macro_only.yaml
@@ -3,4 +3,4 @@ standards:
   - stdc
 macros:
   - macro_name: MACRO_A
-    macro_value: 1
\ No newline at end of file
+    macro_value: 1



More information about the libc-commits mailing list