1 #! /usr/bin/python 2 # -*- coding: utf-8 -*- 3 # 4 # Copyright (C) 2011-2014, International Business Machines 5 # Corporation and others. All Rights Reserved. 6 # 7 # file name: dependencies.py 8 # 9 # created on: 2011may26 10 11 """Reader module for dependency data for the ICU dependency tester. 12 13 Reads dependencies.txt and makes the data available. 14 15 Attributes: 16 files: Set of "library/filename.o" files mentioned in the dependencies file. 17 items: Map from library or group names to item maps. 18 Each item has a "type" ("library" or "group" or "system_symbols"). 19 A library or group item can have an optional set of "files" (as in the files attribute). 20 Each item can have an optional set of "deps" (libraries & groups). 21 A group item also has a "library" name unless it is a group of system symbols. 22 The one "system_symbols" item and its groups have sets of "system_symbols" 23 with standard-library system symbol names. 24 libraries: Set of library names mentioned in the dependencies file. 25 file_to_item: Map from a symbol (ushoe.o) to library or group (shoesize) 26 """ 27 __author__ = "Markus W. Scherer" 28 29 # TODO: Support binary items. 30 # .txt syntax: binary: tools/genrb 31 # item contents: {"type": "binary"} with optional files & deps 32 # A binary must not be used as a dependency for anything else. 33 34 import sys 35 36 files = set() 37 items = {} 38 libraries = set() 39 file_to_item = {} 40 41 _line_number = 0 42 _groups_to_be_defined = set() 43 44 def _CheckLibraryName(name): 45 global _line_number 46 if not name: 47 sys.exit("Error:%d: \"library: \" without name" % _line_number) 48 if name.endswith(".o"): 49 sys.exit("Error:%d: invalid library name %s" % (_line_number, name)) 50 51 def _CheckGroupName(name): 52 global _line_number 53 if not name: 54 sys.exit("Error:%d: \"group: \" without name" % _line_number) 55 if "/" in name or name.endswith(".o"): 56 sys.exit("Error:%d: invalid group name %s" % (_line_number, name)) 57 58 def _CheckFileName(name): 59 global _line_number 60 if "/" in name or not name.endswith(".o"): 61 sys.exit("Error:%d: invalid file name %s" % (_line_number, name)) 62 63 def _RemoveComment(line): 64 global _line_number 65 _line_number = _line_number + 1 66 index = line.find("#") # Remove trailing comment. 67 if index >= 0: line = line[:index] 68 return line.rstrip() # Remove trailing newlines etc. 69 70 def _ReadLine(f): 71 while True: 72 line = _RemoveComment(f.next()) 73 if line: return line 74 75 def _ReadFiles(deps_file, item, library_name): 76 global files 77 item_files = item.get("files") 78 while True: 79 line = _ReadLine(deps_file) 80 if not line: continue 81 if not line.startswith(" "): return line 82 if item_files == None: item_files = item["files"] = set() 83 for file_name in line.split(): 84 _CheckFileName(file_name) 85 file_name = library_name + "/" + file_name 86 if file_name in files: 87 sys.exit("Error:%d: file %s listed in multiple groups" % (_line_number, file_name)) 88 files.add(file_name) 89 item_files.add(file_name) 90 file_to_item[file_name] = item["name"] 91 92 def _IsLibrary(item): return item and item["type"] == "library" 93 94 def _IsLibraryGroup(item): return item and "library" in item 95 96 def _ReadDeps(deps_file, item, library_name): 97 global items, _line_number, _groups_to_be_defined 98 item_deps = item.get("deps") 99 while True: 100 line = _ReadLine(deps_file) 101 if not line: continue 102 if not line.startswith(" "): return line 103 if item_deps == None: item_deps = item["deps"] = set() 104 for dep in line.split(): 105 _CheckGroupName(dep) 106 dep_item = items.get(dep) 107 if item["type"] == "system_symbols" and (_IsLibraryGroup(dep_item) or _IsLibrary(dep_item)): 108 sys.exit(("Error:%d: system_symbols depend on previously defined " + 109 "library or library group %s") % (_line_number, dep)) 110 if dep_item == None: 111 # Add this dependency as a new group. 112 items[dep] = {"type": "group"} 113 if library_name: items[dep]["library"] = library_name 114 _groups_to_be_defined.add(dep) 115 item_deps.add(dep) 116 117 def _AddSystemSymbol(item, symbol): 118 exports = item.get("system_symbols") 119 if exports == None: exports = item["system_symbols"] = set() 120 exports.add(symbol) 121 122 def _ReadSystemSymbols(deps_file, item): 123 global _line_number 124 while True: 125 line = _ReadLine(deps_file) 126 if not line: continue 127 if not line.startswith(" "): return line 128 line = line.lstrip() 129 if '"' in line: 130 # One double-quote-enclosed symbol on the line, allows spaces in a symbol name. 131 symbol = line[1:-1] 132 if line.startswith('"') and line.endswith('"') and '"' not in symbol: 133 _AddSystemSymbol(item, symbol) 134 else: 135 sys.exit("Error:%d: invalid quoted symbol name %s" % (_line_number, line)) 136 else: 137 # One or more space-separate symbols. 138 for symbol in line.split(): _AddSystemSymbol(item, symbol) 139 140 def Load(): 141 """Reads "dependencies.txt" and populates the module attributes.""" 142 global items, libraries, _line_number, _groups_to_be_defined 143 deps_file = open("dependencies.txt") 144 try: 145 line = None 146 current_type = None 147 while True: 148 while not line: line = _RemoveComment(deps_file.next()) 149 150 if line.startswith("library: "): 151 current_type = "library" 152 name = line[9:].lstrip() 153 _CheckLibraryName(name) 154 if name in items: 155 sys.exit("Error:%d: library definition using duplicate name %s" % (_line_number, name)) 156 libraries.add(name) 157 item = items[name] = {"type": "library", "name": name} 158 line = _ReadFiles(deps_file, item, name) 159 elif line.startswith("group: "): 160 current_type = "group" 161 name = line[7:].lstrip() 162 _CheckGroupName(name) 163 if name not in items: 164 sys.exit("Error:%d: group %s defined before mentioned as a dependency" % 165 (_line_number, name)) 166 if name not in _groups_to_be_defined: 167 sys.exit("Error:%d: group definition using duplicate name %s" % (_line_number, name)) 168 _groups_to_be_defined.remove(name) 169 item = items[name] 170 item["name"] = name 171 library_name = item.get("library") 172 if library_name: 173 line = _ReadFiles(deps_file, item, library_name) 174 else: 175 line = _ReadSystemSymbols(deps_file, item) 176 elif line == " deps": 177 if current_type == "library": 178 line = _ReadDeps(deps_file, items[name], name) 179 elif current_type == "group": 180 item = items[name] 181 line = _ReadDeps(deps_file, item, item.get("library")) 182 elif current_type == "system_symbols": 183 item = items[current_type] 184 line = _ReadDeps(deps_file, item, None) 185 else: 186 sys.exit("Error:%d: deps before any library or group" % _line_number) 187 elif line == "system_symbols:": 188 current_type = "system_symbols" 189 if current_type in items: 190 sys.exit("Error:%d: duplicate entry for system_symbols" % _line_number) 191 item = items[current_type] = {"type": current_type, "name": current_type} 192 line = _ReadSystemSymbols(deps_file, item) 193 else: 194 sys.exit("Syntax error:%d: %s" % (_line_number, line)) 195 except StopIteration: 196 pass 197 if _groups_to_be_defined: 198 sys.exit("Error: some groups mentioned in dependencies are undefined: %s" % _groups_to_be_defined) 199