Exemplo n.º 1
0
 def getClass(self, name, cls):
     if in_system_path(name):
         return ExcludedMachO
     for base in self.excludes:
         if name.startswith(base):
             return ExcludedMachO
     return cls
Exemplo n.º 2
0
    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))
Exemplo n.º 3
0
 def search(self, libname):
     # First try global exclude list. If it matches, return its result; otherwise continue with other check.
     result = self._exclude_list.search(libname)
     if result:
         return result
     else:
         return util.in_system_path(libname)
Exemplo n.º 4
0
 def search(self, libname):
     # First try global exclude list. If it matches then
     # return it's result otherwise continue with other check.
     result = self._exclude_list.search(libname)
     if result:
         return result
     else:
         return util.in_system_path(libname)
Exemplo n.º 5
0
def _warn_if_activetcl_or_teapot_installed(tcl_root, tcltree):
    """
    If the current Tcl installation is a Teapot-distributed version of ActiveTcl
    *and* the current platform is OS X, log a non-fatal warning that the
    resulting executable will (probably) fail to run on non-host systems.

    PyInstaller does *not* freeze all ActiveTcl dependencies -- including
    Teapot, which is typically ignorable. Since Teapot is *not* ignorable in
    this case, this function warns of impending failure.

    See Also
    -------
    https://github.com/pyinstaller/pyinstaller/issues/621
    """
    from macholib import util

    # System libraries do not experience this problem.
    if util.in_system_path(tcl_root):
        return

    # Absolute path of the "init.tcl" script.
    try:
        init_resource = [r[1] for r in tcltree if r[1].endswith("init.tcl")][0]
    # If such script could not be found, silently return.
    except IndexError:
        return

    mentions_activetcl = False
    mentions_teapot = False
    # TCL/TK reads files using the `system encoding <https://www.tcl.tk/doc/howto/i18n.html#system_encoding>`_.
    with open_file(
        init_resource, text_read_mode, encoding=locale.getpreferredencoding()
    ) as init_file:
        for line in init_file.readlines():
            line = line.strip().lower()
            if line.startswith("#"):
                continue
            if "activetcl" in line:
                mentions_activetcl = True
            if "teapot" in line:
                mentions_teapot = True
            if mentions_activetcl and mentions_teapot:
                break

    if mentions_activetcl and mentions_teapot:
        logger.warning(
            """
You appear to be using an ActiveTcl build of Tcl/Tk, which PyInstaller has
difficulty freezing. To fix this, comment out all references to "teapot" in:

     %s

See https://github.com/pyinstaller/pyinstaller/issues/621 for more information.
            """
            % init_resource
        )
Exemplo n.º 6
0
 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))
Exemplo n.º 7
0
def _warn_if_activetcl_or_teapot_installed(tcl_root, tcltree):
    """
    If the current Tcl installation is a Teapot-distributed version of ActiveTcl
    *and* the current platform is OS X, log a non-fatal warning that the
    resulting executable will (probably) fail to run on non-host systems.

    PyInstaller does *not* freeze all ActiveTcl dependencies -- including
    Teapot, which is typically ignorable. Since Teapot is *not* ignorable in
    this case, this function warns of impending failure.

    See Also
    -------
    https://github.com/pyinstaller/pyinstaller/issues/621
    """
    from macholib import util

    # System libraries do not experience this problem.
    if util.in_system_path(tcl_root):
        return

    # Absolute path of the "init.tcl" script.
    try:
        init_resource = [r[1] for r in tcltree if r[1].endswith('init.tcl')][0]
    # If such script could not be found, silently return.
    except IndexError:
        return

    mentions_activetcl = False
    mentions_teapot = False
    with open(init_resource, 'r') as init_file:
        for line in init_file.readlines():
            line = line.strip().lower()
            if line.startswith('#'):
                continue
            if 'activetcl' in line:
                mentions_activetcl = True
            if 'teapot' in line:
                mentions_teapot = True
            if mentions_activetcl and mentions_teapot:
                break

    if mentions_activetcl and mentions_teapot:
        logger.warning(
            """
You appear to be using an ActiveTcl build of Tcl/Tk, which PyInstaller has
difficulty freezing. To fix this, comment out all references to "teapot" in:

     %s

See https://github.com/pyinstaller/pyinstaller/issues/621 for more information.
            """ % init_resource)
Exemplo n.º 8
0
 def locate(self, filename):
     if in_system_path(filename):
         return filename
     if filename.startswith(self.base):
         return filename
     for base in self.excludes:
         if filename.startswith(base):
             return filename
     if filename in self.changemap:
         return self.changemap[filename]
     info = framework_info(filename)
     if info is None:
         res = self.copy_dylib(filename)
         self.changemap[filename] = res
         return res
     else:
         res = self.copy_framework(info)
         self.changemap[filename] = res
         return res
Exemplo 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
Exemplo n.º 10
0
def not_system_filter(module):
    """
    Return False if the module is located in a system directory
    """
    return not in_system_path(module.filename)
Exemplo n.º 11
0
def not_system_filter(module):
    """
    Return False if the module is located in a system directory
    """
    return not in_system_path(module.filename)
Exemplo n.º 12
0
def not_system_filter(module: modulegraph.Node) -> bool:
    """
    Return False if the module is located in a system directory
    """
    return not in_system_path(module.filename)