aboutsummaryrefslogtreecommitdiffstats
path: root/setup.py
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2018-04-23 14:38:39 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2018-04-30 09:31:17 +0000
commit6fe563b2aa15c2c23369acce353be69f6ea84c77 (patch)
treee0ef0c6f7ae4106424a9202745651d59e70bd558 /setup.py
parent1d6bad63bcb6720078de1e78c1b495bf08d1c65b (diff)
Split and move various setup.py parts into different files
This is an initial effort to clean up setup.py. A new directory called build_scripts contains most of the logic for building, leaving setup.py as an entry point. The build_scripts directory contains the usual qtinfo, utils, and the setup.py content has been split into main.py and platform specific files under platforms subfolder. The testrunner script has been modified to find the new location of the utils module. Task-number: PYSIDE-558 Change-Id: I3e041d5116ca5c3f96c789317303b65a7b1bbd70 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py1901
1 files changed, 9 insertions, 1892 deletions
diff --git a/setup.py b/setup.py
index e2ad9aa14..dda7b29a0 100644
--- a/setup.py
+++ b/setup.py
@@ -1,9 +1,9 @@
#############################################################################
##
-## Copyright (C) 2016 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
-## This file is part of PySide2.
+## This file is part of the Qt for Python project.
##
## $QT_BEGIN_LICENSE:LGPL$
## Commercial License Usage
@@ -38,7 +38,6 @@
#############################################################################
from __future__ import print_function
-from distutils.version import LooseVersion
"""
This is a distutils setup-script for the Qt for Python project
@@ -199,12 +198,9 @@ OPTIONAL:
an older OS version.
"""
-import os
-import time
-from utils import memoize, has_option, get_python_dict
-OPTION_SNAPSHOT_BUILD = has_option("snapshot-build")
+import os, sys
-# Change the cwd to setup.py's dir.
+# Change the current directory to setup.py's dir.
try:
this_file = __file__
except NameError:
@@ -212,1896 +208,17 @@ except NameError:
this_file = os.path.abspath(this_file)
if os.path.dirname(this_file):
os.chdir(os.path.dirname(this_file))
-script_dir = os.getcwd()
-@memoize
-def get_package_timestamp():
- return int(time.time())
-
-@memoize
-def get_package_version():
- """ Returns the version string for the PySide2 package. """
- pyside_version_py = os.path.join(
- script_dir, "sources", "pyside2", "pyside_version.py")
- d = get_python_dict(pyside_version_py)
-
- final_version = "{}.{}.{}".format(
- d['major_version'], d['minor_version'], d['patch_version'])
- pre_release_version_type = d['pre_release_version_type']
- pre_release_version = d['pre_release_version']
- if pre_release_version and pre_release_version:
- final_version += pre_release_version_type + pre_release_version
-
- # Add the current timestamp to the version number, to suggest it
- # is a development snapshot build.
- if OPTION_SNAPSHOT_BUILD:
- final_version += ".dev{}".format(get_package_timestamp())
- return final_version
+from build_scripts.main import get_package_version
+from build_scripts.main import pyside_package_dir_name
+from build_scripts.main import cmd_class_dict
+from build_scripts.main import README, CHANGES
+from setuptools import setup, Extension
# The __version__ variable is just for PEP compliancy, and shouldn't be
# used as a value source.
__version__ = get_package_version()
-# Buildable extensions.
-containedModules = ['shiboken2', 'pyside2', 'pyside2-tools']
-
-# Git submodules: ["submodule_name",
-# "location_relative_to_sources_folder"]
-submodules = [["pyside2-tools"]]
-
-pyside_package_dir_name = "pyside_package"
-
-try:
- import setuptools
-except ImportError:
- from ez_setup import use_setuptools
- use_setuptools()
-
-import sys
-import platform
-import re
-import fnmatch
-
-import difflib # for a close match of dirname and module
-import functools
-
-from distutils import log
-from distutils.errors import DistutilsOptionError
-from distutils.errors import DistutilsSetupError
-from distutils.sysconfig import get_config_var
-from distutils.sysconfig import get_python_lib
-from distutils.spawn import find_executable
-from distutils.command.build import build as _build
-from distutils.command.build_ext import build_ext as _build_ext
-from distutils.util import get_platform
-
-from setuptools import setup, Extension
-from setuptools.command.install import install as _install
-from setuptools.command.install_lib import install_lib as _install_lib
-from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
-from setuptools.command.develop import develop as _develop
-from setuptools.command.build_py import build_py as _build_py
-
-wheel_module_exists = False
-try:
- from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
- from wheel.bdist_wheel import safer_name as _safer_name
- wheel_module_exists = True
-except ImportError:
- pass
-
-from qtinfo import QtInfo
-from utils import rmtree, detectClang
-from utils import makefile
-from utils import copyfile
-from utils import copydir
-from utils import run_process_output, run_process
-from utils import option_value
-from utils import update_env_path
-from utils import init_msvc_env
-from utils import regenerate_qt_resources
-from utils import filter_match
-from utils import macos_fix_rpaths_for_library
-from utils import copy_icu_libs
-from utils import find_files_using_glob
-
-from textwrap import dedent
-
-# make sure that setup.py is run with an allowed python version
-def check_allowed_python_version():
- import re
- pattern = "'Programming Language :: Python :: (\d+)\.(\d+)'"
- supported = []
- with open(this_file) as setup:
- for line in setup.readlines():
- found = re.search(pattern, line)
- if found:
- major = int(found.group(1))
- minor = int(found.group(2))
- supported.append( (major, minor) )
- this_py = sys.version_info[:2]
- if this_py not in supported:
- print("only these python versions are supported:", supported)
- sys.exit(1)
-
-check_allowed_python_version()
-
-qtSrcDir = ''
-
-# Declare options
-OPTION_DEBUG = has_option("debug")
-OPTION_RELWITHDEBINFO = has_option('relwithdebinfo')
-OPTION_QMAKE = option_value("qmake")
-OPTION_QT_VERSION = option_value("qt")
-OPTION_CMAKE = option_value("cmake")
-OPTION_OPENSSL = option_value("openssl")
-OPTION_ONLYPACKAGE = has_option("only-package")
-OPTION_STANDALONE = has_option("standalone")
-OPTION_MAKESPEC = option_value("make-spec")
-OPTION_IGNOREGIT = has_option("ignore-git")
-# don't include pyside2-examples
-OPTION_NOEXAMPLES = has_option("no-examples")
-# number of parallel build jobs
-OPTION_JOBS = option_value('jobs')
-# Legacy, not used any more.
-OPTION_JOM = has_option('jom')
-# Do not use jom instead of nmake with msvc
-OPTION_NO_JOM = has_option('no-jom')
-OPTION_BUILDTESTS = has_option("build-tests")
-OPTION_MACOS_ARCH = option_value("macos-arch")
-OPTION_MACOS_USE_LIBCPP = has_option("macos-use-libc++")
-OPTION_MACOS_SYSROOT = option_value("macos-sysroot")
-OPTION_MACOS_DEPLOYMENT_TARGET = option_value("macos-deployment-target")
-OPTION_XVFB = has_option("use-xvfb")
-OPTION_REUSE_BUILD = has_option("reuse-build")
-OPTION_SKIP_CMAKE = has_option("skip-cmake")
-OPTION_SKIP_MAKE_INSTALL = has_option("skip-make-install")
-OPTION_SKIP_PACKAGING = has_option("skip-packaging")
-OPTION_MODULE_SUBSET = option_value("module-subset")
-OPTION_RPATH_VALUES = option_value("rpath")
-OPTION_QT_CONF_PREFIX = option_value("qt-conf-prefix")
-OPTION_QT_SRC = option_value("qt-src-dir")
-OPTION_VERBOSE_BUILD = has_option("verbose-build")
-OPTION_SANITIZE_ADDRESS = has_option("sanitize-address")
-
-# This is used automatically by distutils.command.install object, to
-# specify final installation location.
-OPTION_FINAL_INSTALL_PREFIX = option_value("prefix")
-
-
-if OPTION_QT_VERSION is None:
- OPTION_QT_VERSION = "5"
-if OPTION_QMAKE is None:
- OPTION_QMAKE = find_executable("qmake-qt5")
-if OPTION_QMAKE is None:
- OPTION_QMAKE = find_executable("qmake")
-
-# make qtinfo.py independent of relative paths.
-if OPTION_QMAKE is not None and os.path.exists(OPTION_QMAKE):
- OPTION_QMAKE = os.path.abspath(OPTION_QMAKE)
-if OPTION_CMAKE is not None and os.path.exists(OPTION_CMAKE):
- OPTION_CMAKE = os.path.abspath(OPTION_CMAKE)
-
-QMAKE_COMMAND = None
-# Checking whether qmake executable exists
-if OPTION_QMAKE is not None and os.path.exists(OPTION_QMAKE):
- # Looking whether qmake path is a link and whether the link exists
- if os.path.islink(OPTION_QMAKE) and os.path.lexists(OPTION_QMAKE):
- # Set -qt=X here.
- if "qtchooser" in os.readlink(OPTION_QMAKE):
- QMAKE_COMMAND = [OPTION_QMAKE, "-qt={}".format(OPTION_QT_VERSION)]
-if not QMAKE_COMMAND:
- QMAKE_COMMAND = [OPTION_QMAKE]
-
-if len(QMAKE_COMMAND) == 0 or QMAKE_COMMAND[0] is None:
- print("qmake could not be found.")
- sys.exit(1)
-if not os.path.exists(QMAKE_COMMAND[0]):
- print("'{}' does not exist.".format(QMAKE_COMMAND[0]))
- sys.exit(1)
-if OPTION_CMAKE is None:
- OPTION_CMAKE = find_executable("cmake")
-
-if OPTION_CMAKE is None:
- print("cmake could not be found.")
- sys.exit(1)
-if not os.path.exists(OPTION_CMAKE):
- print("'{}' does not exist.".format(OPTION_CMAKE))
- sys.exit(1)
-
-if sys.platform == "win32":
- if OPTION_MAKESPEC is None:
- OPTION_MAKESPEC = "msvc"
- if not OPTION_MAKESPEC in ["msvc", "mingw"]:
- print("Invalid option --make-spec. Available values are {}".format(
- ["msvc", "mingw"]))
- sys.exit(1)
-else:
- if OPTION_MAKESPEC is None:
- OPTION_MAKESPEC = "make"
- if not OPTION_MAKESPEC in ["make"]:
- print("Invalid option --make-spec. Available values are {}".format(
- ["make"]))
- sys.exit(1)
-
-if OPTION_JOBS:
- if sys.platform == 'win32' and OPTION_NO_JOM:
- print("Option --jobs can only be used with jom on Windows.")
- sys.exit(1)
- else:
- if not OPTION_JOBS.startswith('-j'):
- OPTION_JOBS = '-j' + OPTION_JOBS
-else:
- OPTION_JOBS = ''
-
-def is_debug_python():
- return getattr(sys, "gettotalrefcount", None) is not None
-
-# Return a prefix suitable for the _install/_build directory
-def prefix():
- virtualEnvName = os.environ.get('VIRTUAL_ENV', None)
- if virtualEnvName is not None:
- name = os.path.basename(virtualEnvName)
- else:
- name = "pyside"
- name += str(sys.version_info[0])
- if OPTION_DEBUG:
- name += 'd'
- if is_debug_python():
- name += 'p'
- return name
-
-# Initialize, pull and checkout submodules
-def prepareSubModules():
- print("Initializing submodules for PySide2 version: {}".format(
- get_package_version()))
- submodules_dir = os.path.join(script_dir, "sources")
-
- # Create list of [name, desired branch, absolute path, desired
- # branch] and determine whether all submodules are present
- needInitSubModules = False
-
- for m in submodules:
- module_name = m[0]
- module_dir = m[1] if len(m) > 1 else ''
- module_dir = os.path.join(submodules_dir, module_dir, module_name)
- # Check for non-empty directory (repository checked out)
- if not os.listdir(module_dir):
- needInitSubModules = True
- break
-
- if needInitSubModules:
- git_update_cmd = ["git", "submodule", "update", "--init"]
- if run_process(git_update_cmd) != 0:
- m = ("Failed to initialize the git submodules: "
- "update --init failed")
- raise DistutilsSetupError(m)
- git_pull_cmd = ["git", "submodule", "foreach", "git", "fetch", "--all"]
- if run_process(git_pull_cmd) != 0:
- m = ("Failed to initialize the git submodules: "
- "git fetch --all failed")
- raise DistutilsSetupError(m)
- else:
- print("All submodules present.")
-
- git_update_cmd = ["git", "submodule", "update"]
- if run_process(git_update_cmd) != 0:
- m = "Failed to checkout the correct git submodules SHA1s."
- raise DistutilsSetupError(m)
-
-# Single global instance of QtInfo to be used later in multiple code
-# paths.
-qtinfo = QtInfo(QMAKE_COMMAND)
-
-def get_qt_version():
- qt_version = qtinfo.version
-
- if not qt_version:
- log.error("Failed to query the Qt version with qmake {0}".format(
- self.qtinfo.qmake_command))
- sys.exit(1)
-
- if LooseVersion(qtinfo.version) < LooseVersion("5.7"):
- log.error("Incompatible Qt version detected: {}. "
- "A Qt version >= 5.7 is required.".format(qt_version))
- sys.exit(1)
-
- return qt_version
-
-def prepareBuild():
- if (os.path.isdir(".git") and not OPTION_IGNOREGIT and
- not OPTION_ONLYPACKAGE and not OPTION_REUSE_BUILD):
- prepareSubModules()
- # Clean up temp and package folders
- for n in [pyside_package_dir_name, "build"]:
- d = os.path.join(script_dir, n)
- if os.path.isdir(d):
- print("Removing {}".format(d))
- try:
- rmtree(d)
- except Exception as e:
- print('***** problem removing "{}"'.format(d))
- print('ignored error: {}'.format(e))
- # Prepare package folders
- ppdn = pyside_package_dir_name
- absolute_paths = [os.path.join(ppdn, "PySide2"),
- os.path.join(ppdn, "pyside2uic")]
- for pkg in absolute_paths:
- pkg_dir = os.path.join(script_dir, pkg)
- os.makedirs(pkg_dir)
- # locate Qt sources for the documentation
- if OPTION_QT_SRC is None:
- installPrefix = qtinfo.prefix_dir
- if installPrefix:
- global qtSrcDir
- # In-source, developer build
- if installPrefix.endswith("qtbase"):
- qtSrcDir = installPrefix
- else: # SDK: Use 'Src' directory
- qtSrcDir = os.path.join(os.path.dirname(installPrefix),
- 'Src', 'qtbase')
-
-class pyside_install(_install):
- def __init__(self, *args, **kwargs):
- _install.__init__(self, *args, **kwargs)
-
- def initialize_options (self):
- _install.initialize_options(self)
-
- if sys.platform == 'darwin':
- # Because we change the plat_name to include a correct
- # deployment target on macOS distutils 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")
- # 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
- # similar cases.
- self.warn_dir = False
-
- def run(self):
- _install.run(self)
- log.info('*** Install completed')
-
-class pyside_develop(_develop):
-
- def __init__(self, *args, **kwargs):
- _develop.__init__(self, *args, **kwargs)
-
- def run(self):
- self.run_command("build")
- _develop.run(self)
-
-class pyside_bdist_egg(_bdist_egg):
-
- def __init__(self, *args, **kwargs):
- _bdist_egg.__init__(self, *args, **kwargs)
-
- def run(self):
- self.run_command("build")
- _bdist_egg.run(self)
-
-class pyside_build_ext(_build_ext):
-
- def __init__(self, *args, **kwargs):
- _build_ext.__init__(self, *args, **kwargs)
-
- def run(self):
- pass
-
-if wheel_module_exists:
- class pyside_build_wheel(_bdist_wheel):
- def __init__(self, *args, **kwargs):
- _bdist_wheel.__init__(self, *args, **kwargs)
-
- @property
- def wheel_dist_name(self):
- # Slightly modified version of wheel's wheel_dist_name
- # method, to add the Qt version as well.
- # Example:
- # PySide2-5.6-5.6.4-cp27-cp27m-macosx_10_10_intel.whl
- # The PySide2 version is "5.6".
- # The Qt version built against is "5.6.4".
- qt_version = get_qt_version()
- package_version = get_package_version()
- wheel_version = "{}-{}".format(package_version, qt_version)
- components = (_safer_name(self.distribution.get_name()),
- wheel_version)
- if self.build_number:
- components += (self.build_number,)
- return '-'.join(components)
-
- def finalize_options(self):
- if sys.platform == 'darwin':
- # Override the platform name to contain the correct
- # minimum deployment target.
- # This is used in the final wheel name.
- self.plat_name = pyside_build.macos_plat_name()
- _bdist_wheel.finalize_options(self)
-
-# pyside_build_py and pyside_install_lib are reimplemented to preserve
-# symlinks when distutils / setuptools copy files to various
-# directories through the different build stages.
-class pyside_build_py(_build_py):
-
- def __init__(self, *args, **kwargs):
- _build_py.__init__(self, *args, **kwargs)
-
- def build_package_data(self):
- """Copies files from pyside_package into build/xxx directory"""
-
- for package, src_dir, build_dir, filenames in self.data_files:
- for filename in filenames:
- target = os.path.join(build_dir, filename)
- self.mkpath(os.path.dirname(target))
- srcfile = os.path.abspath(os.path.join(src_dir, filename))
- # Using our own copyfile makes sure to preserve symlinks.
- copyfile(srcfile, target)
-
-class pyside_install_lib(_install_lib):
-
- def __init__(self, *args, **kwargs):
- _install_lib.__init__(self, *args, **kwargs)
-
- def install(self):
- """
- Installs files from build/xxx directory into final
- site-packages/PySide2 directory.
- """
-
- if os.path.isdir(self.build_dir):
- # Using our own copydir makes sure to preserve symlinks.
- outfiles = copydir(os.path.abspath(self.build_dir),
- os.path.abspath(self.install_dir))
- else:
- self.warn("'{}' does not exist -- "
- "no Python modules to install".format(self.build_dir))
- return
- return outfiles
-
-class pyside_build(_build):
-
- def __init__(self, *args, **kwargs):
- _build.__init__(self, *args, **kwargs)
-
- def finalize_options(self):
- os_name_backup = os.name
- if sys.platform == 'darwin':
- self.plat_name = pyside_build.macos_plat_name()
- # This is a hack to circumvent the dubious check in
- # distutils.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
- # the os name when finalizing the options, and then
- # restoring the original os name.
- os.name = "nt"
-
- _build.finalize_options(self)
-
- if sys.platform == 'darwin':
- os.name = os_name_backup
-
- def initialize_options(self):
- _build.initialize_options(self)
- self.make_path = None
- self.make_generator = None
- self.debug = False
- self.script_dir = None
- self.sources_dir = None
- self.build_dir = None
- self.install_dir = None
- self.py_executable = None
- self.py_include_dir = None
- self.py_library = None
- self.py_version = None
- self.build_type = "Release"
- self.qtinfo = None
- self.build_tests = False
-
- def run(self):
- prepareBuild()
- platform_arch = platform.architecture()[0]
- log.info("Python architecture is {}".format(platform_arch))
-
- build_type = "Debug" if OPTION_DEBUG else "Release"
- if OPTION_RELWITHDEBINFO:
- build_type = 'RelWithDebInfo'
-
- # Check env
- make_path = None
- make_generator = None
- if not OPTION_ONLYPACKAGE:
- if OPTION_MAKESPEC == "make":
- make_name = "make"
- make_generator = "Unix Makefiles"
- elif OPTION_MAKESPEC == "msvc":
- nmake_path = find_executable("nmake")
- if nmake_path is None or not os.path.exists(nmake_path):
- log.info("nmake not found. "
- "Trying to initialize the MSVC env...")
- init_msvc_env(platform_arch, build_type)
- nmake_path = find_executable("nmake")
- assert(nmake_path is not None and
- os.path.exists(nmake_path))
- jom_path = None if OPTION_NO_JOM else find_executable("jom")
- if jom_path is not None and os.path.exists(jom_path):
- log.info("jom was found in {}".format(jom_path))
- make_name = "jom"
- make_generator = "NMake Makefiles JOM"
- else:
- log.info("nmake was found in {}".format(nmake_path))
- make_name = "nmake"
- make_generator = "NMake Makefiles"
- elif OPTION_MAKESPEC == "mingw":
- make_name = "mingw32-make"
- make_generator = "MinGW Makefiles"
- else:
- raise DistutilsSetupError(
- "Invalid option --make-spec.")
- make_path = find_executable(make_name)
- if make_path is None or not os.path.exists(make_path):
- raise DistutilsSetupError("You need the program '{}' on your "
- "system path to compile PySide2.".format(make_name))
-
- if OPTION_CMAKE is None or not os.path.exists(OPTION_CMAKE):
- raise DistutilsSetupError(
- "Failed to find cmake."
- " Please specify the path to cmake with "
- "--cmake parameter.")
-
- if OPTION_QMAKE is None or not os.path.exists(OPTION_QMAKE):
- raise DistutilsSetupError(
- "Failed to find qmake."
- " Please specify the path to qmake with --qmake parameter.")
-
- # Prepare parameters
- py_executable = sys.executable
- py_version = "{}.{}".format(sys.version_info[0], sys.version_info[1])
- py_include_dir = get_config_var("INCLUDEPY")
- py_libdir = get_config_var("LIBDIR")
- py_prefix = get_config_var("prefix")
- if not py_prefix or not os.path.exists(py_prefix):
- py_prefix = sys.prefix
- if sys.platform == "win32":
- py_scripts_dir = os.path.join(py_prefix, "Scripts")
- else:
- py_scripts_dir = os.path.join(py_prefix, "bin")
- if py_libdir is None or not os.path.exists(py_libdir):
- if sys.platform == "win32":
- py_libdir = os.path.join(py_prefix, "libs")
- else:
- py_libdir = os.path.join(py_prefix, "lib")
- if py_include_dir is None or not os.path.exists(py_include_dir):
- if sys.platform == "win32":
- py_include_dir = os.path.join(py_prefix, "include")
- else:
- py_include_dir = os.path.join(py_prefix,
- "include/python{}".format(py_version))
- dbgPostfix = ""
- if build_type == "Debug":
- dbgPostfix = "_d"
- if sys.platform == "win32":
- if OPTION_MAKESPEC == "mingw":
- static_lib_name = "libpython{}{}.a".format(
- py_version.replace(".", ""), dbgPostfix)
- py_library = os.path.join(py_libdir, static_lib_name)
- else:
- python_lib_name = "python{}{}.lib".format(
- py_version.replace(".", ""), dbgPostfix)
- py_library = os.path.join(py_libdir, python_lib_name)
- else:
- lib_exts = ['.so']
- if sys.platform == 'darwin':
- lib_exts.append('.dylib')
- if sys.version_info[0] > 2:
- lib_suff = getattr(sys, 'abiflags', None)
- else: # Python 2
- lib_suff = ''
- lib_exts.append('.so.1')
- # Suffix for OpenSuSE 13.01
- lib_exts.append('.so.1.0')
- # static library as last gasp
- lib_exts.append('.a')
-
- if sys.version_info[0] == 2 and dbgPostfix:
- # For Python2 add a duplicate set of extensions
- # combined with the dbgPostfix, so we test for both the
- # debug version of the lib and the normal one.
- # This allows a debug PySide2 to be built with a
- # non-debug Python.
- lib_exts = [dbgPostfix + e for e in lib_exts] + lib_exts
-
- python_library_found = False
- libs_tried = []
- for lib_ext in lib_exts:
- lib_name = "libpython{}{}{}".format(py_version, lib_suff,
- lib_ext)
- py_library = os.path.join(py_libdir, lib_name)
- if os.path.exists(py_library):
- python_library_found = True
- break
- libs_tried.append(py_library)
- else:
- # At least on macOS 10.11, the system Python 2.6 does
- # not include a symlink to the framework file disguised
- # as a .dylib file, thus finding the library would
- # fail.
- # Manually check if a framework file "Python" exists in
- # the Python framework bundle.
- if sys.platform == 'darwin' and sys.version_info[:2] == (2, 6):
- # These manipulations essentially transform
- # /System/Library/Frameworks/Python.framework/Versions/2.6/lib
- # to
- # /System/Library/Frameworks/Python.framework/Versions/2.6/Python
- possible_framework_path = os.path.realpath(
- os.path.join(py_libdir, '..'))
- possible_framework_version = os.path.basename(
- possible_framework_path)
- possible_framework_library = os.path.join(
- possible_framework_path, 'Python')
-
- if (possible_framework_version == '2.6' and
- os.path.exists(possible_framework_library)):
- py_library = possible_framework_library
- python_library_found = True
- else:
- libs_tried.append(possible_framework_library)
-
- # Try to find shared libraries which have a multi arch
- # suffix.
- if not python_library_found:
- py_multiarch = get_config_var("MULTIARCH")
- if py_multiarch and not python_library_found:
- try_py_libdir = os.path.join(py_libdir, py_multiarch)
- libs_tried = []
- for lib_ext in lib_exts:
- lib_name = "libpython{}{}{}".format(
- py_version, lib_suff, lib_ext)
- py_library = os.path.join(try_py_libdir, lib_name)
- if os.path.exists(py_library):
- py_libdir = try_py_libdir
- python_library_found = True
- break
- libs_tried.append(py_library)
-
- if not python_library_found:
- raise DistutilsSetupError(
- "Failed to locate the Python library with {}".format(
- ", ".join(libs_tried)))
-
- if py_library.endswith('.a'):
- # Python was compiled as a static library
- log.error("Failed to locate a dynamic Python library, "
- "using {}".format(py_library))
-
- self.qtinfo = qtinfo
- qt_dir = os.path.dirname(OPTION_QMAKE)
- qt_version = get_qt_version()
-
- # Update the PATH environment variable
- additionalPaths = [py_scripts_dir, qt_dir]
-
- # Add Clang to path for Windows.
- # Revisit once Clang is bundled with Qt.
- if (sys.platform == "win32" and
- LooseVersion(self.qtinfo.version) >= LooseVersion("5.7.0")):
- clangDir = detectClang()
- if clangDir[0]:
- clangBinDir = os.path.join(clangDir[0], 'bin')
- if not clangBinDir in os.environ.get('PATH'):
- log.info("Adding {} as detected by {} to PATH".format(
- clangBinDir, clangDir[1]))
- additionalPaths.append(clangBinDir)
- else:
- raise DistutilsSetupError("Failed to detect Clang when checking "
- "LLVM_INSTALL_DIR, CLANG_INSTALL_DIR, llvm-config")
-
- update_env_path(additionalPaths)
-
- build_name = "py{}-qt{}-{}-{}".format(py_version, qt_version,
- platform.architecture()[0], build_type.lower())
-
- script_dir = os.getcwd()
- sources_dir = os.path.join(script_dir, "sources")
- build_dir = os.path.join(script_dir, prefix() + "_build",
- "{}".format(build_name))
- install_dir = os.path.join(script_dir, prefix() + "_install",
- "{}".format(build_name))
-
- # Try to ensure that tools built by this script (such as shiboken2)
- # are found before any that may already be installed on the system.
- update_env_path([os.path.join(install_dir, 'bin')])
-
- # Tell cmake to look here for *.cmake files
- os.environ['CMAKE_PREFIX_PATH'] = install_dir
-
- self.make_path = make_path
- self.make_generator = make_generator
- self.debug = OPTION_DEBUG
- self.script_dir = script_dir
- self.pyside_package_dir = os.path.join(self.script_dir,
- pyside_package_dir_name)
- self.sources_dir = sources_dir
- self.build_dir = build_dir
- self.install_dir = install_dir
- self.py_executable = py_executable
- self.py_include_dir = py_include_dir
- self.py_library = py_library
- self.py_version = py_version
- self.build_type = build_type
- self.site_packages_dir = get_python_lib(1, 0, prefix=install_dir)
- self.build_tests = OPTION_BUILDTESTS
-
- setuptools_install_prefix = get_python_lib(1)
- if OPTION_FINAL_INSTALL_PREFIX:
- setuptools_install_prefix = OPTION_FINAL_INSTALL_PREFIX
-
- # Save the shiboken build dir path for clang deployment
- # purposes.
- self.shiboken_build_dir = os.path.join(self.build_dir, "shiboken2")
-
- log.info("=" * 30)
- log.info("Package version: {}".format(get_package_version()))
- log.info("Build type: {}".format(self.build_type))
- log.info("Build tests: {}".format(self.build_tests))
- log.info("-" * 3)
- log.info("Make path: {}".format(self.make_path))
- log.info("Make generator: {}".format(self.make_generator))
- log.info("Make jobs: {}".format(OPTION_JOBS))
- log.info("-" * 3)
-
- log.info("Script directory: {}".format(self.script_dir))
- log.info("Sources directory: {}".format(self.sources_dir))
-
- log.info(dedent("""
- Building PySide2 will create and touch directories
- in the following order:
- make build directory (py*_build/*/*) ->
- make install directory (py*_install/*/*) ->
- {} directory (pyside_package/*) ->
- setuptools build directory (build/*/*) ->
- setuptools install directory
- (usually path-installed-python/lib/python*/site-packages/*)
- """).format(pyside_package_dir_name))
-
- log.info("make build directory: {}".format(self.build_dir))
- log.info("make install directory: {}".format(self.install_dir))
- log.info("{} directory: {}".format(pyside_package_dir_name,
- self.pyside_package_dir))
- log.info("setuptools build directory: {}".format(
- os.path.join(self.script_dir, "build")))
- log.info("setuptools install directory: {}".format(
- setuptools_install_prefix))
- log.info("make-installed site-packages directory: {} \n"
- " (only relevant for copying files from "
- "'make install directory' to '{} directory'".format(
- self.site_packages_dir, pyside_package_dir_name))
- log.info("-" * 3)
- log.info("Python executable: {}".format(self.py_executable))
- log.info("Python includes: {}".format(self.py_include_dir))
- log.info("Python library: {}".format(self.py_library))
- log.info("Python prefix: {}".format(py_prefix))
- log.info("Python scripts: {}".format(py_scripts_dir))
- log.info("-" * 3)
- log.info("Qt qmake: {}".format(self.qtinfo.qmake_command))
- log.info("Qt version: {}".format(self.qtinfo.version))
- log.info("Qt bins: {}".format(self.qtinfo.bins_dir))
- log.info("Qt docs: {}".format(self.qtinfo.docs_dir))
- log.info("Qt plugins: {}".format(self.qtinfo.plugins_dir))
- log.info("-" * 3)
- if sys.platform == 'win32':
- log.info("OpenSSL dll directory: {}".format(OPTION_OPENSSL))
- if sys.platform == 'darwin':
- pyside_macos_deployment_target = (
- pyside_build.macos_pyside_min_deployment_target()
- )
- log.info("MACOSX_DEPLOYMENT_TARGET set to: {}".format(
- pyside_macos_deployment_target))
- log.info("=" * 30)
-
- # Prepare folders
- if not os.path.exists(self.sources_dir):
- log.info("Creating sources folder {}...".format(self.sources_dir))
- os.makedirs(self.sources_dir)
- if not os.path.exists(self.build_dir):
- log.info("Creating build folder {}...".format(self.build_dir))
- os.makedirs(self.build_dir)
- if not os.path.exists(self.install_dir):
- log.info("Creating install folder {}...".format(self.install_dir))
- os.makedirs(self.install_dir)
-
- if not OPTION_ONLYPACKAGE:
- # Build extensions
- for ext in containedModules:
- self.build_extension(ext)
-
- if OPTION_BUILDTESTS:
- # we record the latest successful build and note the
- # build directory for supporting the tests.
- timestamp = time.strftime('%Y-%m-%d_%H%M%S')
- build_history = os.path.join(script_dir, 'build_history')
- unique_dir = os.path.join(build_history, timestamp)
- os.makedirs(unique_dir)
- fpath = os.path.join(unique_dir, 'build_dir.txt')
- with open(fpath, 'w') as f:
- print(build_dir, file=f)
- log.info("Created {}".format(build_history))
-
- if not OPTION_SKIP_PACKAGING:
- # Build patchelf if needed
- self.build_patchelf()
-
- # Prepare packages
- self.prepare_packages()
-
- # Build packages
- _build.run(self)
- else:
- log.info("Skipped preparing and building packages.")
- log.info('*** Build completed')
-
- @staticmethod
- def macos_qt_min_deployment_target():
- target = qtinfo.macos_min_deployment_target
-
- if not target:
- raise DistutilsSetupError("Failed to query for Qt's "
- "QMAKE_MACOSX_DEPLOYMENT_TARGET.")
- return target
-
- @staticmethod
- @memoize
- def macos_pyside_min_deployment_target():
- """
- Compute and validate PySide2 MACOSX_DEPLOYMENT_TARGET value.
- Candidate sources that are considered:
- - setup.py provided value
- - maximum value between minimum deployment target of the
- Python interpreter and the minimum deployment target of
- the Qt libraries.
- If setup.py value is provided, that takes precedence.
- Otherwise use the maximum of the above mentioned two values.
- """
- python_target = get_config_var('MACOSX_DEPLOYMENT_TARGET') or None
- qt_target = pyside_build.macos_qt_min_deployment_target()
- setup_target = OPTION_MACOS_DEPLOYMENT_TARGET
-
- qt_target_split = [int(x) for x in qt_target.split('.')]
- if python_target:
- python_target_split = [int(x) for x in python_target.split('.')]
- if setup_target:
- setup_target_split = [int(x) for x in setup_target.split('.')]
-
- message = ("Can't set MACOSX_DEPLOYMENT_TARGET value to {} because "
- "{} was built with minimum deployment target set to {}.")
- # setup.py provided OPTION_MACOS_DEPLOYMENT_TARGET value takes
- # precedence.
- if setup_target:
- if python_target and setup_target_split < python_target_split:
- raise DistutilsSetupError(message.format(setup_target,
- "Python", python_target))
- if setup_target_split < qt_target_split:
- raise DistutilsSetupError(message.format(setup_target,
- "Qt", qt_target))
- # All checks clear, use setup.py provided value.
- return setup_target
-
- # Setup.py value not provided,
- # use same value as provided by Qt.
- if python_target:
- maximum_target = '.'.join([str(e) for e in max(python_target_split,
- qt_target_split)])
- else:
- maximum_target = qt_target
- return maximum_target
-
- @staticmethod
- @memoize
- def macos_plat_name():
- deployment_target = pyside_build.macos_pyside_min_deployment_target()
- # Example triple "macosx-10.12-x86_64".
- plat = get_platform().split("-")
- plat_name = "{}-{}-{}".format(plat[0], deployment_target, plat[2])
- return plat_name
-
- def build_patchelf(self):
- if not sys.platform.startswith('linux'):
- return
- log.info("Building patchelf...")
- module_src_dir = os.path.join(self.sources_dir, "patchelf")
- build_cmd = [
- "g++",
- "{}/patchelf.cc".format(module_src_dir),
- "-o",
- "patchelf",
- ]
- if run_process(build_cmd) != 0:
- raise DistutilsSetupError("Error building patchelf")
-
- def build_extension(self, extension):
- # calculate the subrepos folder name
-
- log.info("Building module {}...".format(extension))
-
- # Prepare folders
- os.chdir(self.build_dir)
- module_build_dir = os.path.join(self.build_dir, extension)
- skipflag_file = module_build_dir + '-skip'
- if os.path.exists(skipflag_file):
- log.info("Skipping {} because {} exists".format(extension,
- skipflag_file))
- return
-
- module_build_exists = os.path.exists(module_build_dir)
- if module_build_exists:
- if not OPTION_REUSE_BUILD:
- log.info("Deleting module build folder {}...".format(
- module_build_dir))
- try:
- rmtree(module_build_dir)
- except Exception as e:
- print('***** problem removing "{}"'.format(
- module_build_dir))
- print('ignored error: {}'.format(e))
- else:
- log.info("Reusing module build folder {}...".format(
- module_build_dir))
- if not os.path.exists(module_build_dir):
- log.info("Creating module build folder {}...".format(
- module_build_dir))
- os.makedirs(module_build_dir)
- os.chdir(module_build_dir)
-
- module_src_dir = os.path.join(self.sources_dir, extension)
-
- # Build module
- cmake_cmd = [
- OPTION_CMAKE,
- "-G", self.make_generator,
- "-DBUILD_TESTS={}".format(self.build_tests),
- "-DQt5Help_DIR={}".format(self.qtinfo.docs_dir),
- "-DCMAKE_BUILD_TYPE={}".format(self.build_type),
- "-DCMAKE_INSTALL_PREFIX={}".format(self.install_dir),
- module_src_dir
- ]
- cmake_cmd.append("-DPYTHON_EXECUTABLE={}".format(self.py_executable))
- cmake_cmd.append("-DPYTHON_INCLUDE_DIR={}".format(self.py_include_dir))
- cmake_cmd.append("-DPYTHON_LIBRARY={}".format(self.py_library))
- if OPTION_MODULE_SUBSET:
- moduleSubSet = ''
- for m in OPTION_MODULE_SUBSET.split(','):
- if m.startswith('Qt'):
- m = m[2:]
- if moduleSubSet:
- moduleSubSet += ';'
- moduleSubSet += m
- cmake_cmd.append("-DMODULES={}".format(moduleSubSet))
- # Add source location for generating documentation
- cmake_src_dir = OPTION_QT_SRC if OPTION_QT_SRC else qtSrcDir
- cmake_cmd.append("-DQT_SRC_DIR={}".format(cmake_src_dir))
- log.info("Qt Source dir: {}".format(cmake_src_dir))
-
- if self.build_type.lower() == 'debug':
- cmake_cmd.append("-DPYTHON_DEBUG_LIBRARY={}".format(
- self.py_library))
-
- if OPTION_VERBOSE_BUILD:
- cmake_cmd.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON")
-
- if OPTION_SANITIZE_ADDRESS:
- # Some simple sanity checking. Only use at your own risk.
- if (sys.platform.startswith('linux') or
- sys.platform.startswith('darwin')):
- cmake_cmd.append("-DSANITIZE_ADDRESS=ON")
- else:
- raise DistutilsSetupError("Address sanitizer can only be used "
- "on Linux and macOS.")
-
- if extension.lower() == "pyside2":
- pyside_qt_conf_prefix = ''
- if OPTION_QT_CONF_PREFIX:
- pyside_qt_conf_prefix = OPTION_QT_CONF_PREFIX
- else:
- if OPTION_STANDALONE:
- pyside_qt_conf_prefix = '"Qt"'
- if sys.platform == 'win32':
- pyside_qt_conf_prefix = '"."'
- cmake_cmd.append("-DPYSIDE_QT_CONF_PREFIX={}".format(
- pyside_qt_conf_prefix))
-
- # Pass package version to CMake, so this string can be
- # embedded into _config.py file.
- package_version = get_package_version()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_VERSION={}".format(
- package_version))
-
- # In case if this is a snapshot build, also pass the
- # timestamp as a separate value, because it the only
- # version component that is actually generated by setup.py.
- timestamp = ''
- if OPTION_SNAPSHOT_BUILD:
- timestamp = get_package_timestamp()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_TIMESTAMP={}".format(
- timestamp))
-
- if extension.lower() == "shiboken2":
- cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes")
- if sys.version_info[0] > 2:
- cmake_cmd.append("-DUSE_PYTHON_VERSION=3.3")
-
- if sys.platform == 'darwin':
- if OPTION_MACOS_ARCH:
- # also tell cmake which architecture to use
- cmake_cmd.append("-DCMAKE_OSX_ARCHITECTURES:STRING={}".format(
- OPTION_MACOS_ARCH))
-
- if OPTION_MACOS_USE_LIBCPP:
- # Explicitly link the libc++ standard library (useful
- # for macOS deployment targets lower than 10.9).
- # This is not on by default, because most libraries and
- # executables on macOS <= 10.8 are linked to libstdc++,
- # and mixing standard libraries can lead to crashes.
- # On macOS >= 10.9 with a similar minimum deployment
- # target, libc++ is linked in implicitly, thus the
- # option is a no-op in those cases.
- cmake_cmd.append("-DOSX_USE_LIBCPP=ON")
-
- if OPTION_MACOS_SYSROOT:
- cmake_cmd.append("-DCMAKE_OSX_SYSROOT={}".format(
- OPTION_MACOS_SYSROOT))
- else:
- latest_sdk_path = run_process_output(['xcrun',
- '--show-sdk-path'])
- if latest_sdk_path:
- latest_sdk_path = latest_sdk_path[0]
- cmake_cmd.append("-DCMAKE_OSX_SYSROOT={}".format(
- latest_sdk_path))
-
- # Set macOS minimum deployment target (version).
- # This is required so that calling
- # run_process -> distutils.spawn()
- # does not set its own minimum deployment target
- # environment variable which is based on the python
- # interpreter sysconfig value.
- # Doing so could break the detected clang include paths
- # for example.
- deployment_target = \
- pyside_build.macos_pyside_min_deployment_target()
- cmake_cmd.append("-DCMAKE_OSX_DEPLOYMENT_TARGET={}".format(
- deployment_target))
- os.environ['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
-
- if not OPTION_SKIP_CMAKE:
- log.info("Configuring module {} ({})...".format(extension,
- module_src_dir))
- if run_process(cmake_cmd) != 0:
- raise DistutilsSetupError("Error configuring {}".format(
- extension))
- else:
- log.info("Reusing old configuration for module {} ({})...".format(
- extension, module_src_dir))
-
- log.info("Compiling module {}...".format(extension))
- cmd_make = [self.make_path]
- if OPTION_JOBS:
- cmd_make.append(OPTION_JOBS)
- if run_process(cmd_make) != 0:
- raise DistutilsSetupError("Error compiling {}".format(extension))
-
- if extension.lower() == "shiboken2":
- try:
- # Check if sphinx is installed to proceed
- import sphinx
-
- log.info("Generating Shiboken documentation")
- if run_process([self.make_path, "doc"]) != 0:
- raise DistutilsSetupError(
- "Error generating documentation {}".format(extension))
- except ImportError:
- log.info("Sphinx not found, skipping documentation build")
-
-
- if not OPTION_SKIP_MAKE_INSTALL:
- log.info("Installing module {}...".format(extension))
- # Need to wait a second, so installed file timestamps are
- # older than build file timestamps.
- # See https://gitlab.kitware.com/cmake/cmake/issues/16155
- # for issue details.
- if sys.platform == 'darwin':
- log.info("Waiting 1 second, to ensure installation is "
- "successful...")
- time.sleep(1)
- if run_process([self.make_path, "install/fast"]) != 0:
- raise DistutilsSetupError("Error pseudo installing {}".format(
- extension))
- else:
- log.info("Skipped installing module {}".format(extension))
-
- os.chdir(self.script_dir)
-
- def prepare_packages(self):
- try:
- log.info("Preparing packages...")
- vars = {
- "site_packages_dir": self.site_packages_dir,
- "sources_dir": self.sources_dir,
- "install_dir": self.install_dir,
- "build_dir": self.build_dir,
- "script_dir": self.script_dir,
- "pyside_package_dir": self.pyside_package_dir,
- "ssl_libs_dir": OPTION_OPENSSL,
- "py_version": self.py_version,
- "qt_version": self.qtinfo.version,
- "qt_bin_dir": self.qtinfo.bins_dir,
- "qt_doc_dir": self.qtinfo.docs_dir,
- "qt_lib_dir": self.qtinfo.libs_dir,
- "qt_lib_execs_dir": self.qtinfo.lib_execs_dir,
- "qt_plugins_dir": self.qtinfo.plugins_dir,
- "qt_prefix_dir": self.qtinfo.prefix_dir,
- "qt_translations_dir": self.qtinfo.translations_dir,
- "qt_qml_dir": self.qtinfo.qml_dir,
- }
- os.chdir(self.script_dir)
-
- if sys.platform == "win32":
- vars['dbgPostfix'] = OPTION_DEBUG and "_d" or ""
- return self.prepare_packages_win32(vars)
- else:
- return self.prepare_packages_posix(vars)
- except IOError as e:
- print('setup.py/prepare_packages: ', e)
- raise
-
- def get_built_pyside_config(self, vars):
- # Get config that contains list of built modules, and
- # SOVERSIONs of the built libraries.
- pyside_package_dir = vars['pyside_package_dir']
- config_path = os.path.join(pyside_package_dir, "PySide2", "_config.py")
- config = get_python_dict(config_path)
- return config
-
- def is_webengine_built(self, built_modules):
- return 'WebEngineWidgets' in built_modules or 'WebEngineCore' in built_modules
-
- def prepare_packages_posix(self, vars):
- executables = []
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
- copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
- vars=vars)
- # <install>/lib/site-packages/shiboken2.so ->
- # <setup>/PySide2/shiboken2.so
- shiboken_module_name = 'shiboken2.so'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.so', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
- copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
- vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
- # <install>/bin/* -> PySide2/
- executables.extend(copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=[
- "pyside2-lupdate",
- "pyside2-rcc",
- "shiboken2",
- ],
- recursive=False, vars=vars))
- # <install>/lib/lib* -> PySide2/
- config = self.get_built_pyside_config(vars)
- def adjusted_lib_name(name, version):
- postfix = ''
- if sys.platform.startswith('linux'):
- postfix = '.so.' + version
- elif sys.platform == 'darwin':
- postfix = '.' + version + '.dylib'
- return name + postfix
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=[
- adjusted_lib_name("libpyside*",
- config['pyside_library_soversion']),
- adjusted_lib_name("libshiboken*",
- config['shiboken_library_soversion']),
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
- force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
- # Copy Qt libs to package
- if OPTION_STANDALONE:
- vars['built_modules'] = config['built_modules']
- if sys.platform == 'darwin':
- self.prepare_standalone_package_macos(executables, vars)
- else:
- self.prepare_standalone_package_linux(executables, vars)
-
- # Copy over clang before rpath patching.
- self.prepare_standalone_clang(is_win=False)
-
- # Update rpath to $ORIGIN
- if (sys.platform.startswith('linux') or
- sys.platform.startswith('darwin')):
- self.update_rpath("{pyside_package_dir}/PySide2".format(**vars),
- executables)
-
- def qt_is_framework_build(self):
- if os.path.isdir(self.qtinfo.headers_dir + "/../lib/QtCore.framework"):
- return True
- return False
-
- def prepare_standalone_package_linux(self, executables, vars):
- built_modules = vars['built_modules']
-
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
- destination_lib_dir = "{pyside_package_dir}/PySide2/Qt/lib"
- copydir("{qt_lib_dir}", destination_lib_dir,
- filter=[
- "libQt5*.so.?",
- "libicu*.so.??",
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
-
- # Check if ICU libraries were copied over to the destination
- # Qt libdir.
- resolved_destination_lib_dir = destination_lib_dir.format(**vars)
- maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir,
- "libicu*")
-
- # If no ICU libraries are present in the Qt libdir (like when
- # Qt is built against system ICU, or in the Coin CI where ICU
- # libs are in a different directory) try to find out / resolve
- # which ICU libs are used by QtCore (if used at all) using a
- # custom written ldd, and copy the ICU libs to the Pyside Qt
- # dir if necessary. We choose the QtCore lib to inspect, by
- # checking which QtCore library the shiboken2 executable uses.
- if not maybe_icu_libs:
- copy_icu_libs(resolved_destination_lib_dir)
-
- if self.is_webengine_built(built_modules):
- copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- filter=None,
- recursive=False,
- vars=vars)
-
- copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
- filter=None,
- recursive=False,
- vars=vars)
-
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.so"],
- recursive=True,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- force=False,
- recursive=True,
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
-
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
-
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
-
- def prepare_standalone_package_macos(self, executables, vars):
- built_modules = vars['built_modules']
-
- # Directory filter for skipping unnecessary files.
- def general_dir_filter(dir_name, parent_full_path, dir_full_path):
- if fnmatch.fnmatch(dir_name, "*.dSYM"):
- return False
- return True
-
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
- if self.qt_is_framework_build():
- framework_built_modules = [
- 'Qt' + name + '.framework' for name in built_modules]
-
- def framework_dir_filter(dir_name, parent_full_path,
- dir_full_path):
- if '.framework' in dir_name:
- if dir_name.startswith('QtWebEngine') and not \
- self.is_webengine_built(built_modules):
- return False
- if dir_name in ['Headers', 'fonts']:
- return False
- if dir_full_path.endswith('Versions/Current'):
- return False
- if dir_full_path.endswith('Versions/5/Resources'):
- return False
- if dir_full_path.endswith('Versions/5/Helpers'):
- return False
- return general_dir_filter(dir_name, parent_full_path,
- dir_full_path)
-
- copydir("{qt_lib_dir}", "{pyside_package_dir}/PySide2/Qt/lib",
- recursive=True, vars=vars,
- ignore=["*.la", "*.a", "*.cmake", "*.pc", "*.prl"],
- dir_filter_function=framework_dir_filter)
-
- # Fix rpath for WebEngine process executable. The already
- # present rpath does not work because it assumes a symlink
- # from Versions/5/Helpers, thus adding two more levels of
- # directory hierarchy.
- if self.is_webengine_built(built_modules):
- qt_lib_path = "{pyside_package_dir}/PySide2/Qt/lib".format(
- **vars)
- bundle = "QtWebEngineCore.framework/Helpers/"
- bundle += "QtWebEngineProcess.app"
- binary = "Contents/MacOS/QtWebEngineProcess"
- webengine_process_path = os.path.join(bundle, binary)
- final_path = os.path.join(qt_lib_path, webengine_process_path)
- rpath = "@loader_path/../../../../../"
- macos_fix_rpaths_for_library(final_path, rpath)
- else:
- ignored_modules = []
- if not self.is_webengine_built(built_modules):
- ignored_modules.extend(['libQt5WebEngine*.dylib'])
- if 'WebKit' not in built_modules:
- ignored_modules.extend(['libQt5WebKit*.dylib'])
- accepted_modules = ['libQt5*.5.dylib']
-
- copydir("{qt_lib_dir}",
- "{pyside_package_dir}/PySide2/Qt/lib",
- filter=accepted_modules,
- ignore=ignored_modules,
- recursive=True, vars=vars, force_copy_symlinks=True)
-
- if self.is_webengine_built(built_modules):
- copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- filter=None,
- recursive=False,
- vars=vars)
-
- copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
- filter=None,
- recursive=False,
- vars=vars)
-
- # Fix rpath for WebEngine process executable.
- pyside_package_dir = vars['pyside_package_dir']
- qt_libexec_path = "{}/PySide2/Qt/libexec".format(pyside_package_dir)
- binary = "QtWebEngineProcess"
- final_path = os.path.join(qt_libexec_path, binary)
- rpath = "@loader_path/../lib"
- macos_fix_rpaths_for_library(final_path, rpath)
-
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
-
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.dylib"],
- recursive=True,
- dir_filter_function=general_dir_filter,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- recursive=True,
- force=False,
- dir_filter_function=general_dir_filter,
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
-
- def prepare_packages_win32(self, vars):
- # For now, debug symbols will not be shipped into the package.
- copy_pdbs = False
- pdbs = []
- if (self.debug or self.build_type == 'RelWithDebInfo') and copy_pdbs:
- pdbs = ['*.pdb']
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
- copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
- vars=vars)
- built_modules = self.get_built_pyside_config(vars)['built_modules']
-
- # <build>/pyside2/PySide2/*.pdb -> <setup>/PySide2
- copydir(
- "{build_dir}/pyside2/PySide2",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
-
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
-
- # <install>/lib/site-packages/shiboken2.pyd ->
- # <setup>/PySide2/shiboken2.pyd
- shiboken_module_name = 'shiboken2.pyd'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.pyd', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokengenerator}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/shibokenmodule",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
-
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
- copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
-
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
- vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
-
- # <install>/bin/*.exe,*.dll,*.pdb -> PySide2/
- copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=["*.exe", "*.dll"],
- recursive=False, vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokenmodule}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/generator",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
-
- # <install>/lib/*.lib -> PySide2/
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=["*.lib"],
- recursive=False, vars=vars)
-
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
-
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
-
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
-
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
- force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
-
- # <ssl_libs>/* -> <setup>/PySide2/openssl
- copydir("{ssl_libs_dir}", "{pyside_package_dir}/PySide2/openssl",
- filter=[
- "libeay32.dll",
- "ssleay32.dll"],
- force=False, vars=vars)
-
- # <qt>/bin/*.dll and Qt *.exe -> <setup>/PySide2
- qt_artifacts_permanent = [
- "opengl*.dll",
- "d3d*.dll",
- "libEGL*.dll",
- "libGLESv2*.dll",
- "designer.exe",
- "linguist.exe",
- "lrelease.exe",
- "lupdate.exe",
- "lconvert.exe",
- "qtdiag.exe"
- ]
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- filter=qt_artifacts_permanent,
- recursive=False, vars=vars)
-
- # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/PySide2 part two
- # File filter to copy only debug or only release files.
- qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"]
- if copy_pdbs:
- qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"]
- def qt_build_config_filter(patterns, file_name, file_full_path):
- release = [a.format('') for a in patterns]
- debug = [a.format('d') for a in patterns]
-
- # If qt is not a debug_and_release build, that means there
- # is only one set of shared libraries, so we can just copy
- # them.
- if qtinfo.build_type != 'debug_and_release':
- if filter_match(file_name, release):
- return True
- return False
-
- # In debug_and_release case, choosing which files to copy
- # is more difficult. We want to copy only the files that
- # match the PySide2 build type. So if PySide2 is built in
- # debug mode, we want to copy only Qt debug libraries
- # (ending with "d.dll"). Or vice versa. The problem is that
- # some libraries have "d" as the last character of the
- # actual library name (for example Qt5Gamepad.dll and
- # Qt5Gamepadd.dll). So we can't just match a pattern ending
- # in "d". Instead we check if there exists a file with the
- # same name plus an additional "d" at the end, and using
- # that information we can judge if the currently processed
- # file is a debug or release file.
-
- # e.g. ["Qt5Cored", ".dll"]
- file_split = os.path.splitext(file_name)
- file_base_name = file_split[0]
- file_ext = file_split[1]
- # e.g. "/home/work/qt/qtbase/bin"
- file_path_dir_name = os.path.dirname(file_full_path)
- # e.g. "Qt5Coredd"
- maybe_debug_name = file_base_name + 'd'
- if self.debug:
- filter = debug
- def predicate(path): return not os.path.exists(path)
- else:
- filter = release
- def predicate(path): return os.path.exists(path)
- # e.g. "/home/work/qt/qtbase/bin/Qt5Coredd.dll"
- other_config_path = os.path.join(file_path_dir_name,
- maybe_debug_name + file_ext)
-
- if (filter_match(file_name, filter) and
- predicate(other_config_path)):
- return True
- return False
-
- qt_dll_filter = functools.partial(qt_build_config_filter,
- qt_dll_patterns)
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- file_filter_function=qt_dll_filter,
- recursive=False, vars=vars)
-
- # <qt>/plugins/* -> <setup>/PySide2/plugins
- plugin_dll_patterns = ["*{}.dll"]
- pdb_pattern = "*{}.pdb"
- if copy_pdbs:
- plugin_dll_patterns += [pdb_pattern]
- plugin_dll_filter = functools.partial(qt_build_config_filter,
- plugin_dll_patterns)
- copydir("{qt_plugins_dir}", "{pyside_package_dir}/PySide2/plugins",
- file_filter_function=plugin_dll_filter,
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/qml
- qml_dll_patterns = ["*{}.dll"]
- qml_ignore_patterns = qml_dll_patterns + [pdb_pattern]
- # Remove the "{}" from the patterns
- qml_ignore = [a.format('') for a in qml_ignore_patterns]
- if copy_pdbs:
- qml_dll_patterns += [pdb_pattern]
- qml_ignore = [a.format('') for a in qml_dll_patterns]
- qml_dll_filter = functools.partial(qt_build_config_filter,
- qml_dll_patterns)
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- ignore=qml_ignore,
- force=False,
- recursive=True,
- vars=vars)
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- file_filter_function=qml_dll_filter,
- force=False,
- recursive=True,
- vars=vars)
-
- if self.is_webengine_built(built_modules):
- copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/resources",
- filter=None,
- recursive=False,
- vars=vars)
-
- filter = 'QtWebEngineProcess{}.exe'.format(
- 'd' if self.debug else '')
- copydir("{qt_bin_dir}",
- "{pyside_package_dir}/PySide2",
- filter=[filter],
- recursive=False, vars=vars)
-
- # Copy the qt.conf file to prefix dir.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2",
- vars=vars)
-
- self.prepare_standalone_clang(is_win=True)
-
- # pdb files for libshiboken and libpyside
- copydir(
- "{build_dir}/shiboken2/libshiboken",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
- copydir(
- "{build_dir}/pyside2/libpyside",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
-
- def prepare_standalone_clang(self, is_win = False):
- """
- Copies the libclang library to the pyside package so that
- shiboken executable works.
- """
- log.info('Finding path to the libclang shared library.')
- cmake_cmd = [
- OPTION_CMAKE,
- "-L", # Lists variables
- "-N", # Just inspects the cache (faster)
- "--build", # Specifies the build dir
- self.shiboken_build_dir
- ]
- out = run_process_output(cmake_cmd)
- lines = [s.strip() for s in out]
- pattern = re.compile(r"CLANG_LIBRARY:FILEPATH=(.+)$")
-
- clang_lib_path = None
- for line in lines:
- match = pattern.search(line)
- if match:
- clang_lib_path = match.group(1)
- break
-
- if not clang_lib_path:
- raise RuntimeError("Could not finding location of libclang "
- "library from CMake cache.")
-
- if is_win:
- # clang_lib_path points to the static import library
- # (lib/libclang.lib), whereas we want to copy the shared
- # library (bin/libclang.dll).
- clang_lib_path = re.sub(r'lib/libclang.lib$', 'bin/libclang.dll',
- clang_lib_path)
-
- # Path to directory containing clang.
- clang_lib_dir = os.path.dirname(clang_lib_path)
-
- # The name of the clang file found by CMake.
- basename = os.path.basename(clang_lib_path)
-
- # We want to copy the library and all the symlinks for now,
- # thus the wildcard.
- clang_filter = basename + "*"
-
- # Destination is the package folder near the other extension
- # modules.
- destination_dir = "{}/PySide2".format(os.path.join(self.script_dir,
- 'pyside_package'))
- if os.path.exists(clang_lib_path):
- log.info('Copying libclang shared library to the pyside package.')
-
- copydir(clang_lib_dir, destination_dir,
- filter=[clang_filter],
- recursive=False)
- else:
- raise RuntimeError("Error copying libclang library "
- "from {} to {}. ".format(
- clang_lib_path, destination_dir))
-
- def update_rpath(self, package_path, executables):
- if sys.platform.startswith('linux'):
- pyside_libs = [lib for lib in os.listdir(
- package_path) if filter_match(lib, ["*.so", "*.so.*"])]
-
- patchelf_path = os.path.join(self.script_dir, "patchelf")
-
- def rpath_cmd(srcpath):
- final_rpath = ''
- # Command line rpath option takes precedence over
- # automatically added one.
- if OPTION_RPATH_VALUES:
- final_rpath = OPTION_RPATH_VALUES
- else:
- # Add rpath values pointing to $ORIGIN and the
- # installed qt lib directory.
- local_rpath = '$ORIGIN/'
- qt_lib_dir = self.qtinfo.libs_dir
- if OPTION_STANDALONE:
- qt_lib_dir = "$ORIGIN/Qt/lib"
- final_rpath = local_rpath + ':' + qt_lib_dir
- cmd = [patchelf_path, '--set-rpath', final_rpath, srcpath]
- if run_process(cmd) != 0:
- raise RuntimeError("Error patching rpath in " + srcpath)
-
- elif sys.platform == 'darwin':
- pyside_libs = [lib for lib in os.listdir(
- package_path) if filter_match(lib, ["*.so", "*.dylib"])]
- def rpath_cmd(srcpath):
- final_rpath = ''
- # Command line rpath option takes precedence over
- # automatically added one.
- if OPTION_RPATH_VALUES:
- final_rpath = OPTION_RPATH_VALUES
- else:
- if OPTION_STANDALONE:
- final_rpath = "@loader_path/Qt/lib"
- else:
- final_rpath = self.qtinfo.libs_dir
- macos_fix_rpaths_for_library(srcpath, final_rpath)
-
- else:
- raise RuntimeError('Not configured for platform ' +
- sys.platform)
-
- pyside_libs.extend(executables)
-
- # Update rpath in PySide2 libs
- for srcname in pyside_libs:
- srcpath = os.path.join(package_path, srcname)
- if os.path.isdir(srcpath) or os.path.islink(srcpath):
- continue
- if not os.path.exists(srcpath):
- continue
- rpath_cmd(srcpath)
- print("Patched rpath to '$ORIGIN/' (Linux) or "
- "updated rpath (OS/X) in {}.".format(srcpath))
-
-
-try:
- with open(os.path.join(script_dir, 'README.rst')) as f:
- README = f.read()
- with open(os.path.join(script_dir, 'CHANGES.rst')) as f:
- CHANGES = f.read()
-except IOError:
- README = CHANGES = ''
-
-
-cmd_class_dict = {
- 'build': pyside_build,
- 'build_py': pyside_build_py,
- 'build_ext': pyside_build_ext,
- 'bdist_egg': pyside_bdist_egg,
- 'develop': pyside_develop,
- 'install': pyside_install,
- 'install_lib': pyside_install_lib
-}
-if wheel_module_exists:
- cmd_class_dict['bdist_wheel'] = pyside_build_wheel
-
setup(
name = "PySide2",
version = get_package_version(),