mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-12-26 16:01:36 +08:00
343 lines
13 KiB
Python
343 lines
13 KiB
Python
|
import os
|
||
|
import sys
|
||
|
import shlex
|
||
|
import subprocess
|
||
|
import glob
|
||
|
|
||
|
from setuptools import setup, find_packages
|
||
|
from setuptools.extension import Extension
|
||
|
from distutils import sysconfig, dir_util, spawn, log
|
||
|
from distutils.dep_util import newer
|
||
|
import sipdistutils
|
||
|
import sipconfig
|
||
|
from PyQt5.QtCore import PYQT_CONFIGURATION
|
||
|
from PyQt5.pyrcc_main import processResourceFile
|
||
|
|
||
|
MAJOR = 2
|
||
|
MINOR = 5
|
||
|
MICRO = 1
|
||
|
ISRELEASED = True
|
||
|
VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
|
||
|
MODULE_NAME = "ads"
|
||
|
SRC_PATH = "PyQtAds"
|
||
|
|
||
|
REQUIRE_PYQT = True
|
||
|
if "--conda-recipe" in sys.argv:
|
||
|
REQUIRE_PYQT = False
|
||
|
sys.argv.remove("--conda-recipe")
|
||
|
|
||
|
|
||
|
class HostPythonConfiguration(object):
|
||
|
def __init__(self):
|
||
|
self.platform = sys.platform
|
||
|
self.version = sys.hexversion>>8
|
||
|
|
||
|
self.inc_dir = sysconfig.get_python_inc()
|
||
|
self.venv_inc_dir = sysconfig.get_python_inc(prefix=sys.prefix)
|
||
|
self.module_dir = sysconfig.get_python_lib(plat_specific=1)
|
||
|
|
||
|
if sys.platform == 'win32':
|
||
|
self.data_dir = sys.prefix
|
||
|
self.lib_dir = sys.prefix +'\\libs'
|
||
|
else:
|
||
|
self.data_dir = sys.prefix + '/share'
|
||
|
self.lib_dir = sys.prefix + '/lib'
|
||
|
|
||
|
|
||
|
class TargetQtConfiguration(object):
|
||
|
def __init__(self, qmake):
|
||
|
pipe = os.popen(' '.join([qmake, '-query']))
|
||
|
|
||
|
for l in pipe:
|
||
|
l = l.strip()
|
||
|
|
||
|
tokens = l.split(':', 1)
|
||
|
if isinstance(tokens, list):
|
||
|
if len(tokens) != 2:
|
||
|
error("Unexpected output from qmake: '%s'\n" % l)
|
||
|
|
||
|
name, value = tokens
|
||
|
else:
|
||
|
name = tokens
|
||
|
value = None
|
||
|
|
||
|
name = name.replace('/', '_')
|
||
|
setattr(self, name, value)
|
||
|
|
||
|
pipe.close()
|
||
|
|
||
|
|
||
|
class build_ext(sipdistutils.build_ext):
|
||
|
|
||
|
description = "Builds the " + MODULE_NAME + " module."
|
||
|
|
||
|
user_options = sipdistutils.build_ext.user_options + [
|
||
|
('qmake-bin=', None, "Path to qmake binary"),
|
||
|
('sip-bin=', None, "Path to sip binary"),
|
||
|
('qt-include-dir=', None, "Path to Qt headers"),
|
||
|
('pyqt-sip-dir=', None, "Path to PyQt's SIP files"),
|
||
|
('pyqt-sip-flags=', None, "SIP flags used to generate PyQt bindings"),
|
||
|
('sip-dir=', None, "Path to module's SIP files"),
|
||
|
('inc-dir=', None, "Path to module's include files")
|
||
|
]
|
||
|
|
||
|
def initialize_options (self):
|
||
|
super().initialize_options()
|
||
|
self.qmake_bin = 'qmake'
|
||
|
self.sip_bin = None
|
||
|
self.qt_include_dir = None
|
||
|
self.qt_libinfix = ''
|
||
|
self.pyqt_sip_dir = None
|
||
|
self.pyqt_sip_flags = None
|
||
|
self.sip_files_dir = None
|
||
|
self.sip_inc_dir = None
|
||
|
self.inc_dir = None
|
||
|
self.pyconfig = HostPythonConfiguration()
|
||
|
self.qtconfig = TargetQtConfiguration(self.qmake_bin)
|
||
|
self.config = sipconfig.Configuration()
|
||
|
self.config.default_mod_dir = ("/usr/local/lib/python%i.%i/dist-packages" %
|
||
|
(sys.version_info.major, sys.version_info.minor))
|
||
|
|
||
|
def finalize_options (self):
|
||
|
super().finalize_options()
|
||
|
|
||
|
if not self.qt_include_dir:
|
||
|
self.qt_include_dir = self.qtconfig.QT_INSTALL_HEADERS
|
||
|
|
||
|
if not self.qt_libinfix:
|
||
|
try:
|
||
|
with open(os.path.join(self.qtconfig.QT_INSTALL_PREFIX, 'mkspecs', 'qconfig.pri'), 'r') as f:
|
||
|
for line in f.readlines():
|
||
|
if line.startswith('QT_LIBINFIX'):
|
||
|
self.qt_libinfix = line.split('=')[1].strip('\n').strip()
|
||
|
except (FileNotFoundError, IndexError):
|
||
|
pass
|
||
|
|
||
|
if not self.pyqt_sip_dir:
|
||
|
self.pyqt_sip_dir = os.path.join(self.pyconfig.data_dir, 'sip', 'PyQt5')
|
||
|
|
||
|
if not self.pyqt_sip_flags:
|
||
|
self.pyqt_sip_flags = PYQT_CONFIGURATION.get('sip_flags', '')
|
||
|
|
||
|
if not self.sip_files_dir:
|
||
|
self.sip_files_dir = os.path.abspath(os.path.join(".", "sip"))
|
||
|
|
||
|
if not self.sip_inc_dir:
|
||
|
self.sip_inc_dir = self.pyconfig.venv_inc_dir
|
||
|
|
||
|
if not self.inc_dir:
|
||
|
self.inc_dir = os.path.abspath(os.path.join(".", "src"))
|
||
|
|
||
|
if not self.qt_include_dir:
|
||
|
raise SystemExit('Could not find Qt5 headers. '
|
||
|
'Please specify via --qt-include-dir=')
|
||
|
|
||
|
if not self.pyqt_sip_dir:
|
||
|
raise SystemExit('Could not find PyQt SIP files. '
|
||
|
'Please specify containing directory via '
|
||
|
'--pyqt-sip-dir=')
|
||
|
|
||
|
if not self.pyqt_sip_flags:
|
||
|
raise SystemExit('Could not find PyQt SIP flags. '
|
||
|
'Please specify via --pyqt-sip-flags=')
|
||
|
|
||
|
def _find_sip(self):
|
||
|
"""override _find_sip to allow for manually speficied sip path."""
|
||
|
return self.sip_bin or super()._find_sip()
|
||
|
|
||
|
def _sip_compile(self, sip_bin, source, sbf):
|
||
|
cmd = [sip_bin]
|
||
|
if hasattr(self, 'sip_opts'):
|
||
|
cmd += self.sip_opts
|
||
|
if hasattr(self, '_sip_sipfiles_dir'):
|
||
|
cmd += ['-I', self._sip_sipfiles_dir()]
|
||
|
cmd += [
|
||
|
"-I", self.sip_files_dir,
|
||
|
"-I", self.pyqt_sip_dir,
|
||
|
"-I", self.sip_inc_dir,
|
||
|
"-I", self.inc_dir,
|
||
|
"-c", self._sip_output_dir(),
|
||
|
"-b", sbf,
|
||
|
"-w", "-o"]
|
||
|
|
||
|
cmd += shlex.split(self.pyqt_sip_flags) # use same SIP flags as for PyQt5
|
||
|
cmd.append(source)
|
||
|
self.spawn(cmd)
|
||
|
|
||
|
def swig_sources (self, sources, extension=None):
|
||
|
if not self.extensions:
|
||
|
return
|
||
|
|
||
|
# Add the local include directory to the include path
|
||
|
if extension is not None:
|
||
|
extension.extra_compile_args += ['-D', 'QT_CORE_LIB',
|
||
|
'-D', 'QT_GUI_LIB',
|
||
|
'-D', 'QT_WIDGETS_LIB',
|
||
|
'-D', 'ADS_SHARED_EXPORT']
|
||
|
extension.include_dirs += [self.qt_include_dir, self.inc_dir,
|
||
|
os.path.join(self.qt_include_dir, 'QtCore'),
|
||
|
os.path.join(self.qt_include_dir, 'QtGui'),
|
||
|
os.path.join(self.qt_include_dir, 'QtWidgets')]
|
||
|
extension.libraries += ['Qt5Core' + self.qt_libinfix,
|
||
|
'Qt5Gui' + self.qt_libinfix,
|
||
|
'Qt5Widgets' + self.qt_libinfix]
|
||
|
|
||
|
if sys.platform == 'win32':
|
||
|
extension.library_dirs += [self.qtconfig.QT_INSTALL_LIBS,
|
||
|
self.inc_dir, self._sip_output_dir()]
|
||
|
elif sys.platform == 'darwin':
|
||
|
extension.extra_compile_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
||
|
'-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.9']
|
||
|
extension.extra_link_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
||
|
'-mmacosx-version-min=10.9']
|
||
|
elif sys.platform == 'linux':
|
||
|
extension.extra_compile_args += ['-std=c++11']
|
||
|
|
||
|
return super().swig_sources(sources, extension)
|
||
|
|
||
|
def build_extension(self, ext):
|
||
|
cppsources = [source for source in ext.sources if source.endswith(".cpp")]
|
||
|
|
||
|
dir_util.mkpath(self.build_temp, dry_run=self.dry_run)
|
||
|
|
||
|
# Run moc on all header files.
|
||
|
for source in cppsources:
|
||
|
header = source.replace(".cpp", ".h")
|
||
|
if os.path.exists(header):
|
||
|
moc_file = "moc_" + os.path.basename(header).replace(".h", ".cpp")
|
||
|
out_file = os.path.join(self.build_temp, moc_file)
|
||
|
|
||
|
if newer(header, out_file) or self.force:
|
||
|
call_arg = ["moc", "-o", out_file, header]
|
||
|
spawn.spawn(call_arg, dry_run=self.dry_run)
|
||
|
|
||
|
if os.path.getsize(out_file) > 0:
|
||
|
ext.sources.append(out_file)
|
||
|
|
||
|
# Add the temp build directory to include path, for compiler to find
|
||
|
# the created .moc files
|
||
|
ext.include_dirs += [self._sip_output_dir()]
|
||
|
|
||
|
sipdistutils.build_ext.build_extension(self, ext)
|
||
|
|
||
|
|
||
|
def git_version():
|
||
|
'''Return the git revision as a string'''
|
||
|
|
||
|
def _minimal_ext_cmd(cmd):
|
||
|
# construct minimal environment
|
||
|
env = {}
|
||
|
for k in ['SYSTEMROOT', 'PATH', 'HOME']:
|
||
|
v = os.environ.get(k)
|
||
|
if v is not None:
|
||
|
env[k] = v
|
||
|
# LANGUAGE is used on win32
|
||
|
env['LANGUAGE'] = 'C'
|
||
|
env['LANG'] = 'C'
|
||
|
env['LC_ALL'] = 'C'
|
||
|
out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
|
||
|
return out
|
||
|
|
||
|
try:
|
||
|
out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
|
||
|
GIT_REVISION = out.strip().decode('ascii')
|
||
|
except OSError:
|
||
|
GIT_REVISION = "Unknown"
|
||
|
|
||
|
return GIT_REVISION
|
||
|
|
||
|
|
||
|
def get_version_info():
|
||
|
# Adding the git rev number needs to be done inside write_version_py(),
|
||
|
# otherwise the import of numpy.version messes up the build under Python 3.
|
||
|
FULLVERSION = VERSION
|
||
|
if os.path.exists('.git'):
|
||
|
GIT_REVISION = git_version()
|
||
|
elif os.path.exists(os.path.join(SRC_PATH, 'version.py')):
|
||
|
# must be a source distribution, use existing version file
|
||
|
try:
|
||
|
from PyQtAds.version import git_revision as GIT_REVISION
|
||
|
except ImportError:
|
||
|
raise ImportError("Unable to import git_revision. Try removing " \
|
||
|
"%(module)/version.py and the build directory " \
|
||
|
"before building." % {'module': SRC_PATH})
|
||
|
else:
|
||
|
GIT_REVISION = "Unknown"
|
||
|
|
||
|
if not ISRELEASED:
|
||
|
FULLVERSION += '.dev0+' + GIT_REVISION[:7]
|
||
|
|
||
|
return FULLVERSION, GIT_REVISION
|
||
|
|
||
|
|
||
|
def write_version_py(filename=os.path.join(SRC_PATH, '_version.py')):
|
||
|
cnt = ("# THIS FILE IS GENERATED FROM %(module)s SETUP.PY\n\n"
|
||
|
"short_version = '%(version)s'\n"
|
||
|
"version = '%(version)s'\n"
|
||
|
"full_version = '%(full_version)s'\n"
|
||
|
"git_revision = '%(git_revision)s'\n"
|
||
|
"release = %(isrelease)s\n"
|
||
|
"if not release:\n"
|
||
|
" version = full_version\n")
|
||
|
FULLVERSION, GIT_REVISION = get_version_info()
|
||
|
|
||
|
with open(filename, 'w') as f:
|
||
|
f.write(cnt % {'module': SRC_PATH,
|
||
|
'version': VERSION,
|
||
|
'full_version': FULLVERSION,
|
||
|
'git_revision': GIT_REVISION,
|
||
|
'isrelease': str(ISRELEASED)})
|
||
|
|
||
|
setup_requires = ["PyQt5"] if REQUIRE_PYQT else []
|
||
|
cpp_sources = glob.glob(os.path.join('src', '*.cpp'))
|
||
|
sip_sources = [os.path.join('sip', MODULE_NAME + '.sip')]
|
||
|
if sys.platform == 'linux':
|
||
|
cpp_sources += glob.glob(os.path.join('src', 'linux', '*.cpp'))
|
||
|
ext_modules = [Extension('PyQtAds.QtAds.ads', cpp_sources + sip_sources)]
|
||
|
|
||
|
install_requires = ["PyQt5"]
|
||
|
if sys.platform == 'win32':
|
||
|
install_requires.append("pywin32")
|
||
|
|
||
|
|
||
|
write_version_py(os.path.join(SRC_PATH, '_version.py'))
|
||
|
processResourceFile([os.path.join('src', 'ads.qrc')],
|
||
|
os.path.join(SRC_PATH, 'rc.py'), False)
|
||
|
with open('README.md', 'r') as f:
|
||
|
LONG_DESCRIPTION = f.read()
|
||
|
|
||
|
setup(
|
||
|
name = SRC_PATH,
|
||
|
author = "Nicolas Elie",
|
||
|
author_email = "nicolas.elie@cnrs.fr",
|
||
|
url = "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System",
|
||
|
version = get_version_info()[0],
|
||
|
description = "Advanced Docking System for Qt",
|
||
|
long_description = LONG_DESCRIPTION,
|
||
|
keywords = ["qt"],
|
||
|
license = "LGPLv2+",
|
||
|
classifiers = ["Development Status :: 4 - Beta",
|
||
|
"Intended Audience :: Developers",
|
||
|
"License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)",
|
||
|
"Operating System :: OS Independent",
|
||
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||
|
"Environment :: Win32 (MS Windows)",
|
||
|
"Environment :: MacOS X",
|
||
|
"Environment :: X11 Applications :: Qt",
|
||
|
"Programming Language :: Python :: 3",
|
||
|
"Programming Language :: Python :: 3.2",
|
||
|
"Programming Language :: Python :: 3.3",
|
||
|
"Programming Language :: Python :: 3.4",
|
||
|
"Programming Language :: Python :: 3.5",
|
||
|
"Programming Language :: Python :: 3.6",
|
||
|
"Programming Language :: Python :: 3.7"],
|
||
|
ext_modules = ext_modules,
|
||
|
cmdclass = {
|
||
|
'build_ext': build_ext,
|
||
|
},
|
||
|
packages = find_packages(),
|
||
|
setup_requires = setup_requires,
|
||
|
install_requires = install_requires,
|
||
|
zip_safe=False
|
||
|
)
|