Port build script for building PyQt extensions to PyQt5

This commit is contained in:
Kovid Goyal 2014-04-11 16:48:41 +05:30
parent 3b2eafc2c4
commit f449426476
2 changed files with 89 additions and 61 deletions

View File

@ -6,10 +6,14 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, socket, struct, subprocess, glob
import os, socket, struct, subprocess, glob, re, sys
from distutils.spawn import find_executable
from PyQt4 import pyqtconfig
# QT5XX: Remove this import once migration is complete, ensuring that sipconfig
# comes from PyQt5
sys.path.insert(0, '/opt/pyqt5/lib')
import sipconfig
from setup import isosx, iswindows, is64bit
is64bit
@ -45,6 +49,9 @@ elif find_executable('qmake'):
QMAKE = find_executable('qmake')
QMAKE = os.environ.get('QMAKE', QMAKE)
# QT5XX: Change this to real qmake detection
QMAKE = '/opt/qt5/bin/qmake'
PKGCONFIG = find_executable('pkg-config')
PKGCONFIG = os.environ.get('PKG_CONFIG', PKGCONFIG)
@ -79,11 +86,23 @@ def consolidate(envvar, default):
ans = [x.strip() for x in val.split(os.pathsep)]
return [x for x in ans if x and os.path.exists(x)]
pyqt = pyqtconfig.Configuration()
qraw = subprocess.check_output([QMAKE, '-query']).decode('utf-8')
def readvar(name):
return re.search('%s:(.+)$' % name, qraw, flags=re.M).group(1).strip()
qt_inc = pyqt.qt_inc_dir
pyqt = {x:readvar(y) for x, y in (
('inc', 'QT_INSTALL_HEADERS'), ('lib', 'QT_INSTALL_LIBS')
)}
c = sipconfig.Configuration()
pyqt['sip_bin'] = c.sip_bin
from PyQt5.QtCore import PYQT_CONFIGURATION
pyqt['sip_flags'] = PYQT_CONFIGURATION['sip_flags']
pyqt['default_sip_dir'] = c.default_sip_dir
pyqt['sip_inc_dir'] = c.sip_inc_dir
qt_inc = pyqt['inc']
qt_private_inc = []
qt_lib = pyqt.qt_lib_dir
qt_lib = pyqt['lib']
ft_lib_dirs = []
ft_libs = []
ft_inc_dirs = []

View File

