1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
from copy import copy
from distutils.spawn import find_executable
import os
import re
import subprocess
import sys
import sipconfig
from PyQt5 import QtCore
libqt5_rename = False
class Configuration(sipconfig.Configuration):
def __init__(self):
env = copy(os.environ)
env['QT_SELECT'] = '5'
qmake_exe = 'qmake-qt5' if find_executable('qmake-qt5') else 'qmake'
qtconfig = subprocess.check_output(
[qmake_exe, '-query'], env=env, universal_newlines=True)
qtconfig = dict(line.split(':', 1) for line in qtconfig.splitlines())
pyqtconfig = {
'qt_archdata_dir': qtconfig['QT_INSTALL_DATA'],
'qt_data_dir': qtconfig['QT_INSTALL_DATA'],
'qt_dir': qtconfig['QT_INSTALL_PREFIX'],
'qt_inc_dir': qtconfig['QT_INSTALL_HEADERS'],
'qt_lib_dir': qtconfig['QT_INSTALL_LIBS'],
'qt_threaded': 1,
'qt_version': QtCore.QT_VERSION,
'qt_winconfig': 'shared exceptions',
}
if sys.platform == 'darwin':
if os.path.exists(os.path.join(qtconfig['QT_INSTALL_LIBS'], 'QtCore.framework')):
pyqtconfig['qt_framework'] = 1
else:
global libqt5_rename
libqt5_rename = True
sipconfig.Configuration.__init__(self, [pyqtconfig])
macros = sipconfig._default_macros.copy()
macros['INCDIR_QT'] = qtconfig['QT_INSTALL_HEADERS']
macros['LIBDIR_QT'] = qtconfig['QT_INSTALL_LIBS']
macros['MOC'] = 'moc-qt5' if find_executable('moc-qt5') else 'moc'
self.set_build_macros(macros)
def get_sip_dir_flags(config):
"""
Get the extra SIP flags needed by the imported qt module, and locate PyQt5 sip install files.
Note that this normally only includes those flags (-x and -t) that relate to SIP's versioning
system.
"""
try:
sip_dir = config.pyqt_sip_dir
sip_flags = config.pyqt_sip_flags
return sip_dir, sip_flags
except AttributeError:
# sipconfig.Configuration does not have a pyqt_sip_dir or pyqt_sip_flags AttributeError
sip_flags = QtCore.PYQT_CONFIGURATION['sip_flags']
# Archlinux installs sip files here by default
default_sip_dir = os.path.join(sipconfig._pkg_config['default_mod_dir'], 'PyQt5', 'bindings')
if os.path.exists(default_sip_dir):
return default_sip_dir, sip_flags
# sip4 installs here by default
default_sip_dir = os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt5')
if os.path.exists(default_sip_dir):
return default_sip_dir, sip_flags
# workaround for new path sip dir in pyqt5 >= 5.15.0+dfsg-1+exp1
default_sip_dir = '/usr/lib/python3/dist-packages/PyQt5/bindings'
if os.path.exists(default_sip_dir):
return default_sip_dir, sip_flags
# Homebrew installs sip files here by default
default_sip_dir = os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt5')
if os.path.exists(default_sip_dir):
return default_sip_dir, sip_flags
raise FileNotFoundError('The sip directory for PyQt5 could not be located. Please ensure' +
' that PyQt5 is installed')
if len(sys.argv) != 9:
print('usage: %s build-dir sip-file output_dir include_dirs libs lib_dirs ldflags extra_defines' %
sys.argv[0])
sys.exit(1)
# The SIP build folder, the SIP file, the output directory, the include
# directories, the libraries, the library directories and the linker
# flags.
build_dir, sip_file, output_dir, include_dirs, libs, lib_dirs, ldflags, extra_defines = sys.argv[1:]
# The name of the SIP build file generated by SIP and used by the build system.
build_file = 'pyqtscripting.sbf'
# Get the PyQt configuration information.
config = Configuration()
sip_dir, sip_flags = get_sip_dir_flags(config)
try:
os.makedirs(build_dir)
except OSError:
pass
# Run SIP to generate the code. Note that we tell SIP where to find the qt
# module's specification files using the -I flag.
sip_bin = config.sip_bin
# Without the .exe, this might actually be a directory in Windows
if sys.platform == 'win32' and os.path.isdir(sip_bin):
sip_bin += '.exe'
cmd = [
sip_bin,
'-c', build_dir,
'-b', os.path.join(build_dir, build_file),
'-I', sip_dir,
'-w'
]
cmd += sip_flags.split(' ')
cmd.append(sip_file)
subprocess.check_call(cmd)
# Create the Makefile. The QtModuleMakefile class provided by the
# pyqtconfig module takes care of all the extra preprocessor, compiler and
# linker flags needed by the Qt library.
makefile = sipconfig.SIPModuleMakefile(
dir=build_dir,
configuration=config,
build_file=build_file,
qt=['QtCore', 'QtGui']
)
# hack to override makefile behavior which always prepend -l to libraries
# which is wrong for absolute paths
default_platform_lib_function = sipconfig.SIPModuleMakefile.platform_lib
def custom_platform_lib_function(self, clib, framework=0):
if not clib or clib.isspace():
return None
# Only add '-l' if a library doesn't already start with '-l' and is not an absolute path
if os.path.isabs(clib) or clib.startswith('-l'):
return clib
global libqt5_rename
# sip renames libs to Qt5 automatically on Linux, but not on macOS
if libqt5_rename and not framework and clib.startswith('Qt') and not clib.startswith('Qt5'):
return '-lQt5' + clib[2:]
return default_platform_lib_function(self, clib, framework)
sipconfig.SIPModuleMakefile.platform_lib = custom_platform_lib_function
# split paths on whitespace
# while dealing with whitespaces within the paths if they are escaped with backslashes
def split_paths(paths):
paths = re.split('(?<=[^\\\\]) ', paths)
return paths
for include_dir in split_paths(include_dirs):
include_dir = include_dir.replace('\\', '')
makefile.extra_include_dirs.append(include_dir)
for lib in split_paths(libs):
makefile.extra_libs.append(lib)
for lib_dir in split_paths(lib_dirs):
lib_dir = lib_dir.replace('\\', '')
makefile.extra_lib_dirs.append(lib_dir)
for ldflag in ldflags.split('\\ '):
makefile.LFLAGS.append(ldflag)
for extra_define in extra_defines.split(' '):
makefile.extra_defines.append(extra_define)
# redirect location of generated library
makefile._target = '"%s"' % os.path.join(output_dir, makefile._target)
# Force c++14
if sys.platform == 'win32':
makefile.extra_cxxflags.append('/std:c++14')
# The __cplusplus flag is not properly set on Windows for backwards
# compatibilty. This flag sets it correctly
makefile.CXXFLAGS.append('/Zc:__cplusplus')
else:
makefile.extra_cxxflags.append('-std=c++14')
# Finalise the Makefile, preparing it to be saved to disk
makefile.finalise()
# Replace Qt variables from libraries
libs = makefile.LIBS.as_list()
for i in range(len(libs)):
libs[i] = libs[i].replace('$$[QT_INSTALL_LIBS]', config.build_macros()['LIBDIR_QT'])
makefile.LIBS.set(libs)
# Generate the Makefile itself
makefile.generate()
|