Ejemplo n.º 1
0
    def locate(self, filename, loader=None):
        if not isinstance(filename, (str, unicode)):
            raise TypeError("%r is not a string" % (filename,))
        if filename.startswith('@loader_path/') and loader is not None:
            fn = self.trans_table.get((loader.filename, filename))
            if fn is None:
                loader_path = loader.loader_path

                try:
                    fn = dyld_find(
                        filename, env=self.env,
                        executable_path=self.executable_path,
                        loader_path=loader_path)
                    self.trans_table[(loader.filename, filename)] = fn
                except ValueError:
                    return None

        else:
            fn = self.trans_table.get(filename)
            if fn is None:
                try:
                    fn = dyld_find(
                            filename, env=self.env,
                            executable_path=self.executable_path)
                    self.trans_table[filename] = fn
                except ValueError:
                    return None
        return fn
Ejemplo n.º 2
0
    def locate(self, filename, loader=None):
        assert isinstance(filename, (str, unicode))
        if filename.startswith('@loader_path/') and loader is not None:
            fn = self.trans_table.get((loader.filename, filename))
            if fn is None:
                try:
                    fn = dyld_find(filename, env=self.env,
                        executable_path=self.executable_path,
#-----------------------------------------------
                        loader_path=loader.filename) # was loader=loader.filename
#-----------------------------------------------
                    self.trans_table[(loader.filename, filename)] = fn
                except ValueError:
                    return None

        else:
            fn = self.trans_table.get(filename)
            if fn is None:
                try:
                    fn = dyld_find(filename, env=self.env,
                        executable_path=self.executable_path)
                    self.trans_table[filename] = fn
                except ValueError:
                    return None
        return fn
Ejemplo n.º 3
0
    def locate(self, filename, loader=None):
        if not isinstance(filename, (str, unicode)):
            raise TypeError("%r is not a string" % (filename, ))
        if filename.startswith("@loader_path/") and loader is not None:
            fn = self.trans_table.get((loader.filename, filename))
            if fn is None:
                loader_path = loader.loader_path

                try:
                    fn = dyld_find(
                        filename,
                        env=self.env,
                        executable_path=self.executable_path,
                        loader_path=loader_path,
                    )
                    self.trans_table[(loader.filename, filename)] = fn
                except ValueError:
                    return None

        else:
            fn = self.trans_table.get(filename)
            if fn is None:
                try:
                    fn = dyld_find(filename,
                                   env=self.env,
                                   executable_path=self.executable_path)
                    self.trans_table[filename] = fn
                except ValueError:
                    return None
        return fn
Ejemplo n.º 4
0
 def testBasic(self):
     self.assertEqual(dyld.dyld_find("libSystem.dylib"),
                      "/usr/lib/libSystem.dylib")
     self.assertEqual(
         dyld.dyld_find("System.framework/System"),
         "/System/Library/Frameworks/System.framework/System",
     )
Ejemplo n.º 5
0
 def locate(self, filename):
     fn = self.trans_table.get(filename)
     if fn is None:
         try:
             fn = dyld_find(filename, env=self.env,
                 executable_path=self.executable_path)
             self.trans_table[filename] = fn
         except ValueError:
             return None
     return fn
Ejemplo n.º 6
0
 def locate(self, filename):
     assert isinstance(filename, (str, unicode))
     fn = self.trans_table.get(filename)
     if fn is None:
         try:
             fn = dyld_find(filename, env=self.env,
                 executable_path=self.executable_path)
             self.trans_table[filename] = fn
         except ValueError:
             return None
     return fn
Ejemplo n.º 7
0
 def locate(self, filename):
     assert isinstance(filename, (str, unicode))
     fn = self.trans_table.get(filename)
     if fn is None:
         try:
             fn = dyld_find(filename,
                            env=self.env,
                            executable_path=self.executable_path)
             self.trans_table[filename] = fn
         except ValueError:
             return None
     return fn
Ejemplo n.º 8
0
    def test_dyld_find(self):
        result = dyld.dyld_find('/usr/lib/libSystem.dylib')
        self.assertEqual(result, '/usr/lib/libSystem.dylib')
        self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x

        result = dyld.dyld_find(b'/usr/lib/libSystem.dylib'.decode('ascii'))
        self.assertEqual(result, '/usr/lib/libSystem.dylib')
        self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x

        patcher = DyldPatcher()
        try:
            patcher.log_calls('dyld_image_suffix_search')
            patcher.log_calls('dyld_override_search')
            patcher.log_calls('dyld_executable_path_search')
            patcher.log_calls('dyld_default_search')

            result = dyld.dyld_find('/usr/lib/libSystem.dylib')
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', None), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib', env=None)
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', None), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib', env={})
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}),
                ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib', executable_path="/opt/py2app/bin", env={})
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}),
                ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', "/opt/py2app/bin"), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

        finally:
            patcher.cleanup()
