def compileTree():
    source_dir = OutputDirectories.getSourceDirectoryPath()

    general.info("Completed Python level compilation and optimization.")

    if not Options.shallOnlyExecCCompilerCall():
        general.info("Generating source code for C backend compiler.")

        if Options.isShowProgress() or Options.isShowMemory():
            general.info(
                "Total memory usage before generating C code: {memory}:".
                format(
                    memory=MemoryUsage.getHumanReadableProcessMemoryUsage()))
        # Now build the target language code for the whole tree.
        makeSourceDirectory()

        bytecode_accessor = ConstantAccessor(data_filename="__bytecode.const",
                                             top_level_name="bytecode_data")

        # This should take all bytecode values, even ones needed for frozen or
        # not produce anything.
        loader_code = LoaderCodes.getMetapathLoaderBodyCode(bytecode_accessor)

        writeSourceCode(filename=os.path.join(source_dir, "__loader.c"),
                        source_code=loader_code)

    else:
        source_dir = OutputDirectories.getSourceDirectoryPath()

        if not os.path.isfile(os.path.join(source_dir, "__helpers.h")):
            general.sysexit("Error, no previous build directory exists.")

    if Options.isShowProgress() or Options.isShowMemory():
        general.info(
            "Total memory usage before running scons: {memory}:".format(
                memory=MemoryUsage.getHumanReadableProcessMemoryUsage()))

    if Options.isShowMemory():
        InstanceCounters.printStats()

    if Options.is_debug:
        Reports.doMissingOptimizationReport()

    if Options.shallNotDoExecCCompilerCall():
        return True, {}

    general.info(
        "Running data composer tool for optimal constant value handling.")

    # TODO: On Windows, we could run this in parallel to Scons, on Linux we need it
    # for linking.
    runDataComposer(source_dir)

    general.info("Running C level backend compilation via Scons.")

    # Run the Scons to build things.
    result, options = runSconsBackend(quiet=not Options.isShowScons())

    return result, options
Example #2
0
def compileTree(main_module):
    source_dir = OutputDirectories.getSourceDirectoryPath()

    if not Options.shallOnlyExecCCompilerCall():
        if Options.isShowProgress() or Options.isShowMemory():
            info(
                "Total memory usage before generating C code: {memory}:".format(
                    memory=MemoryUsage.getHumanReadableProcessMemoryUsage()
                )
            )
        # Now build the target language code for the whole tree.
        makeSourceDirectory(main_module=main_module)

        frozen_code = generateBytecodeFrozenCode()

        if frozen_code is not None:
            writeSourceCode(
                filename=os.path.join(source_dir, "__frozen.c"), source_code=frozen_code
            )

        if not isWin32Windows():
            writeBinaryData(
                filename=os.path.join(source_dir, "__constants.bin"),
                binary_data=ConstantCodes.stream_data.getBytes(),
            )
    else:
        source_dir = OutputDirectories.getSourceDirectoryPath()

        if not os.path.isfile(os.path.join(source_dir, "__helpers.h")):
            sys.exit("Error, no previous build directory exists.")

    if Options.isShowProgress() or Options.isShowMemory():
        info(
            "Total memory usage before running scons: {memory}:".format(
                memory=MemoryUsage.getHumanReadableProcessMemoryUsage()
            )
        )

    if Options.isShowMemory():
        InstanceCounters.printStats()

    if Options.isDebug():
        Reports.doMissingOptimizationReport()

    if Options.shallNotDoExecCCompilerCall():
        return True, {}

    # Run the Scons to build things.
    result, options = runScons(main_module=main_module, quiet=not Options.isShowScons())

    return result, options
Example #3
0
def createModuleTree(module, source_ref, source_code, is_main):
    if Options.isShowMemory():
        memory_watch = MemoryUsage.MemoryWatch()

    try:
        module_body = buildParseTree(provider=module,
                                     source_code=source_code,
                                     source_ref=source_ref,
                                     is_module=True,
                                     is_main=is_main)
    except RuntimeError as e:
        if "maximum recursion depth" in e.args[0]:
            raise CodeTooComplexCode(module.getFullName(),
                                     module.getCompileTimeFilename())

        raise

    if module_body.isStatementsFrame():
        module_body = makeStatementsSequenceFromStatement(
            statement=module_body, )

    module.setBody(module_body)

    completeVariableClosures(module)

    if Options.isShowMemory():
        memory_watch.finish()

        info("Memory usage changed loading module '%s': %s" %
             (module.getFullName(), memory_watch.asStr()))
