def selectAssemblies(pth, manifest=None): """ Return a binary's dependent assemblies files that should be included. Return a list of pairs (name, fullpath) """ rv = [] if not os.path.isfile(pth): pth = check_extract_from_egg(pth)[0][0] if manifest: _depNames = set([dep.name for dep in manifest.dependentAssemblies]) for assembly in getAssemblies(pth): if seen.get(assembly.getid().upper(), 0): continue if manifest and not assembly.name in _depNames: # Add assembly as dependency to our final output exe's manifest logger.info("Adding %s to dependent assemblies " "of final executable", assembly.name) manifest.dependentAssemblies.append(assembly) _depNames.add(assembly.name) if not dylib.include_library(assembly.name): logger.debug("Skipping assembly %s", assembly.getid()) continue if assembly.optional: logger.debug("Skipping optional assembly %s", assembly.getid()) continue files = assembly.find_files() if files: seen[assembly.getid().upper()] = 1 for fn in files: fname, fext = os.path.splitext(fn) if fext.lower() == ".manifest": nm = assembly.name + fext else: nm = os.path.basename(fn) ftocnm = nm if assembly.language not in (None, "", "*", "neutral"): ftocnm = os.path.join(assembly.getlanguage(), ftocnm) nm, ftocnm, fn = [item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn)] if not seen.get(fn.upper(), 0): logger.debug("Adding %s", ftocnm) seen[nm.upper()] = 1 seen[fn.upper()] = 1 rv.append((ftocnm, fn)) else: #logger.info("skipping %s part of assembly %s dependency of %s", # ftocnm, assembly.name, pth) pass else: logger.error("Assembly %s not found", assembly.getid()) return rv
def selectAssemblies(pth, manifest=None): """ Return a binary's dependent assemblies files that should be included. Return a list of pairs (name, fullpath) """ rv = [] if not os.path.isfile(pth): pth = check_extract_from_egg(pth)[0][0] if manifest: _depNames = set([dep.name for dep in manifest.dependentAssemblies]) for assembly in getAssemblies(pth): if seen.get(assembly.getid().upper(), 0): continue if manifest and not assembly.name in _depNames: # Add assembly as dependency to our final output exe's manifest logger.info( "Adding %s to dependent assemblies " "of final executable", assembly.name) manifest.dependentAssemblies.append(assembly) _depNames.add(assembly.name) if not dylib.include_library(assembly.name): logger.debug("Skipping assembly %s", assembly.getid()) continue if assembly.optional: logger.debug("Skipping optional assembly %s", assembly.getid()) continue files = assembly.find_files() if files: seen[assembly.getid().upper()] = 1 for fn in files: fname, fext = os.path.splitext(fn) if fext.lower() == ".manifest": nm = assembly.name + fext else: nm = os.path.basename(fn) ftocnm = nm if assembly.language not in (None, "", "*", "neutral"): ftocnm = os.path.join(assembly.getlanguage(), ftocnm) nm, ftocnm, fn = [ item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn) ] if not seen.get(fn.upper(), 0): logger.debug("Adding %s", ftocnm) seen[nm.upper()] = 1 seen[fn.upper()] = 1 rv.append((ftocnm, fn)) else: #logger.info("skipping %s part of assembly %s dependency of %s", # ftocnm, assembly.name, pth) pass else: logger.error("Assembly %s not found", assembly.getid()) return rv
def selectImports(pth, xtrapath=None): """ Return the dependencies of a binary that should be included. Return a list of pairs (name, fullpath) """ rv = [] if xtrapath is None: xtrapath = [os.path.dirname(pth)] else: assert isinstance(xtrapath, list) xtrapath = [os.path.dirname(pth)] + xtrapath # make a copy dlls = getImports(pth) for lib in dlls: if lib.upper() in seen: continue if not compat.is_win: # all other platforms npth = lib lib = os.path.basename(lib) else: # plain win case npth = getfullnameof(lib, xtrapath) # now npth is a candidate lib if found # check again for excludes but with regex FIXME: split the list if npth: candidatelib = npth else: candidatelib = lib if not dylib.include_library(candidatelib): if (candidatelib.find('libpython') < 0 and candidatelib.find('Python.framework') < 0): # skip libs not containing (libpython or Python.framework) if npth.upper() not in seen: logger.debug("Skipping %s dependency of %s", lib, os.path.basename(pth)) continue else: pass if npth: if npth.upper() not in seen: logger.debug("Adding %s dependency of %s from %s", lib, os.path.basename(pth), npth) rv.append((lib, npth)) else: # Don't spew out false warnings on win 10 and UCRT (see issue # #1566). if not (compat.is_win_10 and lib.startswith("api-ms-win-crt")): logger.warning("lib not found: %s dependency of %s", lib, pth) return rv
def selectImports(pth, xtrapath=None): """ Return the dependencies of a binary that should be included. Return a list of pairs (name, fullpath) """ rv = [] if xtrapath is None: xtrapath = [os.path.dirname(pth)] else: assert isinstance(xtrapath, list) xtrapath = [os.path.dirname(pth)] + xtrapath # make a copy dlls = getImports(pth) for lib in dlls: if seen.get(lib.upper(), 0): continue if not is_win and not is_cygwin: # all other platforms npth = lib lib = os.path.basename(lib) else: # plain win case npth = getfullnameof(lib, xtrapath) # now npth is a candidate lib if found # check again for excludes but with regex FIXME: split the list if npth: candidatelib = npth else: candidatelib = lib if not dylib.include_library(candidatelib): if (candidatelib.find('libpython') < 0 and candidatelib.find('Python.framework') < 0): # skip libs not containing (libpython or Python.framework) if not seen.get(npth.upper(), 0): logger.debug("Skipping %s dependency of %s", lib, os.path.basename(pth)) continue else: pass if npth: if not seen.get(npth.upper(), 0): logger.debug("Adding %s dependency of %s", lib, os.path.basename(pth)) rv.append((lib, npth)) else: logger.error("lib not found: %s dependency of %s", lib, pth) return rv
def getAssemblyFiles(pth, manifest=None, redirects=None): """ Find all assemblies that are dependencies of the given binary and return the files that make up the assemblies as (name, fullpath) tuples. If a WinManifest object is passed as `manifest`, also updates that manifest to reference the returned assemblies. This is done only to update the built app's .exe with the dependencies of python.exe If a list is passed as `redirects`, and binding redirects in policy files are applied when searching for assemblies, BindingRedirect objects are appended to this list. Return a list of pairs (name, fullpath) """ rv = [] if manifest: _depNames = set(dep.name for dep in manifest.dependentAssemblies) for assembly in getAssemblies(pth): if assembly.getid().upper() in seen: continue if manifest and assembly.name not in _depNames: # Add assembly as dependency to our final output exe's manifest logger.info( "Adding %s to dependent assemblies " "of final executable\n required by %s", assembly.name, pth) manifest.dependentAssemblies.append(assembly) _depNames.add(assembly.name) if not dylib.include_library(assembly.name): logger.debug("Skipping assembly %s", assembly.getid()) continue if assembly.optional: logger.debug("Skipping optional assembly %s", assembly.getid()) continue from PyInstaller.config import CONF if CONF.get("win_no_prefer_redirects"): files = assembly.find_files() else: files = [] if not len(files): # If no files were found, it may be the case that the required version # of the assembly is not installed, and the policy file is redirecting it # to a newer version. So, we collect the newer version instead. files = assembly.find_files(ignore_policies=False) if len(files) and redirects is not None: # New version was found, old version was not. Add a redirect in the # app configuration old_version = assembly.version new_version = assembly.get_policy_redirect() logger.info("Adding redirect %s version %s -> %s", assembly.name, old_version, new_version) redirects.append( BindingRedirect( name=assembly.name, language=assembly.language, arch=assembly.processorArchitecture, publicKeyToken=assembly.publicKeyToken, oldVersion=old_version, newVersion=new_version, )) if files: seen.add(assembly.getid().upper()) for fn in files: fname, fext = os.path.splitext(fn) if fext.lower() == ".manifest": nm = assembly.name + fext else: nm = os.path.basename(fn) ftocnm = nm if assembly.language not in (None, "", "*", "neutral"): ftocnm = os.path.join(assembly.getlanguage(), ftocnm) nm, ftocnm, fn = [ item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn) ] if fn.upper() not in seen: logger.debug("Adding %s", ftocnm) seen.add(nm.upper()) seen.add(fn.upper()) rv.append((ftocnm, fn)) else: #logger.info("skipping %s part of assembly %s dependency of %s", # ftocnm, assembly.name, pth) pass else: logger.error("Assembly %s not found", assembly.getid()) # Convert items in list from 'bytes' type to 'str' type. # NOTE: With Python 3 we somehow get type 'bytes' and it # then causes other issues and failures with PyInstaller. new_rv = [] for item in rv: a = item[0].decode('ascii') b = item[1].decode('ascii') new_rv.append((a, b)) rv = new_rv return rv
def _resolveCtypesImports(cbinaries): """ Completes ctypes BINARY entries for modules with their full path. Input is a list of c-binary-names (as found by `scan_code_instruction_for_ctypes`). Output is a list of tuples ready to be appended to the ``binaries`` of a modules. This function temporarily extents PATH, LD_LIBRARY_PATH or DYLD_LIBRARY_PATH (depending on the plattform) by CONF['pathex'] so shared libs will be search there, too. Example: >>> _resolveCtypesImports(['libgs.so']) [(libgs.so', ''/usr/lib/libgs.so', 'BINARY')] """ from ctypes.util import find_library from PyInstaller.config import CONF if compat.is_unix: envvar = "LD_LIBRARY_PATH" elif compat.is_darwin: envvar = "DYLD_LIBRARY_PATH" else: envvar = "PATH" def _setPaths(): path = os.pathsep.join(CONF['pathex']) old = compat.getenv(envvar) if old is not None: path = os.pathsep.join((path, old)) compat.setenv(envvar, path) return old def _restorePaths(old): if old is None: compat.unsetenv(envvar) else: compat.setenv(envvar, old) ret = [] # Try to locate the shared library on the disk. This is done by calling ctypes.util.find_library with # ImportTracker's local paths temporarily prepended to the library search paths (and restored after the call). old = _setPaths() for cbin in cbinaries: try: # There is an issue with find_library() where it can run into errors trying to locate the library. See # #5734. cpath = find_library(os.path.splitext(cbin)[0]) except FileNotFoundError: # In these cases, find_library() should return None. cpath = None if compat.is_unix: # CAVEAT: find_library() is not the correct function. ctype's documentation says that it is meant to resolve # only the filename (as a *compiler* does) not the full path. Anyway, it works well enough on Windows and # Mac OS. On Linux, we need to implement more code to find out the full path. if cpath is None: cpath = cbin # "man ld.so" says that we should first search LD_LIBRARY_PATH and then the ldcache. for d in compat.getenv(envvar, '').split(os.pathsep): if os.path.isfile(os.path.join(d, cpath)): cpath = os.path.join(d, cpath) break else: if LDCONFIG_CACHE is None: load_ldconfig_cache() if cpath in LDCONFIG_CACHE: cpath = LDCONFIG_CACHE[cpath] assert os.path.isfile(cpath) else: cpath = None if cpath is None: # Skip warning message if cbin (basename of library) is ignored. This prevents messages like: # 'W: library kernel32.dll required via ctypes not found' if not include_library(cbin): continue logger.warning("Library %s required via ctypes not found", cbin) else: if not include_library(cpath): continue ret.append((cbin, cpath, "BINARY")) _restorePaths(old) return ret
def getAssemblyFiles(pth, manifest=None, redirects=None): """ Find all assemblies that are dependencies of the given binary and return the files that make up the assemblies as (name, fullpath) tuples. If a WinManifest object is passed as `manifest`, also updates that manifest to reference the returned assemblies. This is done only to update the built app's .exe with the dependencies of python.exe If a list is passed as `redirects`, and binding redirects in policy files are applied when searching for assemblies, BindingRedirect objects are appended to this list. Return a list of pairs (name, fullpath) """ rv = [] if manifest: _depNames = set(dep.name for dep in manifest.dependentAssemblies) for assembly in getAssemblies(pth): if assembly.getid().upper() in seen: continue if manifest and assembly.name not in _depNames: # Add assembly as dependency to our final output exe's manifest logger.info("Adding %s to dependent assemblies " "of final executable\n required by %s", assembly.name, pth) manifest.dependentAssemblies.append(assembly) _depNames.add(assembly.name) if not dylib.include_library(assembly.name): logger.debug("Skipping assembly %s", assembly.getid()) continue if assembly.optional: logger.debug("Skipping optional assembly %s", assembly.getid()) continue from ..config import CONF if CONF.get("win_no_prefer_redirects"): files = assembly.find_files() else: files = [] if not len(files): # If no files were found, it may be the case that the required version # of the assembly is not installed, and the policy file is redirecting it # to a newer version. So, we collect the newer version instead. files = assembly.find_files(ignore_policies=False) if len(files) and redirects is not None: # New version was found, old version was not. Add a redirect in the # app configuration old_version = assembly.version new_version = assembly.get_policy_redirect() logger.info("Adding redirect %s version %s -> %s", assembly.name, old_version, new_version) redirects.append(BindingRedirect( name=assembly.name, language=assembly.language, arch=assembly.processorArchitecture, publicKeyToken=assembly.publicKeyToken, oldVersion=old_version, newVersion=new_version, )) if files: seen.add(assembly.getid().upper()) for fn in files: fname, fext = os.path.splitext(fn) if fext.lower() == ".manifest": nm = assembly.name + fext else: nm = os.path.basename(fn) ftocnm = nm if assembly.language not in (None, "", "*", "neutral"): ftocnm = os.path.join(assembly.getlanguage(), ftocnm) nm, ftocnm, fn = [item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn)] if fn.upper() not in seen: logger.debug("Adding %s", ftocnm) seen.add(nm.upper()) seen.add(fn.upper()) rv.append((ftocnm, fn)) else: #logger.info("skipping %s part of assembly %s dependency of %s", # ftocnm, assembly.name, pth) pass else: logger.error("Assembly %s not found", assembly.getid()) # Convert items in list from 'bytes' type to 'str' type. # NOTE: With Python 3 we somehow get type 'bytes' and it # then causes other issues and failures with PyInstaller. new_rv = [] for item in rv: a = item[0].decode('ascii') b = item[1].decode('ascii') new_rv.append((a, b)) rv = new_rv return rv
def selectAssemblies(pth, manifest=None): """ Return a binary's dependent assemblies files that should be included. Return a list of pairs (name, fullpath) """ rv = [] if manifest: _depNames = set([dep.name for dep in manifest.dependentAssemblies]) for assembly in getAssemblies(pth): if seen.get(assembly.getid().upper(), 0): continue if manifest and not assembly.name in _depNames: # Add assembly as dependency to our final output exe's manifest logger.info("Adding %s to dependent assemblies " "of final executable\n required by %s", assembly.name, pth) manifest.dependentAssemblies.append(assembly) _depNames.add(assembly.name) if not dylib.include_library(assembly.name): logger.debug("Skipping assembly %s", assembly.getid()) continue if assembly.optional: logger.debug("Skipping optional assembly %s", assembly.getid()) continue files = assembly.find_files() if files: seen[assembly.getid().upper()] = 1 for fn in files: fname, fext = os.path.splitext(fn) if fext.lower() == ".manifest": nm = assembly.name + fext else: nm = os.path.basename(fn) ftocnm = nm if assembly.language not in (None, "", "*", "neutral"): ftocnm = os.path.join(assembly.getlanguage(), ftocnm) nm, ftocnm, fn = [item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn)] if not seen.get(fn.upper(), 0): logger.debug("Adding %s", ftocnm) seen[nm.upper()] = 1 seen[fn.upper()] = 1 rv.append((ftocnm, fn)) else: #logger.info("skipping %s part of assembly %s dependency of %s", # ftocnm, assembly.name, pth) pass else: logger.error("Assembly %s not found", assembly.getid()) # Convert items in list from 'bytes' type to 'str' type. # NOTE: With Python 3 we somehow get type 'bytes' and it # then causes other issues and failures with PyInstaller. new_rv = [] for item in rv: a = item[0].decode('ascii') b = item[1].decode('ascii') new_rv.append((a, b)) rv = new_rv return rv