Files
aufbau2csv/venv3_12/Lib/site-packages/cx_Freeze/command/build_exe.py

322 lines
11 KiB
Python

"""Implements the 'build_exe' command."""
from __future__ import annotations
import logging
import os
import sys
from sysconfig import get_platform, get_python_version
from typing import ClassVar
from setuptools import Command
from cx_Freeze._compat import IS_WINDOWS
from cx_Freeze.common import normalize_to_list
from cx_Freeze.exception import OptionError, SetupError
from cx_Freeze.freezer import Freezer
from cx_Freeze.module import ConstantsModule
__all__ = ["build_exe"]
class build_exe(Command):
"""Build executables from Python scripts."""
description = "build executables from Python scripts"
user_options: ClassVar[list[tuple[str, str | None, str]]] = [
(
"build-exe=",
"b",
"directory for built executables and dependent files",
),
("includes=", "i", "comma-separated list of modules to include"),
("excludes=", "e", "comma-separated list of modules to exclude"),
(
"packages=",
"p",
"comma-separated list of packages to include, "
"which includes all submodules in the package",
),
(
"replace-paths=",
None,
"comma-separated list of paths to replace in included modules, "
"using the form <search>=<replace>",
),
(
"path=",
None,
"comma-separated list of paths to search for modules; the default "
"value is sys.path (use only if you know what you are doing)",
),
(
"include-path=",
None,
"comma-separated list of paths to modify the search for modules",
),
("constants=", None, "comma-separated list of constants to include"),
(
"bin-includes=",
None,
"list of files to include when determining "
"dependencies of binary files that would normally be excluded",
),
(
"bin-excludes=",
None,
"list of files to exclude when determining "
"dependencies of binary files that would normally be included",
),
(
"bin-path-includes=",
None,
"list of paths from which to include files when determining "
"dependencies of binary files",
),
(
"bin-path-excludes=",
None,
"list of paths from which to exclude files when determining "
"dependencies of binary files",
),
(
"include-files=",
"f",
"list of tuples of additional files to include in distribution",
),
(
"zip-includes=",
None,
"list of tuples of additional files to include in zip file",
),
(
"zip-include-packages=",
None,
"comma-separated list of packages to include in the zip file "
"(or * for all) [default: none]",
),
(
"zip-exclude-packages=",
None,
"comma-separated list of packages to exclude from the zip file "
"and place in the file system instead (or * for all) "
"[default: *]",
),
(
"zip-filename=",
None,
"filename for the shared zipfile (.zip) "
'[default: "library.zip" or None if --no-compress is used]',
),
(
"no-compress",
None,
"create a zip file with no compression (See also --zip-filename)",
),
(
"optimize=",
"O",
'optimization level: -O1 for "python -O", '
'-O2 for "python -OO" and -O0 to disable [default: -O0]',
),
(
"silent",
"s",
"suppress all output except warnings "
"(equivalent to --silent-level=1)",
),
(
"silent-level=",
None,
"suppress output from build_exe command."
" level 0: get all messages; [default]"
" level 1: suppress information messages, but still get warnings;"
" (equivalent to --silent)"
" level 2: suppress missing missing-module warnings"
" level 3: suppress all warning messages",
),
(
"include-msvcr",
None,
"include the Microsoft Visual C runtime files",
),
]
boolean_options: ClassVar[list[str]] = [
"no-compress",
"include-msvcr",
"silent",
]
def add_to_path(self, name) -> None:
source_dir = getattr(self, name.lower())
if source_dir is not None:
sys.path.insert(0, source_dir)
def build_extension(self, name, module_name=None) -> str | None:
# XXX: This method, add_to_path and set_source_location can be deleted?
if module_name is None:
module_name = name
source_dir = getattr(self, name.lower())
if source_dir is None:
return None
orig_dir = os.getcwd()
script_args = ["build"]
command = self.distribution.get_command_obj("build")
if command.compiler is not None:
script_args.append(f"--compiler={command.compiler}")
os.chdir(source_dir)
logging.info("building '%s' extension in '%s'", name, source_dir)
distutils_core = __import__("distutils.core", fromlist=["run_setup"])
distribution = distutils_core.run_setup("setup.py", script_args)
ext_modules = distribution.ext_modules
modules = [m for m in ext_modules if m.name == module_name]
if not modules:
msg = f"no module named '{module_name}' in '{source_dir}'"
raise SetupError(msg)
command = distribution.get_command_obj("build_ext")
command.ensure_finalized()
if command.compiler is None:
command.run()
else:
command.build_extensions()
dir_name = os.path.join(source_dir, command.build_lib)
os.chdir(orig_dir)
if dir_name not in sys.path:
sys.path.insert(0, dir_name)
return os.path.join(
source_dir,
command.build_lib,
command.get_ext_filename(module_name),
)
def initialize_options(self) -> None:
self.list_options = [
"excludes",
"includes",
"packages",
"replace_paths",
"constants",
"include_files",
"include_path",
"bin_excludes",
"bin_includes",
"bin_path_excludes",
"bin_path_includes",
"zip_includes",
"zip_exclude_packages",
"zip_include_packages",
]
for option in self.list_options:
setattr(self, option, [])
self.zip_exclude_packages = ["*"]
self.build_exe = None
self.include_msvcr = None
self.no_compress = False
self.optimize = 0
self.path = None
self.silent = None
self.silent_level = None
self.zip_filename = None
def finalize_options(self) -> None:
build = self.get_finalized_command("build")
# check use of deprecated option
options = build.distribution.get_option_dict("build")
if options.get("build_exe", (None, None)) != (None, None):
msg = (
"[REMOVED] The use of build command with 'build-exe' "
"option is deprecated.\n\t\t"
"Use build_exe command with 'build-exe' option instead."
)
raise OptionError(msg)
# check values of build_base and build_exe
self.build_base = build.build_base
if self.build_exe == self.build_base:
msg = "build_exe option cannot be the same as build_base directory"
raise SetupError(msg)
if not self.build_exe: # empty or None
dir_name = f"exe.{get_platform()}-{get_python_version()}"
self.build_exe = os.path.join(self.build_base, dir_name)
# make sure all options of multiple values are lists
for option in self.list_options:
setattr(self, option, normalize_to_list(getattr(self, option)))
# path - accepts os.pathsep to be backwards compatible with CLI
if self.path and isinstance(self.path, str):
self.path = self.path.replace(os.pathsep, ",")
include_path = self.include_path
if include_path:
self.path = include_path + normalize_to_list(self.path or sys.path)
# the degree of silencing, set from either the silent or silent-level
# option, as appropriate
self.silent = int(self.silent or self.silent_level or 0)
# compression options
self.no_compress = bool(self.no_compress)
if self.zip_filename:
self.zip_filename = os.path.basename(
os.path.splitext(self.zip_filename)[0] + ".zip"
)
elif self.no_compress is False:
self.zip_filename = "library.zip"
# include-msvcr is used on Windows, but not in MingW
self.include_msvcr = IS_WINDOWS and bool(self.include_msvcr)
# optimization level: 0,1,2
self.optimize = int(self.optimize or 0)
def run(self) -> None:
metadata = self.distribution.metadata
constants_module = ConstantsModule(
metadata.version, constants=self.constants
)
freezer: Freezer = Freezer(
self.distribution.executables,
constants_module,
self.includes,
self.excludes,
self.packages,
self.replace_paths,
(not self.no_compress),
self.optimize,
self.path,
self.build_exe,
bin_includes=self.bin_includes,
bin_excludes=self.bin_excludes,
bin_path_includes=self.bin_path_includes,
bin_path_excludes=self.bin_path_excludes,
include_files=self.include_files,
zip_includes=self.zip_includes,
zip_include_packages=self.zip_include_packages,
zip_exclude_packages=self.zip_exclude_packages,
silent=self.silent,
metadata=metadata,
include_msvcr=self.include_msvcr,
zip_filename=self.zip_filename,
)
freezer.freeze()
freezer.print_report()
def set_source_location(self, name, *pathParts) -> None:
env_name = f"{name.upper()}_BASE"
attr_name = name.lower()
source_dir = getattr(self, attr_name)
if source_dir is None:
base_dir = os.environ.get(env_name)
if base_dir is None:
return
source_dir = os.path.join(base_dir, *pathParts)
if os.path.isdir(source_dir):
setattr(self, attr_name, source_dir)
# -- Predicates for the sub-command list ---------------------------
def has_executables(self) -> bool:
return getattr(self.distribution, "executables", None) is not None