Example #4
0
def createModuleTree(module, source_ref, ast_tree, is_main):
    if Options.isShowMemory():
        memory_watch = MemoryUsage.MemoryWatch()

    module_body = buildParseTree(
        provider=module,
        ast_tree=ast_tree,
        source_ref=source_ref,
        is_module=True,
        is_main=is_main,
    )

    if module_body.isStatementsFrame():
        module_body = makeStatementsSequenceFromStatement(
            statement=module_body)

    module.setChild("body", module_body)

    completeVariableClosures(module)

    if Options.isShowMemory():
        memory_watch.finish()

        memory_logger.info("Memory usage changed loading module '%s': %s" %
                           (module.getFullName(), memory_watch.asStr()))
Example #5
0
def optimizeCompiledPythonModule(module):
    if _progress:
        progress_logger.info(
            "Doing module local optimizations for '{module_name}'.".format(
                module_name=module.getFullName()))

    touched = False

    if _progress and Options.isShowMemory():
        memory_watch = MemoryUsage.MemoryWatch()

    while True:
        tag_set.clear()

        try:
            # print("Compute module")
            module.computeModule()
        except BaseException:
            general.info("Interrupted while working on '%s'." % module)
            raise

        Graphs.onModuleOptimizationStep(module)

        # Search for local change tags.
        for tag in tag_set:
            if tag == "new_code":
                continue

            break
        else:
            if _progress:
                progress_logger.info("Finished with the module.")
            break

        if _progress:
            if "new_code" in tag_set:
                tag_set.remove("new_code")

            progress_logger.info(
                "Not finished with the module due to following change kinds: %s"
                % ",".join(sorted(tag_set)))

        # Otherwise we did stuff, so note that for return value.
        touched = True

    if _progress and Options.isShowMemory():
        memory_watch.finish()

        memory_logger.info(
            "Memory usage changed during optimization of '%s': %s" %
            (module.getFullName(), memory_watch.asStr()))

    Plugins.considerImplicitImports(module=module, signal_change=signalChange)

    return touched
Example #6
0
def optimizeCompiledPythonModule(module):
    if _progress:
        info(
            "Doing module local optimizations for '{module_name}'.".format(
                module_name = module.getFullName()
            )
        )

    touched = False

    if _progress and Options.isShowMemory():
        memory_watch = MemoryUsage.MemoryWatch()

    while True:
        tag_set.clear()

        try:
            module.computeModule()
        except BaseException:
            info("Interrupted while working on '%s'." % module)
            raise

        Graphs.onModuleOptimizationStep(module)

        # Search for local change tags.
        for tag in tag_set:
            if tag == "new_code":
                continue

            break
        else:
            break

        # Otherwise we did stuff, so note that for return value.
        touched = True

    if _progress and Options.isShowMemory():
        memory_watch.finish()

        info(
            "Memory usage changed during optimization of '%s': %s" % (
                module.getFullName(),
                memory_watch.asStr()
            )
        )

    Plugins.considerImplicitImports(
        module        = module,
        signal_change = signalChange
    )

    return touched
Example #7
0
def _traceProgress(current_module):
    output = """\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that.""".format(
        module_name=current_module.getFullName(),
        remaining=ModuleRegistry.remainingCount(),
    )

    if Options.isShowMemory():
        output += "Memory usage {memory}:".format(
            memory=MemoryUsage.getHumanReadableProcessMemoryUsage())

    info(output)
Example #8
0
def compileTree(main_module):
    source_dir = getSourceDirectoryPath(main_module)

    if not Options.shallOnlyExecCppCall():
        # Now build the target language code for the whole tree.
        makeSourceDirectory(
            main_module = main_module
        )

        frozen_code = generateBytecodeFrozenCode()

        if frozen_code is not None:
            writeSourceCode(
                filename    = Utils.joinpath(
                    source_dir,
                    "__frozen.c"
                ),
                source_code = frozen_code
            )

        writeBinaryData(
            filename    = Utils.joinpath(source_dir, "__constants.bin"),
            binary_data = ConstantCodes.stream_data.getBytes()
        )
    else:
        source_dir = getSourceDirectoryPath(main_module)

        if not Utils.isFile(Utils.joinpath(source_dir, "__helpers.h")):
            sys.exit("Error, no previous build directory exists.")

    if Options.isShowProgress() or Options.isShowMemory():
        Tracing.printLine(
            "Total memory usage before running scons: {memory}:".format(
                memory = MemoryUsage.getHumanReadableProcessMemoryUsage()
            )
        )

    if Options.isShowMemory():
        InstanceCounters.printStats()

    if Options.shallNotDoExecCppCall():
        return True, {}

    # Run the Scons to build things.
    result, options = runScons(
        main_module = main_module,
        quiet       = not Options.isShowScons()
    )

    return result, options
