| # 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 |