Add PyQt4
authorMichael Büsch <mb@bu3sch.de>
Fri, 20 Aug 2010 18:24:49 +0000 (18:24 +0000)
committerMichael Büsch <mb@bu3sch.de>
Fri, 20 Aug 2010 18:24:49 +0000 (18:24 +0000)
SVN-Revision: 22743

lang/pyqt4/Makefile [new file with mode: 0644]
lang/pyqt4/files/fixup.sh [new file with mode: 0755]
lang/pyqt4/files/qt_versioning.sh [new file with mode: 0755]
lang/pyqt4/patches/100-cross-compile.patch [new file with mode: 0644]

diff --git a/lang/pyqt4/Makefile b/lang/pyqt4/Makefile
new file mode 100644 (file)
index 0000000..902544a
--- /dev/null
@@ -0,0 +1,158 @@
+#
+# Copyright (C) 2010 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=pyqt4
+PKG_VERSION:=4.7.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=PyQt-x11-gpl-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.riverbankcomputing.co.uk/static/Downloads/PyQt4
+PKG_MD5SUM:=88e9f1bc467cccf424d2032e3470982c
+PKG_BUILD_DIR:=$(BUILD_DIR)/PyQt-x11-gpl-$(PKG_VERSION)
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+PKG_BUILD_DEPENDS:=python-sip qt4
+
+include $(INCLUDE_DIR)/package.mk
+$(call include_mk, python-package.mk)
+$(call include_mk, python-sip-package.mk)
+
+define Package/pyqt4
+  SECTION:=language-python
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Python QT4
+  URL:=http://www.riverbankcomputing.co.uk/software/pyqt/download
+  DEPENDS:=+qt4 +dbus-python +python-sip @QT4_WS_X11
+endef
+
+define Package/pyqt4/Description
+  Python QT4 framework bindings.
+endef
+
+TARGET_INCDIRS+=$(STAGING_DIR)/include \
+       $(STAGING_DIR)/usr/include \
+       $(STAGING_DIR)/usr/include/Qt \
+       $(STAGING_DIR)/usr/include/Qt3Support \
+       $(STAGING_DIR)/usr/include/QtCore \
+       $(STAGING_DIR)/usr/include/QtDBus \
+       $(STAGING_DIR)/usr/include/QtGui \
+       $(STAGING_DIR)/usr/include/QtNetwork \
+       $(STAGING_DIR)/usr/include/QtSql \
+       $(STAGING_DIR)/usr/include/QtSvg \
+       $(STAGING_DIR)/usr/include/QtTest \
+       $(STAGING_DIR)/usr/include/QtXml \
+       $(STAGING_DIR)/usr/include/python$(PYTHON_VERSION) \
+       $(STAGING_DIR)/usr/lib/dbus-1.0/include \
+       $(TOOLCHAIN_DIR)/include \
+       $(TOOLCHAIN_DIR)/usr/include
+
+TARGET_LIBDIRS+=$(STAGING_DIR)/lib \
+       $(STAGING_DIR)/usr/lib \
+       $(TOOLCHAIN_DIR)/lib \
+       $(TOOLCHAIN_DIR)/usr/lib
+
+EXTRA_CFLAGS:=
+EXTRA_LDFLAGS:=-Wl,-rpath-link=$(STAGING_DIR)/usr/lib \
+               -Wl,-rpath=/usr/lib/
+
+QTDIRSFILE:=$(PKG_BUILD_DIR)/qtdirs.out
+SIPCFGFILE:=$(PKG_BUILD_DIR)/sipconfig.macros
+
+QT_VERSION:=./files/qt_versioning.sh version "$(STAGING_DIR)/usr/include" "$(PKG_BUILD_DIR)/qtver.tmp"
+QT_EDITION:=./files/qt_versioning.sh edition "$(STAGING_DIR)/usr/include" "$(PKG_BUILD_DIR)/qtver.tmp"
+
+# Welcome to cross compilation hell. Dinner is served!
+
+define Build/Configure
+       echo "$(STAGING_DIR)/usr" > $(QTDIRSFILE); \
+       echo "$(STAGING_DIR)/usr/include" >> $(QTDIRSFILE); \
+       echo "$(STAGING_DIR)/usr/lib" >> $(QTDIRSFILE); \
+       echo "$(STAGING_DIR)/usr/bin" >> $(QTDIRSFILE); \
+       echo "$(STAGING_DIR)/usr/share" >> $(QTDIRSFILE); \
+       echo "$(STAGING_DIR)/usr/lib/Qt/plugins" >> $(QTDIRSFILE); \
+       $(QT_VERSION) >> $(QTDIRSFILE); \
+       $(QT_EDITION) >> $(QTDIRSFILE); \
+       echo "Open Source" >> $(QTDIRSFILE); \
+       echo "shared" >> $(QTDIRSFILE); \
+       \
+       $(CP) "$(PYTHON_SIP_CONFIG_TEMPLATE)" "$(SIPCFGFILE)"; \
+       echo "INCDIR_QT                 $(STAGING_DIR)/usr/include" >> $(SIPCFGFILE); \
+       echo "LIBDIR_QT                 $(STAGING_DIR)/usr/lib" >> $(SIPCFGFILE); \
+       echo "MOC                       $(STAGING_DIR_HOST)/bin/moc" >> $(SIPCFGFILE); \
+       echo "QT_INSTALL_BINS           $(STAGING_DIR)/usr/bin" >> $(SIPCFGFILE); \
+       echo "QT_INSTALL_HEADERS        $(STAGING_DIR)/usr/include" >> $(SIPCFGFILE); \
+       echo "QT_INSTALL_LIBS           $(STAGING_DIR)/usr/lib" >> $(SIPCFGFILE); \
+       echo "INCDIR                    $(TARGET_INCDIRS)" >> $(SIPCFGFILE); \
+       echo "INCDIR_OPENGL             $(TARGET_INCDIRS)" >> $(SIPCFGFILE); \
+       echo "INCDIR_X11                $(TARGET_INCDIRS)" >> $(SIPCFGFILE); \
+       echo "LIBDIR                    $(TARGET_LIBDIRS)" >> $(SIPCFGFILE); \
+       echo "LIBDIR_OPENGL             $(TARGET_LIBDIRS)" >> $(SIPCFGFILE); \
+       echo "LIBDIR_X11                $(TARGET_LIBDIRS)" >> $(SIPCFGFILE); \
+       ( \
+               export PYTHONPATH="$(STAGING_DIR_HOST)/$(PYTHON_PKG_DIR)"; \
+               cd "$(PKG_BUILD_DIR)"; \
+               python -B ./configure.py \
+                       --use-arch="$(ARCH)" \
+                       --qmake="$(STAGING_DIR_HOST)/bin/qmake" \
+                       --qmake-spec="$(STAGING_DIR)/usr/share/mkspecs/linux-openwrt-g++" \
+                       --qmake-prefix='TARGET_CC="$(TARGET_CROSS)gcc"' \
+                       --qmake-prefix='TARGET_CXX="$(TARGET_CROSS)g++"' \
+                       --qmake-prefix='TARGET_AR="$(TARGET_CROSS)ar cqs"' \
+                       --qmake-prefix='TARGET_OBJCOPY="$(TARGET_CROSS)objcopy"' \
+                       --qmake-prefix='TARGET_RANLIB="$(TARGET_CROSS)ranlib"' \
+                       --qmake-prefix='TARGET_CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS)"' \
+                       --qmake-prefix='TARGET_CXXFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS)"' \
+                       --qmake-prefix='TARGET_LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)"' \
+                       --qmake-prefix='TARGET_INCDIRS="$(TARGET_INCDIRS)"' \
+                       --qmake-prefix='TARGET_LIBDIRS="$(TARGET_LIBDIRS)"' \
+                       --qmake-prefix='STAGING_DIR_HOST="$(STAGING_DIR)/../host"' \
+                       --qtdirs-file="$(QTDIRSFILE)" \
+                       --sipconfig-macros="$(SIPCFGFILE)" \
+                       --dbus="$(STAGING_DIR)/usr/include/dbus-1.0" \
+                       --bindir="$(PKG_INSTALL_DIR)/usr/bin" \
+                       --destdir="$(PKG_INSTALL_DIR)/$(PYTHON_PKG_DIR)" \
+                       --plugin-destdir="$(PKG_INSTALL_DIR)/usr/lib/Qt/plugins" \
+                       --pydbus-installdir="$(PKG_INSTALL_DIR)/$(PYTHON_PKG_DIR)" \
+                       --sipdir="$(PKG_INSTALL_DIR)/usr/share/sip" \
+                       --protected-is-public \
+                       --crosscompile \
+                       --no-designer-plugin \
+                       --no-qsci-api \
+                       --confirm-license \
+                       --verbose \
+       ); \
+       ./files/fixup.sh "$(PKG_BUILD_DIR)"
+endef
+
+#FIXME: Something still puts the host Python include path into the CFLAGS.
+#       I'm currently unsure who does this. Most likely SIP. arghh..
+
+define Build/Compile
+       $(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
+endef
+
+define Build/Install
+       $(MAKE_VARS) DESTDIR="" $(MAKE) -C $(PKG_BUILD_DIR) install
+endef
+
+define Package/pyqt4/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_DIR) $(1)/$(PYTHON_PKG_DIR)/PyQt4
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/{pylupdate4,pyrcc4,pyuic4} $(1)/usr/bin
+       $(INSTALL_DATA) $(PKG_INSTALL_DIR)/$(PYTHON_PKG_DIR)/qt.so $(1)/$(PYTHON_PKG_DIR)
+       $(CP) $(PKG_INSTALL_DIR)/$(PYTHON_PKG_DIR)/PyQt4 $(1)/$(PYTHON_PKG_DIR)
+endef
+
+$(eval $(call RequireCommand,python, \
+       Please install Python 2.x \
+))
+
+$(eval $(call BuildPackage,pyqt4))
diff --git a/lang/pyqt4/files/fixup.sh b/lang/pyqt4/files/fixup.sh
new file mode 100755 (executable)
index 0000000..c4203a0
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+PKG_BUILD_DIR="$1"
+
+# SIP uses PyLong_FromUnsignedLong to convert from void * to
+# PyLong. This results in a compilation error for the implicit cast
+# on C++ compilers. Make an explicit cast.
+sed -i -e 's/PyLong_FromUnsignedLong(/PyLong_FromUnsignedLong((unsigned long)/g' $PKG_BUILD_DIR/QtCore/sipQtCoreQThread.cpp
+
diff --git a/lang/pyqt4/files/qt_versioning.sh b/lang/pyqt4/files/qt_versioning.sh
new file mode 100755 (executable)
index 0000000..ec4fe94
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+die()
+{
+       echo "PyQt qt_versioning.sh: $*" >&2
+       exit 1
+}
+
+[ $# -eq 3 ] || die "Invalid arguments"
+
+action="$1"
+qtincdir="$2"
+tmpfile="$3"
+
+cp -f "$qtincdir/QtCore/qglobal.h" "$tmpfile" || die "cp failed"
+echo "int QT_VERSION_IS = QT_VERSION;" >> "$tmpfile" || die "patching failed (1)"
+echo "int QT_EDITION_IS = QT_EDITION;" >> "$tmpfile" || die "patching failed (2)"
+# First resolve all preprocessor macros
+cpp -x c++ -traditional-cpp "-I$qtincdir" "$tmpfile" > "$tmpfile.processed" || die "CPP failed"
+
+if [ "$action" = "version" ]; then
+       raw="$(grep -e 'QT_VERSION_IS' "$tmpfile.processed" | cut -d'=' -f2 | cut -d';' -f1)"
+elif [ "$action" = "edition" ]; then
+       raw="$(grep -e 'QT_EDITION_IS' "$tmpfile.processed" | cut -d'=' -f2 | cut -d';' -f1)"
+else
+       die "Invalid action"
+fi
+# We use python to evaluate the arithmetic C++ expression. Languages are similar
+# enough in that area for this to succeed.
+python -c "print \"%d\" % ($raw)" || die "C++ evaluation failed"
+
+exit 0
diff --git a/lang/pyqt4/patches/100-cross-compile.patch b/lang/pyqt4/patches/100-cross-compile.patch
new file mode 100644 (file)
index 0000000..2eb4580
--- /dev/null
@@ -0,0 +1,362 @@
+---
+ configure.py |  218 ++++++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 149 insertions(+), 69 deletions(-)
+
+--- PyQt-x11-gpl-4.7.4.orig/configure.py
++++ PyQt-x11-gpl-4.7.4/configure.py
+@@ -33,6 +33,7 @@ import os
+ import glob
+ import optparse
+ import shutil
++import re
+ import sipconfig
+@@ -173,25 +174,17 @@ def create_optparser():
+             metavar="PLUGIN", dest="staticplugins", help="add PLUGIN to the "
+             "list be linked (if Qt is built as static libraries)")
+-    if sys.platform != 'win32':
+-        if sys.platform in ('linux2', 'darwin'):
+-            pip_default = True
+-            pip_default_str = "enabled"
+-        else:
+-            pip_default = False
+-            pip_default_str = "disabled"
+-
+-        g.add_option("--protected-is-public", action="store_true",
+-                default=pip_default, dest="prot_is_public",
+-                help="enable building with 'protected' redefined as 'public' "
+-                        "[default: %s]" % pip_default_str)
+-        g.add_option("--protected-not-public", action="store_false",
+-                dest="prot_is_public",
+-                help="disable building with 'protected' redefined as 'public'")
+-        g.add_option("-q", "--qmake", action="callback", metavar="FILE",
+-                default=qmake, dest="qmake", callback=store_abspath_file,
+-                type="string",
+-                help="the pathname of qmake [default: %s]" % (qmake or "none"))
++    g.add_option("--protected-is-public", action="store_true",
++            default=True, dest="prot_is_public",
++            help="enable building with 'protected' redefined as 'public' "
++                    "[default: True]")
++    g.add_option("--protected-not-public", action="store_false",
++            dest="prot_is_public",
++            help="disable building with 'protected' redefined as 'public'")
++    g.add_option("-q", "--qmake", action="callback", metavar="FILE",
++            default=qmake, dest="qmake", callback=store_abspath_file,
++            type="string",
++            help="the pathname of qmake [default: %s]" % (qmake or "none"))
+     g.add_option("-s", "--dbus", action="callback", metavar="DIR",
+             dest="pydbusincdir", callback=store_abspath_dir, type="string",
+@@ -199,13 +192,13 @@ def create_optparser():
+             "[default: supplied by pkg-config]")
+     p.add_option_group(g)
+-    if sys.platform == 'darwin':
+-        g = optparse.OptionGroup(p, title="MacOS X Configuration")
+-        g.add_option("--use-arch", action="store", metavar="ARCH",
+-                dest="use_arch", choices=["i386", "x86_64", "ppc"],
+-                help="the architecture to use when running pyuic4 "
+-                        "[default: system default]")
+-        p.add_option_group(g)
++    g = optparse.OptionGroup(p, title="Arch Configuration")
++    g.add_option("--use-arch", action="store", metavar="ARCH",
++            dest="use_arch", choices=["", "i386", "x86_64", "ppc", "arm"],
++            default="",
++            help="the architecture to use when running pyuic4 "
++                    "[default: system default]")
++    p.add_option_group(g)
+     # Installation.
+     g = optparse.OptionGroup(p, title="Installation")
+@@ -264,12 +257,38 @@ def create_optparser():
+             "QTDIR/qsci]")
+     p.add_option_group(g)
++    # Crosscompilation
++    g = optparse.OptionGroup(p, title="Crosscompilation")
++    g.add_option("--crosscompile", action="store_true",
++                 default=False, dest="crosscompile",
++                 help="Set, if cross-compiling")
++    g.add_option("--sipconfig-macros", action="callback", metavar="FILE",
++                 default=None, dest="sipconfig_macros", type="string",
++                 callback=store_abspath_file,
++                 help="Path to a file containing sipconfig macros")
++    g.add_option("--qmake-prefix", action="append",
++               default=[], dest="qmake_prefixes", type="string",
++               help="Commandline prefix to qmake")
++    g.add_option("--qmake-spec", action="callback", metavar="FILE",
++                default=None, dest="qmake_spec", callback=store_abspath,
++                type="string",
++                help="the pathname to qmake spec file")
++    g.add_option("--qtdirs-file", action="callback", metavar="FILE",
++                 default=None, dest="qtdirs_file", callback=store_abspath_file,
++                 type="string",
++                 help="Path to a predefined qtdirs file")
++    g.add_option("--pydbus-installdir", action="callback", metavar="DIR",
++                 default=None, dest="pydbus_installdir", callback=store_abspath,
++                 type="string",
++                 help="Install dir for pydbus module")
++    p.add_option_group(g)
++
+     return p
+ class pyrccMakefile(sipconfig.ProgramMakefile):
+     """This class implements the Makefile for pyrcc.  This is specialised so
+-    that pyrcc is automatically run against the examples.
++    that pyrcc is automatically run against the examples, if not crosscompiling.
+     """
+     def __init__(self):
+@@ -282,6 +301,8 @@ class pyrccMakefile(sipconfig.ProgramMak
+     def generate_target_default(self, mfile):
+         """Generate the default target."""
+         sipconfig.ProgramMakefile.generate_target_default(self, mfile)
++        if opts.crosscompile:
++            return
+         # The correct call to pyrcc depends on the Python version.
+         if sys.hexversion >= 0x03000000:
+@@ -772,7 +793,7 @@ include(%s)
+             f.close()
+-            run_command("%s %s %s" % (opts.qmake, qmake_args, wrapped_pro))
++            run_qmake("%s %s" % (qmake_args, wrapped_pro))
+             os.chdir(cwd)
+         sipconfig.inform("Creating QPy support libraries Makefile...")
+@@ -825,12 +846,16 @@ include(%s)
+         # not on Windows (so that normal console use will work).
+         sipconfig.inform("Creating pyuic4 wrapper...")
+-        if sys.platform == 'darwin':
+-            gui = True
++        if opts.use_arch:
++            gui = False#FIXME
+             use_arch = opts.use_arch
+         else:
+-            gui = False
+-            use_arch = ''
++            if sys.platform == 'darwin':
++                gui = True
++                use_arch = opts.use_arch
++            else:
++                gui = False
++                use_arch = ''
+         uicdir=os.path.join(pyqt_modroot, "uic")
+         wrapper = sipconfig.create_wrapper(os.path.join(uicdir, "pyuic.py"), os.path.join("pyuic", "pyuic4"), gui, use_arch)
+@@ -880,6 +905,7 @@ include(%s)
+             py_major = sipcfg.py_version >> 16
+             py_minor = (sipcfg.py_version >> 8) & 0x0ff
++            print "FIXME CROSSCOMPILE" #FIXME: Crosscompile
+             if sys.platform == 'win32':
+                 lib_dir_flag = quote("-L%s" % sipcfg.py_lib_dir)
+                 link = "%s -lpython%d%d" % (lib_dir_flag, py_major, py_minor)
+@@ -938,7 +964,7 @@ include(%s)
+                 fout.write(prj)
+                 fout.close()
+-                run_command("%s %s" % (opts.qmake, qmake_args))
++                run_qmake(qmake_args)
+                 os.chdir(cwd)
+                 tool.append("designer")
+@@ -1056,6 +1082,14 @@ def create_config(module, template, macr
+     sipconfig.create_config_module(module, template, content, macros)
++def run_qmake(args):
++    pfx = " ".join(opts.qmake_prefixes)
++    if opts.qmake_spec:
++        spec = "-spec \"" + opts.qmake_spec + "\""
++    else:
++        spec = ""
++    run_command(pfx + " " + opts.qmake + " " + spec + " " + args)
++
+ def run_command(cmd):
+     """Run a command and display the output if verbose mode is enabled.
+@@ -1272,30 +1306,38 @@ def check_dbus():
+     """
+     sipconfig.inform("Checking to see if the dbus support module should be built...")
+-    sout = get_command_stdout("pkg-config --cflags-only-I --libs dbus-1")
+-    iflags = sout.read().strip()
++    if opts.crosscompile and not opts.pydbusincdir:
++       sipconfig.inform("Crosscompiling but no dbus incdir specified. Disabling dbus.")
++       return
++
++    if not opts.crosscompile:
++        sout = get_command_stdout("pkg-config --cflags-only-I --libs dbus-1")
++        iflags = sout.read().strip()
++
++        if not iflags:
++            sipconfig.inform("DBus v1 does not seem to be installed.")
++            return
++
++        # Using str() means it will work with both Python v2 and v3.
++        for f in str(iflags).split():
++            if f.startswith("-I"):
++                dbusincdirs.append(f[2:])
++            elif f.startswith("-L"):
++                dbuslibdirs.append(f[2:])
++            elif f.startswith("-l"):
++                dbuslibs.append(f[2:])
+-    if not iflags:
+-        sipconfig.inform("DBus v1 does not seem to be installed.")
+-        return
+-
+-    # Using str() means it will work with both Python v2 and v3.
+-    for f in str(iflags).split():
+-        if f.startswith("-I"):
+-            dbusincdirs.append(f[2:])
+-        elif f.startswith("-L"):
+-            dbuslibdirs.append(f[2:])
+-        elif f.startswith("-l"):
+-            dbuslibs.append(f[2:])
+-
+-    try:
+-        import dbus.mainloop
+-    except:
+-        sipconfig.inform("The Python dbus module doesn't seem to be installed.")
+-        return
++        try:
++            import dbus.mainloop
++        except:
++            sipconfig.inform("The Python dbus module doesn't seem to be installed.")
++            return
+     global pydbusmoddir
+-    pydbusmoddir = dbus.mainloop.__path__[0]
++    if opts.pydbus_installdir:
++        pydbusmoddir = opts.pydbus_installdir
++    else:
++        pydbusmoddir = dbus.mainloop.__path__[0]
+     # Try and find dbus-python.h.  We don't use pkg-config because it is broken
+     # for dbus-python (at least for versions up to and including v0.81.0).
+@@ -1381,6 +1423,7 @@ def set_sip_flags(pyqt):
+     pyqt is the configuration instance.
+     """
++    #FIXME: Needs some crosscompile fixes.
+     # If we don't check for signed interpreters, we exclude the 'VendorID'
+     # feature
+     if not opts.vendorcheck:
+@@ -1779,6 +1822,8 @@ def check_qt_installation(macros):
+ def fix_qmake_args(args=""):
+     """Make any platform specific adjustments to the arguments passed to qmake.
+     """
++    if opts.crosscompile:
++        return args
+     if sys.platform == "darwin":
+         # The Qt binary installer has macx-xcode as the default.
+         args = "-spec %s %s" % (sipcfg.platform, args)
+@@ -1930,7 +1975,7 @@ int main(int, char **)
+     # Create the makefile, first making sure it doesn't already exist.
+     remove_file(make_file)
+-    run_command("%s %s %s" % (opts.qmake, qmake_args, pro_file))
++    run_qmake("%s %s" % (qmake_args, pro_file))
+     if not os.access(make_file, os.F_OK):
+         sipconfig.error("%s failed to create a makefile. %s" % (opts.qmake, MSG_CHECK_QMAKE))
+@@ -1952,15 +1997,30 @@ int main(int, char **)
+     if not os.access(exe_file, os.X_OK):
+         sipconfig.error("Failed to determine the layout of your Qt installation. Try again using the --verbose flag to see more detail about the problem.")
+-    # Create the output file, first making sure it doesn't exist.
+-    remove_file(out_file)
+-    run_command(exe_file)
++    if opts.qtdirs_file:
++        # The user supplied a partial qtdirs.out file. We're probably crosscompiling.
++        # Do _not_ try to execute our qtdirs exe. Take the supplied qtdirs.out files
++        # instead and add the PyQt_... flags by grepping through the executable.
++        # This assumes the executable is not compiled with -O0.
++        read_qtdirs_file(opts.qtdirs_file)
++        global qt_xfeatures
++        print("Got %d features from qtdirs.out file: %s" % (len(qt_xfeatures), str(qt_xfeatures)))
++        found = re.findall(r'PyQt_[\w]+', file(exe_file, "r").read())
++        print("Grepped %d features from qtdirs.exe file: %s" % (len(found), str(found)))
++        qt_xfeatures.extend(found)
++    else:
++        # Create the output file, first making sure it doesn't exist.
++        remove_file(out_file)
++        run_command(exe_file)
++
++        if not os.access(out_file, os.F_OK):
++            sipconfig.error("%s failed to create %s. Make sure your Qt v4 installation is correct." % (exe_file, out_file))
+-    if not os.access(out_file, os.F_OK):
+-        sipconfig.error("%s failed to create %s. Make sure your Qt v4 installation is correct." % (exe_file, out_file))
++        # Read the directories.
++        read_qtdirs_file(out_file)
+-    # Read the directories.
+-    f = open(out_file, "r")
++def read_qtdirs_file(filename):
++    f = open(filename, "r")
+     lines = f.read().strip().split("\n")
+     f.close()
+@@ -2022,6 +2082,24 @@ int main(int, char **)
+             sipconfig.error("Qt has been built as static libraries so either the -g or -k argument should be used.")
++def load_sipconfig_macros(filename):
++    macros = {}
++    fd = file(filename, "r")
++    for line in fd.readlines():
++        line = line.split()
++        try:
++            key = line[0]
++        except IndexError:
++            sipconfig.error("Invalid sipconfig macros file format")
++        value = ""
++        try:
++            value = " ".join(line[1:])
++        except IndexError:
++            pass
++        macros[key] = value
++    return macros
++
++
+ def main():
+     """Create the configuration module module.
+     """
+@@ -2036,7 +2114,7 @@ def main():
+     opts, args = p.parse_args()
+     # Provide defaults for platform-specific options.
+-    if sys.platform == 'win32':
++    if sys.platform == 'win32' and not opts.crosscompile:
+         opts.qmake = find_default_qmake()
+         opts.prot_is_public = False
+@@ -2069,12 +2147,14 @@ def main():
+             # Install the API file if the default directory exists.
+             opts.api = os.path.isdir(opts.qscidir)
+-    # Replace the existing build macros with the ones from the Qt installation.
+-    macros = get_build_macros(args)
+-
+-    if macros is None:
+-        p.print_help()
+-        sys.exit(2)
++    if opts.sipconfig_macros:
++        macros = load_sipconfig_macros(opts.sipconfig_macros)
++    else:
++        # Replace the existing build macros with the ones from the Qt installation.
++        macros = get_build_macros(args)
++        if macros is None:
++            p.print_help()
++            sys.exit(2)
+     sipcfg.set_build_macros(macros)