def _fixupBinaryDLLPathsMacOS(binary_filename, package_name, dll_map, duplicate_dlls, original_location): """For macOS, the binary needs to be told to use relative DLL paths""" # There may be nothing to do, in case there are no DLLs. if not dll_map: return had_self, rpath_map = _detectBinaryPathDLLsMacOS( original_dir=os.path.dirname(original_location), binary_filename=original_location, package_name=package_name, keep_unresolved=True, recursive=False, ) mapping = [] for resolved_filename, rpath_filename in rpath_map.items(): for (original_path, _package_name, dist_path) in dll_map: if resolved_filename == original_path: break # Might have been a removed duplicate, check those too. if original_path in duplicate_dlls.get(resolved_filename, ()): break else: dist_path = None if dist_path is None: inclusion_logger.sysexit("""\ Error, problem with dependency scan of '%s' with '%s' please report the bug.""" % (binary_filename, rpath_filename)) mapping.append((rpath_filename, "@executable_path/" + dist_path)) if mapping or had_self: callInstallNameTool( filename=binary_filename, mapping=mapping, id_path=os.path.basename(binary_filename) if had_self else None, rpath=None, )
def fixupBinaryDLLPathsMacOS(binary_filename, dll_map, original_location): """ For macOS, the binary needs to be told to use relative DLL paths """ # There may be nothing to do, in case there are no DLLs. if not dll_map: return rpath_map = _detectBinaryPathDLLsMacOS( original_dir=os.path.dirname(original_location), binary_filename=original_location, keep_unresolved=True, ) for i, o in enumerate(dll_map): dll_map[i] = (rpath_map.get(o[0], o[0]), o[1]) callInstallNameTool( filename=binary_filename, mapping=((original_path, "@executable_path/" + dist_path) for (original_path, dist_path) in dll_map), )
def executePostProcessing(result_filename): if not os.path.exists(result_filename): sys.exit("Error, scons failed to create the expected file '%s'. " % result_filename) if isWin32Windows(): # Copy the Windows manifest from the CPython binary to the created # executable, so it finds "MSCRT.DLL". This is needed for Python2 # only, for Python3 newer MSVC doesn't hide the C runtime. if python_version < 300 and not Options.shallMakeModule(): copyResourcesFromFileToFile( sys.executable, target_filename=result_filename, resource_kind=RT_MANIFEST, ) assert os.path.exists(result_filename) # Attach the binary blob as a Windows resource. addResourceToFile( target_filename=result_filename, data=ConstantCodes.stream_data.getBytes(), resource_kind=RT_RCDATA, res_name=3, lang_id=0, ) # On macOS, we update the executable path for searching the "libpython" # library. if (getOS() == "Darwin" and not Options.shallMakeModule() and not Options.shallUseStaticLibPython()): python_version_str = ".".join(str(s) for s in sys.version_info[0:2]) python_abi_version = python_version_str + getPythonABI() python_dll_filename = "libpython" + python_abi_version + ".dylib" python_lib_path = os.path.join(sys.prefix, "lib") if os.path.exists(os.path.join(sys.prefix, "conda-meta")): callInstallNameToolAddRPath(result_filename, python_lib_path) callInstallNameTool( filename=result_filename, mapping=(( python_dll_filename, os.path.join(python_lib_path, python_dll_filename), ), ), ) # Modules should not be executable, but Scons creates them like it, fix # it up here. if not isWin32Windows() and Options.shallMakeModule(): old_stat = os.stat(result_filename) mode = old_stat.st_mode mode &= ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) if mode != old_stat.st_mode: os.chmod(result_filename, mode) if isWin32Windows() and Options.shallMakeModule(): candidate = os.path.join( os.path.dirname(result_filename), "lib" + os.path.basename(result_filename)[:-4] + ".a", ) if os.path.exists(candidate): os.unlink(candidate) if isWin32Windows() and Options.shallTreatUninstalledPython(): shutil.copy(getTargetPythonDLLPath(), os.path.dirname(result_filename) or ".")
def executePostProcessing(): # These is a bunch of stuff to consider, pylint: disable=too-many-branches result_filename = OutputDirectories.getResultFullpath() if not os.path.exists(result_filename): postprocessing_logger.sysexit( "Error, scons failed to create the expected file %r. " % result_filename) if isWin32Windows(): if not Options.shallMakeModule(): needs_manifest = False manifest = None if python_version < 0x300: # Copy the Windows manifest from the CPython binary to the created # executable, so it finds "MSCRT.DLL". This is needed for Python2 # only, for Python3 newer MSVC doesn't hide the C runtime. manifest = getWindowsExecutableManifest(sys.executable) if manifest is not None: needs_manifest = True if (Options.shallAskForWindowsAdminRights() or Options.shallAskForWindowsUIAccessRights()): needs_manifest = True if manifest is None: manifest = getDefaultWindowsExecutableManifest() if Options.shallAskForWindowsAdminRights(): manifest.addUacAdmin() if Options.shallAskForWindowsUIAccessRights(): manifest.addUacUiAccess() if needs_manifest: manifest.addResourceToFile(result_filename, logger=postprocessing_logger) if (Options.getWindowsVersionInfoStrings() or Options.getWindowsProductVersion() or Options.getWindowsFileVersion()): version_resources.update( addVersionInfoResource( string_values=Options.getWindowsVersionInfoStrings(), product_version=Options.getWindowsProductVersion(), file_version=Options.getWindowsFileVersion(), file_date=(0, 0), is_exe=not Options.shallMakeModule(), result_filename=result_filename, logger=postprocessing_logger, )) source_dir = OutputDirectories.getSourceDirectoryPath() # Attach the binary blob as a Windows resource. addResourceToFile( target_filename=result_filename, data=getFileContents(getConstantBlobFilename(source_dir), "rb"), resource_kind=RT_RCDATA, res_name=3, lang_id=0, logger=postprocessing_logger, ) # Attach icons from template file if given. template_exe = Options.getWindowsIconExecutablePath() if template_exe is not None: res_copied = copyResourcesFromFileToFile( template_exe, target_filename=result_filename, resource_kinds=(RT_ICON, RT_GROUP_ICON), ) if res_copied == 0: postprocessing_logger.warning( "The specified icon template executable %r didn't contain anything to copy." % template_exe) else: postprocessing_logger.warning( "Copied %d icon resources from %r." % (res_copied, template_exe)) else: addWindowsIconFromIcons() # On macOS, we update the executable path for searching the "libpython" # library. if (getOS() == "Darwin" and not Options.shallMakeModule() and not Options.shallUseStaticLibPython()): python_abi_version = python_version_str + getPythonABI() python_dll_filename = "libpython" + python_abi_version + ".dylib" python_lib_path = os.path.join(sys.prefix, "lib") # Note: For CPython and potentially others, the rpath for the Python # library needs to be set. callInstallNameTool( filename=result_filename, mapping=( ( python_dll_filename, os.path.join(python_lib_path, python_dll_filename), ), ( "@rpath/Python3.framework/Versions/%s/Python3" % python_version_str, os.path.join(python_lib_path, python_dll_filename), ), ), rpath=python_lib_path, ) # Modules should not be executable, but Scons creates them like it, fix # it up here. if not isWin32Windows() and Options.shallMakeModule(): removeFileExecutablePermission(result_filename) if isWin32Windows() and Options.shallMakeModule(): candidate = os.path.join( os.path.dirname(result_filename), "lib" + os.path.basename(result_filename)[:-4] + ".a", ) if os.path.exists(candidate): os.unlink(candidate) if isWin32Windows() and Options.shallTreatUninstalledPython(): shutil.copy(getTargetPythonDLLPath(), os.path.dirname(result_filename) or ".")
def executePostProcessing(): """Postprocessing of the resulting binary. These are in part required steps, not usable after failure. """ result_filename = OutputDirectories.getResultFullpath(onefile=False) if not os.path.exists(result_filename): postprocessing_logger.sysexit( "Error, scons failed to create the expected file %r. " % result_filename) if isWin32Windows(): if not Options.shallMakeModule(): if python_version < 0x300: # Copy the Windows manifest from the CPython binary to the created # executable, so it finds "MSCRT.DLL". This is needed for Python2 # only, for Python3 newer MSVC doesn't hide the C runtime. manifest = getWindowsExecutableManifest(sys.executable) else: manifest = None executePostProcessingResources(manifest=manifest, onefile=False) source_dir = OutputDirectories.getSourceDirectoryPath() # Attach the binary blob as a Windows resource. addResourceToFile( target_filename=result_filename, data=getFileContents(getConstantBlobFilename(source_dir), "rb"), resource_kind=RT_RCDATA, res_name=3, lang_id=0, logger=postprocessing_logger, ) # On macOS, we update the executable path for searching the "libpython" # library. if (isMacOS() and not Options.shallMakeModule() and not Options.shallUseStaticLibPython()): python_abi_version = python_version_str + getPythonABI() python_dll_filename = "libpython" + python_abi_version + ".dylib" python_lib_path = os.path.join(sys.prefix, "lib") # Note: For CPython and potentially others, the rpath for the Python # library needs to be set. callInstallNameTool( filename=result_filename, mapping=( ( python_dll_filename, os.path.join(python_lib_path, python_dll_filename), ), ( "@rpath/Python3.framework/Versions/%s/Python3" % python_version_str, os.path.join(python_lib_path, python_dll_filename), ), ), id_path=None, rpath=python_lib_path, ) if Options.shallCreateAppBundle(): createPlistInfoFile(logger=postprocessing_logger, onefile=False) # Modules should not be executable, but Scons creates them like it, fix # it up here. if not isWin32Windows() and Options.shallMakeModule(): removeFileExecutablePermission(result_filename) if isWin32Windows() and Options.shallMakeModule(): candidate = os.path.join( os.path.dirname(result_filename), "lib" + os.path.basename(result_filename)[:-4] + ".a", ) if os.path.exists(candidate): os.unlink(candidate) # Might have to create a CMD file, potentially with debugger run. if Options.shallCreateCmdFileForExecution(): dll_directory = getExternalUsePath( os.path.dirname(getTargetPythonDLLPath())) cmd_filename = OutputDirectories.getResultRunFilename(onefile=False) cmd_contents = """ @echo off rem This script was created by Nuitka to execute '%(exe_filename)s' with Python DLL being found. set PATH=%(dll_directory)s;%%PATH%% set PYTHONHOME=%(dll_directory)s %(debugger_call)s"%%~dp0.\\%(exe_filename)s" %%* """ % { "debugger_call": (" ".join(wrapCommandForDebuggerForExec()) + " ") if Options.shallRunInDebugger() else "", "dll_directory": dll_directory, "exe_filename": os.path.basename(result_filename), } putTextFileContents(cmd_filename, cmd_contents) # Create a ".pyi" file for created modules if Options.shallMakeModule() and Options.shallCreatePyiFile(): pyi_filename = OutputDirectories.getResultBasepath() + ".pyi" putTextFileContents( filename=pyi_filename, contents="""\ # This file was generated by Nuitka and describes the types of the # created shared library. # At this time it lists only the imports made and can be used by the # tools that bundle libraries, including Nuitka itself. For instance # standalone mode usage of the created library will need it. # In the future, this will also contain type information for values # in the module, so IDEs will use this. Therefore please include it # when you make software releases of the extension module that it # describes. %(imports)s # This is not Python source even if it looks so. Make it clear for # now. This was decided by PEP 484 designers. __name__ = ... """ % { "imports": "\n".join("import %s" % module_name for module_name in getImportedNames()) }, )
def executePostProcessing(): """Postprocessing of the resulting binary. These are in part required steps, not usable after failure. """ result_filename = OutputDirectories.getResultFullpath(onefile=False) if not os.path.exists(result_filename): postprocessing_logger.sysexit( "Error, scons failed to create the expected file %r. " % result_filename ) if isWin32Windows(): if not Options.shallMakeModule(): if python_version < 0x300: # Copy the Windows manifest from the CPython binary to the created # executable, so it finds "MSCRT.DLL". This is needed for Python2 # only, for Python3 newer MSVC doesn't hide the C runtime. manifest = getWindowsExecutableManifest(sys.executable) else: manifest = None executePostProcessingResources(manifest=manifest, onefile=False) source_dir = OutputDirectories.getSourceDirectoryPath() # Attach the binary blob as a Windows resource. addResourceToFile( target_filename=result_filename, data=getFileContents(getConstantBlobFilename(source_dir), "rb"), resource_kind=RT_RCDATA, res_name=3, lang_id=0, logger=postprocessing_logger, ) # On macOS, we update the executable path for searching the "libpython" # library. if ( getOS() == "Darwin" and not Options.shallMakeModule() and not Options.shallUseStaticLibPython() ): python_abi_version = python_version_str + getPythonABI() python_dll_filename = "libpython" + python_abi_version + ".dylib" python_lib_path = os.path.join(sys.prefix, "lib") # Note: For CPython and potentially others, the rpath for the Python # library needs to be set. callInstallNameTool( filename=result_filename, mapping=( ( python_dll_filename, os.path.join(python_lib_path, python_dll_filename), ), ( "@rpath/Python3.framework/Versions/%s/Python3" % python_version_str, os.path.join(python_lib_path, python_dll_filename), ), ), rpath=python_lib_path, ) # Modules should not be executable, but Scons creates them like it, fix # it up here. if not isWin32Windows() and Options.shallMakeModule(): removeFileExecutablePermission(result_filename) if isWin32Windows() and Options.shallMakeModule(): candidate = os.path.join( os.path.dirname(result_filename), "lib" + os.path.basename(result_filename)[:-4] + ".a", ) if os.path.exists(candidate): os.unlink(candidate) if isWin32Windows() and Options.shallTreatUninstalledPython(): shutil.copy(getTargetPythonDLLPath(), os.path.dirname(result_filename) or ".")