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