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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user