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