PageRenderTime 95ms CodeModel.GetById 73ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/ctypes/macholib/dyld.py

http://unladen-swallow.googlecode.com/
Python | 169 lines | 112 code | 27 blank | 30 comment | 38 complexity | 5081f04e74aefc449d1288bc4784f54a MD5 | raw file
  1######################################################################
  2#  This file should be kept compatible with Python 2.3, see PEP 291. #
  3######################################################################
  4"""
  5dyld emulation
  6"""
  7
  8import os
  9from framework import framework_info
 10from dylib import dylib_info
 11from itertools import *
 12
 13__all__ = [
 14    'dyld_find', 'framework_find',
 15    'framework_info', 'dylib_info',
 16]
 17
 18# These are the defaults as per man dyld(1)
 19#
 20DEFAULT_FRAMEWORK_FALLBACK = [
 21    os.path.expanduser("~/Library/Frameworks"),
 22    "/Library/Frameworks",
 23    "/Network/Library/Frameworks",
 24    "/System/Library/Frameworks",
 25]
 26
 27DEFAULT_LIBRARY_FALLBACK = [
 28    os.path.expanduser("~/lib"),
 29    "/usr/local/lib",
 30    "/lib",
 31    "/usr/lib",
 32]
 33
 34def ensure_utf8(s):
 35    """Not all of PyObjC and Python understand unicode paths very well yet"""
 36    if isinstance(s, unicode):
 37        return s.encode('utf8')
 38    return s
 39
 40def dyld_env(env, var):
 41    if env is None:
 42        env = os.environ
 43    rval = env.get(var)
 44    if rval is None:
 45        return []
 46    return rval.split(':')
 47
 48def dyld_image_suffix(env=None):
 49    if env is None:
 50        env = os.environ
 51    return env.get('DYLD_IMAGE_SUFFIX')
 52
 53def dyld_framework_path(env=None):
 54    return dyld_env(env, 'DYLD_FRAMEWORK_PATH')
 55
 56def dyld_library_path(env=None):
 57    return dyld_env(env, 'DYLD_LIBRARY_PATH')
 58
 59def dyld_fallback_framework_path(env=None):
 60    return dyld_env(env, 'DYLD_FALLBACK_FRAMEWORK_PATH')
 61
 62def dyld_fallback_library_path(env=None):
 63    return dyld_env(env, 'DYLD_FALLBACK_LIBRARY_PATH')
 64
 65def dyld_image_suffix_search(iterator, env=None):
 66    """For a potential path iterator, add DYLD_IMAGE_SUFFIX semantics"""
 67    suffix = dyld_image_suffix(env)
 68    if suffix is None:
 69        return iterator
 70    def _inject(iterator=iterator, suffix=suffix):
 71        for path in iterator:
 72            if path.endswith('.dylib'):
 73                yield path[:-len('.dylib')] + suffix + '.dylib'
 74            else:
 75                yield path + suffix
 76            yield path
 77    return _inject()
 78
 79def dyld_override_search(name, env=None):
 80    # If DYLD_FRAMEWORK_PATH is set and this dylib_name is a
 81    # framework name, use the first file that exists in the framework
 82    # path if any.  If there is none go on to search the DYLD_LIBRARY_PATH
 83    # if any.
 84
 85    framework = framework_info(name)
 86
 87    if framework is not None:
 88        for path in dyld_framework_path(env):
 89            yield os.path.join(path, framework['name'])
 90
 91    # If DYLD_LIBRARY_PATH is set then use the first file that exists
 92    # in the path.  If none use the original name.
 93    for path in dyld_library_path(env):
 94        yield os.path.join(path, os.path.basename(name))
 95
 96def dyld_executable_path_search(name, executable_path=None):
 97    # If we haven't done any searching and found a library and the
 98    # dylib_name starts with "@executable_path/" then construct the
 99    # library name.
100    if name.startswith('@executable_path/') and executable_path is not None:
101        yield os.path.join(executable_path, name[len('@executable_path/'):])
102
103def dyld_default_search(name, env=None):
104    yield name
105
106    framework = framework_info(name)
107
108    if framework is not None:
109        fallback_framework_path = dyld_fallback_framework_path(env)
110        for path in fallback_framework_path:
111            yield os.path.join(path, framework['name'])
112
113    fallback_library_path = dyld_fallback_library_path(env)
114    for path in fallback_library_path:
115        yield os.path.join(path, os.path.basename(name))
116
117    if framework is not None and not fallback_framework_path:
118        for path in DEFAULT_FRAMEWORK_FALLBACK:
119            yield os.path.join(path, framework['name'])
120
121    if not fallback_library_path:
122        for path in DEFAULT_LIBRARY_FALLBACK:
123            yield os.path.join(path, os.path.basename(name))
124
125def dyld_find(name, executable_path=None, env=None):
126    """
127    Find a library or framework using dyld semantics
128    """
129    name = ensure_utf8(name)
130    executable_path = ensure_utf8(executable_path)
131    for path in dyld_image_suffix_search(chain(
132                dyld_override_search(name, env),
133                dyld_executable_path_search(name, executable_path),
134                dyld_default_search(name, env),
135            ), env):
136        if os.path.isfile(path):
137            return path
138    raise ValueError("dylib %s could not be found" % (name,))
139
140def framework_find(fn, executable_path=None, env=None):
141    """
142    Find a framework using dyld semantics in a very loose manner.
143
144    Will take input such as:
145        Python
146        Python.framework
147        Python.framework/Versions/Current
148    """
149    try:
150        return dyld_find(fn, executable_path=executable_path, env=env)
151    except ValueError, e:
152        pass
153    fmwk_index = fn.rfind('.framework')
154    if fmwk_index == -1:
155        fmwk_index = len(fn)
156        fn += '.framework'
157    fn = os.path.join(fn, os.path.basename(fn[:fmwk_index]))
158    try:
159        return dyld_find(fn, executable_path=executable_path, env=env)
160    except ValueError:
161        raise e
162
163def test_dyld_find():
164    env = {}
165    assert dyld_find('libSystem.dylib') == '/usr/lib/libSystem.dylib'
166    assert dyld_find('System.framework/System') == '/System/Library/Frameworks/System.framework/System'
167
168if __name__ == '__main__':
169    test_dyld_find()