[PyQt] How to compile with PyQt5?

Kovid Goyal kovid at kovidgoyal.net
Fri Jul 25 04:36:40 BST 2014


1600 lines? That's crazy. Here's an extract from calibre's build system.


To get all the data for building in PyQt5:

qraw = subprocess.check_output([QMAKE, '-query']).decode('utf-8')
def readvar(name):
    return re.search('%s:(.+)$' % name, qraw, flags=re.M).group(1).strip()


pyqt = {x:readvar(y) for x, y in (
    ('inc', 'QT_INSTALL_HEADERS'), ('lib', 'QT_INSTALL_LIBS')
)}
qt = {x:readvar(y) for x, y in {'libs':'QT_INSTALL_LIBS', 'plugins':'QT_INSTALL_PLUGINS'}.iteritems()}
c = sipconfig.Configuration()
pyqt['sip_bin'] = c.sip_bin + ('.exe' if iswindows and not c.sip_bin.endswith('.exe') else '')

from PyQt5.QtCore import PYQT_CONFIGURATION
pyqt['sip_flags'] = PYQT_CONFIGURATION['sip_flags']
def get_sip_dir(q):
    for x in ('', 'PyQt5', 'sip/PyQt5'):
        base = os.path.join(q, x)
        if os.path.exists(os.path.join(base, 'QtWidgets')):
            return base
    return q
pyqt['pyqt_sip_dir'] = get_sip_dir(c.default_sip_dir)
pyqt['sip_inc_dir'] = c.sip_inc_dir


And to build pyqt extensions using that data on linux, os x and windows.

    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}
            TARGET_EXT = .dll
        }}
        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=py_lib,
            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'))
        if ext.qt_private_headers:
            qph = ' '.join(x + '-private' for x in ext.qt_private_headers)
            pro += '\nQT += ' + qph
        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' % ('release/' 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]+([] if iswindows else ['-j%d'%(cpu_count or 1)]))
                shutil.copy2(os.path.realpath(name), dest)
                if iswindows:
                    shutil.copy2(name + '.manifest', dest + '.manifest')

        finally:
            os.chdir(cwd)


You will find this code in the master and qt5 brnaches of calibre in
setup/build_environment.py and setup/extensions.py

Kovid.

On Thu, Jul 24, 2014 at 09:07:02PM -0400, Jacob Floyd wrote:
> Hello everybody,
> 
> I'm trying to get sip bindings[1] for FakeVim[2] (Vim emulation in
> QTextEdit, QPlainTextEdit and similar Qt widgets), so of course it will be
> built on PyQt. However, I'm having a hard time getting a build system to
> reliably build those sip bindings on both PyQt4 and PyQt5.
> 
> With PyQt4, pyqtconfig made for a fairly simple configure.py, but I need it
> to work with both PyQt4 and PyQt5, so pyqtconfig is no longer an option.
> 
> The docs[3][4] list QScintilla as a good example of something that builds
> on PyQt.
> Plus, according to Phil[5], I should just copy/paste/modify QScintilla's
> configure.py.
> So, I copy/paste QScintilla's Python/configure*.py and then ran it through
> sed[6][7] to remove all of the QScintilla stuff.
> 
> When I showed what I did to hluk, the maintainer of FakeVim, he said[8]:
> > The new configure.py file has over 1600 lines. This starts to be overly
> complicated.
> > There must be simpler way to do this, otherwise it would be hell to
> maintain.
> 
> So, after searching docs, the ml, and the web in general, I'm looking for
> advice here: Isn't there a simpler way? A simple build system for modules
> that support extending both PyQt4 & PyQt5? There's only one sip file right
> now, so it seems like 1600 lines is quite a bit of overhead to compile so
> few sip bindings.
> 
> At least in its current state (run build.sh in the qscintilla folder[9]) my
> test can't import FakeVim, so I'm left wondering where the build system, or
> maybe the test script, needs to be tweaked.
> 
> What should I do next in my quest for FakeVim sip bindings for both PyQt 4
> and PyQt 5? Is there a simpler build system than the one provided in
> QScintilla?
> 
> Thanks,
> Jacob Floyd
> 
> [1] https://github.com/hluk/FakeVim/issues/5
> [2] https://github.com/hluk/FakeVim
> [3] http://pyqt.sourceforge.net/Docs/PyQt4/build_system.html
> [4] http://pyqt.sourceforge.net/Docs/PyQt5/extension_api.html
> [5] http://article.gmane.org/gmane.comp.python.pyqt-pykde/27125
> [6] https://github.com/hluk/FakeVim/issues/5#issuecomment-50088032
> [7]
> https://github.com/cognifloyd/FakeVim/blob/python/qscintilla/sed-configure.sh
> Aside: One of the issues that this sed script takes care of is changing
> qscintilla's hardcoded sip files that are hardcoded outside of the
> "editable" section.
> There is an assumption that sip files will always be in sip/ which should
> be editable.
> [8] https://github.com/hluk/FakeVim/issues/5#issuecomment-50054483
> [9] https://github.com/cognifloyd/FakeVim/tree/python/qscintilla
> 
> 
> !DSPAM:3,53d1b37b16783439398687!

> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
> 
> !DSPAM:3,53d1b37b16783439398687!


-- 
_____________________________________

Dr. Kovid Goyal 
http://www.kovidgoyal.net
http://calibre-ebook.com
_____________________________________
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20140725/5c5a3be9/attachment.sig>


More information about the PyQt mailing list