1# Copyright (C) 2018 and later: Unicode, Inc. and others. 2# License & terms of use: http://www.unicode.org/copyright.html 3 4# Python 2/3 Compatibility (ICU-20299) 5# TODO(ICU-20301): Remove this. 6from __future__ import print_function 7 8from . import * 9from .. import * 10from .. import utils 11from ..request_types import * 12 13def get_gnumake_rules(build_dirs, requests, makefile_vars, **kwargs): 14 makefile_string = "" 15 16 # Common Variables 17 common_vars = kwargs["common_vars"] 18 for key, value in sorted(makefile_vars.items()): 19 makefile_string += "{KEY} = {VALUE}\n".format( 20 KEY = key, 21 VALUE = value 22 ) 23 makefile_string += "\n" 24 25 # Directories 26 dirs_timestamp_file = "{TMP_DIR}/dirs.timestamp".format(**common_vars) 27 makefile_string += "DIRS = {TIMESTAMP_FILE}\n\n".format( 28 TIMESTAMP_FILE = dirs_timestamp_file 29 ) 30 makefile_string += "{TIMESTAMP_FILE}:\n\t$(MKINSTALLDIRS) {ALL_DIRS}\n\techo timestamp > {TIMESTAMP_FILE}\n\n".format( 31 TIMESTAMP_FILE = dirs_timestamp_file, 32 ALL_DIRS = " ".join(build_dirs).format(**common_vars) 33 ) 34 35 # Generate Rules 36 make_rules = [] 37 for request in requests: 38 make_rules += get_gnumake_rules_helper(request, **kwargs) 39 40 # Main Commands 41 for rule in make_rules: 42 if isinstance(rule, MakeFilesVar): 43 makefile_string += "{NAME} = {FILE_LIST}\n\n".format( 44 NAME = rule.name, 45 FILE_LIST = files_to_makefile(rule.files, wrap = True, **kwargs), 46 ) 47 continue 48 49 if isinstance(rule, MakeStringVar): 50 makefile_string += "define {NAME}\n{CONTENT}\nendef\nexport {NAME}\n\n".format( 51 NAME = rule.name, 52 CONTENT = rule.content 53 ) 54 continue 55 56 assert isinstance(rule, MakeRule) 57 header_line = "{OUT_FILE}: {DEP_FILES} {DEP_LITERALS} | $(DIRS)".format( 58 OUT_FILE = files_to_makefile([rule.output_file], **kwargs), 59 DEP_FILES = files_to_makefile(rule.dep_files, wrap = True, **kwargs), 60 DEP_LITERALS = " ".join(rule.dep_literals) 61 ) 62 63 if len(rule.cmds) == 0: 64 makefile_string += "%s\n\n" % header_line 65 continue 66 67 makefile_string += "{HEADER_LINE}\n{RULE_LINES}\n\n".format( 68 HEADER_LINE = header_line, 69 RULE_LINES = "\n".join("\t%s" % cmd for cmd in rule.cmds) 70 ) 71 72 return makefile_string 73 74def files_to_makefile(files, common_vars, wrap = False, **kwargs): 75 if len(files) == 0: 76 return "" 77 dirnames = [utils.dir_for(file).format(**common_vars) for file in files] 78 join_str = " \\\n\t\t" if wrap and len(files) > 2 else " " 79 if len(files) == 1: 80 return "%s/%s" % (dirnames[0], files[0].filename) 81 elif len(set(dirnames)) == 1: 82 return "$(addprefix %s/,%s)" % (dirnames[0], join_str.join(file.filename for file in files)) 83 else: 84 return join_str.join("%s/%s" % (d, f.filename) for d,f in zip(dirnames, files)) 85 86def get_gnumake_rules_helper(request, common_vars, **kwargs): 87 88 if isinstance(request, PrintFileRequest): 89 var_name = "%s_CONTENT" % request.name.upper() 90 return [ 91 MakeStringVar( 92 name = var_name, 93 content = request.content 94 ), 95 MakeRule( 96 name = request.name, 97 dep_literals = [], 98 dep_files = [], 99 output_file = request.output_file, 100 cmds = [ 101 "echo \"$${VAR_NAME}\" > {MAKEFILENAME}".format( 102 VAR_NAME = var_name, 103 MAKEFILENAME = files_to_makefile([request.output_file], common_vars), 104 **common_vars 105 ) 106 ] 107 ) 108 ] 109 110 111 if isinstance(request, CopyRequest): 112 return [ 113 MakeRule( 114 name = request.name, 115 dep_literals = [], 116 dep_files = [request.input_file], 117 output_file = request.output_file, 118 cmds = ["cp %s %s" % ( 119 files_to_makefile([request.input_file], common_vars), 120 files_to_makefile([request.output_file], common_vars)) 121 ] 122 ) 123 ] 124 125 if isinstance(request, VariableRequest): 126 return [ 127 MakeFilesVar( 128 name = request.name.upper(), 129 files = request.input_files 130 ) 131 ] 132 133 if request.tool.name == "make": 134 cmd_template = "$(MAKE) {ARGS}" 135 elif request.tool.name == "gentest": 136 cmd_template = "$(INVOKE) $(GENTEST) {ARGS}" 137 else: 138 assert isinstance(request.tool, IcuTool) 139 cmd_template = "$(INVOKE) $(TOOLBINDIR)/{TOOL} {{ARGS}}".format( 140 TOOL = request.tool.name 141 ) 142 143 if isinstance(request, SingleExecutionRequest): 144 cmd = utils.format_single_request_command(request, cmd_template, common_vars) 145 dep_files = request.all_input_files() 146 147 if len(request.output_files) > 1: 148 # Special case for multiple output files: Makefile rules should have only one 149 # output file apiece. More information: 150 # https://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html 151 timestamp_var_name = "%s_ALL" % request.name.upper() 152 timestamp_file = TmpFile("%s.timestamp" % request.name) 153 rules = [ 154 MakeFilesVar( 155 name = timestamp_var_name, 156 files = [timestamp_file] 157 ), 158 MakeRule( 159 name = "%s_all" % request.name, 160 dep_literals = [], 161 dep_files = dep_files, 162 output_file = timestamp_file, 163 cmds = [ 164 cmd, 165 "echo timestamp > {MAKEFILENAME}".format( 166 MAKEFILENAME = files_to_makefile([timestamp_file], common_vars) 167 ) 168 ] 169 ) 170 ] 171 for i, file in enumerate(request.output_files): 172 rules += [ 173 MakeRule( 174 name = "%s_%d" % (request.name, i), 175 dep_literals = ["$(%s)" % timestamp_var_name], 176 dep_files = [], 177 output_file = file, 178 cmds = [] 179 ) 180 ] 181 return rules 182 183 elif len(dep_files) > 5: 184 # For nicer printing, for long input lists, use a helper variable. 185 dep_var_name = "%s_DEPS" % request.name.upper() 186 return [ 187 MakeFilesVar( 188 name = dep_var_name, 189 files = dep_files 190 ), 191 MakeRule( 192 name = request.name, 193 dep_literals = ["$(%s)" % dep_var_name], 194 dep_files = [], 195 output_file = request.output_files[0], 196 cmds = [cmd] 197 ) 198 ] 199 200 else: 201 return [ 202 MakeRule( 203 name = request.name, 204 dep_literals = [], 205 dep_files = dep_files, 206 output_file = request.output_files[0], 207 cmds = [cmd] 208 ) 209 ] 210 211 if isinstance(request, RepeatedExecutionRequest): 212 rules = [] 213 dep_literals = [] 214 # To keep from repeating the same dep files many times, make a variable. 215 if len(request.common_dep_files) > 0: 216 dep_var_name = "%s_DEPS" % request.name.upper() 217 dep_literals = ["$(%s)" % dep_var_name] 218 rules += [ 219 MakeFilesVar( 220 name = dep_var_name, 221 files = request.common_dep_files 222 ) 223 ] 224 # Add a rule for each individual file. 225 for loop_vars in utils.repeated_execution_request_looper(request): 226 (_, specific_dep_files, input_file, output_file) = loop_vars 227 name_suffix = input_file[input_file.filename.rfind("/")+1:input_file.filename.rfind(".")] 228 cmd = utils.format_repeated_request_command( 229 request, 230 cmd_template, 231 loop_vars, 232 common_vars 233 ) 234 rules += [ 235 MakeRule( 236 name = "%s_%s" % (request.name, name_suffix), 237 dep_literals = dep_literals, 238 dep_files = specific_dep_files + [input_file], 239 output_file = output_file, 240 cmds = [cmd] 241 ) 242 ] 243 return rules 244 245 assert False 246