def wrapCommandForDebuggerForExec(*args): """Wrap a command for system debugger to call exec Args: args: (list of str) args for call to be debugged Returns: args tuple with debugger command inserted Notes: Currently only gdb and lldb are supported, but adding more debuggers would be very welcome. """ gdb_path = getExecutablePath("gdb") # Windows extra ball, attempt the downloaded one. if isWin32Windows() and gdb_path is None: from nuitka.Options import assumeYesForDownloads mingw64_gcc_path = getCachedDownloadedMinGW64( target_arch=getArchitecture(), assume_yes_for_downloads=assumeYesForDownloads(), ) with withEnvironmentPathAdded("PATH", os.path.dirname(mingw64_gcc_path)): lldb_path = getExecutablePath("lldb") if gdb_path is None and lldb_path is None: lldb_path = getExecutablePath("lldb") if lldb_path is None: general.sysexit("Error, no 'gdb' or 'lldb' binary found in path.") if gdb_path is not None: args = (gdb_path, "gdb", "-ex=run", "-ex=where", "-ex=quit", "--args") + args else: args = (lldb_path, "lldb", "-o", "run", "-o", "bt", "-o", "quit", "--") + args return args
def getAppImageToolPath(): """Return the path of appimagetool (for Linux). Will prompt the user to download if not already cached in AppData directory for Nuitka. """ appimagetool_url = ( "https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-%s.AppImage" % getArchitecture()) return getCachedDownload( url=appimagetool_url, is_arch_specific=True, binary=appimagetool_url.rsplit("/", 1)[1], flatten=True, specifity=appimagetool_url.rsplit("/", 2)[1], message="""\ Nuitka will make use of AppImage (https://appimage.org/) tool to combine Nuitka dist folder to onefile binary.""", reject="Nuitka does not work in --onefile on Linux without.", assume_yes_for_downloads=assumeYesForDownloads(), )
def getDependsExePath(): """Return the path of depends.exe (for Windows). Will prompt the user to download if not already cached in AppData directory for Nuitka. """ if getArchitecture() == "x86": depends_url = "https://dependencywalker.com/depends22_x86.zip" else: depends_url = "https://dependencywalker.com/depends22_x64.zip" return getCachedDownload( url=depends_url, is_arch_specific=getArchitecture(), binary="depends.exe", flatten=True, specificity="", # Note: If there ever was an update, put version here. message="""\ Nuitka will make use of Dependency Walker (https://dependencywalker.com) tool to analyze the dependencies of Python extension modules.""", reject="Nuitka does not work in --standalone or --onefile on Windows without.", assume_yes_for_downloads=assumeYesForDownloads(), )
def packDistFolderToOnefileLinux(onefile_output_filename, dist_dir, binary_filename): """Pack to onefile binary on Linux. Notes: This is mostly a wrapper around AppImage, which does all the heavy lifting. """ if not locateDLL("fuse"): postprocessing_logger.sysexit( """\ Error, the fuse library (libfuse.so.x from fuse2, *not* fuse3) must be installed for onefile creation to work on Linux.""" ) # This might be possible to avoid being done with --runtime-file. apprun_filename = os.path.join(dist_dir, "AppRun") with open(apprun_filename, "w") as output_file: output_file.write( """\ #!/bin/bash exec -a $ARGV0 $APPDIR/%s $@""" % os.path.basename(binary_filename) ) addFileExecutablePermission(apprun_filename) binary_basename = os.path.basename(getResultBasepath()) icon_paths = getIconPaths() assert icon_paths extension = os.path.splitext(icon_paths[0])[1].lower() shutil.copyfile(icon_paths[0], getResultBasepath() + extension) with open(getResultBasepath() + ".desktop", "w") as output_file: output_file.write( """\ [Desktop Entry] Name=%(binary_basename)s Exec=%(binary_filename)s Icon=%(binary_basename)s Type=Application Categories=Utility;""" % { "binary_basename": binary_basename, "binary_filename": os.path.basename(binary_filename), } ) postprocessing_logger.info( "Creating single file from dist folder, this may take a while." ) stdout_filename = binary_filename + ".appimage.stdout.txt" stderr_filename = binary_filename + ".appimage.stderr.txt" stdout_file = open(stdout_filename, "wb") stderr_file = open(stderr_filename, "wb") # Starting the process while locked, so file handles are not duplicated. appimagetool_process = subprocess.Popen( ( _getAppImageToolPath( for_operation=True, assume_yes_for_downloads=assumeYesForDownloads() ), dist_dir, "--comp", "xz", "-n", onefile_output_filename, ), shell=False, stdin=getNullInput(), stdout=stdout_file, stderr=stderr_file, ) result = appimagetool_process.wait() stdout_file.close() stderr_file.close() if not os.path.exists(onefile_output_filename): postprocessing_logger.sysexit( "Error, expected output file %r not created by AppImage, check its outputs %r and %r." % (onefile_output_filename, stdout_filename, stderr_filename) ) if result != 0: # Useless now. os.unlink(onefile_output_filename) if b"Text file busy" in getFileContents(stderr_filename, mode="rb"): postprocessing_logger.sysexit( "Error, error exit from AppImage because target file is locked." ) postprocessing_logger.sysexit( "Error, error exit from AppImage, check its outputs %r and %r." % (stdout_filename, stderr_filename) ) os.unlink(stdout_filename) os.unlink(stderr_filename) postprocessing_logger.info("Completed onefile creation.")
def getDependsExePath(): """ Return the path of depends.exe (for Windows). Will prompt the user to download if not already cached in AppData directory for Nuitka. """ if Utils.getArchitecture() == "x86": depends_url = "http://dependencywalker.com/depends22_x86.zip" else: depends_url = "http://dependencywalker.com/depends22_x64.zip" nuitka_app_dir = getAppDir() nuitka_depends_dir = os.path.join(nuitka_app_dir, Utils.getArchitecture()) nuitka_depends_zip = os.path.join(nuitka_depends_dir, os.path.basename(depends_url)) depends_exe = os.path.join(nuitka_depends_dir, "depends.exe") makePath(nuitka_depends_dir) if not os.path.isfile(nuitka_depends_zip) and not os.path.isfile( depends_exe): if assumeYesForDownloads(): reply = "y" else: Tracing.printLine("""\ Nuitka will make use of Dependency Walker (http://dependencywalker.com) tool to analyze the dependencies of Python extension modules. Is it OK to download and put it in "%s". No installer needed, cached, one time question. Proceed and download? [Yes]/No """ % (nuitka_app_dir)) Tracing.flushStdout() reply = raw_input() if reply.lower() in ("no", "n"): sys.exit( "Nuitka does not work in --standalone on Windows without.") info("Downloading '%s'" % depends_url) try: urlretrieve(depends_url, nuitka_depends_zip) except Exception: # Any kind of error, pylint: disable=broad-except sys.exit("""Failed to download '%s'.\ Contents should manually be extracted to '%s'.""" % (depends_url, nuitka_depends_dir)) if not os.path.isfile(depends_exe): info("Extracting to '%s'" % depends_exe) import zipfile try: depends_zip = zipfile.ZipFile(nuitka_depends_zip) depends_zip.extractall(nuitka_depends_dir) except Exception: # Catching anything zip throws, pylint: disable=broad-except info("Problem with the downloaded zip file, deleting it.") deleteFile(depends_exe, must_exist=False) deleteFile(nuitka_depends_zip, must_exist=True) sys.exit("Error, need '%s' as extracted from '%s'." % (depends_exe, depends_url)) assert os.path.isfile(depends_exe) return depends_exe
def packDistFolderToOnefileLinux(onefile_output_filename, dist_dir, binary_filename): """Pack to onefile binary on Linux. Notes: This is mostly a wrapper around AppImage, which does all the heavy lifting. """ if not locateDLL("fuse"): postprocessing_logger.sysexit("""\ Error, the fuse library (libfuse.so.x from fuse2, *not* fuse3) must be installed for onefile creation to work on Linux.""") # This might be possible to avoid being done with --runtime-file. apprun_filename = os.path.join(dist_dir, "AppRun") putTextFileContents( apprun_filename, contents="""\ #!/bin/bash exec -a $ARGV0 $APPDIR/%s \"$@\"""" % os.path.basename(binary_filename), ) addFileExecutablePermission(apprun_filename) binary_basename = os.path.basename(getResultBasepath()) icon_paths = getIconPaths() assert icon_paths extension = os.path.splitext(icon_paths[0])[1].lower() copyFile(icon_paths[0], getResultBasepath() + extension) putTextFileContents( getResultBasepath() + ".desktop", contents="""\ [Desktop Entry] Name=%(binary_basename)s Exec=%(binary_filename)s Icon=%(binary_basename)s Type=Application Categories=Utility;""" % { "binary_basename": binary_basename, "binary_filename": os.path.basename(binary_filename), }, ) postprocessing_logger.info( "Creating single file from dist folder, this may take a while.") stdout_filename = binary_filename + ".appimage.stdout.txt" stderr_filename = binary_filename + ".appimage.stderr.txt" stdout_file = openTextFile(stdout_filename, "wb") stderr_file = openTextFile(stderr_filename, "wb") command = ( _getAppImageToolPath(for_operation=True, assume_yes_for_downloads=assumeYesForDownloads()), dist_dir, "--comp", getAppImageCompression(), "-n", onefile_output_filename, ) stderr_file.write(b"Executed %r\n" % " ".join(command)) # Starting the process while locked, so file handles are not duplicated, we # need fine grained control over process here, therefore we cannot use the # Execution.executeProcess() function without making it too complex and not # all Python versions allow using with, pylint: disable=consider-using-with # pylint: disable appimagetool_process = subprocess.Popen( command, shell=False, stdin=getNullInput(), stdout=stdout_file, stderr=stderr_file, ) result = appimagetool_process.wait() stdout_file.close() stderr_file.close() if result != 0: # Useless result if there were errors, so now remove it. deleteFile(onefile_output_filename, must_exist=False) stderr = getFileContents(stderr_filename, mode="rb") if b"Text file busy" in stderr: postprocessing_logger.sysexit( "Error, error exit from AppImage because target file is locked." ) if b"modprobe fuse" in stderr: postprocessing_logger.sysexit( "Error, error exit from AppImage because fuse kernel module was not loaded." ) postprocessing_logger.sysexit( "Error, error exit from AppImage, check its outputs '%s' and '%s'." % (stdout_filename, stderr_filename)) if not os.path.exists(onefile_output_filename): postprocessing_logger.sysexit( "Error, expected output file %r not created by AppImage, check its outputs '%s' and '%s'." % (onefile_output_filename, stdout_filename, stderr_filename)) deleteFile(stdout_filename, must_exist=True) deleteFile(stderr_filename, must_exist=True) postprocessing_logger.info("Completed onefile creation.")
def getDependsExePath(): """ Return the path of depends.exe (for Windows). Will prompt the user to download if not already cached in AppData directory for Nuitka. """ if Utils.getArchitecture() == "x86": depends_url = "http://dependencywalker.com/depends22_x86.zip" else: depends_url = "http://dependencywalker.com/depends22_x64.zip" nuitka_app_dir = getAppDir() nuitka_depends_dir = os.path.join(nuitka_app_dir, Utils.getArchitecture()) nuitka_depends_zip = os.path.join(nuitka_depends_dir, os.path.basename(depends_url)) depends_exe = os.path.join(nuitka_depends_dir, "depends.exe") makePath(nuitka_depends_dir) if not os.path.isfile(nuitka_depends_zip) and not os.path.isfile(depends_exe): if assumeYesForDownloads(): reply = "y" else: Tracing.printLine( """\ Nuitka will make use of Dependency Walker (http://dependencywalker.com) tool to analyze the dependencies of Python extension modules. Is it OK to download and put it in "%s". No installer needed, cached, one time question. Proceed and download? [Yes]/No """ % (nuitka_app_dir) ) Tracing.flushStdout() reply = raw_input() if reply.lower() in ("no", "n"): sys.exit("Nuitka does not work in --standalone on Windows without.") info("Downloading '%s'" % depends_url) try: urlretrieve(depends_url, nuitka_depends_zip) except Exception: # Any kind of error, pylint: disable=broad-except sys.exit( """Failed to download '%s'.\ Contents should manually be extracted to '%s'.""" % (depends_url, nuitka_depends_dir) ) if not os.path.isfile(depends_exe): info("Extracting to '%s'" % depends_exe) import zipfile try: depends_zip = zipfile.ZipFile(nuitka_depends_zip) depends_zip.extractall(nuitka_depends_dir) except Exception: # Catching anything zip throws, pylint:disable=W0703 info("Problem with the downloaded zip file, deleting it.") deleteFile(depends_exe, must_exist=False) deleteFile(nuitka_depends_zip, must_exist=True) sys.exit( "Error, need '%s' as extracted from '%s'." % (depends_exe, depends_url) ) assert os.path.isfile(depends_exe) return depends_exe