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