| Index: source/test/depstest/depstest.py
|
| diff --git a/source/test/depstest/depstest.py b/source/test/depstest/depstest.py
|
| deleted file mode 100755
|
| index 0dc8cfe3ced3cdbae4c325f1c2e7aa6849cae4af..0000000000000000000000000000000000000000
|
| --- a/source/test/depstest/depstest.py
|
| +++ /dev/null
|
| @@ -1,198 +0,0 @@
|
| -#! /usr/bin/python
|
| -# -*- coding: utf-8 -*-
|
| -#
|
| -# Copyright (C) 2011-2015, International Business Machines
|
| -# Corporation and others. All Rights Reserved.
|
| -#
|
| -# file name: depstest.py
|
| -#
|
| -# created on: 2011may24
|
| -
|
| -"""ICU dependency tester.
|
| -
|
| -This probably works only on Linux.
|
| -
|
| -The exit code is 0 if everything is fine, 1 for errors, 2 for only warnings.
|
| -
|
| -Sample invocation:
|
| - ~/svn.icu/trunk/src/source/test/depstest$ ./depstest.py ~/svn.icu/trunk/dbg
|
| -"""
|
| -
|
| -__author__ = "Markus W. Scherer"
|
| -
|
| -import glob
|
| -import os.path
|
| -import subprocess
|
| -import sys
|
| -
|
| -import dependencies
|
| -
|
| -_ignored_symbols = set()
|
| -_obj_files = {}
|
| -_symbols_to_files = {}
|
| -_return_value = 0
|
| -
|
| -# Classes with vtables (and thus virtual methods).
|
| -_virtual_classes = set()
|
| -# Classes with weakly defined destructors.
|
| -# nm shows a symbol class of "W" rather than "T".
|
| -_weak_destructors = set()
|
| -
|
| -def _ReadObjFile(root_path, library_name, obj_name):
|
| - global _ignored_symbols, _obj_files, _symbols_to_files
|
| - global _virtual_classes, _weak_destructors
|
| - lib_obj_name = library_name + "/" + obj_name
|
| - if lib_obj_name in _obj_files:
|
| - print "Warning: duplicate .o file " + lib_obj_name
|
| - _return_value = 2
|
| - return
|
| -
|
| - path = os.path.join(root_path, library_name, obj_name)
|
| - nm_result = subprocess.Popen(["nm", "--demangle", "--format=sysv",
|
| - "--extern-only", "--no-sort", path],
|
| - stdout=subprocess.PIPE).communicate()[0]
|
| - obj_imports = set()
|
| - obj_exports = set()
|
| - for line in nm_result.splitlines():
|
| - fields = line.split("|")
|
| - if len(fields) == 1: continue
|
| - name = fields[0].strip()
|
| - # Ignore symbols like '__cxa_pure_virtual',
|
| - # 'vtable for __cxxabiv1::__si_class_type_info' or
|
| - # 'DW.ref.__gxx_personality_v0'.
|
| - # '__dso_handle' belongs to __cxa_atexit().
|
| - if (name.startswith("__cxa") or "__cxxabi" in name or "__gxx" in name or
|
| - name == "__dso_handle"):
|
| - _ignored_symbols.add(name)
|
| - continue
|
| - type = fields[2].strip()
|
| - if type == "U":
|
| - obj_imports.add(name)
|
| - else:
|
| - obj_exports.add(name)
|
| - _symbols_to_files[name] = lib_obj_name
|
| - # Is this a vtable? E.g., "vtable for icu_49::ByteSink".
|
| - if name.startswith("vtable for icu"):
|
| - _virtual_classes.add(name[name.index("::") + 2:])
|
| - # Is this a destructor? E.g., "icu_49::ByteSink::~ByteSink()".
|
| - index = name.find("::~")
|
| - if index >= 0 and type == "W":
|
| - _weak_destructors.add(name[index + 3:name.index("(", index)])
|
| - _obj_files[lib_obj_name] = {"imports": obj_imports, "exports": obj_exports}
|
| -
|
| -def _ReadLibrary(root_path, library_name):
|
| - obj_paths = glob.glob(os.path.join(root_path, library_name, "*.o"))
|
| - for path in obj_paths:
|
| - _ReadObjFile(root_path, library_name, os.path.basename(path))
|
| -
|
| -def _Resolve(name, parents):
|
| - global _ignored_symbols, _obj_files, _symbols_to_files, _return_value
|
| - item = dependencies.items[name]
|
| - item_type = item["type"]
|
| - if name in parents:
|
| - sys.exit("Error: %s %s has a circular dependency on itself: %s" %
|
| - (item_type, name, parents))
|
| - # Check if already cached.
|
| - exports = item.get("exports")
|
| - if exports != None: return item
|
| - # Calculcate recursively.
|
| - parents.append(name)
|
| - imports = set()
|
| - exports = set()
|
| - system_symbols = item.get("system_symbols")
|
| - if system_symbols == None: system_symbols = item["system_symbols"] = set()
|
| - files = item.get("files")
|
| - if files:
|
| - for file_name in files:
|
| - obj_file = _obj_files[file_name]
|
| - imports |= obj_file["imports"]
|
| - exports |= obj_file["exports"]
|
| - imports -= exports | _ignored_symbols
|
| - deps = item.get("deps")
|
| - if deps:
|
| - for dep in deps:
|
| - dep_item = _Resolve(dep, parents)
|
| - # Detect whether this item needs to depend on dep,
|
| - # except when this item has no files, that is, when it is just
|
| - # a deliberate umbrella group or library.
|
| - dep_exports = dep_item["exports"]
|
| - dep_system_symbols = dep_item["system_symbols"]
|
| - if files and imports.isdisjoint(dep_exports) and imports.isdisjoint(dep_system_symbols):
|
| - print "Info: %s %s does not need to depend on %s\n" % (item_type, name, dep)
|
| - # We always include the dependency's exports, even if we do not need them
|
| - # to satisfy local imports.
|
| - exports |= dep_exports
|
| - system_symbols |= dep_system_symbols
|
| - item["exports"] = exports
|
| - item["system_symbols"] = system_symbols
|
| - imports -= exports | system_symbols
|
| - for symbol in imports:
|
| - for file_name in files:
|
| - if symbol in _obj_files[file_name]["imports"]:
|
| - neededFile = _symbols_to_files.get(symbol)
|
| - if neededFile in dependencies.file_to_item:
|
| - neededItem = "but %s does not depend on %s (for %s)" % (name, dependencies.file_to_item[neededFile], neededFile)
|
| - else:
|
| - neededItem = "- is this a new system symbol?"
|
| - sys.stderr.write("Error: in %s %s: %s imports %s %s\n" %
|
| - (item_type, name, file_name, symbol, neededItem))
|
| - _return_value = 1
|
| - del parents[-1]
|
| - return item
|
| -
|
| -def Process(root_path):
|
| - """Loads dependencies.txt, reads the libraries' .o files, and processes them.
|
| -
|
| - Modifies dependencies.items: Recursively builds each item's system_symbols and exports.
|
| - """
|
| - global _ignored_symbols, _obj_files, _return_value
|
| - global _virtual_classes, _weak_destructors
|
| - dependencies.Load()
|
| - for name_and_item in dependencies.items.iteritems():
|
| - name = name_and_item[0]
|
| - item = name_and_item[1]
|
| - system_symbols = item.get("system_symbols")
|
| - if system_symbols:
|
| - for symbol in system_symbols:
|
| - _symbols_to_files[symbol] = name
|
| - for library_name in dependencies.libraries:
|
| - _ReadLibrary(root_path, library_name)
|
| - o_files_set = set(_obj_files.keys())
|
| - files_missing_from_deps = o_files_set - dependencies.files
|
| - files_missing_from_build = dependencies.files - o_files_set
|
| - if files_missing_from_deps:
|
| - sys.stderr.write("Error: files missing from dependencies.txt:\n%s\n" %
|
| - sorted(files_missing_from_deps))
|
| - _return_value = 1
|
| - if files_missing_from_build:
|
| - sys.stderr.write("Error: files in dependencies.txt but not built:\n%s\n" %
|
| - sorted(files_missing_from_build))
|
| - _return_value = 1
|
| - if not _return_value:
|
| - for library_name in dependencies.libraries:
|
| - _Resolve(library_name, [])
|
| - if not _return_value:
|
| - virtual_classes_with_weak_destructors = _virtual_classes & _weak_destructors
|
| - if virtual_classes_with_weak_destructors:
|
| - sys.stderr.write("Error: Some classes have virtual methods, and "
|
| - "an implicit or inline destructor "
|
| - "(see ICU ticket #8454 for details):\n%s\n" %
|
| - sorted(virtual_classes_with_weak_destructors))
|
| - _return_value = 1
|
| -
|
| -def main():
|
| - global _return_value
|
| - if len(sys.argv) <= 1:
|
| - sys.exit(("Command line error: " +
|
| - "need one argument with the root path to the built ICU libraries/*.o files."))
|
| - Process(sys.argv[1])
|
| - if _ignored_symbols:
|
| - print "Info: ignored symbols:\n%s" % sorted(_ignored_symbols)
|
| - if not _return_value:
|
| - print "OK: Specified and actual dependencies match."
|
| - else:
|
| - print "Error: There were errors, please fix them and re-run. Processing may have terminated abnormally."
|
| - return _return_value
|
| -
|
| -if __name__ == "__main__":
|
| - sys.exit(main())
|
|
|