Ejemplo n.º 9
0
def _getImports_macholib(pth):
    """
    Find the binary dependencies of PTH.

    This implementation is for Mac OS X and uses library macholib.
    """
    from macholib.MachO import MachO
    from macholib.mach_o import LC_RPATH
    from macholib.dyld import dyld_find
    from macholib.util import in_system_path
    rslt = set()
    seen = set()  # Libraries read from binary headers.

    ## Walk through mach binary headers.

    m = MachO(pth)
    for header in m.headers:
        for idx, name, lib in header.walkRelocatables():
            # Sometimes some libraries are present multiple times.
            if lib not in seen:
                seen.add(lib)

    # Walk through mach binary headers and look for LC_RPATH.
    # macholib can't handle @rpath. LC_RPATH has to be read
    # from the MachO header.
    # TODO Do we need to remove LC_RPATH from MachO load commands?
    #      Will it cause any harm to leave them untouched?
    #      Removing LC_RPATH should be implemented when getting
    #      files from the bincache if it is necessary.
    run_paths = set()
    for header in m.headers:
        for command in header.commands:
            # A command is a tupple like:
            #   (<macholib.mach_o.load_command object at 0x>,
            #    <macholib.mach_o.rpath_command object at 0x>,
            #    '../lib\x00\x00')
            cmd_type = command[0].cmd
            if cmd_type == LC_RPATH:
                rpath = command[2].decode('utf-8')
                # Remove trailing '\x00' characters.
                # e.g. '../lib\x00\x00'
                rpath = rpath.rstrip('\x00')
                # Replace the @executable_path and @loader_path keywords
                # with the actual path to the binary.
                executable_path = os.path.dirname(pth)
                rpath = re.sub('^@(executable_path|loader_path|rpath)(/|$)',
                               executable_path + r'\2', rpath)
                # Make rpath absolute. According to Apple doc LC_RPATH
                # is always relative to the binary location.
                rpath = os.path.normpath(os.path.join(executable_path, rpath))
                run_paths.update([rpath])
            else:
                # Frameworks that have this structure Name.framework/Versions/N/Name
                # need to to search at the same level as the framework dir.
                # This is specifically needed so that the QtWebEngine dependencies
                # can be found.
                if '.framework' in pth:
                    run_paths.update(['../../../'])

    # for distributions like Anaconda, all of the dylibs are stored in the lib directory
    # of the Python distribution, not alongside of the .so's in each module's subdirectory.
    run_paths.add(os.path.join(base_prefix, 'lib'))

    ## Try to find files in file system.

    # In cases with @loader_path or @executable_path
    # try to look in the same directory as the checked binary is.
    # This seems to work in most cases.
    exec_path = os.path.abspath(os.path.dirname(pth))

    for lib in seen:

        # Suppose that @rpath is not used for system libraries and
        # using macholib can be avoided.
        # macholib can't handle @rpath.
        if lib.startswith('@rpath'):
            lib = lib.replace('@rpath', '.')  # Make path relative.
            final_lib = None  # Absolute path to existing lib on disk.
            # Try multiple locations.
            for run_path in run_paths:
                # @rpath may contain relative value. Use exec_path as
                # base path.
                if not os.path.isabs(run_path):
                    run_path = os.path.join(exec_path, run_path)
                # Stop looking for lib when found in first location.
                if os.path.exists(os.path.join(run_path, lib)):
                    final_lib = os.path.abspath(os.path.join(run_path, lib))
                    rslt.add(final_lib)
                    break
            # Log error if no existing file found.
            if not final_lib:
                logger.error('Can not find path %s (needed by %s)', lib, pth)

        # Macholib has to be used to get absolute path to libraries.
        else:
            # macholib can't handle @loader_path. It has to be
            # handled the same way as @executable_path.
            # It is also replaced by 'exec_path'.
            if lib.startswith('@loader_path'):
                lib = lib.replace('@loader_path', '@executable_path')
            try:
                lib = dyld_find(lib, executable_path=exec_path)
                rslt.add(lib)
            except ValueError:
                # Starting with Big Sur, system libraries are hidden. And
                # we do not collect system libraries on any macOS version
                # anyway, so suppress the corresponding error messages.
                if not in_system_path(lib):
                    logger.error('Can not find path %s (needed by %s)', lib,
                                 pth)

    return rslt
