aboutsummaryrefslogtreecommitdiffstats
path: root/build_scripts/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'build_scripts/main.py')
-rw-r--r--build_scripts/main.py199
1 files changed, 117 insertions, 82 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py
index 4660c9879..9a8d4fb3f 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -10,11 +10,10 @@ import sysconfig
import time
from packaging.version import parse as parse_version
from pathlib import Path
-from shutil import copytree
+from shutil import copytree, rmtree
from textwrap import dedent
# PYSIDE-1760: Pre-load setuptools modules early to avoid racing conditions.
-# Please be careful: All setuptools modules must be loaded before _distutils
# may be touched (should be avoided anyway, btw.)
# Note: This bug is only visible when tools like pyenv are not used. They have some
# pre-loading effect so that setuptools is already in the cache, hiding the problem.
@@ -28,8 +27,7 @@ from setuptools.command.install import install as _install
from setuptools.command.install_lib import install_lib as _install_lib
from setuptools.command.install_scripts import install_scripts # noqa: preload only
-# Use the distutils implementation within setuptools (but not before)
-from .log import log
+from .log import log, LogLevel
from setuptools.errors import SetupError
from .build_info_collector import BuildInfoCollectorMixin
@@ -38,8 +36,8 @@ from .options import OPTION, CommandMixin
from .platforms.unix import prepare_packages_posix
from .platforms.windows_desktop import prepare_packages_win32
from .qtinfo import QtInfo
-from .utils import (copydir, copyfile, detect_clang, filter_match,
- get_numpy_location, get_python_dict, init_msvc_env,
+from .utils import (copydir, copyfile, detect_clang,
+ get_numpy_location, get_python_dict,
linux_fix_rpaths_for_library, macos_fix_rpaths_for_library,
platform_cmake_options, remove_tree, run_process,
run_process_output, update_env_path, which)
@@ -52,11 +50,11 @@ setup_script_dir = Path.cwd()
build_scripts_dir = setup_script_dir / 'build_scripts'
setup_py_path = setup_script_dir / "setup.py"
-start_time = int(time.time())
+start_time = time.time()
def elapsed():
- return int(time.time()) - start_time
+ return int(time.time() - start_time)
def get_setuptools_extension_modules():
@@ -78,18 +76,14 @@ def _get_make(platform_arch, build_type):
if makespec == "make":
return ("make", "Unix Makefiles")
if makespec == "msvc":
- nmake_path = Path(which("nmake"))
- if nmake_path is None or not nmake_path.exists():
- log.info("nmake not found. Trying to initialize the MSVC env...")
- init_msvc_env(platform_arch, build_type)
- nmake_path = Path(which("nmake"))
- if not nmake_path or not nmake_path.exists():
- raise SetupError('"nmake" could not be found.')
if not OPTION["NO_JOM"]:
jom_path = Path(which("jom"))
if jom_path:
log.info(f"jom was found in {jom_path}")
return (jom_path, "NMake Makefiles JOM")
+ nmake_path = Path(which("nmake"))
+ if nmake_path is None or not nmake_path.exists():
+ raise SetupError("nmake not found")
log.info(f"nmake was found in {nmake_path}")
if OPTION["JOBS"]:
msg = "Option --jobs can only be used with 'jom' on Windows."
@@ -184,12 +178,12 @@ class PysideInstall(_install, CommandMixin):
if sys.platform == 'darwin' or self.is_cross_compile:
# Because we change the plat_name to include a correct
- # deployment target on macOS distutils thinks we are
+ # deployment target on macOS setuptools thinks we are
# cross-compiling, and throws an exception when trying to
# execute setup.py install. The check looks like this
# if self.warn_dir and build_plat != get_platform():
- # raise DistutilsPlatformError("Can't install when "
- # "cross-compiling")
+ # raise PlatformError("Can't install when "
+ # "cross-compiling")
# Obviously get_platform will return the old deployment
# target. The fix is to disable the warn_dir flag, which
# was created for bdist_* derived classes to override, for
@@ -241,7 +235,7 @@ class PysideBuildPy(_build_py):
# _install_lib is reimplemented to preserve
-# symlinks when distutils / setuptools copy files to various
+# symlinks when setuptools copy files to various
# directories from the setup tools build dir to the install dir.
class PysideInstallLib(_install_lib):
@@ -288,7 +282,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
if use_os_name_hack:
# This is a hack to circumvent the dubious check in
- # distutils.commands.build -> finalize_options, which only
+ # setuptool.commands.build -> finalize_options, which only
# allows setting the plat_name for windows NT.
# That is not the case for the wheel module though (which
# does allow setting plat_name), so we circumvent by faking
@@ -576,14 +570,22 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
# Build module
cmake_cmd = [str(OPTION["CMAKE"])]
- if OPTION["QUIET"]:
+ cmake_quiet_build = 1
+ cmake_rule_messages = 0
+ if OPTION["LOG_LEVEL"] == LogLevel.VERBOSE:
# Pass a special custom option, to allow printing a lot less information when doing
# a quiet build.
- cmake_cmd.append('-DQUIET_BUILD=1')
+ cmake_quiet_build = 0
if self.make_generator == "Unix Makefiles":
# Hide progress messages for each built source file.
# Doesn't seem to work if set within the cmake files themselves.
- cmake_cmd.append('-DCMAKE_RULE_MESSAGES=0')
+ cmake_rule_messages = 1
+
+ if OPTION["UNITY"]:
+ cmake_cmd.append("-DCMAKE_UNITY_BUILD=ON")
+ batch_size = OPTION["UNITY_BUILD_BATCH_SIZE"]
+ cmake_cmd.append(f"-DCMAKE_UNITY_BUILD_BATCH_SIZE={batch_size}")
+ log.info("Using UNITY build")
cmake_cmd += [
"-G", self.make_generator,
@@ -594,6 +596,8 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
# Record the minimum/maximum Python version for later use in Shiboken.__init__
f"-DMINIMUM_PYTHON_VERSION={get_allowed_python_versions()[0]}",
f"-DMAXIMUM_PYTHON_VERSION={get_allowed_python_versions()[-1]}",
+ f"-DQUIET_BUILD={cmake_quiet_build}",
+ f"-DCMAKE_RULE_MESSAGES={cmake_rule_messages}",
str(module_src_dir)
]
@@ -607,9 +611,9 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
# embedding_generator.py. Pass it as a separate option.
cmake_cmd.append(f"-DQFP_PYTHON_HOST_PATH={sys.executable}")
else:
- cmake_cmd.append(f"-DPYTHON_EXECUTABLE={self.py_executable}")
- cmake_cmd.append(f"-DPYTHON_INCLUDE_DIR={self.py_include_dir}")
- cmake_cmd.append(f"-DPYTHON_LIBRARY={self.py_library}")
+ cmake_cmd.append(f"-DPython_EXECUTABLE={self.py_executable}")
+ cmake_cmd.append(f"-DPython_INCLUDE_DIR={self.py_include_dir}")
+ cmake_cmd.append(f"-DPython_LIBRARY={self.py_library}")
# If a custom shiboken cmake config directory path was provided, pass it to CMake.
if OPTION["SHIBOKEN_CONFIG_DIR"] and config.is_internal_pyside_build():
@@ -631,6 +635,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
module_sub_set += ';'
module_sub_set += m
cmake_cmd.append(f"-DMODULES={module_sub_set}")
+
if OPTION["SKIP_MODULES"]:
skip_modules = ''
for m in OPTION["SKIP_MODULES"].split(','):
@@ -669,10 +674,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
else:
log.warning('numpy include directory was not found.')
- if self.build_type.lower() == 'debug':
- if not self.is_cross_compile:
- cmake_cmd.append(f"-DPYTHON_DEBUG_LIBRARY={self.py_library}")
- else:
+ if self.build_type.lower() != 'debug':
if OPTION['NO_STRIP']:
cmake_cmd.append("-DQFP_NO_STRIP=1")
if OPTION['NO_OVERRIDE_OPTIMIZATION_FLAGS']:
@@ -688,10 +690,15 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
else:
raise SetupError("option limited-api must be 'yes' or 'no' "
"(default yes if applicable, i.e. Python "
- "version >= 3.7 and release build if on Windows)")
+ "version >= 3.9 and release build if on Windows)")
+
+ if OPTION["DISABLE_PYI"]:
+ cmake_cmd.append("-DDISABLE_PYI=yes")
- if OPTION["VERBOSE_BUILD"]:
+ if OPTION["LOG_LEVEL"] == LogLevel.VERBOSE:
cmake_cmd.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON")
+ else:
+ cmake_cmd.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=OFF")
if OPTION['COMPILER_LAUNCHER']:
compiler_launcher = OPTION['COMPILER_LAUNCHER']
@@ -717,6 +724,9 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
pyside_qt_conf_prefix = '"."'
cmake_cmd.append(f"-DPYSIDE_QT_CONF_PREFIX={pyside_qt_conf_prefix}")
+ if OPTION["STANDALONE"]:
+ cmake_cmd.append("-DSTANDALONE:BOOL=ON")
+
# Pass package version to CMake, so this string can be
# embedded into _config.py file.
package_version = get_package_version()
@@ -731,8 +741,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
cmake_cmd.append(f"-DPACKAGE_SETUP_PY_PACKAGE_TIMESTAMP={timestamp}")
if extension.lower() in [SHIBOKEN]:
- cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes")
- cmake_cmd.append("-DUSE_PYTHON_VERSION=3.7")
+ cmake_cmd.append("-DUSE_PYTHON_VERSION=3.9")
cmake_cmd += platform_cmake_options()
@@ -763,7 +772,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
# Set macOS minimum deployment target (version).
# This is required so that calling
- # run_process -> distutils.spawn()
+ # run_process -> subprocess.call()
# does not set its own minimum deployment target
# environment variable which is based on the python
# interpreter sysconfig value.
@@ -774,7 +783,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
os.environ['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
if OPTION["BUILD_DOCS"]:
- # Build the whole documentation (rst + API) by default
+ # Build the whole documentation (Base + API) by default
cmake_cmd.append("-DFULLDOCSBUILD=1")
if OPTION["DOC_BUILD_ONLINE"]:
@@ -800,7 +809,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
cmake_cmd.append(f"-DQFP_QT_HOST_PATH={self.qt_host_path}")
if self.is_cross_compile and (not OPTION["SHIBOKEN_HOST_PATH"]
- or not OPTION["SHIBOKEN_HOST_PATH"].exists()):
+ or not Path(OPTION["SHIBOKEN_HOST_PATH"]).exists()):
raise SetupError("Please specify the location of host shiboken tools via "
"--shiboken-host-path=")
@@ -828,7 +837,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
cmd_make = [str(self.make_path)]
if OPTION["JOBS"]:
cmd_make.append(OPTION["JOBS"])
- if OPTION["VERBOSE_BUILD"] and self.make_generator == "Ninja":
+ if OPTION["LOG_LEVEL"] == LogLevel.VERBOSE and self.make_generator == "Ninja":
cmd_make.append("-v")
if run_process(cmd_make) != 0:
raise SetupError(f"Error compiling {extension}")
@@ -846,11 +855,10 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
if found:
log.info("Generating Shiboken documentation")
make_doc_cmd = [str(self.make_path), "doc"]
- if OPTION["VERBOSE_BUILD"] and self.make_generator == "Ninja":
+ if OPTION["LOG_LEVEL"] == LogLevel.VERBOSE and self.make_generator == "Ninja":
make_doc_cmd.append("-v")
if run_process(make_doc_cmd) != 0:
- raise SetupError("Error generating documentation "
- f"for {extension}")
+ raise SetupError(f"Error generating documentation for {extension}")
else:
log.info("Sphinx not found, skipping documentation build")
else:
@@ -878,13 +886,13 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
def prepare_packages(self):
"""
This will copy all relevant files from the various locations in the "cmake install dir",
- to the setup tools build dir (which is read from self.build_lib provided by distutils).
+ to the setup tools build dir (which is read from self.build_lib provided by setuptools).
After that setuptools.command.build_py is smart enough to copy everything
from the build dir to the install dir (the virtualenv site-packages for example).
"""
try:
- log.info("\nPreparing setup tools build directory.\n")
+ log.info("Preparing setup tools build directory.")
_vars = {
"site_packages_dir": self.site_packages_dir,
"sources_dir": self.sources_dir,
@@ -901,6 +909,8 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
"qt_data_dir": self.qtinfo.data_dir,
"qt_doc_dir": self.qtinfo.docs_dir,
"qt_lib_dir": self.qtinfo.libs_dir,
+ "qt_module_json_files_dir": self.qtinfo.module_json_files_dir,
+ "qt_metatypes_dir": self.qtinfo.metatypes_dir,
"qt_lib_execs_dir": self.qtinfo.lib_execs_dir,
"qt_plugins_dir": self.qtinfo.plugins_dir,
"qt_prefix_dir": self.qtinfo.prefix_dir,
@@ -994,8 +1004,8 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
# (lib/libclang.lib), whereas we want to copy the shared
# library (bin/libclang.dll).
clang_lib_path = Path(re.sub(r'lib/libclang.lib$',
- 'bin/libclang.dll',
- clang_lib_path))
+ 'bin/libclang.dll',
+ clang_lib_path))
else:
clang_lib_path = Path(clang_lib_path)
# shiboken6 links against libclang.so.6 or a similarly
@@ -1047,7 +1057,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
if self.is_cross_compile:
if 'darwin' in self.plat_name or 'macos' in self.plat_name:
filters = darwin_filters
- elif 'linux' in self.plat_name:
+ elif 'linux' in self.plat_name or 'android' in self.plat_name:
filters = unix_filters
else:
log.warning(f"No shared library filters found for platform {self.plat_name}. "
@@ -1059,29 +1069,31 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
filters = unix_filters
return filters
+ def _find_shared_libraries(self, path, recursive=False):
+ """Helper to find shared libraries in a path."""
+ result = set()
+ for filter in self.get_shared_library_filters():
+ glob_pattern = f"**/{filter}" if recursive else filter
+ for library in path.glob(glob_pattern):
+ result.add(library)
+ return list(result)
+
def package_libraries(self, package_path):
"""Returns the libraries of the Python module"""
- filters = self.get_shared_library_filters()
- return [lib for lib in os.listdir(
- package_path) if filter_match(lib, filters)]
+ return self._find_shared_libraries(package_path)
def get_shared_libraries_in_path_recursively(self, initial_path):
"""Returns shared library plugins in given path (collected
recursively)"""
- filters = self.get_shared_library_filters()
- libraries = []
- for dir_path, dir_names, file_names in os.walk(initial_path):
- for name in file_names:
- if filter_match(name, filters):
- library_path = Path(dir_path) / name
- libraries.append(library_path)
- return libraries
-
- def update_rpath(self, package_path, executables, libexec=False):
+ return self._find_shared_libraries(initial_path, recursive=True)
+
+ def update_rpath(self, executables, libexec=False, message=None):
ROOT = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'
QT_PATH = '/../lib' if libexec else '/Qt/lib'
+ message = "Patched rpath to '$ORIGIN/' in"
if sys.platform.startswith('linux'):
+
def rpath_cmd(srcpath):
final_rpath = ''
# Command line rpath option takes precedence over
@@ -1099,6 +1111,8 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
override=override)
elif sys.platform == 'darwin':
+ message = "Updated rpath in"
+
def rpath_cmd(srcpath):
final_rpath = ''
# Command line rpath option takes precedence over
@@ -1116,15 +1130,13 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
raise RuntimeError(f"Not configured for platform {sys.platform}")
# Update rpath
- for srcname in executables:
- srcpath = Path(package_path) / srcname
- if srcpath.is_dir() or srcpath.is_symlink():
+ for executable in executables:
+ if executable.is_dir() or executable.is_symlink():
continue
- if not srcpath.exists():
+ if not executable.exists():
continue
- rpath_cmd(srcpath)
- log.info("Patched rpath to '$ORIGIN/' (Linux) or "
- f"updated rpath (OS/X) in {srcpath}.")
+ rpath_cmd(executable)
+ log.debug(f"{message} {executable}.")
def update_rpath_for_linux_plugins(
self,
@@ -1144,7 +1156,6 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
log.info("Patching rpath for Qt and QML plugins.")
for plugin in plugin_paths:
- plugin = Path(plugin)
if plugin.is_dir() or plugin.is_symlink():
continue
if not plugin.exists():
@@ -1162,7 +1173,7 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
linux_fix_rpaths_for_library(self._patchelf_path, plugin, rpath_value,
override=True)
- log.info(f"Patched rpath to '{rpath_value}' in {plugin}.")
+ log.debug(f"Patched rpath to '{rpath_value}' in {plugin}.")
def update_rpath_for_linux_qt_libraries(self, qt_lib_dir):
# Ensure that Qt libs and ICU libs have $ORIGIN in their rpath.
@@ -1174,29 +1185,27 @@ class PysideBuild(_build, CommandMixin, BuildInfoCollectorMixin):
qt_lib_dir = Path(qt_lib_dir)
rpath_value = "$ORIGIN"
log.info(f"Patching rpath for Qt and ICU libraries in {qt_lib_dir}.")
- libs = self.package_libraries(qt_lib_dir)
- lib_paths = [qt_lib_dir / lib for lib in libs]
- for library in lib_paths:
+ for library in self.package_libraries(qt_lib_dir):
if library.is_dir() or library.is_symlink():
continue
- if library.exists():
+ if not library.exists():
continue
linux_fix_rpaths_for_library(self._patchelf_path, library, rpath_value, override=True)
- log.info(f"Patched rpath to '{rpath_value}' in {library}.")
+ log.debug(f"Patched rpath to '{rpath_value}' in {library}.")
-class PysideRstDocs(Command, CommandMixin):
- description = "Build .rst documentation only"
+class PysideBaseDocs(Command, CommandMixin):
+ description = "Build the base documentation only"
user_options = CommandMixin.mixin_user_options
def __init__(self, *args, **kwargs):
- self.command_name = "build_rst_docs"
+ self.command_name = "build_base_docs"
Command.__init__(self, *args, **kwargs)
CommandMixin.__init__(self)
def initialize_options(self):
- log.info("-- This build process will not include the API documentation."
+ log.info("-- This build process will not include the API documentation. "
"API documentation requires a full build of pyside/shiboken.")
self.skip = False
if config.is_internal_shiboken_generator_build():
@@ -1206,8 +1215,13 @@ class PysideRstDocs(Command, CommandMixin):
self.doc_dir = config.setup_script_dir / "sources" / self.name / "doc"
# Check if sphinx is installed to proceed.
found = importlib.util.find_spec("sphinx")
+ self.html_dir = Path("html")
if found:
if self.name == SHIBOKEN:
+ # Delete the 'html' directory since new docs will be generated anyway
+ if self.html_dir.is_dir():
+ rmtree(self.html_dir)
+ log.info("-- Deleted old html directory")
log.info("-- Generating Shiboken documentation")
log.info(f"-- Documentation directory: 'html/{PYSIDE}/{SHIBOKEN}/'")
elif self.name == PYSIDE:
@@ -1215,7 +1229,6 @@ class PysideRstDocs(Command, CommandMixin):
log.info(f"-- Documentation directory: 'html/{PYSIDE}/'")
else:
raise SetupError("Sphinx not found - aborting")
- self.html_dir = Path("html")
# creating directories html/pyside6/shiboken6
try:
@@ -1245,13 +1258,35 @@ class PysideRstDocs(Command, CommandMixin):
"-DDOC_OUTPUT_FORMAT=html",
"-DFULLDOCSBUILD=0",
]
- if OPTION["QUIET"]:
- cmake_cmd.append('-DQUIET_BUILD=1')
+
+ cmake_quiet_build = 1
+ cmake_message_log_level = "STATUS"
+
+ # Define log level
+ if OPTION["LOG_LEVEL"] == LogLevel.VERBOSE:
+ cmake_quiet_build = 0
+ cmake_message_log_level = "VERBOSE"
+ elif OPTION["LOG_LEVEL"] == LogLevel.QUIET:
+ cmake_message_log_level = "ERROR"
+
+ cmake_cmd.append(f"-DQUIET_BUILD={cmake_quiet_build}")
+ cmake_cmd.append(f"-DCMAKE_MESSAGE_LOG_LEVEL={cmake_message_log_level}")
+
if run_process(cmake_cmd) != 0:
raise SetupError(f"Error running CMake for {self.doc_dir}")
if self.name == PYSIDE:
- self.sphinx_src = self.out_dir / "rst"
+ self.sphinx_src = self.out_dir / "base"
+ example_gallery = config.setup_script_dir / "tools" / "example_gallery" / "main.py"
+ assert example_gallery.is_file()
+ example_gallery_cmd = [sys.executable, os.fspath(example_gallery)]
+ if OPTION["LOG_LEVEL"] == LogLevel.QUIET:
+ example_gallery_cmd.append("--quiet")
+ qt_src_dir = OPTION['QT_SRC']
+ if qt_src_dir:
+ example_gallery_cmd.extend(["--qt-src-dir", qt_src_dir])
+ if run_process(example_gallery_cmd) != 0:
+ raise SetupError(f"Error running example gallery for {self.doc_dir}")
elif self.name == SHIBOKEN:
self.sphinx_src = self.out_dir
@@ -1276,7 +1311,7 @@ cmd_class_dict = {
'develop': PysideDevelop,
'install': PysideInstall,
'install_lib': PysideInstallLib,
- 'build_rst_docs': PysideRstDocs,
+ 'build_base_docs': PysideBaseDocs,
}
if wheel_module_exists:
pyside_bdist_wheel = get_bdist_wheel_override()