def main(): parser = OptionParser() _options, positional_args = parser.parse_args() if not positional_args: sys.exit("No DLLs given.") for filename in positional_args: my_print("Filename: %s" % filename) my_print("Version Information: %s" % getWindowsDLLVersion(filename)) my_print("SXS information (manifests):") sxs = getSxsFromDLL(filename=filename, with_data=True) if sxs: my_print(sxs) my_print("DLLs recursively dependended (depends.exe):") with TimerReport( message="Finding dependencies for %s took %%.2f seconds" % filename): r = detectBinaryPathDLLsWindowsDependencyWalker( is_main_executable=False, source_dir="notexist", original_dir=os.path.dirname(filename), binary_filename=filename, package_name=None, use_cache=False, update_cache=False, ) for dll_filename in sorted(r): my_print(" %s" % dll_filename) my_print("Total: %d" % len(r))
def copyUsedDLLs(source_dir, dist_dir, standalone_entry_points): # This is terribly complex, because we check the list of used DLLs # trying to avoid duplicates, and detecting errors with them not # being binary identical, so we can report them. And then of course # we also need to handle OS specifics. # pylint: disable=too-many-branches,too-many-locals,too-many-statements used_dlls = detectUsedDLLs( source_dir=source_dir, standalone_entry_points=standalone_entry_points, use_cache=not Options.shallNotUseDependsExeCachedResults() and not Options.getWindowsDependencyTool() == "depends.exe", update_cache=not Options.shallNotStoreDependsExeCachedResults() and not Options.getWindowsDependencyTool() == "depends.exe", ) removed_dlls = set() warned_about = set() # Fist make checks and remove some. for dll_filename1, sources1 in tuple(iterItems(used_dlls)): if dll_filename1 in removed_dlls: continue for dll_filename2, sources2 in tuple(iterItems(used_dlls)): if dll_filename1 == dll_filename2: continue if dll_filename2 in removed_dlls: continue # Colliding basenames are an issue to us. if os.path.basename(dll_filename1) != os.path.basename( dll_filename2): continue # May already have been removed earlier if dll_filename1 not in used_dlls: continue if dll_filename2 not in used_dlls: continue dll_name = os.path.basename(dll_filename1) if Options.isShowInclusion(): inclusion_logger.info( """Colliding DLL names for %s, checking identity of \ '%s' <-> '%s'.""" % (dll_name, dll_filename1, dll_filename2)) # Check that if a DLL has the same name, if it's identical, then it's easy. if haveSameFileContents(dll_filename1, dll_filename2): del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) continue # For Win32 we can check out file versions. if Utils.isWin32Windows(): dll_version1 = getWindowsDLLVersion(dll_filename1) dll_version2 = getWindowsDLLVersion(dll_filename2) if dll_version2 < dll_version1: del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) solved = True elif dll_version1 < dll_version2: del used_dlls[dll_filename1] removed_dlls.add(dll_filename1) solved = True else: solved = False if solved: if dll_name not in warned_about and dll_name not in ms_runtime_dlls: warned_about.add(dll_name) inclusion_logger.warning( "Conflicting DLLs for '%s' in your installation, newest file version used, hoping for the best." % dll_name) continue # So we have conflicting DLLs, in which case we do report the fact. inclusion_logger.warning("""\ Ignoring non-identical DLLs for '%s'. %s used by: %s different from %s used by %s""" % ( dll_name, dll_filename1, "\n ".join(sources1), dll_filename2, "\n ".join(sources2), )) del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) dll_map = [] for dll_filename, sources in iterItems(used_dlls): dll_name = os.path.basename(dll_filename) target_path = os.path.join(dist_dir, dll_name) shutil.copyfile(dll_filename, target_path) dll_map.append((dll_filename, dll_name)) if Options.isShowInclusion(): inclusion_logger.info( "Included used shared library '%s' (used by %s)." % (dll_filename, ", ".join(sources))) if Utils.getOS() == "Darwin": # For macOS, the binary and the DLLs needs to be changed to reflect # the relative DLL location in the ".dist" folder. for standalone_entry_point in standalone_entry_points: fixupBinaryDLLPathsMacOS( binary_filename=standalone_entry_point.dest_path, dll_map=dll_map, original_location=standalone_entry_point.source_path, ) for original_path, dll_filename in dll_map: fixupBinaryDLLPathsMacOS( binary_filename=os.path.join(dist_dir, dll_filename), dll_map=dll_map, original_location=original_path, ) # Remove code signature from CPython installed library candidate = os.path.join( dist_dir, "Python", ) if os.path.exists(candidate): removeMacOSCodeSignature(candidate) # Remove rpath settings. if Utils.getOS() in ("Linux", "Darwin"): # For Linux, the "rpath" of libraries may be an issue and must be # removed. if Utils.getOS() == "Darwin": start = 0 else: start = 1 for standalone_entry_point in standalone_entry_points[start:]: removeSharedLibraryRPATH(standalone_entry_point.dest_path) for _original_path, dll_filename in dll_map: removeSharedLibraryRPATH(os.path.join(dist_dir, dll_filename)) if Utils.isWin32Windows(): if python_version < 0x300: # For Win32, we might have to remove SXS paths for standalone_entry_point in standalone_entry_points[1:]: removeSxsFromDLL(standalone_entry_point.dest_path) for _original_path, dll_filename in dll_map: removeSxsFromDLL(os.path.join(dist_dir, dll_filename))
def copyUsedDLLs(source_dir, dist_dir, standalone_entry_points): # This is terribly complex, because we check the list of used DLLs # trying to avoid duplicates, and detecting errors with them not # being binary identical, so we can report them. And then of course # we also need to handle OS specifics. # pylint: disable=too-many-branches,too-many-locals,too-many-statements used_dlls = detectUsedDLLs(source_dir, standalone_entry_points) removed_dlls = set() # Fist make checks and remove some. for dll_filename1, sources1 in tuple(iterItems(used_dlls)): if dll_filename1 in removed_dlls: continue for dll_filename2, sources2 in tuple(iterItems(used_dlls)): if dll_filename1 == dll_filename2: continue if dll_filename2 in removed_dlls: continue # Colliding basenames are an issue to us. if os.path.basename(dll_filename1) != os.path.basename( dll_filename2): continue # May already have been removed earlier if dll_filename1 not in used_dlls: continue if dll_filename2 not in used_dlls: continue dll_name = os.path.basename(dll_filename1) if Options.isShowInclusion(): info("""Colliding DLL names for %s, checking identity of \ '%s' <-> '%s'.""" % (dll_name, dll_filename1, dll_filename2)) # Check that if a DLL has the same name, if it's identical, # happens at least for OSC and Fedora 20. import filecmp if filecmp.cmp(dll_filename1, dll_filename2): del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) continue # For Win32 we can check out file versions. if Utils.isWin32Windows(): dll_version1 = getWindowsDLLVersion(dll_filename1) dll_version2 = getWindowsDLLVersion(dll_filename2) if dll_version2 < dll_version1: del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) solved = True elif dll_version1 < dll_version2: del used_dlls[dll_filename1] removed_dlls.add(dll_filename1) solved = True else: solved = False if solved: warning( "Ignoring conflicting DLLs for '%s' and using newest file version." % dll_name) continue # So we have conflicting DLLs, in which case we do not proceed. warning("""Ignoring non-identical DLLs for '%s'. %s used by: %s different from %s used by %s""" % ( dll_name, dll_filename1, "\n ".join(sources1), dll_filename2, "\n ".join(sources2), )) del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) dll_map = [] for dll_filename, sources in iterItems(used_dlls): dll_name = os.path.basename(dll_filename) target_path = os.path.join(dist_dir, dll_name) shutil.copyfile(dll_filename, target_path) dll_map.append((dll_filename, dll_name)) if Options.isShowInclusion(): info("Included used shared library '%s' (used by %s)." % (dll_filename, ", ".join(sources))) if Utils.getOS() == "Darwin": # For macOS, the binary and the DLLs needs to be changed to reflect # the relative DLL location in the ".dist" folder. for standalone_entry_point in standalone_entry_points: fixupBinaryDLLPaths( binary_filename=standalone_entry_point[1], is_exe=standalone_entry_point is standalone_entry_points[0], dll_map=dll_map, ) for _original_path, dll_filename in dll_map: fixupBinaryDLLPaths( binary_filename=os.path.join(dist_dir, dll_filename), is_exe=False, dll_map=dll_map, ) if Utils.getOS() == "Linux": # For Linux, the "rpath" of libraries may be an issue and must be # removed. for standalone_entry_point in standalone_entry_points[1:]: removeSharedLibraryRPATH(standalone_entry_point[1]) for _original_path, dll_filename in dll_map: removeSharedLibraryRPATH(os.path.join(dist_dir, dll_filename)) elif Utils.isWin32Windows(): if python_version < 300: # For Win32, we might have to remove SXS paths for standalone_entry_point in standalone_entry_points[1:]: removeSxsFromDLL(standalone_entry_point[1]) for _original_path, dll_filename in dll_map: removeSxsFromDLL(os.path.join(dist_dir, dll_filename))
def main(): parser = OptionParser() parser.add_option( "--verbose", action="store_true", dest="verbose", default=False, help="""\ Be verbose in output. Default is %default.""", ) parser.add_option( "--pefile", action="store_true", dest="pefile", default=False, help="""\ Use pefile dependencies. Default is %default.""", ) options, positional_args = parser.parse_args() if not positional_args: sys.exit("No DLLs given.") for filename in positional_args: print("Filename:", filename) print("Version Information:", getWindowsDLLVersion(filename)) print("DLLs directly dependended (pefile):", getPEFileInformation(filename)) print("SXS information (manifests):") sxs = getSxsFromDLL(filename=filename, with_data=True) if sxs: print(sxs) print("DLLs recursively dependended (pefile):") if options.pefile: with TimerReport( message="Finding dependencies for %s took %%.2f seconds" % filename): from nuitka import Options Options.options.dependency_tool = "pefile" r = detectBinaryPathDLLsWindowsPE( is_main_executable=False, source_dir="notexist", original_dir=os.path.dirname(filename), binary_filename=filename, package_name=None, use_cache=False, update_cache=True, ) Options.options.dependency_tool = "depends.exe" for dll_filename in sorted(r): print(" ", dll_filename) print("Total: %d" % len(r)) print("DLLs recursively dependended (depends.exe):") with TimerReport( message="Finding dependencies for %s took %%.2f seconds" % filename): r = detectBinaryPathDLLsWindowsDependencyWalker( is_main_executable=False, source_dir="notexist", original_dir=os.path.dirname(filename), binary_filename=filename, package_name=None, use_cache=False, update_cache=False, ) for dll_filename in sorted(r): print(" ", dll_filename) print("Total: %d" % len(r))
def _removeDuplicateDlls(used_dlls): # Many things to consider, pylint: disable=too-many-branches removed_dlls = set() warned_about = set() # Identical DLLs are interesting for DLL resolution on macOS at least. duplicate_dlls = {} # Fist make checks and remove some, in loops we copy the items so we can remove # the used_dll list freely. for dll_filename1, (_package_name1, sources1) in tuple(iterItems(used_dlls)): if dll_filename1 in removed_dlls: continue for dll_filename2, (_package_name1, sources2) in tuple(iterItems(used_dlls)): if dll_filename1 == dll_filename2: continue if dll_filename2 in removed_dlls: continue # Colliding basenames are an issue to us. if os.path.basename(dll_filename1) != os.path.basename( dll_filename2): continue # May already have been removed earlier if dll_filename1 not in used_dlls: continue if dll_filename2 not in used_dlls: continue dll_name = os.path.basename(dll_filename1) if Options.isShowInclusion(): inclusion_logger.info( """Colliding DLL names for %s, checking identity of \ '%s' <-> '%s'.""" % (dll_name, dll_filename1, dll_filename2)) # Check that if a DLL has the same name, if it's identical, then it's easy. if haveSameFileContents(dll_filename1, dll_filename2): del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) duplicate_dlls.setdefault(dll_filename1, []).append(dll_filename2) duplicate_dlls.setdefault(dll_filename2, []).append(dll_filename1) continue # For Win32 we can check out file versions. if Utils.isWin32Windows(): dll_version1 = getWindowsDLLVersion(dll_filename1) dll_version2 = getWindowsDLLVersion(dll_filename2) if dll_version2 < dll_version1: del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) solved = True elif dll_version1 < dll_version2: del used_dlls[dll_filename1] removed_dlls.add(dll_filename1) solved = True else: solved = False if solved: if dll_name not in warned_about and dll_name not in ms_runtime_dlls: warned_about.add(dll_name) inclusion_logger.warning( "Conflicting DLLs for '%s' in your installation, newest file version used, hoping for the best." % dll_name) continue # So we have conflicting DLLs, in which case we do report the fact. inclusion_logger.warning("""\ Ignoring non-identical DLLs for '%s'. %s used by: %s different from %s used by %s""" % ( dll_name, dll_filename1, "\n ".join(sources1), dll_filename2, "\n ".join(sources2), )) del used_dlls[dll_filename2] removed_dlls.add(dll_filename2) return duplicate_dlls