vndk-def: Add GenericRefs.classify_lib().

This commit adds classify_lib() function which is a generalization of
is_equivalent_lib().  According to the input library argument, it will
run NEW_LIB, EXPORT_EQUAL, EXPORT_SUPER_SET, and MODIFIED.

Test: ./tests/test_generic_refs.py
Change-Id: I3073efe975be6e08ff67bb31d7fcb2eb8b556230
This commit is contained in:
Logan Chien
2017-02-18 20:06:53 +08:00
parent 2f7f4f4405
commit 984bea8f00
2 changed files with 92 additions and 54 deletions

View File

@@ -13,72 +13,91 @@ from compat import TemporaryDirectory, makedirs
from vndk_definition_tool import GenericRefs
test_dir = None
test_dir_base = None
class MockELF(object):
def __init__(self, exported_symbols):
self.exported_symbols = exported_symbols
class MockLib(object):
def __init__(self, path, exported_symbols):
self.path = path
self.elf = MockELF(exported_symbols)
class GenericRefsTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
if test_dir:
cls.test_dir = test_dir
else:
cls.tmp_dir = TemporaryDirectory()
cls.test_dir = cls.tmp_dir.name
cls._build_fixtures()
@classmethod
def tearDownClass(cls):
if not test_dir:
cls.tmp_dir.cleanup()
@classmethod
def _build_fixture(cls, path, content):
def _build_file_fixture(self, path, content):
makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as f:
f.write(content)
@classmethod
def _build_fixtures(cls):
lib32 = os.path.join(cls.test_dir, 'system', 'lib')
lib64 = os.path.join(cls.test_dir, 'system', 'lib64')
def _build_dir_fixtures(self, test_dir):
lib32 = os.path.join(test_dir, 'system', 'lib')
lib64 = os.path.join(test_dir, 'system', 'lib64')
for lib_dir in (lib32, lib64):
cls._build_fixture(os.path.join(lib_dir, 'libc.so.sym'),
'fclose\nfopen\nfread\nfwrite\n')
cls._build_fixture(os.path.join(lib_dir, 'libm.so.sym'),
'cos\nsin\ntan\n')
self._build_file_fixture(os.path.join(lib_dir, 'libc.so.sym'),
'fclose\nfopen\nfread\nfwrite\n')
self._build_file_fixture(os.path.join(lib_dir, 'libm.so.sym'),
'cos\nsin\ntan\n')
def _build_fixture(self):
res = GenericRefs()
res.add('/system/lib/libc.so', {'fclose', 'fopen', 'fread', 'fwrite'})
res.add('/system/lib/libm.so', {'cos', 'sin', 'tan'})
res.add('/system/lib64/libc.so', {'fclose', 'fopen', 'fread', 'fwrite'})
res.add('/system/lib64/libm.so', {'cos', 'sin', 'tan'})
return res
def test_create_from_dir(self):
g = GenericRefs.create_from_dir(self.test_dir)
self.assertEqual(4, len(g.refs))
try:
if test_dir_base:
test_dir = test_dir_base
else:
tmp_dir = TemporaryDirectory()
test_dir = tmp_dir.name
self.assertIn('/system/lib/libc.so', g.refs)
self.assertIn('/system/lib/libm.so', g.refs)
self.assertIn('/system/lib64/libc.so', g.refs)
self.assertIn('/system/lib64/libm.so', g.refs)
self._build_dir_fixtures(test_dir)
g = GenericRefs.create_from_dir(test_dir)
self.assertEqual(4, len(g.refs))
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
g.refs['/system/lib/libc.so'])
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
g.refs['/system/lib64/libc.so'])
self.assertIn('/system/lib/libc.so', g.refs)
self.assertIn('/system/lib/libm.so', g.refs)
self.assertIn('/system/lib64/libc.so', g.refs)
self.assertIn('/system/lib64/libm.so', g.refs)
self.assertEqual({'cos', 'sin', 'tan'},
g.refs['/system/lib/libm.so'])
self.assertEqual({'cos', 'sin', 'tan'},
g.refs['/system/lib64/libm.so'])
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
g.refs['/system/lib/libc.so'])
self.assertEqual({'fclose', 'fopen', 'fread', 'fwrite'},
g.refs['/system/lib64/libc.so'])
self.assertEqual({'cos', 'sin', 'tan'},
g.refs['/system/lib/libm.so'])
self.assertEqual({'cos', 'sin', 'tan'},
g.refs['/system/lib64/libm.so'])
finally:
if not test_dir_base:
tmp_dir.cleanup()
def test_classify_lib(self):
g = self._build_fixture()
libc_sub = MockLib('/system/lib/libc.so', {'fclose', 'fopen', 'fread'})
libc_sup = MockLib('/system/lib/libc.so',
{'fclose', 'fopen', 'fread', 'fwrite', 'open'})
libc_eq = MockLib('/system/lib/libc.so',
{'fclose', 'fopen', 'fread', 'fwrite'})
libfoo = MockLib('/system/lib/libfoo.so', {})
self.assertEqual(GenericRefs.MODIFIED, g.classify_lib(libc_sub))
self.assertEqual(GenericRefs.EXPORT_SUPER_SET, g.classify_lib(libc_sup))
self.assertEqual(GenericRefs.EXPORT_EQUAL, g.classify_lib(libc_eq))
self.assertEqual(GenericRefs.NEW_LIB, g.classify_lib(libfoo))
def test_is_equivalent_lib(self):
g = GenericRefs.create_from_dir(self.test_dir)
class MockELF(object):
def __init__(self, exported_symbols):
self.exported_symbols = exported_symbols
class MockLib(object):
def __init__(self, path, exported_symbols):
self.path = path
self.elf = MockELF(exported_symbols)
g = self._build_fixture()
libc_sub = MockLib('/system/lib/libc.so', {'fclose', 'fopen', 'fread'})
libc_sup = MockLib('/system/lib/libc.so',
@@ -99,10 +118,10 @@ def main():
args, unittest_args = parser.parse_known_args()
# Convert command line options.
global test_dir
global test_dir_base
if args.test_dir:
test_dir = args.test_dir
test_dir_base = args.test_dir
# Run unit test.
unittest.main(argv=[sys.argv[0]] + unittest_args)

View File

@@ -864,9 +864,17 @@ class ELFLinker(object):
#------------------------------------------------------------------------------
class GenericRefs(object):
NEW_LIB = 0
EXPORT_EQUAL = 1
EXPORT_SUPER_SET = 2
MODIFIED = 3
def __init__(self):
self.refs = dict()
def add(self, name, symbols):
self.refs[name] = symbols
def _load_from_dir(self, root):
root = os.path.abspath(root)
prefix_len = len(root) + 1
@@ -877,7 +885,7 @@ class GenericRefs(object):
path = os.path.join(base, filename)
lib_name = '/' + path[prefix_len:-4]
with open(path, 'r') as f:
self.refs[lib_name] = set(line.strip() for line in f)
self.add(lib_name, set(line.strip() for line in f))
@staticmethod
def create_from_dir(root):
@@ -885,8 +893,19 @@ class GenericRefs(object):
result._load_from_dir(root)
return result
def classify_lib(self, lib):
ref_lib_symbols = self.refs.get(lib.path)
if not ref_lib_symbols:
return GenericRefs.NEW_LIB
exported_symbols = lib.elf.exported_symbols
if exported_symbols == ref_lib_symbols:
return GenericRefs.EXPORT_EQUAL
if exported_symbols > ref_lib_symbols:
return GenericRefs.EXPORT_SUPER_SET
return GenericRefs.MODIFIED
def is_equivalent_lib(self, lib):
return self.refs.get(lib.path) == lib.elf.exported_symbols
return self.classify_lib(lib) == GenericRefs.EXPORT_EQUAL
#------------------------------------------------------------------------------