示例#1
0
def modify_object_macholib(cur_path, paths_to_paths):
    """
    This function is used when install machO buildcaches on linux by
    rewriting mach-o loader commands for dependency library paths of
    mach-o binaries and the id path for mach-o libraries.
    Rewritting of rpaths is handled by replace_prefix_bin.
    Inputs
    mach-o binary to be modified
    dictionary mapping paths in old install layout to new install layout
    """

    dll = MachO(cur_path)

    changedict = paths_to_paths

    def changefunc(path):
        npath = changedict.get(path, None)
        return npath

    dll.rewriteLoadCommands(changefunc)

    try:
        f = open(dll.filename, 'rb+')
        for header in dll.headers:
            f.seek(0)
            dll.write(f)
        f.seek(0, 2)
        f.flush()
        f.close()
    except Exception:
        pass

    return
示例#2
0
def rewriteFramework(framework, frameworkMap):

    basename = os.path.splitext(os.path.basename(framework))[0]
    dyld = os.path.abspath(os.path.join(framework, basename))

    macho = MachO(dyld)

    def changefunc(key):
        if key == dyld:
            return dyld

        dirname, filename = os.path.split(key)
        return frameworkMap.get(filename)

    macho.rewriteLoadCommands(changefunc)
    macho.write(open(dyld, "rb+"))
示例#3
0
def rewriteFramework(framework, frameworkMap):

    basename = os.path.splitext(os.path.basename(framework))[0]
    dyld = os.path.abspath(os.path.join(framework, basename))

    macho = MachO(dyld)

    def changefunc(key):
        if key == dyld:
            return dyld

        dirname, filename = os.path.split(key)
        return frameworkMap.get(filename)

    macho.rewriteLoadCommands(changefunc)
    macho.write(open(dyld, "rb+"))
示例#4
0
def modify_object_macholib(cur_path, old_dir, new_dir):
    """
    Modify MachO binary path_name by replacing old_dir with new_dir
    or the relative path to spack install root.
    The old install dir in LC_ID_DYLIB is replaced with the new install dir
    using py-macholib
    The old install dir in LC_LOAD_DYLIB is replaced with the new install dir
    using py-macholib
    The old install dir in LC_RPATH is replaced with the new install dir using
    using py-macholib
    """
    if cur_path.endswith('.o'):
        return
    try:
        from macholib.MachO import MachO
    except ImportError as e:
        raise MissingMacholibException(e)

    def match_func(cpath):
        rpath = cpath.replace(old_dir, new_dir)
        return rpath

    dll = MachO(cur_path)
    dll.rewriteLoadCommands(match_func)
    try:
        f = open(dll.filename, 'rb+')
        for header in dll.headers:
            f.seek(0)
            dll.write(f)
        f.seek(0, 2)
        f.flush()
        f.close()
    except Exception:
        pass

    return
