blob: dc7052e747019fe62406d7755d2cb702628ac178 [file] [log] [blame]
Thomas Hellerbabddfc2006-03-08 19:56:54 +00001"""
2dyld emulation
3"""
4
5import os
Guido van Rossumbf12cdb2006-08-17 20:24:18 +00006from ctypes.macholib.framework import framework_info
7from ctypes.macholib.dylib import dylib_info
Thomas Hellerbabddfc2006-03-08 19:56:54 +00008from itertools import *
9
10__all__ = [
11 'dyld_find', 'framework_find',
12 'framework_info', 'dylib_info',
13]
14
15# These are the defaults as per man dyld(1)
16#
17DEFAULT_FRAMEWORK_FALLBACK = [
18 os.path.expanduser("~/Library/Frameworks"),
19 "/Library/Frameworks",
20 "/Network/Library/Frameworks",
21 "/System/Library/Frameworks",
22]
23
24DEFAULT_LIBRARY_FALLBACK = [
25 os.path.expanduser("~/lib"),
26 "/usr/local/lib",
27 "/lib",
28 "/usr/lib",
29]
30
Thomas Hellerbabddfc2006-03-08 19:56:54 +000031def dyld_env(env, var):
32 if env is None:
33 env = os.environ
34 rval = env.get(var)
35 if rval is None:
36 return []
37 return rval.split(':')
38
39def dyld_image_suffix(env=None):
40 if env is None:
41 env = os.environ
42 return env.get('DYLD_IMAGE_SUFFIX')
43
44def dyld_framework_path(env=None):
45 return dyld_env(env, 'DYLD_FRAMEWORK_PATH')
46
47def dyld_library_path(env=None):
48 return dyld_env(env, 'DYLD_LIBRARY_PATH')
49
50def dyld_fallback_framework_path(env=None):
51 return dyld_env(env, 'DYLD_FALLBACK_FRAMEWORK_PATH')
52
53def dyld_fallback_library_path(env=None):
54 return dyld_env(env, 'DYLD_FALLBACK_LIBRARY_PATH')
55
56def dyld_image_suffix_search(iterator, env=None):
57 """For a potential path iterator, add DYLD_IMAGE_SUFFIX semantics"""
58 suffix = dyld_image_suffix(env)
59 if suffix is None:
60 return iterator
61 def _inject(iterator=iterator, suffix=suffix):
62 for path in iterator:
63 if path.endswith('.dylib'):
64 yield path[:-len('.dylib')] + suffix + '.dylib'
65 else:
66 yield path + suffix
67 yield path
68 return _inject()
69
70def dyld_override_search(name, env=None):
71 # If DYLD_FRAMEWORK_PATH is set and this dylib_name is a
72 # framework name, use the first file that exists in the framework
73 # path if any. If there is none go on to search the DYLD_LIBRARY_PATH
74 # if any.
75
76 framework = framework_info(name)
77
78 if framework is not None:
79 for path in dyld_framework_path(env):
80 yield os.path.join(path, framework['name'])
81
82 # If DYLD_LIBRARY_PATH is set then use the first file that exists
83 # in the path. If none use the original name.
84 for path in dyld_library_path(env):
85 yield os.path.join(path, os.path.basename(name))
86
87def dyld_executable_path_search(name, executable_path=None):
88 # If we haven't done any searching and found a library and the
89 # dylib_name starts with "@executable_path/" then construct the
90 # library name.
91 if name.startswith('@executable_path/') and executable_path is not None:
92 yield os.path.join(executable_path, name[len('@executable_path/'):])
93
94def dyld_default_search(name, env=None):
95 yield name
96
97 framework = framework_info(name)
98
99 if framework is not None:
100 fallback_framework_path = dyld_fallback_framework_path(env)
101 for path in fallback_framework_path:
102 yield os.path.join(path, framework['name'])
103
104 fallback_library_path = dyld_fallback_library_path(env)
105 for path in fallback_library_path:
106 yield os.path.join(path, os.path.basename(name))
107
108 if framework is not None and not fallback_framework_path:
109 for path in DEFAULT_FRAMEWORK_FALLBACK:
110 yield os.path.join(path, framework['name'])
111
112 if not fallback_library_path:
113 for path in DEFAULT_LIBRARY_FALLBACK:
114 yield os.path.join(path, os.path.basename(name))
115
116def dyld_find(name, executable_path=None, env=None):
117 """
118 Find a library or framework using dyld semantics
119 """
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000120 for path in dyld_image_suffix_search(chain(
121 dyld_override_search(name, env),
122 dyld_executable_path_search(name, executable_path),
123 dyld_default_search(name, env),
124 ), env):
125 if os.path.isfile(path):
126 return path
Collin Wintera73bfee2007-08-30 03:47:13 +0000127 raise ValueError("dylib %s could not be found" % (name,))
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000128
129def framework_find(fn, executable_path=None, env=None):
130 """
131 Find a framework using dyld semantics in a very loose manner.
132
133 Will take input such as:
134 Python
135 Python.framework
136 Python.framework/Versions/Current
137 """
138 try:
139 return dyld_find(fn, executable_path=executable_path, env=env)
Guido van Rossumb940e112007-01-10 16:19:56 +0000140 except ValueError as e:
Thomas Hellerbabddfc2006-03-08 19:56:54 +0000141 pass
142 fmwk_index = fn.rfind('.framework')
143 if fmwk_index == -1:
144 fmwk_index = len(fn)
145 fn += '.framework'
146 fn = os.path.join(fn, os.path.basename(fn[:fmwk_index]))
147 try:
148 return dyld_find(fn, executable_path=executable_path, env=env)
149 except ValueError:
150 raise e
151
152def test_dyld_find():
153 env = {}
154 assert dyld_find('libSystem.dylib') == '/usr/lib/libSystem.dylib'
155 assert dyld_find('System.framework/System') == '/System/Library/Frameworks/System.framework/System'
156
157if __name__ == '__main__':
158 test_dyld_find()