Example #9
0
def compileTree(main_module):
    source_dir = getSourceDirectoryPath(main_module)

    if not Options.shallOnlyExecCppCall():
        # Now build the target language code for the whole tree.
        makeSourceDirectory(
            main_module = main_module
        )

        frozen_code = generateBytecodeFrozenCode()

        if frozen_code is not None:
            writeSourceCode(
                filename    = Utils.joinpath(
                    source_dir,
                    "__frozen.cpp"
                ),
                source_code = frozen_code
            )

        writeBinaryData(
            filename    = Utils.joinpath(source_dir, "__constants.bin"),
            binary_data = ConstantCodes.stream_data.getBytes()
        )
    else:
        source_dir = getSourceDirectoryPath(main_module)

        if not Utils.isFile(Utils.joinpath(source_dir, "__helpers.hpp")):
            sys.exit("Error, no previous build directory exists.")

    if Options.isShowProgress() or Options.isShowMemory():
        Tracing.printLine(
            "Total memory usage before running scons: {memory}:".format(
                memory = MemoryUsage.getHumanReadableProcessMemoryUsage()
            )
        )

    if Options.isShowMemory():
        InstanceCounters.printStats()

    if Options.shallNotDoExecCppCall():
        return True, {}

    # Run the Scons to build things.
    result, options = runScons(
        main_module = main_module,
        quiet       = not Options.isShowScons()
    )

    return result, options
Example #10
0
def _traceProgress(current_module):
    output = """\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that.""".format(
            module_name = current_module.getFullName(),
            remaining   = ModuleRegistry.remainingCount(),
    )

    if Options.isShowMemory():
        output += "Memory usage {memory}:".format(
            memory = MemoryUsage.getHumanReadableProcessMemoryUsage()
        )

    printLine(output)
Example #11
0
def optimizePythonModule(module):
    if _progress:
        printLine(
            "Doing module local optimizations for '{module_name}'.".format(
                module_name=module.getFullName()))

    # The tag set is global, so it can react to changes without context.
    # pylint: disable=W0603
    global tag_set
    tag_set = TagSet()

    touched = False

    if _progress:
        memory_watch = MemoryUsage.MemoryWatch()

    while True:
        tag_set.clear()

        try:
            module.computeModule()
        except BaseException:
            info("Interrupted while working on '%s'." % module)
            raise

        if not tag_set:
            break

        if graph is not None:
            computation_counters[module] = computation_counters.get(module,
                                                                    0) + 1
            module_graph = module.asGraph(computation_counters[module])

            graph.subgraph(module_graph)

        touched = True

    if _progress:
        memory_watch.finish()

        printLine("Memory usage changed during optimization of '%s': %s" %
                  (module.getFullName(), memory_watch.asStr()))

    Plugins.considerImplicitImports(module, signal_change=signalChange)

    return touched
Example #12
0
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()
Example #13
0
def optimize():
    # This is somewhat complex with many cases, pylint: disable=R0912

    # We maintain this globally to make it accessible, pylint: disable=W0603
    global graph

    if Options.shouldCreateGraph():

        try:
            from graphviz import Digraph  # pylint: disable=F0401,I0021
            graph = Digraph('G')
        except ImportError:
            warning("Cannot import graphviz module, no graphing capability.")

    while True:
        finished = True

        ModuleRegistry.startTraversal()

        while True:
            current_module = ModuleRegistry.nextModule()

            if current_module is None:
                break

            if _progress:
                printLine("""\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that. Memory usage {memory}:""".format(
                    module_name=current_module.getFullName(),
                    remaining=ModuleRegistry.remainingCount(),
                    memory=MemoryUsage.getHumanReadableProcessMemoryUsage()))

            if current_module.isPythonShlibModule():
                optimizeShlibModule(current_module)
            else:
                changed = optimizePythonModule(current_module)

                if changed:
                    finished = False

        # Unregister collection traces from now unused code.
        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                for function in current_module.getUnusedFunctions():
                    VariableRegistry.updateFromCollection(
                        old_collection=function.constraint_collection,
                        new_collection=None)

                    function.constraint_collection = None

        if VariableRegistry.considerCompletion():
            finished = False

        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                optimizeVariables(current_module)

        if finished:
            break

    if graph is not None:
        graph.engine = "dot"
        graph.graph_attr["rankdir"] = "TB"
        graph.render("something.dot")

        printLine(graph.source)