示例#5
0
def mac_set_relative_dylib_deps(libname, distname):
    """
    On Mac OS X set relative paths to dynamic library dependencies
    of `libname`.

    Relative paths allow to avoid using environment variable DYLD_LIBRARY_PATH.
    There are known some issues with DYLD_LIBRARY_PATH. Relative paths is
    more flexible mechanism.

    Current location of dependend libraries is derived from the location
    of the library path (paths start with '@loader_path').

    'distname'  path of the library relative to dist directory of frozen
                executable. We need this to determine the level of directory
                level for @loader_path of binaries not found in dist directory.

                E.g. qt4 plugins are not in the same directory as Qt*.dylib
                files. Without using '@loader_path/../..' for qt plugins
                Mac OS X would not be able to resolve shared library
                dependencies and qt plugins will not be loaded.
    """

    from macholib import util
    from macholib.MachO import MachO

    # Ignore bootloader otherwise PyInstaller fails with exception like
    # 'ValueError: total_size > low_offset (288 > 0)'
    if os.path.basename(libname) in _BOOTLOADER_FNAMES:
        return

    # Determine how many directories up is the directory with shared
    # dynamic libraries. '../'
    # E.g.  ./qt4_plugins/images/ -> ./../../
    parent_dir = ''
    # Check if distname is not only base filename.
    if os.path.dirname(distname):
        parent_level = len(os.path.dirname(distname).split(os.sep))
        parent_dir = parent_level * (os.pardir + os.sep)

    def match_func(pth):
        """
        For system libraries is still used absolute path. It is unchanged.
        """
        # Leave system dynamic libraries unchanged
        if util.in_system_path(pth):
            return None

        # The older python.org builds that use system Tcl/Tk framework
        # have their _tkinter.cpython-*-darwin.so library linked against
        # /Library/Frameworks/Tcl.framework/Versions/8.5/Tcl and
        # /Library/Frameworks/Tk.framework/Versions/8.5/Tk, although the
        # actual frameworks are located in /System/Library/Frameworks.
        # Therefore, they slip through the above in_system_path() check,
        # and we need to exempt them manually.
        _exemptions = [
            '/Library/Frameworks/Tcl.framework/',
            '/Library/Frameworks/Tk.framework/'
        ]
        if any([x in pth for x in _exemptions]):
            return None

        # Use relative path to dependent dynamic libraries based on the
        # location of the executable.
        return os.path.join('@loader_path', parent_dir, os.path.basename(pth))

    # Rewrite mach headers with @loader_path.
    dll = MachO(libname)
    dll.rewriteLoadCommands(match_func)

    # Write changes into file.
    # Write code is based on macholib example.
    try:
        with open(dll.filename, 'rb+') as f:
            for header in dll.headers:
                f.seek(0)
                dll.write(f)
            f.seek(0, 2)
            f.flush()
    except Exception:
        pass
示例#6
0
文件: dylib.py 项目: L37sg0/key-robot
def mac_set_relative_dylib_deps(libname, distname):
    """
    On Mac OS X set relative paths to dynamic library dependencies
    of `libname`.

    Relative paths allow to avoid using environment variable DYLD_LIBRARY_PATH.
    There are known some issues with DYLD_LIBRARY_PATH. Relative paths is
    more flexible mechanism.

    Current location of dependend libraries is derived from the location
    of the library path (paths start with '@loader_path').

    'distname'  path of the library relative to dist directory of frozen
                executable. We need this to determine the level of directory
                level for @loader_path of binaries not found in dist directory.

                E.g. qt4 plugins are not in the same directory as Qt*.dylib
                files. Without using '@loader_path/../..' for qt plugins
                Mac OS X would not be able to resolve shared library
                dependencies and qt plugins will not be loaded.
    """

    from macholib import util
    from macholib.MachO import MachO

    # Ignore bootloader otherwise PyInstaller fails with exception like
    # 'ValueError: total_size > low_offset (288 > 0)'
    if os.path.basename(libname) in _BOOTLOADER_FNAMES:
        return

    # Determine how many directories up is the directory with shared
    # dynamic libraries. '../'
    # E.g.  ./qt4_plugins/images/ -> ./../../
    parent_dir = ''
    # Check if distname is not only base filename.
    if os.path.dirname(distname):
        parent_level = len(os.path.dirname(distname).split(os.sep))
        parent_dir = parent_level * (os.pardir + os.sep)

    def match_func(pth):
        """
        For system libraries is still used absolute path. It is unchanged.
        """
        # Match non system dynamic libraries.
        if not util.in_system_path(pth):
            # Use relative path to dependend dynamic libraries bases on
            # location of the executable.
            return os.path.join('@loader_path', parent_dir,
                os.path.basename(pth))

    # Rewrite mach headers with @loader_path.
    dll = MachO(libname)
    dll.rewriteLoadCommands(match_func)

    # Write changes into file.
    # Write code is based on macholib example.
    try:
        with open(dll.filename, 'rb+') as f:
            for header in dll.headers:
                f.seek(0)
                dll.write(f)
            f.seek(0, 2)
            f.flush()
    except Exception:
        pass