summaryrefslogtreecommitdiffstats
path: root/libc/utils/build_scripts/gen_hdr.py
diff options
context:
space:
mode:
authorSiva Chandra <sivachandra@google.com>2019-10-04 17:30:54 +0000
committerSiva Chandra <sivachandra@google.com>2019-10-04 17:30:54 +0000
commit4380647e79bd80af1ebf6191c2d6629855ccf556 (patch)
tree35f6a4c1125c9f4b344b4f22081678ef63732c33 /libc/utils/build_scripts/gen_hdr.py
parent717e540f7ea13eb73707b76bf9062a1704fc68b9 (diff)
downloadbcm5719-llvm-4380647e79bd80af1ebf6191c2d6629855ccf556.tar.gz
bcm5719-llvm-4380647e79bd80af1ebf6191c2d6629855ccf556.zip
Add few docs and implementation of strcpy and strcat.
Summary: This patch illustrates some of the features like modularity we want in the new libc. Few other ideas like different kinds of testing, redirectors etc are not yet present. Reviewers: dlj, hfinkel, theraven, jfb, alexshap, jdoerfert Subscribers: mgorny, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67867 llvm-svn: 373764
Diffstat (limited to 'libc/utils/build_scripts/gen_hdr.py')
-rwxr-xr-xlibc/utils/build_scripts/gen_hdr.py188
1 files changed, 188 insertions, 0 deletions
diff --git a/libc/utils/build_scripts/gen_hdr.py b/libc/utils/build_scripts/gen_hdr.py
new file mode 100755
index 00000000000..54ee0063a02
--- /dev/null
+++ b/libc/utils/build_scripts/gen_hdr.py
@@ -0,0 +1,188 @@
+#! /usr/bin/python
+#===---------------- Script to generate header files ----------------------===#
+#
+# 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
+#
+#===-----------------------------------------------------------------------===#
+#
+# This script takes a .h.def file and generates a .h header file.
+# See docs/header_generation.md for more information.
+#
+#===-----------------------------------------------------------------------===#
+
+import argparse
+import contextlib
+import os
+import sys
+
+COMMAND_PREFIX = "%%"
+COMMENT_PREFIX = "<!>"
+
+BEGIN_COMMAND = "begin"
+COMMENT_COMMAND = "comment"
+INCLUDE_FILE_COMMAND = "include_file"
+
+
+class _Location(object):
+ def __init__(self, filename, line_number):
+ self.filename = filename
+ self.line_number = line_number
+
+ def __str__(self):
+ return "%s:%s" % (self.filename, self.line_number)
+
+
+@contextlib.contextmanager
+def output_stream_manager(filename):
+ if filename is None:
+ try:
+ yield sys.stdout
+ finally:
+ pass
+ else:
+ output_stream = open(filename, "w")
+ try:
+ yield output_stream
+ finally:
+ output_stream.close()
+
+
+def _parse_command(loc, line):
+ open_paren = line.find("(")
+ if open_paren < 0 or line[-1] != ")":
+ return _fatal_error(loc, "Incorrect header generation command syntax.")
+ command_name = line[len(COMMAND_PREFIX):open_paren]
+ args = line[open_paren + 1:-1].split(",")
+ args = [a.strip() for a in args]
+ if len(args) == 1 and not args[0]:
+ # There are no args, so we will make the args list an empty list.
+ args = []
+ return command_name.strip(), args
+
+
+def _is_named_arg(token):
+ if token.startswith("${") and token.endswith("}"):
+ return True
+ else:
+ return False
+
+
+def _get_arg_name(token):
+ return token[2:-1]
+
+
+def _fatal_error(loc, msg):
+ sys.exit("ERROR:%s: %s" % (loc, msg))
+
+
+def _is_begin_command(line):
+ if line.startswith(COMMAND_PREFIX + BEGIN_COMMAND):
+ return True
+
+
+def include_file_command(out_stream, loc, args, values):
+ if len(args) != 1:
+ _fatal_error(loc, "`%%include_file` command takes exactly one "
+ "argument. %d given." % len(args))
+ include_file_path = args[0]
+ if _is_named_arg(include_file_path):
+ arg_name = _get_arg_name(include_file_path)
+ include_file_path = values.get(arg_name)
+ if not include_file_path:
+ _fatal_error(
+ loc,
+ "No value specified for argument '%s'." % arg_name)
+ if not os.path.exists(include_file_path):
+ _fatal_error(
+ loc,
+ "Include file %s not found." % include_file_path)
+ with open(include_file_path, "r") as include_file:
+ begin = False
+ for line in include_file.readlines():
+ line = line.strip()
+ if _is_begin_command(line):
+ # Parse the command to make sure there are no errors.
+ command_name, args = _parse_command(loc, line)
+ if args:
+ _fatal_error(loc, "Begin command does not take any args.")
+ begin = True
+ # Skip the line on which %%begin() is listed.
+ continue
+ if begin:
+ out_stream.write(line + "\n")
+
+
+def begin_command(out_stream, loc, args, values):
+ # "begin" command can only occur in a file included with %%include_file
+ # command. It is not a replacement command. Hence, we just fail with
+ # a fatal error.
+ _fatal_error(loc, "Begin command cannot be listed in an input file.")
+
+
+# Mapping from a command name to its implementation function.
+REPLACEMENT_COMMANDS = {
+ INCLUDE_FILE_COMMAND: include_file_command,
+ BEGIN_COMMAND: begin_command,
+}
+
+
+def apply_replacement_command(out_stream, loc, line, values):
+ if not line.startswith(COMMAND_PREFIX):
+ # This line is not a replacement command.
+ return line
+ command_name, args = _parse_command(loc, line)
+ command = REPLACEMENT_COMMANDS.get(command_name.strip())
+ if not command:
+ _fatal_error(loc, "Unknown replacement command `%`", command_name)
+ command(out_stream, loc, args, values)
+
+
+def parse_options():
+ parser = argparse.ArgumentParser(
+ description="Script to generate header files from .def files.")
+ parser.add_argument("def_file", metavar="DEF_FILE",
+ help="Path to the .def file.")
+ parser.add_argument("--args", "-P", nargs= "*", default=[],
+ help="NAME=VALUE pairs for command arguments in the "
+ "input .def file.")
+ # The output file argument is optional. If not specified, the generated
+ # header file content will be written to stdout.
+ parser.add_argument("--out-file", "-o",
+ help="Path to the generated header file. Defaults to "
+ "stdout")
+ opts = parser.parse_args()
+ if not all(["=" in arg for arg in opts.args]):
+ # We want all args to be specified in the form "name=value".
+ _fatal_error(
+ __file__ + ":" + "[command line]",
+ "Command arguments should be listed in the form NAME=VALUE")
+ return opts
+
+
+def main():
+ opts = parse_options()
+ arg_values = {}
+ for name_value_pair in opts.args:
+ name, value = name_value_pair.split("=")
+ arg_values[name] = value
+ with open(opts.def_file, "r") as def_file:
+ loc = _Location(opts.def_file, 0)
+ with output_stream_manager(opts.out_file) as out_stream:
+ for line in def_file:
+ loc.line_number += 1
+ line = line.strip()
+ if line.startswith(COMMAND_PREFIX):
+ replacement_text = apply_replacement_command(
+ out_stream, loc, line, arg_values)
+ out_stream.write("\n")
+ elif line.startswith(COMMENT_PREFIX):
+ # Ignore comment line
+ continue
+ else:
+ out_stream.write(line + "\n")
+
+
+if __name__ == "__main__":
+ main()
OpenPOWER on IntegriCloud