/Lib/ctypes/macholib/dyld.py

http://unladen-swallow.googlecode.com/ · Python · 169 lines · 112 code · 27 blank · 30 comment · 29 complexity · 5081f04e74aefc449d1288bc4784f54a MD5 · raw file

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