From 968b6aaef1c543e126d8f63bcdadea1e8164d8b6 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Thu, 26 Mar 2026 13:02:34 -0700 Subject: [PATCH] [libc][hdrgen] Print __BEGIN_C_DECLS / __END_C_DECLS conditionally. (#188830) 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 1af741844bd0..e2ebbdb6e519 100644 --- a/libc/utils/hdrgen/hdrgen/header.py +++ b/libc/utils/hdrgen/hdrgen/header.py @@ -280,9 +280,14 @@ class HeaderFile: 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 @@ class HeaderFile: 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 000000000000..dde3ca288016 --- /dev/null +++ b/libc/utils/hdrgen/tests/expected_output/macro_only.h @@ -0,0 +1,16 @@ +//===-- Standard C header --===// +// +// 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 000000000000..84c2b31781e8 --- /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 diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py index 4ec3fa566c00..8848afe29d50 100644 --- a/libc/utils/hdrgen/tests/test_integration.py +++ b/libc/utils/hdrgen/tests/test_integration.py @@ -82,13 +82,20 @@ class TestHeaderGenIntegration(unittest.TestCase): 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(