Ejemplo n.º 10
0
def _getImports_macholib(pth):
    """
    Find the binary dependencies of PTH.

    This implementation is for Mac OS X and uses library macholib.
    """
    from macholib.MachO import MachO
    from macholib.mach_o import LC_RPATH
    from macholib.dyld import dyld_find
    rslt = set()
    seen = set()  # Libraries read from binary headers.

    ## Walk through mach binary headers.

    m = MachO(pth)
    for header in m.headers:
        for idx, name, lib in header.walkRelocatables():
            # Sometimes some libraries are present multiple times.
            if lib not in seen:
                seen.add(lib)

    # Walk through mach binary headers and look for LC_RPATH.
    # macholib can't handle @rpath. LC_RPATH has to be read
    # from the MachO header.
    # TODO Do we need to remove LC_RPATH from MachO load commands?
    #      Will it cause any harm to leave them untouched?
    #      Removing LC_RPATH should be implemented when getting
    #      files from the bincache if it is necessary.
    run_paths = set()
    for header in m.headers:
        for command in header.commands:
            # A command is a tupple like:
            #   (<macholib.mach_o.load_command object at 0x>,
            #    <macholib.mach_o.rpath_command object at 0x>,
            #    '../lib\x00\x00')
            cmd_type = command[0].cmd
            if cmd_type == LC_RPATH:
                rpath = command[2].decode('utf-8')
                # Remove trailing '\x00' characters.
                # e.g. '../lib\x00\x00'
                rpath = rpath.rstrip('\x00')
                # Replace the @executable_path and @loader_path keywords
                # with the actual path to the binary.
                executable_path = os.path.dirname(pth)
                rpath = re.sub('^@(executable_path|loader_path|rpath)/',
                               executable_path + '/', rpath)
                # Make rpath absolute. According to Apple doc LC_RPATH
                # is always relative to the binary location.
                rpath = os.path.normpath(os.path.join(executable_path, rpath))
                run_paths.update([rpath])
            else:
                # Frameworks that have this structure Name.framework/Versions/N/Name
                # need to to search at the same level as the framework dir.
                # This is specifically needed so that the QtWebEngine dependencies
                # can be found.
                if '.framework' in pth:
                    run_paths.update(['../../../'])

    # for distributions like Anaconda, all of the dylibs are stored in the lib directory
    # of the Python distribution, not alongside of the .so's in each module's subdirectory.
    run_paths.add(os.path.join(base_prefix, 'lib'))

    ## Try to find files in file system.

    # In cases with @loader_path or @executable_path
    # try to look in the same directory as the checked binary is.
    # This seems to work in most cases.
    exec_path = os.path.abspath(os.path.dirname(pth))

 
    for lib in seen:

        # Suppose that @rpath is not used for system libraries and
        # using macholib can be avoided.
        # macholib can't handle @rpath.
        if lib.startswith('@rpath'):
            lib = lib.replace('@rpath', '.')  # Make path relative.
            final_lib = None  # Absolute path to existing lib on disk.
            # Try multiple locations.
            for run_path in run_paths:
                # @rpath may contain relative value. Use exec_path as
                # base path.
                if not os.path.isabs(run_path):
                    run_path = os.path.join(exec_path, run_path)
                # Stop looking for lib when found in first location.
                if os.path.exists(os.path.join(run_path, lib)):
                    final_lib = os.path.abspath(os.path.join(run_path, lib))
                    rslt.add(final_lib)
                    break
            # Log error if no existing file found.
            if not final_lib:
                logger.error('Can not find path %s (needed by %s)', lib, pth)

        # Macholib has to be used to get absolute path to libraries.
        else:
            # macholib can't handle @loader_path. It has to be
            # handled the same way as @executable_path.
            # It is also replaced by 'exec_path'.
            if lib.startswith('@loader_path'):
                lib = lib.replace('@loader_path', '@executable_path')
            try:
                lib = dyld_find(lib, executable_path=exec_path)
                rslt.add(lib)
            except ValueError:
                logger.error('Can not find path %s (needed by %s)', lib, pth)

    return rslt
Ejemplo n.º 11
0
 def testBasic(self):
     self.assertEqual(dyld.dyld_find('libSystem.dylib'),
                      '/usr/lib/libSystem.dylib')
     self.assertEqual(dyld.dyld_find('System.framework/System'),
                      '/System/Library/Frameworks/System.framework/System')
