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