Example #14
0
def main():
    """Main program flow of Nuitka

    At this point, options will be parsed already, Nuitka will be executing
    in the desired version of Python with desired flags, and we just get
    to execute the task assigned.

    We might be asked to only re-compile generated C, dump only an XML
    representation of the internal node tree after optimization, etc.
    """

    # Main has to fulfill many options, leading to many branches and statements
    # to deal with them.  pylint: disable=too-many-branches,too-many-statements

    # In case we are in a PGO run, we read its information first, so it becomes
    # available for later parts.
    pgo_filename = getPythonPgoInput()
    if pgo_filename is not None:
        readPGOInputFile(pgo_filename)

    if not Options.shallDumpBuiltTreeXML():
        general.info(
            "Starting Python compilation with Nuitka %r on Python %r commercial %r."
            % (getNuitkaVersion(), python_version_str, getCommercialVersion())
        )

    filename = Options.getPositionalArgs()[0]

    # Inform the importing layer about the main script directory, so it can use
    # it when attempting to follow imports.
    Importing.setMainScriptDirectory(
        main_dir=os.path.dirname(os.path.abspath(filename))
    )

    addIncludedDataFilesFromFileOptions()

    # Turn that source code into a node tree structure.
    try:
        main_module = _createNodeTree(filename=filename)
    except (SyntaxError, IndentationError) as e:
        handleSyntaxError(e)

    addIncludedDataFilesFromPackageOptions()

    if Options.shallDumpBuiltTreeXML():
        # XML output only.
        for module in ModuleRegistry.getDoneModules():
            dumpTreeXML(module)
    else:
        # Make the actual compilation.
        result, options = compileTree()

        # Exit if compilation failed.
        if not result:
            sys.exit(1)

        # Relaunch in case of Python PGO input to be produced.
        if Options.shallCreatePgoInput():
            # Will not return.
            pgo_filename = OutputDirectories.getPgoRunInputFilename()
            general.info(
                "Restarting compilation using collected information from '%s'."
                % pgo_filename
            )
            reExecuteNuitka(pgo_filename=pgo_filename)

        if Options.shallNotDoExecCCompilerCall():
            if Options.isShowMemory():
                MemoryUsage.showMemoryTrace()

            sys.exit(0)

        executePostProcessing()

        copyDataFiles()

        if Options.isStandaloneMode():
            binary_filename = options["result_exe"]

            setMainEntryPoint(binary_filename)

            dist_dir = OutputDirectories.getStandaloneDirectoryPath()

            for module in ModuleRegistry.getDoneModules():
                addIncludedEntryPoints(Plugins.considerExtraDlls(dist_dir, module))

            copyDllsUsed(
                source_dir=OutputDirectories.getSourceDirectoryPath(),
                dist_dir=dist_dir,
                standalone_entry_points=getStandaloneEntryPoints(),
            )

            Plugins.onStandaloneDistributionFinished(dist_dir)

            if Options.isOnefileMode():
                packDistFolderToOnefile(dist_dir, binary_filename)

                if Options.isRemoveBuildDir():
                    general.info("Removing dist folder %r." % dist_dir)

                    removeDirectory(path=dist_dir, ignore_errors=False)
                else:
                    general.info(
                        "Keeping dist folder %r for inspection, no need to use it."
                        % dist_dir
                    )

        # Remove the source directory (now build directory too) if asked to.
        source_dir = OutputDirectories.getSourceDirectoryPath()

        if Options.isRemoveBuildDir():
            general.info("Removing build directory %r." % source_dir)

            removeDirectory(path=source_dir, ignore_errors=False)
            assert not os.path.exists(source_dir)
        else:
            general.info("Keeping build directory %r." % source_dir)

        final_filename = OutputDirectories.getResultFullpath(
            onefile=Options.isOnefileMode()
        )

        if Options.isStandaloneMode() and isMacOS():
            general.info(
                "Created binary that runs on macOS %s (%s) or higher."
                % (options["macos_min_version"], options["macos_target_arch"])
            )

        Plugins.onFinalResult(final_filename)

        general.info("Successfully created %r." % final_filename)

        report_filename = Options.getCompilationReportFilename()

        if report_filename:
            writeCompilationReport(report_filename)

        # Execute the module immediately if option was given.
        if Options.shallExecuteImmediately():
            run_filename = OutputDirectories.getResultRunFilename(
                onefile=Options.isOnefileMode()
            )

            general.info("Launching %r." % run_filename)

            if Options.shallMakeModule():
                executeModule(
                    tree=main_module,
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
            else:
                executeMain(
                    binary_filename=run_filename,
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
Example #15
0
def optimize():
    # This is somewhat complex with many cases, pylint: disable=R0912

    # We maintain this globally to make it accessible, pylint: disable=W0603
    global graph

    if Options.shouldCreateGraph():

        try:
            from graphviz import Digraph # pylint: disable=F0401,I0021
            graph = Digraph('G')
        except ImportError:
            warning("Cannot import graphviz module, no graphing capability.")

    while True:
        finished = True

        ModuleRegistry.startTraversal()

        while True:
            current_module = ModuleRegistry.nextModule()

            if current_module is None:
                break

            if _progress:
                printLine(
                    """\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that. Memory usage {memory}:""".format(
                        module_name = current_module.getFullName(),
                        remaining   = ModuleRegistry.remainingCount(),
                        memory      = MemoryUsage.getHumanReadableProcessMemoryUsage()
                    )
                )

            if current_module.isPythonShlibModule():
                optimizeShlibModule(current_module)
            else:
                changed = optimizePythonModule(current_module)

                if changed:
                    finished = False

        # Unregister collection traces from now unused code.
        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                for function in current_module.getUnusedFunctions():
                    VariableRegistry.updateFromCollection(
                        old_collection = function.constraint_collection,
                        new_collection = None
                    )

                    function.constraint_collection = None

        if VariableRegistry.considerCompletion():
            finished = False

        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                optimizeVariables(current_module)

        if finished:
            break


    if graph is not None:
        graph.engine = "dot"
        graph.graph_attr["rankdir"] = "TB"
        graph.render("something.dot")

        printLine(graph.source)
Example #16
0
def main():
    """Main program flow of Nuitka

    At this point, options will be parsed already, Nuitka will be executing
    in the desired version of Python with desired flags, and we just get
    to execute the task assigned.

    We might be asked to only re-compile generated C, dump only an XML
    representation of the internal node tree after optimization, etc.
    """

    # Main has to fulfill many options, leading to many branches and statements
    # to deal with them.  pylint: disable=too-many-branches,too-many-statements
    if not Options.shallDumpBuiltTreeXML():
        general.info("Starting Python compilation.")

    filename = Options.getPositionalArgs()[0]

    # Inform the importing layer about the main script directory, so it can use
    # it when attempting to follow imports.
    Importing.setMainScriptDirectory(
        main_dir=os.path.dirname(os.path.abspath(filename))
    )

    # Turn that source code into a node tree structure.
    try:
        main_module = _createNodeTree(filename=filename)
    except (SyntaxError, IndentationError) as e:
        handleSyntaxError(e)

    if Options.shallDumpBuiltTreeXML():
        # XML output only.
        for module in ModuleRegistry.getDoneModules():
            dumpTreeXML(module)
    else:
        # Make the actual compilation.
        result, options = compileTree()

        # Exit if compilation failed.
        if not result:
            sys.exit(1)

        if Options.shallNotDoExecCCompilerCall():
            if Options.isShowMemory():
                MemoryUsage.showMemoryTrace()

            sys.exit(0)

        executePostProcessing()

        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()
                    )
                },
            )

        if Options.isStandaloneMode():
            binary_filename = options["result_exe"]

            setMainEntryPoint(binary_filename)

            dist_dir = OutputDirectories.getStandaloneDirectoryPath()

            for module in ModuleRegistry.getDoneModules():
                addIncludedEntryPoints(Plugins.considerExtraDlls(dist_dir, module))

            copyUsedDLLs(
                source_dir=OutputDirectories.getSourceDirectoryPath(),
                dist_dir=dist_dir,
                standalone_entry_points=getStandaloneEntryPoints(),
            )

            copyDataFiles(dist_dir=dist_dir)

            Plugins.onStandaloneDistributionFinished(dist_dir)

            if Options.isOnefileMode():
                packDistFolderToOnefile(dist_dir, binary_filename)

                if Options.isRemoveBuildDir():
                    general.info("Removing dist folder %r." % dist_dir)

                    removeDirectory(path=dist_dir, ignore_errors=False)
                else:
                    general.info(
                        "Keeping dist folder %r for inspection, no need to use it."
                        % dist_dir
                    )

        # Remove the source directory (now build directory too) if asked to.
        source_dir = OutputDirectories.getSourceDirectoryPath()

        if Options.isRemoveBuildDir():
            general.info("Removing build directory %r." % source_dir)

            removeDirectory(path=source_dir, ignore_errors=False)
            assert not os.path.exists(source_dir)
        else:
            general.info("Keeping build directory %r." % source_dir)

        final_filename = OutputDirectories.getResultFullpath(
            onefile=Options.isOnefileMode()
        )

        Plugins.onFinalResult(final_filename)

        general.info("Successfully created %r." % final_filename)

        # Execute the module immediately if option was given.
        if Options.shallExecuteImmediately():
            general.info("Launching %r." % final_filename)

            if Options.shallMakeModule():
                executeModule(
                    tree=main_module,
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
            else:
                executeMain(
                    binary_filename=final_filename,
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
Example #17
0
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()
Example #18
0
def main():
    """ Main program flow of Nuitka

        At this point, options will be parsed already, Nuitka will be executing
        in the desired version of Python with desired flags, and we just get
        to execute the task assigned.

        We might be asked to only re-compile generated C, dump only an XML
        representation of the internal node tree after optimization, etc.
    """

    # Main has to fulfill many options, leading to many branches and statements
    # to deal with them.  pylint: disable=too-many-branches
    filename = Options.getPositionalArgs()[0]

    # Inform the importing layer about the main script directory, so it can use
    # it when attempting to follow imports.
    Importing.setMainScriptDirectory(
        main_dir = os.path.dirname(os.path.abspath(filename))
    )

    # Detect to be frozen modules if any, so we can consider to not recurse
    # to them.
    if Options.isStandaloneMode():
        for module in detectEarlyImports():
            ModuleRegistry.addUncompiledModule(module)

            if module.getName() == "site":
                origin_prefix_filename = os.path.join(
                    os.path.dirname(module.getCompileTimeFilename()),
                    "orig-prefix.txt"
                )

                if os.path.isfile(origin_prefix_filename):
                    data_files.append(
                        (filename, "orig-prefix.txt")
                    )

    # Turn that source code into a node tree structure.
    try:
        main_module = createNodeTree(
            filename = filename
        )
    except (SyntaxError, IndentationError) as e:
        handleSyntaxError(e)

    if Options.shallDumpBuiltTreeXML():
        # XML output only.
        for module in ModuleRegistry.getDoneModules():
            dumpTreeXML(module)
    else:
        # Make the actual compilation.
        result, options = compileTree(
            main_module = main_module
        )

        # Exit if compilation failed.
        if not result:
            sys.exit(1)

        if Options.shallNotDoExecCCompilerCall():
            if Options.isShowMemory():
                MemoryUsage.showMemoryTrace()

            sys.exit(0)

        if Options.isStandaloneMode():
            binary_filename = options["result_exe"]

            standalone_entry_points.insert(
                0,
                (binary_filename, binary_filename, None)
            )

            dist_dir = getStandaloneDirectoryPath(main_module)

            for module in ModuleRegistry.getDoneUserModules():
                standalone_entry_points.extend(
                    Plugins.considerExtraDlls(dist_dir, module)
                )

            for module in ModuleRegistry.getUncompiledModules():
                standalone_entry_points.extend(
                    Plugins.considerExtraDlls(dist_dir, module)
                )

            copyUsedDLLs(
                source_dir              = getSourceDirectoryPath(main_module),
                dist_dir                = dist_dir,
                standalone_entry_points = standalone_entry_points
            )

            for module in ModuleRegistry.getDoneModules():
                data_files.extend(
                    Plugins.considerDataFiles(module)
                )

            for source_filename, target_filename in data_files:
                target_filename = os.path.join(
                    getStandaloneDirectoryPath(main_module),
                    target_filename
                )

                makePath(os.path.dirname(target_filename))

                shutil.copy2(
                    source_filename,
                    target_filename
                )

        # Remove the source directory (now build directory too) if asked to.
        if Options.isRemoveBuildDir():
            removeDirectory(
                path          = getSourceDirectoryPath(main_module),
                ignore_errors = False
            )

        # Modules should not be executable, but Scons creates them like it, fix
        # it up here. TODO: Move inside scons file and avoid subprocess call.
        if Utils.getOS() != "Windows" and Options.shallMakeModule():
            subprocess.call(
                (
                    "chmod",
                    "-x",
                    getResultFullpath(main_module)
                )
            )

        if Options.shallMakeModule() and Options.shallCreatePyiFile():
            pyi_filename = getResultBasepath(main_module) + ".pyi"

            with open(pyi_filename, 'w') as pyi_file:
                pyi_file.write(
                    """\
# 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()
                        )

                    }
                )


        # Execute the module immediately if option was given.
        if Options.shallExecuteImmediately():
            if Options.shallMakeModule():
                executeModule(
                    tree       = main_module,
                    clean_path = Options.shallClearPythonPathEnvironment()
                )
            else:
                executeMain(
                    binary_filename = getResultFullpath(main_module),
                    clean_path      = Options.shallClearPythonPathEnvironment()
                )
Example #19
0
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 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

    # In case we need to re-execute.
    if needs_reexec:
        from nuitka.utils.ReExecute import reExecuteNuitka  # isort:skip

        # Does not return
        reExecuteNuitka(pgo_filename=None)

    # We don't care about deprecations in any version, and these are triggered
    # by run time calculations of "range" and others, while on python2.7 they
    # are disabled by default.
    import warnings

    warnings.simplefilter("ignore", DeprecationWarning)

    from nuitka import Options  # isort:skip

    Options.parseArgs()

    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()
Example #20
0
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()
Example #21
0
def main():
    """ Main program flow of Nuitka

        At this point, options will be parsed already, Nuitka will be executing
        in the desired version of Python with desired flags, and we just get
        to execute the task assigned.

        We might be asked to only re-compile generated C, dump only an XML
        representation of the internal node tree after optimization, etc.
    """

    # Main has to fulfill many options, leading to many branches and statements
    # to deal with them.  pylint: disable=too-many-branches
    filename = Options.getPositionalArgs()[0]

    # Inform the importing layer about the main script directory, so it can use
    # it when attempting to follow imports.
    Importing.setMainScriptDirectory(
        main_dir=os.path.dirname(os.path.abspath(filename)))

    # Detect to be frozen modules if any, so we can consider to not recurse
    # to them.
    if Options.isStandaloneMode():
        for module in detectEarlyImports():
            ModuleRegistry.addUncompiledModule(module)

            if module.getName() == "site":
                origin_prefix_filename = os.path.join(
                    os.path.dirname(module.getCompileTimeFilename()),
                    "orig-prefix.txt")

                if os.path.isfile(origin_prefix_filename):
                    data_files.append((filename, "orig-prefix.txt"))

    # Turn that source code into a node tree structure.
    try:
        main_module = createNodeTree(filename=filename)
    except (SyntaxError, IndentationError) as e:
        handleSyntaxError(e)

    if Options.shallDumpBuiltTreeXML():
        for module in ModuleRegistry.getDoneModules():
            dumpTreeXML(module)
    elif Options.shallDisplayBuiltTree():
        displayTree(main_module)
    else:
        result, options = compileTree(main_module=main_module)

        # Exit if compilation failed.
        if not result:
            sys.exit(1)

        if Options.shallNotDoExecCCompilerCall():
            if Options.isShowMemory():
                MemoryUsage.showMemoryTrace()

            sys.exit(0)

        # Remove the source directory (now build directory too) if asked to.
        if Options.isRemoveBuildDir():
            removeDirectory(path=getSourceDirectoryPath(main_module),
                            ignore_errors=False)

        if Options.isStandaloneMode():
            binary_filename = options["result_name"] + ".exe"

            standalone_entry_points.insert(
                0, (binary_filename, binary_filename, None))

            dist_dir = getStandaloneDirectoryPath(main_module)

            for module in ModuleRegistry.getDoneUserModules():
                standalone_entry_points.extend(
                    Plugins.considerExtraDlls(dist_dir, module))

            for module in ModuleRegistry.getUncompiledModules():
                standalone_entry_points.extend(
                    Plugins.considerExtraDlls(dist_dir, module))

            copyUsedDLLs(dist_dir=dist_dir,
                         standalone_entry_points=standalone_entry_points)

            for module in ModuleRegistry.getDoneModules():
                data_files.extend(Plugins.considerDataFiles(module))

            for source_filename, target_filename in data_files:
                target_filename = os.path.join(
                    getStandaloneDirectoryPath(main_module), target_filename)

                makePath(os.path.dirname(target_filename))

                shutil.copy2(source_filename, target_filename)

        # Modules should not be executable, but Scons creates them like it, fix
        # it up here.
        if Utils.getOS() != "Windows" and Options.shallMakeModule():
            subprocess.call(("chmod", "-x", getResultFullpath(main_module)))

        # Execute the module immediately if option was given.
        if Options.shallExecuteImmediately():
            if Options.shallMakeModule():
                executeModule(
                    tree=main_module,
                    clean_path=Options.shallClearPythonPathEnvironment())
            else:
                executeMain(
                    binary_filename=getResultFullpath(main_module),
                    clean_path=Options.shallClearPythonPathEnvironment())
Example #22
0
def main():
    """ Main program flow of Nuitka

        At this point, options will be parsed already, Nuitka will be executing
        in the desired version of Python with desired flags, and we just get
        to execute the task assigned.

        We might be asked to only re-compile generated C, dump only an XML
        representation of the internal node tree after optimization, etc.
    """

    # Main has to fulfill many options, leading to many branches and statements
    # to deal with them.  pylint: disable=too-many-branches
    filename = Options.getPositionalArgs()[0]

    # Inform the importing layer about the main script directory, so it can use
    # it when attempting to follow imports.
    Importing.setMainScriptDirectory(
        main_dir=os.path.dirname(os.path.abspath(filename))
    )

    # Detect to be frozen modules if any, so we can consider to not recurse
    # to them.
    if Options.isStandaloneMode():
        for module in detectEarlyImports():
            ModuleRegistry.addUncompiledModule(module)

    # Turn that source code into a node tree structure.
    try:
        main_module = createNodeTree(filename=filename)
    except (SyntaxError, IndentationError) as e:
        handleSyntaxError(e)

    if Options.shallDumpBuiltTreeXML():
        # XML output only.
        for module in ModuleRegistry.getDoneModules():
            dumpTreeXML(module)
    else:
        # Make the actual compilation.
        result, options = compileTree(main_module=main_module)

        # Exit if compilation failed.
        if not result:
            sys.exit(1)

        if Options.shallNotDoExecCCompilerCall():
            if Options.isShowMemory():
                MemoryUsage.showMemoryTrace()

            sys.exit(0)

        executePostProcessing(getResultFullpath(main_module))

        if Options.isStandaloneMode():
            binary_filename = options["result_exe"]

            standalone_entry_points.insert(0, (binary_filename, binary_filename, None))

            dist_dir = getStandaloneDirectoryPath(main_module)

            for module in ModuleRegistry.getDoneUserModules():
                standalone_entry_points.extend(
                    Plugins.considerExtraDlls(dist_dir, module)
                )

            copyUsedDLLs(
                source_dir=getSourceDirectoryPath(main_module),
                dist_dir=dist_dir,
                standalone_entry_points=standalone_entry_points,
            )

            data_files = []
            for module in ModuleRegistry.getDoneModules():
                data_files.extend(Plugins.considerDataFiles(module))

            copyDataFiles(dist_dir=dist_dir, data_files=data_files)

            Plugins.onStandaloneDistributionFinished(dist_dir)

        # Remove the source directory (now build directory too) if asked to.
        if Options.isRemoveBuildDir():
            removeDirectory(
                path=getSourceDirectoryPath(main_module), ignore_errors=False
            )

        if Options.shallMakeModule() and Options.shallCreatePyiFile():
            pyi_filename = getResultBasepath(main_module) + ".pyi"

            with open(pyi_filename, "w") as pyi_file:
                pyi_file.write(
                    """\
# 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()
                        )
                    }
                )

        # Execute the module immediately if option was given.
        if Options.shallExecuteImmediately():
            if Options.shallMakeModule():
                executeModule(
                    tree=main_module,
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
            else:
                executeMain(
                    binary_filename=getResultFullpath(main_module),
                    clean_path=Options.shallClearPythonPathEnvironment(),
                )
Example #23
0
            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'

    Execution.callExec(args)

if Options.isShowMemory():
    from nuitka.utils import MemoryUsage
    MemoryUsage.startMemoryTracing()

# Inform the user about potential issues.
if current_version not in Options.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