def getPython2ExePath(): """ Find a way to call any Python2. Scons needs it.""" if python_version < 300: return sys.executable elif Utils.getOS() == "Windows": python_exe = _getPython2ExePathWindows() if python_exe is not None: return python_exe else: sys.exit("""\ Error, while Nuitka is fully Python3 compatible, it needs to find a Python2 executable under C:\\Python26 or C:\\Python27 to execute scons which is not yet Python3 compatible.""") candidate = Execution.getExecutablePath("python2.7") if candidate is None: candidate = Execution.getExecutablePath("python2.6") if candidate is None: candidate = Execution.getExecutablePath("python2") # Our weakest bet is that there is no "python3" named "python", but we # take it, as on some systems it's true. if candidate is None: candidate = "python" return candidate
def checkVersion(): # pylint: disable=global-statement global pylint_version if not hasModule("pylint"): sys.exit( "Error, pylint is not installed for this interpreter %r version." % os.environ["PYTHON"] ) if pylint_version is None: with open(os.devnull, "w") as devnull: pylint_version = Execution.check_output( [os.environ["PYTHON"], "-m", "pylint", "--version"], stderr=devnull ) if str is not bytes: pylint_version = pylint_version.decode("utf8") pylint_version = pylint_version.split("\n")[0].split()[-1].strip(",") if pylint_version < "1.6.5": sys.exit("Error, needs PyLint 1.6.5 or higher not %r." % pylint_version) my_print("Using PyLint version:", pylint_version)
def _getMatplotlibInfo(): """Determine the filename of matplotlibrc and the default backend. Notes: There might exist a local version outside 'matplotlib/mpl-data' which we then must use instead. Determine its name by aksing matplotlib. """ cmd = """\ from __future__ import print_function from matplotlib import matplotlib_fname, get_backend, _get_data_path, __version__ print(matplotlib_fname()) print(get_backend()) print(_get_data_path()) print(__version__) """ feedback = Execution.check_output([sys.executable, "-c", cmd]) if str is not bytes: # ensure str in Py3 and up feedback = feedback.decode("utf8") feedback = feedback.replace("\r", "") ( matplotlibrc_filename, backend, data_path, matplotlib_version, ) = feedback.splitlines() return matplotlibrc_filename, backend, data_path, matplotlib_version
def _getSconsBinaryCall(): """Return a way to execute Scons. Using potentially in-line copy if no system Scons is available or if we are on Windows, there it is mandatory. """ inline_path = os.path.join(_getSconsInlinePath(), "bin", "scons.py") if os.path.exists(inline_path): return [ _getPythonForSconsExePath(), "-W", "ignore", # Disable Python warnings in case of debug Python. getExternalUsePath(inline_path), ] else: scons_path = Execution.getExecutablePath("scons") if scons_path is not None: return [scons_path] else: Tracing.scons_logger.sysexit( "Error, the inline copy of scons is not present, nor a scons binary in the PATH." )
def executeMain(binary_filename, clean_path): if Options.shallRunInDebugger(): args = Execution.wrapCommandForDebuggerForExec(binary_filename) else: args = (binary_filename, binary_filename) callExecPython(clean_path=clean_path, add_path=False, args=args)
def getPylintBinaryPath(): # pylint: disable=global-statement global pylint_binary if pylint_binary is None: pylint_binary = Execution.getExecutablePath("pylint") return pylint_binary
def _wrapForDebugger(*args): gdb_path = Execution.getExecutablePath("gdb") if gdb_path is None: sys.exit("Error, no 'gdb' binary found in path.") args = (gdb_path, "gdb", "-ex=run", "-ex=where", "--args") + args return args
def executeModule(tree, clean_path): python_command = "__import__('%s')" % tree.getName() if Options.shallRunInDebugger(): args = Execution.wrapCommandForDebuggerForExec(sys.executable, "-c", python_command) else: args = (sys.executable, "python", "-c", python_command) callExecPython(clean_path=clean_path, add_path=True, args=args)
def callExecPython(args, clean_path, add_path): old_python_path = os.environ.get("PYTHONPATH", None) if clean_path and old_python_path is not None: os.environ["PYTHONPATH"] = "" if add_path: if "PYTHONPATH" in os.environ: os.environ["PYTHONPATH"] += ":" + Options.getOutputDir() else: os.environ["PYTHONPATH"] = Options.getOutputDir() # We better flush these, "os.execl" won't do it anymore. sys.stdout.flush() sys.stderr.flush() # Add the main arguments, previous separated. args += Options.getPositionalArgs()[1:] + Options.getMainArgs() Execution.callExec(args)
def callExecPython(args, clean_path, add_path): old_python_path = os.environ.get("PYTHONPATH", None) if clean_path and old_python_path is not None: os.environ["PYTHONPATH"] = "" if add_path: if "PYTHONPATH" in os.environ: os.environ["PYTHONPATH"] += ':' + Options.getOutputDir() else: os.environ["PYTHONPATH"] = Options.getOutputDir() # We better flush these, "os.execl" won't do it anymore. sys.stdout.flush() sys.stderr.flush() # Add the main arguments, previous separated. args += Options.getPositionalArgs()[1:] + Options.getMainArgs() Execution.callExec(args)
def _getPython2ExePath(): """ Find a way to call any Python2. Scons needs it as it doesn't support Python3. """ python_exe = Options.getPython2PathForScons() if python_exe is not None: return python_exe if python_version < 300: return sys.executable elif Utils.getOS() == "Windows": python_exe = _getPython2ExePathWindows() if python_exe is not None: return python_exe else: sys.exit("""\ Error, while Nuitka is fully Python3 compatible, it needs to find a Python2 executable under C:\\Python26 or C:\\Python27 to execute Scons utility which is used to build the C files to binary, and which is not yet Python3 compatible. You may provide it using option "--python2-for-scons=path_to_python.exe" in case it is not visible in registry, e.g. uninstalled AnaConda Python. """) candidate = Execution.getExecutablePath("python2.7") if candidate is None: candidate = Execution.getExecutablePath("python2.6") if candidate is None: candidate = Execution.getExecutablePath("python2") # Our weakest bet is that there is no "python3" named "python", but we # take it, as on some systems it's true. if candidate is None: candidate = "python" return candidate
def executeMain(binary_filename, clean_path): args = (binary_filename, binary_filename) if Options.shallRunInDebugger(): gdb_path = Execution.getExecutablePath("gdb") if gdb_path is None: sys.exit("Error, no 'gdb' binary found in path.") args = (gdb_path, "gdb", "-ex=run", "-ex=where", "--args", binary_filename) callExecPython(clean_path=clean_path, add_path=False, args=args)
def getPyQtPluginDirs(self, qt_version): if qt_version in self.qt_dirs: return self.qt_dirs[qt_version] command = """\ from __future__ import print_function from __future__ import absolute_import import PyQt%(qt_version)d.QtCore for v in PyQt%(qt_version)d.QtCore.QCoreApplication.libraryPaths(): print(v) import os # Standard CPython has installations like this. guess_path = os.path.join(os.path.dirname(PyQt%(qt_version)d.__file__), "plugins") if os.path.exists(guess_path): print("GUESS:", guess_path) # Anaconda has this, but it seems not automatic. guess_path = os.path.join(os.path.dirname(PyQt%(qt_version)d.__file__), "..", "..", "..", "Library", "plugins") if os.path.exists(guess_path): print("GUESS:", guess_path) """ % { "qt_version": qt_version } output = Execution.check_output([sys.executable, "-c", command]) # May not be good for everybody, but we cannot have bytes in paths, or # else working with them breaks down. if str is not bytes: output = output.decode("utf-8") result = [] for line in output.replace("\r", "").split("\n"): if not line: continue # Take the guessed path only if necessary. if line.startswith("GUESS: "): if result: continue line = line[len("GUESS: ") :] result.append(os.path.normpath(line)) # Avoid duplicates. result = tuple(sorted(set(result))) self.qt_dirs[qt_version] = result return result
def _getMatplotlibInfo(self): """Determine the filename of matplotlibrc and the default backend, etc. Notes: There might exist a local version outside 'matplotlib/mpl-data' which we then must use instead. Determine its name by aksing matplotlib. """ # TODO: Replace this with using self.queryRuntimeInformationMultiple to remove # code duplication. if self.matplotlib_info is None: cmd = r"""\ from __future__ import print_function from matplotlib import matplotlib_fname, get_backend, __version__ try: from matplotlib import get_data_path except ImportError: from matplotlib import _get_data_path as get_data_path from inspect import getsource print(repr(matplotlib_fname())) print(repr(get_backend())) print(repr(get_data_path())) print(repr(__version__)) print(repr("MATPLOTLIBDATA" in getsource(get_data_path))) """ # TODO: Make this is a re-usable pattern, output from a script with values per line feedback = Execution.check_output([sys.executable, "-c", cmd]) if str is not bytes: # ensure str in Py3 and up feedback = feedback.decode("utf8") # Ignore Windows newlines difference. feedback = feedback.replace("\r", "") MatplotlibInfo = namedtuple( "MatplotlibInfo", ( "matplotlibrc_filename", "backend", "data_path", "matplotlib_version", "needs_matplotlibdata_env", ), ) # We are being lazy here, the code is trusted, pylint: disable=eval-used self.matplotlib_info = MatplotlibInfo( *(eval(value) for value in feedback.splitlines())) return self.matplotlib_info
def _getPythonSconsExePathWindows(): """Find Python for Scons on Windows. Only 3.5 or higher will do. """ # Ordered in the list of preference. python_dir = Execution.getPythonInstallPathWindows(supported=("3.5", "3.6", "3.7", "3.8", "3.9")) if python_dir is not None: return os.path.join(python_dir, "python.exe") else: return None
def getSconsBinaryCall(): """ Return a way to execute Scons. Using potentially in-line copy if no system Scons is available or if we are on Windows. """ if Utils.getOS() != "Windows": scons_path = Execution.getExecutablePath("scons") if scons_path is not None: return [scons_path] return [ getPython2ExePath(), Utils.joinpath(getSconsInlinePath(), "bin", "scons.py") ]
def _getSconsBinaryCall(): """ Return a way to execute Scons. Using potentially in-line copy if no system Scons is available or if we are on Windows, there it is mandatory. """ if Utils.getOS() != "Windows": scons_path = Execution.getExecutablePath("scons") if scons_path is not None: return [scons_path] return [ _getPythonForSconsExePath(), os.path.join(_getSconsInlinePath(), "bin", "scons.py") ]
def checkVersion(): # pylint: disable=global-statement global pylint_version if getPylintBinaryPath() is None: sys.exit("Error, pylint is not installed.") if pylint_version is None: pylint_version = Execution.check_output( [sys.executable, getPylintBinaryPath(), "--version"], stderr = open(os.devnull, 'w') ) pylint_version = pylint_version.split(b"\n")[0].split()[-1] if pylint_version < b"1.6.5": sys.exit("Error, needs PyLint 1.6.5 or higher not %r." % pylint_version)
def runScons(options, quiet, scons_filename): with _setupSconsEnvironment(): if Options.shallCompileWithoutBuildDirectory(): # Make sure we become non-local, by changing all paths to be # absolute, but ones that can be resolved by any program # externally, as the Python of Scons may not be good at unicode. options = copy.deepcopy(options) source_dir = options["source_dir"] options["source_dir"] = "." options["result_name"] = getExternalUsePath(options["result_name"], only_dirname=True) options["nuitka_src"] = getExternalUsePath(options["nuitka_src"]) if "result_exe" in options: options["result_exe"] = getExternalUsePath( options["result_exe"], only_dirname=True) if "compiled_exe" in options: options["compiled_exe"] = getExternalUsePath( options["compiled_exe"], only_dirname=True) else: source_dir = None scons_command = _buildSconsCommand(quiet=quiet, options=options, scons_filename=scons_filename) if Options.isShowScons(): Tracing.printLine("Scons command:", " ".join(scons_command)) Tracing.flushStandardOutputs() # Call scons, make sure to pass on quiet setting. with Execution.withEnvironmentVarOverridden( "NUITKA_QUIET", "1" if Tracing.is_quiet else "0"): result = subprocess.call(scons_command, shell=False, cwd=source_dir) flushSconsReports() if result == 0: checkCachingSuccess(source_dir or options["source_dir"]) return result == 0
def _getPythonSconsExePathWindows(): """Find Python for Scons on Windows. First try a few guesses, the look into registry for user or system wide installations of Python2. Both Python 2.6 and 2.7, and 3.5 or higher will do. """ # Ordered in the list of preference. python_dir = Execution.getPythonInstallPathWindows(supported=("2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "2.6")) if python_dir is not None: return os.path.join(python_dir, "python.exe") else: return None
def _getSconsBinaryCall(): """ Return a way to execute Scons. Using potentially in-line copy if no system Scons is available or if we are on Windows, there it is mandatory. """ if Utils.getOS() != "Windows": scons_path = Execution.getExecutablePath("scons") if scons_path is not None: return [scons_path] return [ _getPythonForSconsExePath(), "-W", "ignore", # Disable Python warnings in case of debug Python. os.path.join(_getSconsInlinePath(), "bin", "scons.py"), ]
def _getPythonForSconsExePath(): """Find a way to call any Python that works for Scons. Scons needs it as it doesn't support all Python versions. """ python_exe = Options.getPythonPathForScons() if python_exe is not None: return python_exe if python_version < 0x300 and not Utils.isWin32Windows(): # Python 2.6 and 2.7 are fine for scons on all platforms, but not # on Windows due to clcache usage. return sys.executable elif python_version >= 0x350: # Python 3.5 or higher work on all platforms. return sys.executable elif Utils.isWin32Windows(): python_exe = _getPythonSconsExePathWindows() if python_exe is not None: return python_exe else: Tracing.scons_logger.sysexit( """\ Error, while Nuitka works with older Python, Scons does not, and therefore Nuitka needs to find a Python 3.5 or higher executable, so please install it. You may provide it using option "--python-for-scons=path_to_python.exe" in case it is not visible in registry, e.g. due to using uninstalled Anaconda Python. """ ) for version_candidate in ("2.7", "2.6", "3.5", "3.6", "3.7", "3.8", "3.9"): candidate = Execution.getExecutablePath("python" + version_candidate) if candidate is not None: return candidate # Lets be optimistic, this is most often going to be new enough or a # Python2 variant. return "python"
def getPyQtPluginDirs(self, qt_version): if qt_version in self.qt_dirs: return self.qt_dirs[qt_version] command = """\ from __future__ import print_function import PyQt%(qt_version)d.QtCore for v in PyQt%(qt_version)d.QtCore.QCoreApplication.libraryPaths(): print(v) import os guess_path = os.path.join(os.path.dirname(PyQt%(qt_version)d.__file__), "plugins") if os.path.exists(guess_path): print("GUESS:", guess_path) """ % { "qt_version": qt_version } output = Execution.check_output([sys.executable, "-c", command]) # May not be good for everybody, but we cannot have bytes in paths, or # else working with them breaks down. if str is not bytes: output = output.decode("utf-8") result = [] for line in output.replace("\r", "").split("\n"): if not line: continue # Take the guessed path only if necessary. if line.startswith("GUESS: "): if result: continue line = line[len("GUESS: ") :] result.append(os.path.normpath(line)) self.qt_dirs[qt_version] = result return result
def getPyQtPluginDirs(self, qt_version): if qt_version in self.qt_dirs: return self.qt_dirs[qt_version] command = """\ from __future__ import print_function import PyQt%(qt_version)d.QtCore for v in PyQt%(qt_version)d.QtCore.QCoreApplication.libraryPaths(): print(v) import os guess_path = os.path.join(os.path.dirname(PyQt%(qt_version)d.__file__), "plugins") if os.path.exists(guess_path): print("GUESS:", guess_path) """ % { "qt_version": qt_version } output = Execution.check_output([sys.executable, "-c", command]) # May not be good for everybody, but we cannot have bytes in paths, or # else working with them breaks down. if str is not bytes: output = output.decode("utf-8") result = [] for line in output.replace('\r', "").split('\n'): if not line: continue # Take the guessed path only if necessary. if line.startswith("GUESS: "): if result: continue line = line[len("GUESS: "):] result.append(os.path.normpath(line)) self.qt_dirs[qt_version] = result return result
def _getPythonForSconsExePath(): """ Find a way to call any Python2. Scons needs it as it doesn't support Python3. """ python_exe = Options.getPythonPathForScons() if python_exe is not None: return python_exe if python_version < 300 or python_version >= 350: return sys.executable elif Utils.getOS() == "Windows": python_exe = _getPythonSconsExePathWindows() if python_exe is not None: return python_exe else: sys.exit( """\ Error, while Nuitka works with Python 3.2 to 3.4, scons does not, and Nuitka needs to find a Python executable 2.6/2.7 or 3.5 or higher. Simply under the C:\\PythonXY, e.g. C:\\Python27 to execute the scons utility which is used to build the C files to binary. You may provide it using option "--python-for-scons=path_to_python.exe" in case it is not visible in registry, e.g. due to using uninstalled AnaConda Python. """ ) for version_candidate in ("2.7", "2.6", "3.5", "3.6", "3.7"): candidate = Execution.getExecutablePath("python" + version_candidate) if candidate is not None: return candidate # Lets be optimistic, this is most often going to be new enough or a # Python2 variant. return "python"
def _getPythonForSconsExePath(): """ Find a way to call any Python2. Scons needs it as it doesn't support Python3. """ python_exe = Options.getPythonPathForScons() if python_exe is not None: return python_exe if python_version < 300 or python_version >= 350: return sys.executable elif Utils.getOS() == "Windows": python_exe = _getPythonSconsExePathWindows() if python_exe is not None: return python_exe else: sys.exit( """\ Error, while Nuitka works with Python 3.3 and 3.4, scons does not, and Nuitka needs to find a Python executable 2.6/2.7 or 3.5 or higher. Simply under the C:\\PythonXY, e.g. C:\\Python27 to execute the scons utility which is used to build the C files to binary. You may provide it using option "--python-for-scons=path_to_python.exe" in case it is not visible in registry, e.g. due to using uninstalled AnaConda Python. """ ) for version_candidate in ("2.7", "2.6", "3.5", "3.6", "3.7", "3.8"): candidate = Execution.getExecutablePath("python" + version_candidate) if candidate is not None: return candidate # Lets be optimistic, this is most often going to be new enough or a # Python2 variant. return "python"
def checkVersion(): # pylint: disable=global-statement global pylint_version if not hasModule("pylint"): sys.exit("Error, pylint is not installed for this interpreter version.") if pylint_version is None: with open(os.devnull, "w") as devnull: pylint_version = Execution.check_output( [os.environ["PYTHON"], "-m", "pylint", "--version"], stderr=devnull ) if str is not bytes: pylint_version = pylint_version.decode("utf8") pylint_version = pylint_version.split("\n")[0].split()[-1].strip(",") if pylint_version < "1.6.5": sys.exit("Error, needs PyLint 1.6.5 or higher not %r." % pylint_version) my_print("Using PyLint version:", pylint_version)
# not match, we restart ourselves with matching configuration. needs_reexec = False current_version = "%d.%d" % (sys.version_info[0], sys.version_info[1]) # We support to execute with a specified version. intended_version = Options.getIntendedPythonVersion() if intended_version is None: intended_version = current_version # If it's a different version, we find it by guessing it, otherwise we use the # one previously used. if current_version != intended_version: if Utils.getOS() == "Windows": python_binary = Execution.getPythonExePathWindows( intended_version, Options.getIntendedPythonArch() ) else: python_binary = Execution.getExecutablePath("python" + intended_version) if python_binary is None: sys.exit( "Error, cannot find Python %s binary in PATH (%s)." % ( intended_version, os.environ.get("PATH", "") ) ) needs_reexec = True else: python_binary = sys.executable
def main(): # PyLint for Python3 thinks we import from ourselves if we really # import from package, pylint:disable=I0021,no-name-in-module # Also high complexity. # pylint: disable=too-many-branches,too-many-locals,too-many-statements if "NUITKA_BINARY_NAME" in os.environ: sys.argv[0] = os.environ["NUITKA_BINARY_NAME"] if "NUITKA_PYTHONPATH" in os.environ: # Restore the PYTHONPATH gained from the site module, that we chose not # to have imported. pylint: disable=eval-used sys.path = eval(os.environ["NUITKA_PYTHONPATH"]) del os.environ["NUITKA_PYTHONPATH"] else: # Remove path element added for being called via "__main__.py", this can # only lead to trouble, having e.g. a "distutils" in sys.path that comes # from "nuitka.distutils". sys.path = [ path_element for path_element in sys.path if os.path.dirname(os.path.abspath(__file__)) != path_element ] # For re-execution, we might not have done this. from nuitka import Options # isort:skip Options.parseArgs() import logging # isort:skip logging.basicConfig(format="Nuitka:%(levelname)s:%(message)s") # We don't care, and these are triggered by run time calculations of "range" and # others, while on python2.7 they are disabled by default. warnings.simplefilter("ignore", DeprecationWarning) # We will run with the Python configuration as specified by the user, if it does # not match, we restart ourselves with matching configuration. needs_reexec = False current_version = "%d.%d" % (sys.version_info[0], sys.version_info[1]) if sys.flags.no_site == 0: needs_reexec = True # The hash randomization totally changes the created source code created, # changing it every single time Nuitka is run. This kills any attempt at # caching it, and comparing generated source code. While the created binary # actually may still use it, during compilation we don't want to. So lets # disable it. if os.environ.get("PYTHONHASHSEED", "-1") != "0": needs_reexec = True # In case we need to re-execute. if needs_reexec: if not Options.isAllowedToReexecute(): sys.exit("Error, not allowed to re-execute, but that would be needed.") our_filename = sys.modules[__name__].__file__ # Execute with full path as the process name, so it can find itself and its # libraries. args = [sys.executable, sys.executable] if current_version >= "3.7" and sys.flags.utf8_mode: args += ["-X", "utf8"] args += ["-S", our_filename] os.environ["NUITKA_BINARY_NAME"] = sys.modules["__main__"].__file__ if Options.is_nuitka_run: args.append("--run") # Same arguments as before. args += sys.argv[1:] + list(Options.getMainArgs()) os.environ["NUITKA_PYTHONPATH"] = repr(sys.path) from nuitka.importing.PreloadedPackages import ( detectPreLoadedPackagePaths, detectPthImportedPackages, ) os.environ["NUITKA_NAMESPACES"] = repr(detectPreLoadedPackagePaths()) if "site" in sys.modules: os.environ["NUITKA_SITE_FILENAME"] = sys.modules["site"].__file__ os.environ["NUITKA_PTH_IMPORTED"] = repr(detectPthImportedPackages()) os.environ["NUITKA_SITE_FLAG"] = ( str(sys.flags.no_site) if "no_site" not in Options.getPythonFlags() else "1" ) os.environ["PYTHONHASHSEED"] = "0" from nuitka.utils import Execution # isort:skip Execution.callExec(args) if Options.isShowMemory(): from nuitka.utils import MemoryUsage MemoryUsage.startMemoryTracing() # Inform the user about potential issues. from nuitka.PythonVersions import getSupportedPythonVersions if current_version not in getSupportedPythonVersions(): # Do not disturb run of automatic tests, detected from the presence of # that environment variable. if "PYTHON" not in os.environ: logging.warning( "The version '%s' is not currently supported. Expect problems.", current_version, ) if "NUITKA_NAMESPACES" in os.environ: # Restore the detected name space packages, that were force loaded in # site.py, and will need a free pass later on. pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPreloadedPackagePaths setPreloadedPackagePaths(eval(os.environ["NUITKA_NAMESPACES"])) del os.environ["NUITKA_NAMESPACES"] if "NUITKA_PTH_IMPORTED" in os.environ: # Restore the packages that the ".pth" files asked to import. # pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPthImportedPackages setPthImportedPackages(eval(os.environ["NUITKA_PTH_IMPORTED"])) del os.environ["NUITKA_PTH_IMPORTED"] # Now the real main program of Nuitka can take over. from nuitka import MainControl # isort:skip MainControl.main() if Options.isShowMemory(): MemoryUsage.showMemoryTrace()
def main(): # PyLint for Python3 thinks we import from ourselves if we really # import from package, pylint: disable=I0021,no-name-in-module # Also high complexity. # pylint: disable=too-many-branches,too-many-locals,too-many-statements if "NUITKA_BINARY_NAME" in os.environ: sys.argv[0] = os.environ["NUITKA_BINARY_NAME"] if "NUITKA_PYTHONPATH" in os.environ: # Restore the PYTHONPATH gained from the site module, that we chose not # to have imported. pylint: disable=eval-used sys.path = eval(os.environ["NUITKA_PYTHONPATH"]) del os.environ["NUITKA_PYTHONPATH"] else: # Remove path element added for being called via "__main__.py", this can # only lead to trouble, having e.g. a "distutils" in sys.path that comes # from "nuitka.distutils". sys.path = [ path_element for path_element in sys.path if os.path.dirname(os.path.abspath(__file__)) != path_element ] # We don't care, and these are triggered by run time calculations of "range" and # others, while on python2.7 they are disabled by default. warnings.simplefilter("ignore", DeprecationWarning) # We will run with the Python configuration as specified by the user, if it does # not match, we restart ourselves with matching configuration. needs_reexec = False if sys.flags.no_site == 0: needs_reexec = True # The hash randomization totally changes the created source code created, # changing it every single time Nuitka is run. This kills any attempt at # caching it, and comparing generated source code. While the created binary # actually may still use it, during compilation we don't want to. So lets # disable it. if os.environ.get("PYTHONHASHSEED", "-1") != "0": needs_reexec = True # For re-execution, we might not have done this. from nuitka import Options # isort:skip # In case we need to re-execute. if needs_reexec: # TODO: If that's the only one, why do it at all.. Options.parseArgs(will_reexec=True) if not Options.isAllowedToReexecute(): sys.exit( "Error, not allowed to re-execute, but that would be needed.") our_filename = sys.modules[__name__].__file__ # Execute with full path as the process name, so it can find itself and its # libraries. args = [sys.executable, sys.executable] from nuitka.PythonVersions import python_version if python_version >= 0x370 and sys.flags.utf8_mode: args += ["-X", "utf8"] args += ["-S", our_filename] os.environ["NUITKA_BINARY_NAME"] = sys.modules["__main__"].__file__ os.environ["NUITKA_PACKAGE_HOME"] = os.path.dirname( os.path.abspath(sys.modules["nuitka"].__path__[0])) if Options.is_nuitka_run: args.append("--run") # Same arguments as before. args += sys.argv[1:] + list(Options.getMainArgs()) os.environ["NUITKA_PYTHONPATH"] = repr(sys.path) from nuitka.importing.PreloadedPackages import ( detectPreLoadedPackagePaths, detectPthImportedPackages, ) os.environ["NUITKA_NAMESPACES"] = repr(detectPreLoadedPackagePaths()) if "site" in sys.modules: os.environ["NUITKA_SITE_FILENAME"] = sys.modules["site"].__file__ os.environ["NUITKA_PTH_IMPORTED"] = repr( detectPthImportedPackages()) os.environ["NUITKA_SITE_FLAG"] = (str( sys.flags.no_site) if not Options.hasPythonFlagNoSite() else "1") os.environ["PYTHONHASHSEED"] = "0" from nuitka.utils import Execution # isort:skip Execution.callExec(args) Options.parseArgs(will_reexec=False) Options.commentArgs() # Load plugins after we know, we don't execute again. from nuitka.plugins.Plugins import activatePlugins activatePlugins() if Options.isShowMemory(): from nuitka.utils import MemoryUsage MemoryUsage.startMemoryTracing() if "NUITKA_NAMESPACES" in os.environ: # Restore the detected name space packages, that were force loaded in # site.py, and will need a free pass later on. pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPreloadedPackagePaths setPreloadedPackagePaths(eval(os.environ["NUITKA_NAMESPACES"])) del os.environ["NUITKA_NAMESPACES"] if "NUITKA_PTH_IMPORTED" in os.environ: # Restore the packages that the ".pth" files asked to import. # pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPthImportedPackages setPthImportedPackages(eval(os.environ["NUITKA_PTH_IMPORTED"])) del os.environ["NUITKA_PTH_IMPORTED"] # Now the real main program of Nuitka can take over. from nuitka import MainControl # isort:skip MainControl.main() if Options.isShowMemory(): MemoryUsage.showMemoryTrace()
def main(): # PyLint for Python3 thinks we import from ourselves if we really # import from package, pylint:disable=I0021,no-name-in-module # Also high complexity. # pylint: disable=too-many-branches,too-many-locals,too-many-statements if "NUITKA_BINARY_NAME" in os.environ: sys.argv[0] = os.environ["NUITKA_BINARY_NAME"] if "NUITKA_PYTHONPATH" in os.environ: # Restore the PYTHONPATH gained from the site module, that we chose not # to have imported. pylint: disable=eval-used sys.path = eval(os.environ["NUITKA_PYTHONPATH"]) del os.environ["NUITKA_PYTHONPATH"] else: # Remove path element added for being called via "__main__.py", this can # only lead to trouble, having e.g. a "distutils" in sys.path that comes # from "nuitka.distutils". sys.path = [ path_element for path_element in sys.path if os.path.dirname(os.path.abspath(__file__)) != path_element ] # For re-execution, we might not have done this. from nuitka import Options # isort:skip Options.parseArgs() import logging # isort:skip logging.basicConfig(format="Nuitka:%(levelname)s:%(message)s") # We don't care, and these are triggered by run time calculations of "range" and # others, while on python2.7 they are disabled by default. warnings.simplefilter("ignore", DeprecationWarning) # We will run with the Python configuration as specified by the user, if it does # not match, we restart ourselves with matching configuration. needs_reexec = False current_version = "%d.%d" % (sys.version_info[0], sys.version_info[1]) if sys.flags.no_site == 0: needs_reexec = True # The hash randomization totally changes the created source code created, # changing it every single time Nuitka is run. This kills any attempt at # caching it, and comparing generated source code. While the created binary # actually may still use it, during compilation we don't want to. So lets # disable it. if os.environ.get("PYTHONHASHSEED", "-1") != '0': needs_reexec = True # In case we need to re-execute. if needs_reexec: if not Options.isAllowedToReexecute(): sys.exit( "Error, not allowed to re-execute, but that would be needed.") our_filename = sys.modules[__name__].__file__ # Execute with full path as the process name, so it can find itself and its # libraries. args = [sys.executable, sys.executable] if current_version >= "3.7" and sys.flags.utf8_mode: args += ["-X", "utf8"] args += [ "-S", our_filename, ] os.environ["NUITKA_BINARY_NAME"] = sys.modules["__main__"].__file__ if Options.is_nuitka_run: args.append("--run") # Same arguments as before. args += sys.argv[1:] + list(Options.getMainArgs()) os.environ["NUITKA_PYTHONPATH"] = repr(sys.path) from nuitka.importing.PreloadedPackages import detectPreLoadedPackagePaths, detectPthImportedPackages os.environ["NUITKA_NAMESPACES"] = repr(detectPreLoadedPackagePaths()) if "site" in sys.modules: os.environ["NUITKA_SITE_FILENAME"] = sys.modules["site"].__file__ os.environ["NUITKA_PTH_IMPORTED"] = repr( detectPthImportedPackages()) os.environ["NUITKA_SITE_FLAG"] = str(sys.flags.no_site) \ if "no_site" not in Options.getPythonFlags() \ else '1' os.environ["PYTHONHASHSEED"] = '0' from nuitka.utils import Execution # isort:skip Execution.callExec(args) if Options.isShowMemory(): from nuitka.utils import MemoryUsage MemoryUsage.startMemoryTracing() # Inform the user about potential issues. from nuitka.PythonVersions import getSupportedPythonVersions if current_version not in getSupportedPythonVersions(): # Do not disturb run of automatic tests, detected from the presence of # that environment variable. if "PYTHON" not in os.environ: logging.warning( "The version '%s' is not currently supported. Expect problems.", current_version) if "NUITKA_NAMESPACES" in os.environ: # Restore the detected name space packages, that were force loaded in # site.py, and will need a free pass later on. pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPreloadedPackagePaths setPreloadedPackagePaths(eval(os.environ["NUITKA_NAMESPACES"])) del os.environ["NUITKA_NAMESPACES"] if "NUITKA_PTH_IMPORTED" in os.environ: # Restore the packages that the ".pth" files asked to import. # pylint: disable=eval-used from nuitka.importing.PreloadedPackages import setPthImportedPackages setPthImportedPackages(eval(os.environ["NUITKA_PTH_IMPORTED"])) del os.environ["NUITKA_PTH_IMPORTED"] # Now the real main program of Nuitka can take over. from nuitka import MainControl # isort:skip MainControl.main() if Options.isShowMemory(): MemoryUsage.showMemoryTrace()