Ejemplo n.º 12
0
    def test_dyld_find(self):
        result = dyld.dyld_find('/usr/lib/libSystem.dylib')
        self.assertEqual(result, '/usr/lib/libSystem.dylib')
        self.assertIsInstance(result, str)  # bytes on 2.x, unicode on 3.x

        result = dyld.dyld_find(b'/usr/lib/libSystem.dylib'.decode('ascii'))
        self.assertEqual(result, '/usr/lib/libSystem.dylib')
        self.assertIsInstance(result, str)  # bytes on 2.x, unicode on 3.x

        patcher = DyldPatcher()
        try:
            patcher.log_calls('dyld_image_suffix_search')
            patcher.log_calls('dyld_override_search')
            patcher.log_calls('dyld_executable_path_search')
            patcher.log_calls('dyld_default_search')

            result = dyld.dyld_find('/usr/lib/libSystem.dylib')
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_executable_path_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib', env=None)
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_executable_path_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib', env={})
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}),
                ('dyld_executable_path_search',
                 ('/usr/lib/libSystem.dylib', None), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

            result = dyld.dyld_find('/usr/lib/libSystem.dylib',
                                    executable_path="/opt/py2app/bin",
                                    env={})
            self.assertEqual(patcher.calls[:-1], [
                ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}),
                ('dyld_executable_path_search',
                 ('/usr/lib/libSystem.dylib', "/opt/py2app/bin"), {}),
                ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}),
            ])
            self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search')
            patcher.clear_calls()

        finally:
            patcher.cleanup()
Ejemplo n.º 13
0
 def testBasic(self):
     self.assertEqual(dyld.dyld_find('libSystem.dylib'), '/usr/lib/libSystem.dylib')
     self.assertEqual(dyld.dyld_find('System.framework/System'), '/System/Library/Frameworks/System.framework/System')
Ejemplo n.º 14
0
    def test_dyld_find(self):
        result = dyld.dyld_find("/usr/lib/libSystem.dylib")
        self.assertEqual(result, "/usr/lib/libSystem.dylib")
        self.assertIsInstance(result, str)  # bytes on 2.x, unicode on 3.x

        result = dyld.dyld_find(b"/usr/lib/libSystem.dylib".decode("ascii"))
        self.assertEqual(result, "/usr/lib/libSystem.dylib")
        self.assertIsInstance(result, str)  # bytes on 2.x, unicode on 3.x

        patcher = DyldPatcher()
        try:
            patcher.log_calls("dyld_image_suffix_search")
            patcher.log_calls("dyld_override_search")
            patcher.log_calls("dyld_executable_path_search")
            patcher.log_calls("dyld_default_search")

            result = dyld.dyld_find("/usr/lib/libSystem.dylib")
            self.assertEqual(
                patcher.calls[:-1],
                [
                    ("dyld_override_search",
                     ("/usr/lib/libSystem.dylib", None), {}),
                    (
                        "dyld_executable_path_search",
                        ("/usr/lib/libSystem.dylib", None),
                        {},
                    ),
                    ("dyld_default_search",
                     ("/usr/lib/libSystem.dylib", None), {}),
                ],
            )
            self.assertEqual(patcher.calls[-1][0], "dyld_image_suffix_search")
            patcher.clear_calls()

            result = dyld.dyld_find("/usr/lib/libSystem.dylib", env=None)
            self.assertEqual(
                patcher.calls[:-1],
                [
                    ("dyld_override_search",
                     ("/usr/lib/libSystem.dylib", None), {}),
                    (
                        "dyld_executable_path_search",
                        ("/usr/lib/libSystem.dylib", None),
                        {},
                    ),
                    ("dyld_default_search",
                     ("/usr/lib/libSystem.dylib", None), {}),
                ],
            )
            self.assertEqual(patcher.calls[-1][0], "dyld_image_suffix_search")
            patcher.clear_calls()

            result = dyld.dyld_find("/usr/lib/libSystem.dylib", env={})
            self.assertEqual(
                patcher.calls[:-1],
                [
                    ("dyld_override_search",
                     ("/usr/lib/libSystem.dylib", {}), {}),
                    (
                        "dyld_executable_path_search",
                        ("/usr/lib/libSystem.dylib", None),
                        {},
                    ),
                    ("dyld_default_search",
                     ("/usr/lib/libSystem.dylib", {}), {}),
                ],
            )
            self.assertEqual(patcher.calls[-1][0], "dyld_image_suffix_search")
            patcher.clear_calls()

            result = dyld.dyld_find("/usr/lib/libSystem.dylib",
                                    executable_path="/opt/py2app/bin",
                                    env={})
            self.assertEqual(
                patcher.calls[:-1],
                [
                    ("dyld_override_search",
                     ("/usr/lib/libSystem.dylib", {}), {}),
                    (
                        "dyld_executable_path_search",
                        ("/usr/lib/libSystem.dylib", "/opt/py2app/bin"),
                        {},
                    ),
                    ("dyld_default_search",
                     ("/usr/lib/libSystem.dylib", {}), {}),
                ],
            )
            self.assertEqual(patcher.calls[-1][0], "dyld_image_suffix_search")
            patcher.clear_calls()

        finally:
            patcher.cleanup()