• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import os
2import sys
3import unittest
4
5# Bob Ippolito:
6#
7# Ok.. the code to find the filename for __getattr__ should look
8# something like:
9#
10# import os
11# from macholib.dyld import dyld_find
12#
13# def find_lib(name):
14#      possible = ['lib'+name+'.dylib', name+'.dylib',
15#      name+'.framework/'+name]
16#      for dylib in possible:
17#          try:
18#              return os.path.realpath(dyld_find(dylib))
19#          except ValueError:
20#              pass
21#      raise ValueError, "%s not found" % (name,)
22#
23# It'll have output like this:
24#
25#  >>> find_lib('pthread')
26# '/usr/lib/libSystem.B.dylib'
27#  >>> find_lib('z')
28# '/usr/lib/libz.1.dylib'
29#  >>> find_lib('IOKit')
30# '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit'
31#
32# -bob
33
34from ctypes.macholib.dyld import dyld_find
35from ctypes.macholib.dylib import dylib_info
36from ctypes.macholib.framework import framework_info
37
38def find_lib(name):
39    possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name]
40    for dylib in possible:
41        try:
42            return os.path.realpath(dyld_find(dylib))
43        except ValueError:
44            pass
45    raise ValueError("%s not found" % (name,))
46
47
48def d(location=None, name=None, shortname=None, version=None, suffix=None):
49    return {'location': location, 'name': name, 'shortname': shortname,
50            'version': version, 'suffix': suffix}
51
52
53class MachOTest(unittest.TestCase):
54    @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
55    def test_find(self):
56        self.assertEqual(dyld_find('libSystem.dylib'),
57                         '/usr/lib/libSystem.dylib')
58        self.assertEqual(dyld_find('System.framework/System'),
59                         '/System/Library/Frameworks/System.framework/System')
60
61        # On Mac OS 11, system dylibs are only present in the shared cache,
62        # so symlinks like libpthread.dylib -> libSystem.B.dylib will not
63        # be resolved by dyld_find
64        self.assertIn(find_lib('pthread'),
65                              ('/usr/lib/libSystem.B.dylib', '/usr/lib/libpthread.dylib'))
66
67        result = find_lib('z')
68        # Issue #21093: dyld default search path includes $HOME/lib and
69        # /usr/local/lib before /usr/lib, which caused test failures if
70        # a local copy of libz exists in one of them. Now ignore the head
71        # of the path.
72        self.assertRegex(result, r".*/lib/libz.*\.dylib")
73
74        self.assertIn(find_lib('IOKit'),
75                              ('/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit',
76                              '/System/Library/Frameworks/IOKit.framework/IOKit'))
77
78    @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
79    def test_info(self):
80        self.assertIsNone(dylib_info('completely/invalid'))
81        self.assertIsNone(dylib_info('completely/invalide_debug'))
82        self.assertEqual(dylib_info('P/Foo.dylib'), d('P', 'Foo.dylib', 'Foo'))
83        self.assertEqual(dylib_info('P/Foo_debug.dylib'),
84                         d('P', 'Foo_debug.dylib', 'Foo', suffix='debug'))
85        self.assertEqual(dylib_info('P/Foo.A.dylib'),
86                         d('P', 'Foo.A.dylib', 'Foo', 'A'))
87        self.assertEqual(dylib_info('P/Foo_debug.A.dylib'),
88                         d('P', 'Foo_debug.A.dylib', 'Foo_debug', 'A'))
89        self.assertEqual(dylib_info('P/Foo.A_debug.dylib'),
90                         d('P', 'Foo.A_debug.dylib', 'Foo', 'A', 'debug'))
91
92    @unittest.skipUnless(sys.platform == "darwin", 'OSX-specific test')
93    def test_framework_info(self):
94        self.assertIsNone(framework_info('completely/invalid'))
95        self.assertIsNone(framework_info('completely/invalid/_debug'))
96        self.assertIsNone(framework_info('P/F.framework'))
97        self.assertIsNone(framework_info('P/F.framework/_debug'))
98        self.assertEqual(framework_info('P/F.framework/F'),
99                         d('P', 'F.framework/F', 'F'))
100        self.assertEqual(framework_info('P/F.framework/F_debug'),
101                         d('P', 'F.framework/F_debug', 'F', suffix='debug'))
102        self.assertIsNone(framework_info('P/F.framework/Versions'))
103        self.assertIsNone(framework_info('P/F.framework/Versions/A'))
104        self.assertEqual(framework_info('P/F.framework/Versions/A/F'),
105                         d('P', 'F.framework/Versions/A/F', 'F', 'A'))
106        self.assertEqual(framework_info('P/F.framework/Versions/A/F_debug'),
107                         d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug'))
108
109if __name__ == "__main__":
110    unittest.main()
111