]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/python/icutools/databuilder/renderers/makefile.py
ICU-66108.tar.gz
[apple/icu.git] / icuSources / python / icutools / databuilder / renderers / makefile.py
diff --git a/icuSources/python/icutools/databuilder/renderers/makefile.py b/icuSources/python/icutools/databuilder/renderers/makefile.py
new file mode 100644 (file)
index 0000000..9b2005b
--- /dev/null
@@ -0,0 +1,245 @@
+# Copyright (C) 2018 and later: Unicode, Inc. and others.
+# License & terms of use: http://www.unicode.org/copyright.html
+
+# Python 2/3 Compatibility (ICU-20299)
+# TODO(ICU-20301): Remove this.
+from __future__ import print_function
+
+from . import *
+from .. import *
+from .. import utils
+from ..request_types import *
+
+def get_gnumake_rules(build_dirs, requests, makefile_vars, **kwargs):
+    makefile_string = ""
+
+    # Common Variables
+    common_vars = kwargs["common_vars"]
+    for key, value in sorted(makefile_vars.items()):
+        makefile_string += "{KEY} = {VALUE}\n".format(
+            KEY = key,
+            VALUE = value
+        )
+    makefile_string += "\n"
+
+    # Directories
+    dirs_timestamp_file = "{TMP_DIR}/dirs.timestamp".format(**common_vars)
+    makefile_string += "DIRS = {TIMESTAMP_FILE}\n\n".format(
+        TIMESTAMP_FILE = dirs_timestamp_file
+    )
+    makefile_string += "{TIMESTAMP_FILE}:\n\t$(MKINSTALLDIRS) {ALL_DIRS}\n\techo timestamp > {TIMESTAMP_FILE}\n\n".format(
+        TIMESTAMP_FILE = dirs_timestamp_file,
+        ALL_DIRS = " ".join(build_dirs).format(**common_vars)
+    )
+
+    # Generate Rules
+    make_rules = []
+    for request in requests:
+        make_rules += get_gnumake_rules_helper(request, **kwargs)
+
+    # Main Commands
+    for rule in make_rules:
+        if isinstance(rule, MakeFilesVar):
+            makefile_string += "{NAME} = {FILE_LIST}\n\n".format(
+                NAME = rule.name,
+                FILE_LIST = files_to_makefile(rule.files, wrap = True, **kwargs),
+            )
+            continue
+
+        if isinstance(rule, MakeStringVar):
+            makefile_string += "define {NAME}\n{CONTENT}\nendef\nexport {NAME}\n\n".format(
+                NAME = rule.name,
+                CONTENT = rule.content
+            )
+            continue
+
+        assert isinstance(rule, MakeRule)
+        header_line = "{OUT_FILE}: {DEP_FILES} {DEP_LITERALS} | $(DIRS)".format(
+            OUT_FILE = files_to_makefile([rule.output_file], **kwargs),
+            DEP_FILES = files_to_makefile(rule.dep_files, wrap = True, **kwargs),
+            DEP_LITERALS = " ".join(rule.dep_literals)
+        )
+
+        if len(rule.cmds) == 0:
+            makefile_string += "%s\n\n" % header_line
+            continue
+
+        makefile_string += "{HEADER_LINE}\n{RULE_LINES}\n\n".format(
+            HEADER_LINE = header_line,
+            RULE_LINES = "\n".join("\t%s" % cmd for cmd in rule.cmds)
+        )
+
+    return makefile_string
+
+def files_to_makefile(files, common_vars, wrap = False, **kwargs):
+    if len(files) == 0:
+        return ""
+    dirnames = [utils.dir_for(file).format(**common_vars) for file in files]
+    join_str = " \\\n\t\t" if wrap and len(files) > 2 else " "
+    if len(files) == 1:
+        return "%s/%s" % (dirnames[0], files[0].filename)
+    elif len(set(dirnames)) == 1:
+        return "$(addprefix %s/,%s)" % (dirnames[0], join_str.join(file.filename for file in files))
+    else:
+        return join_str.join("%s/%s" % (d, f.filename) for d,f in zip(dirnames, files))
+
+def get_gnumake_rules_helper(request, common_vars, **kwargs):
+
+    if isinstance(request, PrintFileRequest):
+        var_name = "%s_CONTENT" % request.name.upper()
+        return [
+            MakeStringVar(
+                name = var_name,
+                content = request.content
+            ),
+            MakeRule(
+                name = request.name,
+                dep_literals = [],
+                dep_files = [],
+                output_file = request.output_file,
+                cmds = [
+                    "echo \"$${VAR_NAME}\" > {MAKEFILENAME}".format(
+                        VAR_NAME = var_name,
+                        MAKEFILENAME = files_to_makefile([request.output_file], common_vars),
+                        **common_vars
+                    )
+                ]
+            )
+        ]
+
+
+    if isinstance(request, CopyRequest):
+        return [
+            MakeRule(
+                name = request.name,
+                dep_literals = [],
+                dep_files = [request.input_file],
+                output_file = request.output_file,
+                cmds = ["cp %s %s" % (
+                    files_to_makefile([request.input_file], common_vars),
+                    files_to_makefile([request.output_file], common_vars))
+                ]
+            )
+        ]
+
+    if isinstance(request, VariableRequest):
+        return [
+            MakeFilesVar(
+                name = request.name.upper(),
+                files = request.input_files
+            )
+        ]
+
+    if request.tool.name == "make":
+        cmd_template = "$(MAKE) {ARGS}"
+    elif request.tool.name == "gentest":
+        cmd_template = "$(INVOKE) $(GENTEST) {ARGS}"
+    else:
+        assert isinstance(request.tool, IcuTool)
+        cmd_template = "$(INVOKE) $(TOOLBINDIR)/{TOOL} {{ARGS}}".format(
+            TOOL = request.tool.name
+        )
+
+    if isinstance(request, SingleExecutionRequest):
+        cmd = utils.format_single_request_command(request, cmd_template, common_vars)
+        dep_files = request.all_input_files()
+
+        if len(request.output_files) > 1:
+            # Special case for multiple output files: Makefile rules should have only one
+            # output file apiece. More information:
+            # https://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html
+            timestamp_var_name = "%s_ALL" % request.name.upper()
+            timestamp_file = TmpFile("%s.timestamp" % request.name)
+            rules = [
+                MakeFilesVar(
+                    name = timestamp_var_name,
+                    files = [timestamp_file]
+                ),
+                MakeRule(
+                    name = "%s_all" % request.name,
+                    dep_literals = [],
+                    dep_files = dep_files,
+                    output_file = timestamp_file,
+                    cmds = [
+                        cmd,
+                        "echo timestamp > {MAKEFILENAME}".format(
+                            MAKEFILENAME = files_to_makefile([timestamp_file], common_vars)
+                        )
+                    ]
+                )
+            ]
+            for i, file in enumerate(request.output_files):
+                rules += [
+                    MakeRule(
+                        name = "%s_%d" % (request.name, i),
+                        dep_literals = ["$(%s)" % timestamp_var_name],
+                        dep_files = [],
+                        output_file = file,
+                        cmds = []
+                    )
+                ]
+            return rules
+
+        elif len(dep_files) > 5:
+            # For nicer printing, for long input lists, use a helper variable.
+            dep_var_name = "%s_DEPS" % request.name.upper()
+            return [
+                MakeFilesVar(
+                    name = dep_var_name,
+                    files = dep_files
+                ),
+                MakeRule(
+                    name = request.name,
+                    dep_literals = ["$(%s)" % dep_var_name],
+                    dep_files = [],
+                    output_file = request.output_files[0],
+                    cmds = [cmd]
+                )
+            ]
+
+        else:
+            return [
+                MakeRule(
+                    name = request.name,
+                    dep_literals = [],
+                    dep_files = dep_files,
+                    output_file = request.output_files[0],
+                    cmds = [cmd]
+                )
+            ]
+
+    if isinstance(request, RepeatedExecutionRequest):
+        rules = []
+        dep_literals = []
+        # To keep from repeating the same dep files many times, make a variable.
+        if len(request.common_dep_files) > 0:
+            dep_var_name = "%s_DEPS" % request.name.upper()
+            dep_literals = ["$(%s)" % dep_var_name]
+            rules += [
+                MakeFilesVar(
+                    name = dep_var_name,
+                    files = request.common_dep_files
+                )
+            ]
+        # Add a rule for each individual file.
+        for loop_vars in utils.repeated_execution_request_looper(request):
+            (_, specific_dep_files, input_file, output_file) = loop_vars
+            name_suffix = input_file[input_file.filename.rfind("/")+1:input_file.filename.rfind(".")]
+            cmd = utils.format_repeated_request_command(
+                request,
+                cmd_template,
+                loop_vars,
+                common_vars
+            )
+            rules += [
+                MakeRule(
+                    name = "%s_%s" % (request.name, name_suffix),
+                    dep_literals = dep_literals,
+                    dep_files = specific_dep_files + [input_file],
+                    output_file = output_file,
+                    cmds = [cmd]
+                )
+            ]
+        return rules
+
+    assert False