xref: /llvm-project/libc/utils/hdrgen/main.py (revision cdbba15c6cd53291358bf95a9a9057042fcbf163)
16ad0dcf6SRoland McGrath#!/usr/bin/env python3
26ad0dcf6SRoland McGrath#
36ad0dcf6SRoland McGrath# ===- Generate headers for libc functions  ------------------*- python -*--==#
46ad0dcf6SRoland McGrath#
56ad0dcf6SRoland McGrath# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
66ad0dcf6SRoland McGrath# See https://llvm.org/LICENSE.txt for license information.
76ad0dcf6SRoland McGrath# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
86ad0dcf6SRoland McGrath#
96ad0dcf6SRoland McGrath# ==------------------------------------------------------------------------==#
106ad0dcf6SRoland McGrath
116ad0dcf6SRoland McGrathimport argparse
126ad0dcf6SRoland McGrathimport sys
136ad0dcf6SRoland McGrathfrom pathlib import Path
146ad0dcf6SRoland McGrath
156ad0dcf6SRoland McGrathfrom header import HeaderFile
166ad0dcf6SRoland McGrathfrom yaml_to_classes import load_yaml_file, fill_public_api
176ad0dcf6SRoland McGrath
186ad0dcf6SRoland McGrath
196ad0dcf6SRoland McGrathdef main():
206ad0dcf6SRoland McGrath    parser = argparse.ArgumentParser(description="Generate header files from YAML")
216ad0dcf6SRoland McGrath    parser.add_argument(
226ad0dcf6SRoland McGrath        "yaml_file",
236ad0dcf6SRoland McGrath        help="Path to the YAML file containing header specification",
246ad0dcf6SRoland McGrath        metavar="FILE",
256ad0dcf6SRoland McGrath        type=Path,
266ad0dcf6SRoland McGrath        nargs=1,
276ad0dcf6SRoland McGrath    )
286ad0dcf6SRoland McGrath    parser.add_argument(
296ad0dcf6SRoland McGrath        "-o",
306ad0dcf6SRoland McGrath        "--output",
316ad0dcf6SRoland McGrath        help="Path to write generated header file",
326ad0dcf6SRoland McGrath        type=Path,
336ad0dcf6SRoland McGrath        required=True,
346ad0dcf6SRoland McGrath    )
356ad0dcf6SRoland McGrath    parser.add_argument(
366ad0dcf6SRoland McGrath        "--depfile",
376ad0dcf6SRoland McGrath        help="Path to write a depfile",
386ad0dcf6SRoland McGrath        type=Path,
396ad0dcf6SRoland McGrath    )
406ad0dcf6SRoland McGrath    parser.add_argument(
41*cdbba15cSRoland McGrath        "--write-if-changed",
42*cdbba15cSRoland McGrath        help="Write the output file only if its contents have changed",
43*cdbba15cSRoland McGrath        action="store_true",
44*cdbba15cSRoland McGrath        default=False,
45*cdbba15cSRoland McGrath    )
46*cdbba15cSRoland McGrath    parser.add_argument(
476ad0dcf6SRoland McGrath        "-e",
486ad0dcf6SRoland McGrath        "--entry-point",
496ad0dcf6SRoland McGrath        help="Entry point to include; may be given many times",
506ad0dcf6SRoland McGrath        metavar="SYMBOL",
516ad0dcf6SRoland McGrath        action="append",
526ad0dcf6SRoland McGrath    )
536ad0dcf6SRoland McGrath    args = parser.parse_args()
546ad0dcf6SRoland McGrath
556ad0dcf6SRoland McGrath    [yaml_file] = args.yaml_file
566ad0dcf6SRoland McGrath    files_read = {yaml_file}
576ad0dcf6SRoland McGrath
586ad0dcf6SRoland McGrath    def write_depfile():
596ad0dcf6SRoland McGrath        if not args.depfile:
606ad0dcf6SRoland McGrath            return
616ad0dcf6SRoland McGrath        deps = " ".join(str(f) for f in sorted(files_read))
626ad0dcf6SRoland McGrath        args.depfile.parent.mkdir(parents=True, exist_ok=True)
636ad0dcf6SRoland McGrath        with open(args.depfile, "w") as depfile:
646ad0dcf6SRoland McGrath            depfile.write(f"{args.output}: {deps}\n")
656ad0dcf6SRoland McGrath
666ad0dcf6SRoland McGrath    header = load_yaml_file(yaml_file, HeaderFile, args.entry_point)
676ad0dcf6SRoland McGrath
686ad0dcf6SRoland McGrath    if not header.template_file:
696ad0dcf6SRoland McGrath        print(f"{yaml_file}: Missing header_template", sys.stderr)
706ad0dcf6SRoland McGrath        return 2
716ad0dcf6SRoland McGrath
726ad0dcf6SRoland McGrath    # The header_template path is relative to the containing YAML file.
736ad0dcf6SRoland McGrath    template_path = yaml_file.parent / header.template_file
746ad0dcf6SRoland McGrath
756ad0dcf6SRoland McGrath    files_read.add(template_path)
766ad0dcf6SRoland McGrath    with open(template_path) as template:
776ad0dcf6SRoland McGrath        contents = fill_public_api(header.public_api(), template.read())
786ad0dcf6SRoland McGrath
796ad0dcf6SRoland McGrath    write_depfile()
806ad0dcf6SRoland McGrath
81*cdbba15cSRoland McGrath    if (
82*cdbba15cSRoland McGrath        not args.write_if_changed
83*cdbba15cSRoland McGrath        or not args.output.exists()
84*cdbba15cSRoland McGrath        or args.output.read_text() != contents
85*cdbba15cSRoland McGrath    ):
866ad0dcf6SRoland McGrath        args.output.parent.mkdir(parents=True, exist_ok=True)
87*cdbba15cSRoland McGrath        args.output.write_text(contents)
886ad0dcf6SRoland McGrath
896ad0dcf6SRoland McGrath
906ad0dcf6SRoland McGrathif __name__ == "__main__":
916ad0dcf6SRoland McGrath    sys.exit(main())
92