@ -6,13 +6,11 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import textwrap, os, shlex, subprocess, glob, shutil
import textwrap, os, shlex, subprocess, glob, shutil, re, sys
from distutils import sysconfig
from multiprocessing import cpu_count
from PyQt4.pyqtconfig import QtGuiModuleMakefile
from setup import Command, islinux, isbsd, isosx, SRC, iswindows
from setup import Command, islinux, isbsd, isosx, SRC, iswindows, __version__
from setup.build_environment import (chmlib_inc_dirs,
podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE,
msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs,
@ -23,6 +21,7 @@ MT
isunix = islinux or isosx or isbsd
make = 'make' if isunix else NMAKE
py_lib_dir = os.path.join(sys.prefix, 'lib')
class Extension(object):
@ -584,66 +583,76 @@ class Build(Command):
finally:
os.chdir(ocwd)
def build_qt_objects(self, ext):
obj_pat = 'release\\*.obj' if iswindows else '*.o'
objects = glob.glob(obj_pat)
if not objects or self.newer(objects, ext.sources+ext.headers):
archs = 'x86 x86_64'
pro = textwrap.dedent('''\
TARGET = %s
TEMPLATE = lib
HEADERS = %s
SOURCES = %s
VERSION = 1.0.0
CONFIG += %s
''')%(ext.name, ' '.join(ext.headers), ' '.join(ext.sources), archs)
if ext.inc_dirs:
idir = ' '.join(ext.inc_dirs)
pro += 'INCLUDEPATH = %s\n'%idir
pro = pro.replace('\\', '\\\\')
open(ext.name+'.pro', 'wb').write(pro)
qmc = [QMAKE, '-o', 'Makefile']
if iswindows:
qmc += ['-spec', 'win32-msvc2008']
self.check_call(qmc + [ext.name+'.pro'])
self.check_call([make, '-f', 'Makefile']+([] if iswindows else ['-j%d'%(cpu_count() or 1)]))
objects = glob.glob(obj_pat)
return list(map(self.a, objects))
def build_pyqt_extension(self, ext, dest):
pyqt_dir = self.j(self.d(self.SRC), 'build', 'pyqt')
src_dir = self.j(pyqt_dir, ext.name)
qt_dir = self.j(src_dir, 'qt')
if not self.e(qt_dir):
os.makedirs(qt_dir)
cwd = os.getcwd()
try:
os.chdir(qt_dir)
qt_objects = self.build_qt_objects(ext)
finally:
os.chdir(cwd)
def build_sip_files(self, ext, src_dir):
sip_files = ext.sip_files
ext.sip_files = []
sipf = sip_files[0]
sbf = self.j(src_dir, self.b(sipf)+'.sbf')
if self.newer(sbf, [sipf]+ext.headers):
exe = '.exe' if iswindows else ''
cmd = [pyqt.sip_bin+exe, '-w', '-c', src_dir, '-b', sbf, '-I'+
pyqt.pyqt_sip_dir] + shlex.split(pyqt.pyqt_sip_flags) + [sipf]
cmd = [pyqt['sip_bin'], '-w', '-c', src_dir, '-b', sbf, '-I'+
pyqt['default_sip_dir']+'/sip/PyQt5'] + shlex.split(pyqt['sip_flags']) + [sipf]
self.info(' '.join(cmd))
self.check_call(cmd)
module = self.j(src_dir, self.b(dest))
if self.newer(dest, [sbf]+qt_objects):
mf = self.j(src_dir, 'Makefile')
makefile = QtGuiModuleMakefile(configuration=pyqt, build_file=sbf,
makefile=mf, universal=OSX_SDK, qt=1)
makefile.extra_lflags = qt_objects
makefile.extra_include_dirs = ext.inc_dirs
makefile.generate()
self.info('')
raw = open(sbf, 'rb').read().decode('utf-8')
def read(x):
ans = re.search('^%s\s*=\s*(.+)$' % x, raw, flags=re.M).group(1).strip()
if x != 'target':
ans = ans.split()
return ans
return {x:read(x) for x in ('target', 'sources', 'headers')}
self.check_call([make, '-f', mf], cwd=src_dir)
shutil.copy2(module, dest)
def build_pyqt_extension(self, ext, dest):
pyqt_dir = self.j(self.d(self.SRC), 'build', 'pyqt')
src_dir = self.j(pyqt_dir, ext.name)
if not os.path.exists(src_dir):
os.makedirs(src_dir)
sip = self.build_sip_files(ext, src_dir)
pro = textwrap.dedent(
'''\
TEMPLATE = lib
CONFIG += release plugin
QT += widgets
TARGET = {target}
HEADERS = {headers}
SOURCES = {sources}
INCLUDEPATH += {sipinc} {pyinc}
VERSION = {ver}
win32 {{
LIBS += {py_lib_dir}
}}
macx {{
QMAKE_LFLAGS += "-undefined dynamic_lookup"
}}
''').format(
target=sip['target'], headers=' '.join(sip['headers'] + ext.headers), sources=' '.join(ext.sources + sip['sources']),
sipinc=pyqt['sip_inc_dir'], pyinc=sysconfig.get_python_inc(), py_lib_dir=py_lib_dir,
ver=__version__
)
for incdir in ext.inc_dirs:
pro += '\nINCLUDEPATH += ' + incdir
if not iswindows and not isosx:
# Ensure that only the init symbol is exported
pro += '\nQMAKE_LFLAGS += -Wl,--version-script=%s.exp' % sip['target']
with open(os.path.join(src_dir, sip['target'] + '.exp'), 'wb') as f:
f.write(('{ global: init%s; local: *; };' % sip['target']).encode('utf-8'))
proname = '%s.pro' % sip['target']
with open(os.path.join(src_dir, proname), 'wb') as f:
f.write(pro.encode('utf-8'))
cwd = os.getcwdu()
qmc = []
if iswindows:
qmc += ['-spec', 'win32-msvc2008']
fext = 'dll' if iswindows else 'dylib' if isosx else 'so'
name = '%s%s.%s' % ('' if iswindows else 'lib', sip['target'], fext)
try:
os.chdir(src_dir)
if self.newer(dest, sip['headers'] + sip['sources'] + ext.sources + ext.headers):
self.check_call([QMAKE] + qmc + [proname])
self.check_call([make])
shutil.copy2(os.path.realpath(name), dest)
finally:
os.chdir(cwd)
def clean(self):
for ext in extensions: