Files
clang-p2996/libc/utils/hdrgen/main.py
Roland McGrath 303f241544 [libc] Make template_header optional for hdrgen (#127259)
This allows a YAML file to omit `template_header` and have no
`.h.def` file.  A default template is generated based purely on
the information in the YAML file.  This should handle most of the
cases.  For now, it's exercised (aside from the hdrgen tests)
only for one of the simplest cases: <ctype.h>.

This includes making the parser notice the "standards" YAML field
at the top (header) level, not just in "functions" lists.  The
standards listed for the header overall and for the individual
functions both feed into how a fully-generated header describes
itself in comments.  To go with this, files using the default
generated template must stick to a new uniform set of spellings
for the "standards" lists.  As more custom template files are
retired, the corresponding YAML files will need all their
standards lists normalized.  For now, ctype.yaml is updated
with correct attribution for the POSIX `_l` extensions.
2025-02-14 14:01:18 -08:00

86 lines
2.4 KiB
Python
Executable File

#!/usr/bin/env python3
#
# ===- Generate headers for libc functions ------------------*- python -*--==#
#
# 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
#
# ==------------------------------------------------------------------------==#
import argparse
import sys
from pathlib import Path
from header import HeaderFile
from yaml_to_classes import load_yaml_file, fill_public_api
def main():
parser = argparse.ArgumentParser(description="Generate header files from YAML")
parser.add_argument(
"yaml_file",
help="Path to the YAML file containing header specification",
metavar="FILE",
type=Path,
nargs=1,
)
parser.add_argument(
"-o",
"--output",
help="Path to write generated header file",
type=Path,
required=True,
)
parser.add_argument(
"--depfile",
help="Path to write a depfile",
type=Path,
)
parser.add_argument(
"--write-if-changed",
help="Write the output file only if its contents have changed",
action="store_true",
default=False,
)
parser.add_argument(
"-e",
"--entry-point",
help="Entry point to include; may be given many times",
metavar="SYMBOL",
action="append",
)
args = parser.parse_args()
[yaml_file] = args.yaml_file
files_read = {yaml_file}
def write_depfile():
if not args.depfile:
return
deps = " ".join(str(f) for f in sorted(files_read))
args.depfile.parent.mkdir(parents=True, exist_ok=True)
with open(args.depfile, "w") as depfile:
depfile.write(f"{args.output}: {deps}\n")
header = load_yaml_file(yaml_file, HeaderFile, args.entry_point)
# The header_template path is relative to the containing YAML file.
template = header.template(yaml_file.parent, files_read)
contents = fill_public_api(header.public_api(), template)
write_depfile()
if (
not args.write_if_changed
or not args.output.exists()
or args.output.read_text() != contents
):
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(contents)
if __name__ == "__main__":
sys.exit(main())