diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-11-29 00:31:00 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-11-29 00:31:00 -0600 |
commit | b388516ca2691303a076a0764fd40bf7116fe43d (patch) | |
tree | 6f1615d1f12b325f4d1cd9c25d1519303794001a /configure.py | |
download | pytqt-b388516ca2691303a076a0764fd40bf7116fe43d.tar.gz pytqt-b388516ca2691303a076a0764fd40bf7116fe43d.zip |
Initial import of python-qt3
Diffstat (limited to 'configure.py')
-rw-r--r-- | configure.py | 1457 |
1 files changed, 1457 insertions, 0 deletions
diff --git a/configure.py b/configure.py new file mode 100644 index 0000000..cbbc1c2 --- /dev/null +++ b/configure.py @@ -0,0 +1,1457 @@ +# This script generates the PyQt configuration and generates the Makefiles. +# +# Copyright (c) 2007 +# Riverbank Computing Limited <info@riverbankcomputing.co.uk> +# +# This file is part of PyQt. +# +# This copy of PyQt is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any later +# version. +# +# PyQt is supplied in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyQt; see the file LICENSE. If not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import sys +import os +import string +import glob +import getopt +import shutil +import py_compile + +import sipconfig + +src_dir = os.path.dirname(os.path.abspath(__file__)) + +# Initialise the globals. +pyqt_version = 0x031201 +pyqt_version_str = "3.18.1" + +sip_min_version = 0x040800 + + +# Try and find a Qt installation to use as the default. +try: + qt_dir = os.environ["QTDIR"] +except KeyError: + qt_dir = "" + + +qt_version = 0 +qt_edition = "" +qt_incdir = None +qt_libdir = None +qt_threaded = 0 +qt_winconfig = "" + +pyqt = None +pyqt_modules = [] +qt_sip_flags = [] +qtext_sip_flags = [] +qtpe_sip_flags = [] +qsci_version = 0 +disabled_classes = [] + +if sys.platform == "win32": + qsci_define = "QEXTSCINTILLA_DLL" +else: + qsci_define = "" + +# Get the SIP configuration. +sipcfg = sipconfig.Configuration() + +# Command line options. +opt_qtlib = None +opt_qconfigdir = None +opt_pyqtbindir = sipcfg.default_bin_dir +opt_pyqtmoddir = sipcfg.default_mod_dir +opt_pyqtsipdir = sipcfg.default_sip_dir +opt_qtpetag = None +opt_qsciincdir = None +opt_qscilibdir = None +opt_static = 0 +opt_debug = 0 +opt_concat = 0 +opt_split = 1 +opt_tracing = 0 +opt_verbose = 0 +opt_keepfeatures = 0 + +opt_vendorcheck = 0 +opt_vendincdir = sipcfg.py_inc_dir +opt_vendlibdir = sipcfg.py_lib_dir + + +def usage(rcode = 2): + """Display a usage message and exit. + + rcode is the return code passed back to the calling process. + """ + if qt_dir: + def_qt_dir = qt_dir + else: + def_qt_dir = "none" + + sys.stdout.write("Usage:\n") + sys.stdout.write(" python configure.py [-h] [-a tag] [-b dir] [-c] [-d dir] [-f] [-g dir] [-i] [-j #] [-k] [-l dir] [-m dir] [-n dir] [-o dir] [-q dir] [-r] [-s] [-u] [-v dir] [-w] [-y lib] option=value option+=value ...\n") + sys.stdout.write("where:\n") + sys.stdout.write(" -h display this help message\n") + sys.stdout.write(" -a tag explicitly enable the qtpe module\n") + sys.stdout.write(" -b dir where pyuic and pylupdate will be installed [default %s]\n" % opt_pyqtbindir) + sys.stdout.write(" -c concatenate each module's C/C++ source files\n") + sys.stdout.write(" -d dir where the PyQt modules will be installed [default %\ns]" % opt_pyqtmoddir) + sys.stdout.write(" -f keep any existing features file (when cross-compiling) [default remove]\n") + sys.stdout.write(" -g dir where the Qt qconfig.h file can be found [default Qt include directory]\n") + sys.stdout.write(" -i enable checking of signed interpreters using the VendorID package [default disabled]\n") + sys.stdout.write(" -j # split the concatenated C++ source files into # pieces [default 1]\n") + sys.stdout.write(" -k build the PyQt modules as static libraries\n") + sys.stdout.write(" -l dir the directory containing the VendorID header file [default %s]\n" % opt_vendincdir) + sys.stdout.write(" -m dir the directory containing the VendorID library [default %s]\n" % opt_vendlibdir) + sys.stdout.write(" -n dir the directory containing the QScintilla header files [default Qt include directory]\n") + sys.stdout.write(" -o dir the directory containing the QScintilla library [default Qt lib directory]\n") + sys.stdout.write(" -q dir the root directory of the Qt installation [default %s]\n" % def_qt_dir) + sys.stdout.write(" -r generate code with tracing enabled [default disabled]\n") + sys.stdout.write(" -s QScintilla is a static library and not a DLL (Windows only)\n") + sys.stdout.write(" -u build with debugging symbols (requires a debug build of Python on Windows\n") + sys.stdout.write(" -v dir where the PyQt .sip files will be installed [default %s]\n" % opt_pyqtsipdir) + sys.stdout.write(" -w don't suppress compiler output during configuration\n") + sys.stdout.write(" -y lib explicitly specify the type of Qt library, either qt, qt-mt, qte, qte-mt or qtmt\n") + + sys.exit(rcode) + + +class ConfigureBase: + """This is the base class for all PyQt version specific configurer classes. + Anything here is common to all configurers. + """ + def check_modules(self): + """Check which modules should be built and add them to the global list. + + Returns the name of any additional library that needs to be linked with + the main module. + """ + return None + + def sip_flags(self): + """Get the configuration specific SIP flags. + + Returns a list of flags. + """ + return [] + + def qt_version_tags(self): + """Get the versions tags for the configuration. + + Returns a dictionary of versions and corresponding tags. + """ + return {} + + def code(self, extra_include_dirs, extra_lib_dir, extra_libs): + """Generate the code for a configuration. + + extra_include_dirs is a list of directories to add to those supplied by + the SIP configuration. + extra_lib_dir is an optional directory to add to those supplied by the + SIP configuration. + extra_lib_dirs is an optional list of directories to add to those + supplied by the SIP configuration. + """ + pass + + def tools(self): + """Create the Makefiles for any other sub-directories and return a list + of those directories. + + Returns a list of sub-directories with Makefile. + """ + return [] + + def module_dir(self): + """Return the configuration's module directory. + """ + return opt_pyqtmoddir + + def module_installs(self): + """Return a list of files to install in the module directory other than + the modules themselves. + """ + return ["pyqtconfig.py"] + + def sip_dir(self): + """Return the configuration's .sip files directory. + """ + return opt_pyqtsipdir + + +class ConfigurePyQt3(ConfigureBase): + """This class defines the methods to configure PyQt v3. + """ + def check_modules(self): + pyqt_modules.append("qt") + + check_module("qtcanvas", "qcanvas.h", "QCanvas()") + check_module("qtnetwork", "qsocket.h", "QSocket()") + check_module("qttable", "qtable.h", "QTable()") + check_module("qtxml", "qdom.h", "QDomImplementation()") + check_module("qtgl", "qgl.h", "QGLWidget()", opengl=1) + + if qt_version >= 0x030000: + check_module("qtui", "qwidgetfactory.h", "QWidgetFactory()", lib="qui") + + if qt_edition in ("enterprise", "free"): + check_module("qtsql", "qsql.h", "QSql()") + + if sys.platform == "win32" and sipcfg.sip_version >= 0x040200: + check_module("qtaxcontainer", "qaxobject.h", "QAxObject()", lib="qaxcontainer") + + if qsci_version: + check_module("qtext", "qextscintillabase.h", "QextScintillaBase()", define=qsci_define, include_dir=opt_qsciincdir, lib_dir=opt_qscilibdir, lib="qscintilla") + + if opt_qtpetag: + pyqt_modules.append("qtpe") + + qtmod_lib = None + + if qt_version >= 0x030100: + sipconfig.inform("Checking to see if the QAssistantClient class is available...") + + if check_class("qassistantclient.h", "QAssistantClient(\"foo\")", lib="qassistantclient"): + qtmod_lib = "qassistantclient" + else: + disabled_classes.append("QAssistantClient") + + return qtmod_lib + + def sip_flags(self): + return get_feature_flags() + + def qt_version_tags(self): + return { + 0x010403: None, + 0x020000: "Qt_1_43", + 0x020100: "Qt_2_00", + 0x020200: "Qt_2_1_0", + 0x020300: "Qt_2_2_0", + 0x020301: "Qt_2_3_0", + 0x030000: "Qt_2_3_1", + 0x030001: "Qt_3_0_0", + 0x030002: "Qt_3_0_1", + 0x030004: "Qt_3_0_2", + 0x030005: "Qt_3_0_4", + 0x030006: "Qt_3_0_5", + 0x030100: "Qt_3_0_6", + 0x030101: "Qt_3_1_0", + 0x030102: "Qt_3_1_1", + 0x030200: "Qt_3_1_2", + 0x030300: "Qt_3_2_0", + 0x030305: "Qt_3_3_0", + 0x030306: "Qt_3_3_5", + 0x040000: "Qt_3_3_6" + } + + def code(self, extra_include_dirs, extra_lib_dir, extra_libs): + generate_code("qt", extra_include_dirs=extra_include_dirs, extra_lib_dir=extra_lib_dir, extra_libs=extra_libs) + + if "qtext" in pyqt_modules: + generate_code("qtext", extra_define=qsci_define, extra_include_dirs=[opt_qsciincdir], extra_lib_dir=opt_qscilibdir, extra_libs=["qscintilla"], sip_flags=qtext_sip_flags) + + if "qtgl" in pyqt_modules: + generate_code("qtgl", opengl=1) + + if "qtpe" in pyqt_modules: + generate_code("qtpe", extra_libs=["qpe"], sip_flags=qtpe_sip_flags) + + if "qtui" in pyqt_modules: + generate_code("qtui", extra_libs=["qui"]) + + if "qtaxcontainer" in pyqt_modules: + generate_code("qtaxcontainer", extra_libs=["qaxcontainer"]) + + # The rest don't need special handling. + for m in ("qtcanvas", "qtnetwork", "qtsql", "qttable", "qtxml"): + if m in pyqt_modules: + generate_code(m) + + def tools(self): + tool_dirs = [] + + if qt_version >= 0x030000: + # The Professional Edition needs special handling. + prof = (qt_edition == "professional") + + sipconfig.inform("Creating pyuic Makefile...") + + if prof or "qtxml" not in pyqt_modules: + buildfile= "pyuic-prof.sbf" + + for xml in ("qdom.cpp", "qxml.cpp"): + shutil.copyfile(qt_dir + "/src/xml/" + xml, "pyuic3/" + xml) + else: + buildfile= "pyuic.sbf" + + makefile = sipconfig.ProgramMakefile( + configuration=sipcfg, + build_file=os.path.join(src_dir, "pyuic3", buildfile), + dir="pyuic3", + install_dir=opt_pyqtbindir, + console=1, + qt=1, + warnings=1 + ) + + makefile.extra_defines.append("UIC") + makefile.extra_defines.append("QT_INTERNAL_XML") + + if prof or "qtxml" not in pyqt_modules: + makefile.extra_defines.append("QT_MODULE_XML") + + if qt_version < 0x030100: + makefile.extra_include_dirs.append(qt_dir + "/src/3rdparty/zlib") + makefile.extra_include_dirs.append(os.path.join(src_dir, "pyuic3")) + + makefile.generate() + tool_dirs.append("pyuic3") + + sipconfig.inform("Creating pylupdate Makefile...") + + if prof or "qtxml" not in pyqt_modules: + buildfile= "pylupdate-prof.sbf" + + shutil.copyfile(qt_dir + "/src/xml/qxml.cpp", "pylupdate3/qxml.cpp") + else: + buildfile= "pylupdate.sbf" + + makefile = sipconfig.ProgramMakefile( + configuration=sipcfg, + build_file=os.path.join(src_dir, "pylupdate3", buildfile), + dir="pylupdate3", + install_dir=opt_pyqtbindir, + console=1, + qt=1, + warnings=1 + ) + + makefile.extra_defines.append("QT_INTERNAL_XML") + + if prof or "qtxml" not in pyqt_modules: + makefile.extra_defines.append("QT_MODULE_XML") + + makefile.extra_include_dirs.append(os.path.join(src_dir, "pylupdate3")) + + makefile.generate() + tool_dirs.append("pylupdate3") + elif qt_version >= 0x020000: + sipconfig.inform("Creating pyuic Makefile...") + + makefile = sipconfig.ProgramMakefile( + configuration=sipcfg, + build_file="pyuic.sbf", + dir="pyuic2", + install_dir=opt_pyqtbindir, + console=1, + qt=1, + warnings=1 + ) + + makefile.extra_defines.append("UIC") + makefile.extra_include_dirs.append(qt_dir + "/src/3rdparty/zlib") + + makefile.generate() + tool_dirs.append("pyuic2") + + return tool_dirs + + +def inform_user(): + """Tell the user the option values that are going to be used. + """ + if qt_edition: + edstr = qt_edition + " edition " + else: + edstr = "" + + sipconfig.inform("Qt v%s %sis being used." % (sipconfig.version_to_string(qt_version), edstr)) + sipconfig.inform("SIP %s is being used." % sipcfg.sip_version_str) + sipconfig.inform("These PyQt modules will be built: %s." % string.join(pyqt_modules)) + + if disabled_classes: + sipconfig.inform("Support for these Qt classes has been disabled: %s." % string.join(disabled_classes)) + + sipconfig.inform("The PyQt modules will be installed in %s." % opt_pyqtmoddir) + sipconfig.inform("The PyQt .sip files will be installed in %s." % opt_pyqtsipdir) + + sipconfig.inform("The Qt header files are in %s." % qt_incdir) + sipconfig.inform("The %s Qt library is in %s." % (opt_qtlib, qt_libdir)) + + if qt_version >= 0x020000: + sipconfig.inform("pyuic will be installed in %s." % opt_pyqtbindir) + + if qt_version >= 0x030000: + sipconfig.inform("pylupdate will be installed in %s." % opt_pyqtbindir) + + if opt_vendorcheck: + sipconfig.inform("PyQt will only be usable with signed interpreters.") + + +def create_config(module, template, macros): + """Create the PyQt configuration module so that it can be imported by build + scripts. + + module is the module file name. + template is the template file name. + macros is the dictionary of platform specific build macros. + """ + sipconfig.inform("Creating %s..." % module) + + content = { + "pyqt_config_args": sys.argv[1:], + "pyqt_version": pyqt_version, + "pyqt_version_str": pyqt_version_str, + "pyqt_bin_dir": opt_pyqtbindir, + "pyqt_mod_dir": opt_pyqtmoddir, + "pyqt_sip_dir": opt_pyqtsipdir, + "pyqt_modules": pyqt_modules, + "pyqt_qt_sip_flags": qt_sip_flags, + "qt_version": qt_version, + "qt_edition": qt_edition, + "qt_winconfig": qt_winconfig, + "qt_framework": 0, + "qt_threaded": qt_threaded, + "qt_dir": qt_dir, + "qt_inc_dir": qt_incdir, + "qt_lib": opt_qtlib, + "qt_lib_dir": qt_libdir + } + + if "qtaxcontainer" in pyqt_modules: + content["pyqt_qtaxcontainer_sip_flags"] = qt_sip_flags + + if "qtcanvas" in pyqt_modules: + content["pyqt_qtcanvas_sip_flags"] = qt_sip_flags + + if "qtext" in pyqt_modules: + content["pyqt_qtext_sip_flags"] = qtext_sip_flags + + # These are internal. + content["_pyqt_qscintilla_defines"] = qsci_define + content["_pyqt_qscintilla_inc_dir"] = opt_qsciincdir + content["_pyqt_qscintilla_lib_dir"] = opt_qscilibdir + + if "qtgl" in pyqt_modules: + content["pyqt_qtgl_sip_flags"] = qt_sip_flags + + if "qtnetwork" in pyqt_modules: + content["pyqt_qtnetwork_sip_flags"] = qt_sip_flags + + if "qtpe" in pyqt_modules: + content["pyqt_qtpe_sip_flags"] = qtpe_sip_flags + + if "qtsql" in pyqt_modules: + content["pyqt_qtsql_sip_flags"] = qt_sip_flags + + if "qttable" in pyqt_modules: + content["pyqt_qttable_sip_flags"] = qt_sip_flags + + if "qtui" in pyqt_modules: + content["pyqt_qtui_sip_flags"] = qt_sip_flags + + if "qtxml" in pyqt_modules: + content["pyqt_qtxml_sip_flags"] = qt_sip_flags + + sipconfig.create_config_module(module, template, content, macros) + + +def compile_qt_program(name, define=None, include_dir=None, lib_dir=None, lib=None, opengl=0, python=0, debug=0): + """Compile a simple Qt application. + + name is the name of the single source file. + define is a name to add to the list of preprocessor defines. + include_dir is the name of a directory to add to the list of include + directories. + lib_dir is the name of a directory to add to the list of library + directories. + lib is the name of a library to add to the list of libraries. + opengl is set if the application uses OpenGL. + python is set if the application #includes Python.h. + debug is set if this is a debug build. + + Returns the name of the executable suitable for running or None if it + wasn't created. + """ + makefile = sipconfig.ProgramMakefile(sipcfg, console=1, qt=1, warnings=0, opengl=opengl, python=python, debug=debug) + + if define: + makefile.extra_defines.append(define) + + if include_dir: + makefile.extra_include_dirs.append(include_dir) + + if lib_dir: + makefile.extra_lib_dirs.append(lib_dir) + + if lib: + makefile.extra_libs.append(lib) + + exe, build = makefile.build_command(name) + + # Make sure the executable file doesn't exist. + try: + os.remove(exe) + except OSError: + pass + + if not opt_verbose: + try: + import subprocess + + p = subprocess.Popen(build, shell=True, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + fout = p.stdout + except ImportError: + _, fout = os.popen4(build) + + # Read stdout and stderr until there is no more output. + lout = fout.readline() + while lout: + lout = fout.readline() + + fout.close() + + try: + os.wait() + except: + pass + else: + os.system(build) + + if not os.access(exe, os.X_OK): + return None + + if sys.platform != "win32": + exe = "./" + exe + + return exe + + +def check_qscintilla(): + """See if QScintilla can be found and what its version is. + """ + # Set the defaults if they haven't been explicitly specified. + global opt_qsciincdir, opt_qscilibdir + + if opt_qsciincdir is None: + opt_qsciincdir = qt_incdir + + if opt_qscilibdir is None: + opt_qscilibdir = qt_libdir + + # Find the QScintilla header files. + sciglobal = os.path.join(opt_qsciincdir, "qextscintillaglobal.h") + + if os.access(sciglobal, os.F_OK): + # Get the QScintilla version number. + global qsci_version + + qsci_version, sciversstr = sipconfig.read_version(sciglobal, "QScintilla", "QSCINTILLA_VERSION", "QSCINTILLA_VERSION_STR") + + if glob.glob(os.path.join(opt_qscilibdir, "*qscintilla*")): + sipconfig.inform("QScintilla %s is being used." % sciversstr) + + # If we find a snapshot then set a negative version number as a + # special case. + if string.find(sciversstr, "snapshot") >= 0: + qsci_version = -1 + else: + sipconfig.inform("The QScintilla library could not be found in %s and so the qtext module will not be built. If QScintilla is installed then use the -o argument to explicitly specify the correct directory." % opt_qscilibdir) + else: + sipconfig.inform("qextscintillaglobal.h could not be found in %s and so the qtext module will not be built. If QScintilla is installed then use the -n argument to explicitly specify the correct directory." % opt_qsciincdir) + + +def check_vendorid(): + """See if the VendorID library and include file can be found. + """ + global opt_vendorcheck + + if opt_vendorcheck: + if os.access(os.path.join(opt_vendincdir, "vendorid.h"), os.F_OK): + if glob.glob(os.path.join(opt_vendlibdir, "*vendorid*")): + sipconfig.inform("The VendorID package was found.") + else: + opt_vendorcheck = 0 + sipconfig.inform("The VendorID library could not be found in %s and so signed interpreter checking will be disabled. If the VendorID library is installed then use the -m argument to explicitly specify the correct directory." % opt_vendlibdir) + else: + opt_vendorcheck = 0 + sipconfig.inform("vendorid.h could not be found in %s and so signed interpreter checking will be disabled. If the VendorID package is installed then use the -l argument to explicitly specify the correct directory." % opt_vendincdir) + + +def check_module(mname, incfile, ctor, define=None, include_dir=None, lib_dir=None, lib=None, opengl=0): + """See if a module can be built and, if so, add it to the global list of + modules. + + mname is the name of the module. + incfile is the name of the include file needed for the test. + ctor is the C++ constructor of the class being used for the test. + define is a name to add to the list of preprocessor defines. + include_dir is the name of a directory to add to the list of include + directories. + lib_dir is the name of a directory to add to the list of library + directories. + lib is the name of a library to add to the list of libraries. + opengl is set if the application uses OpenGL. + """ + # Check the module's main .sip file exists. + if os.access(os.path.join(src_dir, "sip", mname, mname + "mod.sip"), os.F_OK): + sipconfig.inform("Checking to see if the %s module should be built..." % mname) + + if check_class(incfile, ctor, define, include_dir, lib_dir, lib, opengl): + pyqt_modules.append(mname) + + +def check_class(incfile, ctor, define=None, include_dir=None, lib_dir=None, lib=None, opengl=0): + """Return non-zero if a class is available. + + incfile is the name of the include file needed for the test. + ctor is the C++ constructor of the class. + define is a name to add to the list of preprocessor defines. + include_dir is the name of a directory to add to the list of include + directories. + lib_dir is the name of a directory to add to the list of library + directories. + lib is the name of a library to add to the list of libraries. + opengl is set if the application uses OpenGL. + """ + cfgtest = "cfgtest.cpp" + + f = open(cfgtest, "w") + + f.write("""#include <%s> + +int main(int argc, char **argv) +{ + new %s; +} +""" % (incfile, ctor)) + + f.close() + + return compile_qt_program(cfgtest, define, include_dir, lib_dir, lib, opengl) + + +def check_plugin(cname, incfile): + """Return non-zero if a class that might be a plugin is in the main Qt + library. + + cname is the name of the class. + incfile is the name of the include file needed for the test. + """ + sipconfig.inform("Checking to see if the %s class is built in..." % cname) + + return check_class(incfile, cname + "()") + + +def create_features_file(name): + """Create the features file. + + name is the name of the features file in the current directory. + """ + # The features that a given Qt configuration may or may not support. Note + # that STYLE_WINDOWSXP and ASSISTANTCLIENT require special handling. + flist = ["ACTION", "CLIPBOARD", "CODECS", "COLORDIALOG", "DATASTREAM", + "DIAL", "DNS", "DOM", "DRAGANDDROP", "ICONVIEW", "IMAGE_TEXT", + "INPUTDIALOG", "FILEDIALOG", "FONTDATABASE", "FONTDIALOG", + "MESSAGEBOX", "MIMECLIPBOARD", + "NETWORKPROTOCOL", "NETWORKPROTOCOL_FTP", "NETWORKPROTOCOL_HTTP", + "PICTURE", "PRINTDIALOG", "PRINTER", "PROGRESSDIALOG", + "PROPERTIES", + "SEMIMODAL", "SIZEGRIP", "SOUND", "SPLITTER", "STYLE_CDE", + "STYLE_INTERLACE", "STYLE_MOTIF", "STYLE_MOTIFPLUS", + "STYLE_PLATINUM", "STYLE_SGI", "STYLE_WINDOWS", + "TABDIALOG", "TABLE", "TABLEVIEW", "TRANSFORMATIONS", + "TRANSLATION", "WIZARD", "WORKSPACE"] + + # Generate the program which will generate the features file. + f = open("mkfeatures.cpp", "w") + + f.write( +"""#include <Python.h> +#include <stdio.h> +#include <qglobal.h> +#include <qapplication.h> + +int main(int argc,char **argv) +{ + FILE *fp; + QApplication app(argc,argv,0); + + if ((fp = fopen("%s","w")) == NULL) + { + printf("Unable to create '%s'\\n"); + return 1; + } + +#if !defined(WITH_THREAD) || !defined(QT_THREAD_SUPPORT) + fprintf(fp,"-x Qt_THREAD_SUPPORT\\n"); +#endif + +#if !defined(Q_WS_WIN) || QT_VERSION < 0x030000 || defined(QT_NO_STYLE_WINDOWSXP) + fprintf(fp,"-x Qt_STYLE_WINDOWSXP\\n"); +#endif + +#if defined(Q_OS_WIN64) + fprintf(fp,"-x Qt_Q_LONG_IS_long\\n"); +#endif +""" % (name, name)) + + for feat in flist: + f.write( +""" +#if defined(QT_NO_%s) + fprintf(fp,"-x Qt_%s\\n"); +#endif +""" % (feat, feat)) + + # Disable QAssistantClient for the Professional Edition. + if "QAssistantClient" in disabled_classes: + f.write( +""" + fprintf(fp,"-x Qt_ASSISTANTCLIENT\\n"); +""") + + f.write( +""" + fclose(fp); + + return 0; +} +""") + + f.close() + + # Build the program. + exe = compile_qt_program("mkfeatures.cpp", include_dir=sipcfg.py_inc_dir, python=1) + if not exe: + sipconfig.error("Unable to build mkfeatures utility.") + + os.system(exe) + + # Check the file was created. + if not os.access(name, os.F_OK): + sipconfig.error("There was an error creating the features file.") + + # Check what features have been implemented as plugins and disable them. + plugins = [("STYLE_CDE", "qcdestyle.h", "QCDEStyle"), + ("STYLE_INTERLACE", "qinterlacestyle.h", "QInterlaceStyle"), + ("STYLE_MOTIF", "qmotifstyle.h", "QMotifStyle"), + ("STYLE_MOTIFPLUS", "qmotifplusstyle.h", "QMotifPlusStyle"), + ("STYLE_PLATINUM", "qplatinumstyle.h", "QPlatinumStyle"), + ("STYLE_SGI", "qsgistyle.h", "QSGIStyle"), + ("STYLE_WINDOWSXP", "qwindowsxpstyle.h", "QWindowsXPStyle"), + ("STYLE_WINDOWS", "qwindowsstyle.h", "QWindowsStyle")] + + f = open(name, "a") + + for (feat, incfile, cname) in plugins: + if not check_plugin(cname, incfile): + f.write("-x Qt_%s\n" % feat) + disabled_classes.append(cname) + + f.close() + + +def get_feature_flags(): + """Return the list of SIP flags that exclude unsupported Qt features. + """ + featfile = "features" + + # Create the features file if it doesn't exist and we are not keeping it. + if opt_keepfeatures and os.access(featfile,os.F_OK): + sipconfig.inform("Using existing features file.") + else: + sipconfig.inform("Creating features file...") + create_features_file(featfile) + + # Parse the features file. + ff = open(featfile, "r") + + flags = [] + + line = ff.readline() + while line: + flags.extend(string.split(line)) + line = ff.readline() + + if sipcfg.sip_version >= 0x040702: + flags.extend(['-x', 'Qt_SIP_PRE_4_7_2']) + + return flags + + +def set_sip_flags(): + """Set the SIP platform, version and feature flags. + """ + qt_sip_flags.extend(pyqt.sip_flags()) + + # If we don't check for signed interpreters, we exclude the 'VendorID' + # feature + if not opt_vendorcheck: + qt_sip_flags.append("-x") + qt_sip_flags.append("VendorID") + + # Handle the platform tag. + if opt_qtpetag: + plattag = "WS_QWS" + elif sys.platform == "win32": + plattag = "WS_WIN" + elif sys.platform == "darwin": + if "__DARWIN_X11__" in sipcfg.build_macros()["DEFINES"]: + plattag = "WS_X11" + else: + plattag = "WS_MACX" + else: + plattag = "WS_X11" + + qt_sip_flags.append("-t") + qt_sip_flags.append(plattag) + + # Handle the Qt version tag. + verstag = sipconfig.version_to_sip_tag(qt_version, pyqt.qt_version_tags(), "Qt") + + if verstag: + qt_sip_flags.append("-t") + qt_sip_flags.append(verstag) + + # The flags so far are common. + for f in qt_sip_flags: + qtext_sip_flags.append(f) + qtpe_sip_flags.append(f) + + # Handle the QScintilla version tag. + if qsci_version: + qscitags = { + 0x010100: None, + 0x010200: "QScintilla_1_1", + 0x010300: "QScintilla_1_2", + 0x010400: "QScintilla_1_3", + 0x010500: "QScintilla_1_4", + 0x010600: "QScintilla_1_5", + 0x010700: "QScintilla_1_6", + 0x020000: "QScintilla_1_7" + } + + verstag = sipconfig.version_to_sip_tag(qsci_version, qscitags, "QScintilla") + + if verstag: + qtext_sip_flags.append("-t") + qtext_sip_flags.append(verstag) + + # Handle the Qtopia tag. + if opt_qtpetag: + qtpe_sip_flags.append("-t") + qtpe_sip_flags.append(opt_qtpetag) + + +def generate_code(mname, extra_cflags=None, extra_cxxflags=None, extra_define=None, extra_include_dirs=None, extra_lflags=None, extra_lib_dir=None, extra_libs=None, opengl=0, sip_flags=None): + """Generate the code for a module. + + mname is the name of the module. + extra_cflags is a string containing additional C compiler flags. + extra_cxxflags is a string containing additional C++ compiler flags. + extra_define is a name to add to the list of preprocessor defines. + extra_include_dirs is a list of directories to add to the list of include + directories. + extra_lflags is a string containing additional linker flags. + extra_lib_dir is the name of a directory to add to the list of library + directories. + extra_libs is a list of the names of extra libraries to add to the list of + libraries. + opengl is set if the module needs OpenGL support. + sip_flags is the list of sip flags to use instead of the defaults. + """ + sipconfig.inform("Generating the C++ source for the %s module..." % mname) + + try: + shutil.rmtree(mname) + except: + pass + + try: + os.mkdir(mname) + except: + sipconfig.error("Unable to create the %s directory." % mname) + + # Build the SIP command line. + argv = ['"' + sipcfg.sip_bin + '"'] + + if sip_flags is None: + sip_flags = qt_sip_flags + + argv.extend(sip_flags) + + if opt_concat: + argv.append("-j") + argv.append(str(opt_split)) + + if opt_tracing: + argv.append("-r") + + argv.append("-c") + argv.append(mname) + + buildfile = os.path.join(mname, mname + ".sbf") + argv.append("-b") + argv.append(buildfile) + + argv.append("-I") + argv.append(os.path.join(src_dir, "sip")) + + # SIP assumes POSIX style path separators. + argv.append(string.join([src_dir, "sip", mname, mname + "mod.sip"], "/")) + + os.system(string.join(argv)) + + # Check the result. + if not os.access(buildfile, os.F_OK): + sipconfig.error("Unable to create the C++ code.") + + # Generate the Makefile. + sipconfig.inform("Creating the Makefile for the %s module..." % mname) + + installs = [] + sipfiles = [] + + for s in glob.glob("sip/" + mname + "/*.sip"): + sipfiles.append(os.path.join(src_dir, "sip", mname, os.path.basename(s))) + + installs.append([sipfiles, os.path.join(pyqt.sip_dir(), mname)]) + + makefile = sipconfig.SIPModuleMakefile( + configuration=sipcfg, + build_file=mname + ".sbf", + dir=mname, + install_dir=pyqt.module_dir(), + installs=installs, + qt=1, + opengl=opengl, + warnings=1, + static=opt_static, + debug=opt_debug + ) + + if extra_cflags: + makefile.extra_cflags.append(extra_cflags) + + if extra_cxxflags: + makefile.extra_cxxflags.append(extra_cxxflags) + + if extra_define: + makefile.extra_defines.append(extra_define) + + if extra_include_dirs: + makefile.extra_include_dirs.extend(extra_include_dirs) + + if extra_lflags: + makefile.extra_lflags.append(extra_lflags) + + if extra_lib_dir: + makefile.extra_lib_dirs.append(extra_lib_dir) + + if extra_libs: + makefile.extra_libs.extend(extra_libs) + + makefile.generate() + + +def check_license(): + """Handle the validation of the PyQt license. + """ + try: + import license + ltype = license.LicenseType + lname = license.LicenseName + + try: + lfile = license.LicenseFile + except AttributeError: + lfile = None + except ImportError: + ltype = None + + if ltype is None: + ltype = "GPL" + lname = "GNU General Public License" + lfile = None + + sipconfig.inform("This is the %s version of PyQt %s (licensed under the %s) for Python %s on %s." % (ltype, pyqt_version_str, lname, string.split(sys.version)[0], sys.platform)) + + # Common checks. + if ltype == "GPL" and sys.platform == "win32": + error("You cannot use the GPL version of PyQt under Windows.") + + try: + qted = qt_edition + except AttributeError: + qted = None + + if qted and ltype != "internal": + if (qted == "free" and ltype != "GPL") or (qted != "free" and ltype == "GPL"): + sipconfig.error("This version of PyQt and the %s edition of Qt have incompatible licenses." % qted) + + # Confirm the license. + sys.stdout.write(""" +Type 'L' to view the license. +Type 'yes' to accept the terms of the license. +Type 'no' to decline the terms of the license. + +""") + + while 1: + try: + resp = raw_input("Do you accept the terms of the license? ") + except: + resp = "" + + resp = string.lower(string.strip(resp)) + + if resp == "yes": + break + + if resp == "no": + sys.exit(0) + + if resp == "l": + os.system("more LICENSE") + + # If there should be a license file then check it is where it should be. + if lfile: + if os.access(os.path.join("sip", lfile), os.F_OK): + sipconfig.inform("Found the license file %s." % lfile) + else: + sipconfig.error("Please copy the license file %s to the sip directory." % lfile) + + +def get_build_macros(overrides): + """Return the dictionary of platform specific build macros from the Qt + installation. Return None if any of the overrides was invalid. + + overrides is a list of macros overrides from the user. + """ + # Get the name of the qmake configuration file to take the macros from. + if "QMAKESPEC" in os.environ.keys(): + fname = os.path.join(qt_dir, "mkspecs", os.environ["QMAKESPEC"], "qmake.conf") + else: + fname = os.path.join(qt_dir, "mkspecs", "default", "qmake.conf") + + if not os.access(fname, os.F_OK): + sipconfig.error("Unable to find the default configuration file %s. You can use the QMAKESPEC environment variable to specify the correct platform instead of \"default\"." % fname) + + # Add the Qt specific macros to the default. + names = sipcfg.build_macros().keys() + names.append("INCDIR_QT") + names.append("LIBDIR_QT") + names.append("MOC") + + # Make sure $QTDIR reflects any directory passed on the command line. + os.environ["QTDIR"] = qt_dir + + properties = { + "QT_INSTALL_BINS": os.path.join(qt_dir, "bin"), + "QT_INSTALL_HEADERS": os.path.join(qt_dir, "include"), + "QT_INSTALL_LIBS": os.path.join(qt_dir, "lib") + } + + return sipconfig.parse_build_macros(fname, names, overrides, properties) + + +def check_qt_installation(macros): + """Check the Qt installation and get the version number and edition. + + macros is the dictionary of build macros. + """ + # Get the Makefile generator. + generator = macros["MAKEFILE_GENERATOR"] + + # Set the Qt include and lib directories. + global qt_incdir, qt_libdir + + qt_incdir = macros["INCDIR_QT"] + + if not qt_incdir: + qt_incdir = os.path.join(qt_dir, "include") + macros["INCDIR_QT"] = qt_incdir + + qt_libdir = macros["LIBDIR_QT"] + + if not qt_libdir: + qt_libdir = os.path.join(qt_dir, "lib") + macros["LIBDIR_QT"] = qt_libdir + + # Check the Qt header files have been installed. Quietly check for Qt v4. + qt4_d = os.path.join(qt_incdir, "QtCore") + + qglobal = os.path.join(qt4_d, "qglobal.h") + + if not os.access(qglobal, os.F_OK): + qglobal = os.path.join(qt_incdir, "qglobal.h") + + if not os.access(qglobal, os.F_OK): + sipconfig.error("qglobal.h could not be found in %s." % qt_incdir) + + # Get the Qt version number. + global qt_version + + qt_version, ignore = sipconfig.read_version(qglobal, "Qt", "QT_VERSION") + + # Early versions of Qt for the Mac didn't include everything. Rather than + # maintain these in the future we just mandate a later version. + if sys.platform == "darwin" and qt_version < 0x030100: + sipconfig.error("PyQt for MacOS/X requires Qt v3.1.0 or later.") + + # The way SIP v4.2 and later handle connections between signals and Python + # slots only works with Qt v3 and later. Therefore Qt v2 and earlier needs + # SIP v3. + if qt_version < 0x030000: + sipconfig.error("Qt v2.x and earlier require SIP v3.x.") + + if qt_version >= 0x040000: + sipconfig.error("Qt v4.x requires PyQt v4.x.") + + # Try and work out which edition it is. + global qt_edition + + if qt_version >= 0x030000: + if opt_qconfigdir: + qconfigdir = opt_qconfigdir + else: + qconfigdir = qt_incdir + + qconfig = os.path.join(qconfigdir, "qconfig.h") + + if not os.access(qconfig,os.F_OK): + sipconfig.error("qconfig.h could not be found in %s." % qconfigdir) + + f = open(qconfig) + l = f.readline() + + while l: + wl = string.split(l) + if len(wl) == 3 and wl[0] == "#define" and wl[1] == "QT_PRODUCT_LICENSE": + qt_edition = wl[2][4:-1] + break + + l = f.readline() + + f.close() + + if not qt_edition: + sipconfig.error("The Qt edition could not be determined by parsing %s." % qconfig) + elif qt_version == 0x020300 and sys.platform == "win32": + # See if we have the Qt v2 non-commercial version. + if os.access(os.path.join(qt_libdir, "qt-mt230nc.lib"), os.F_OK): + qt_edition = "non-commercial" + + if sys.platform == "win32": + # Work out how Qt was built on Windows. + + global qt_winconfig + + try: + f = open(os.path.join(qt_dir, ".qtwinconfig"), "r") + except IOError: + f = None + + if f: + cfg = f.readline() + f.close() + + val = string.find(cfg, "=") + + if val >= 0: + qt_winconfig = string.strip(cfg[val + 1:]) + else: + # Assume it was built as a DLL. + qt_winconfig = "shared" + + # Determine the Qt library to link against and if it has thread support. + global qt_threaded + + resolve_qt3_library(generator) + + if opt_qtlib in ("qt-mt", "qt-mtedu", "qt-mteval", "qte-mt", "qtmt", "qtmtedu", "qtmteval"): + qt_threaded = 1 + + global pyqt + + pyqt = ConfigurePyQt3() + + # We haven't yet factored out sipconfig's knowledge of how to build Qt + # binaries and it is expecting to find these in the configuration when it + # generates the Makefiles. + sipcfg.qt_version = qt_version + sipcfg.qt_edition = qt_edition + sipcfg.qt_winconfig = qt_winconfig + sipcfg.qt_framework = 0 + sipcfg.qt_threaded = qt_threaded + sipcfg.qt_dir = qt_dir + sipcfg.qt_lib = opt_qtlib + sipcfg.qt_lib_dir = qt_libdir + + +def resolve_qt3_library(generator): + """See which version of the Qt v3 library can be found. (We can't trust + the configuration files.) + + generator is the name of the Makefile generator. + """ + global opt_qtlib + + if opt_qtlib: + if not is_qt_library(generator, opt_qtlib): + sipconfig.error("The %s Qt library could not be found in %s." % (opt_qtlib, qt_libdir)) + else: + stlib = is_qt_library(generator, "qt") + mtlib = is_qt_library(generator, "qt-mt") + edlib = is_qt_library(generator, "qt-mtedu") + evlib = is_qt_library(generator, "qt-mteval") + emlib = is_qt_library(generator, "qte") + etlib = is_qt_library(generator, "qte-mt") + + # Borland likes to be a little different. + bmtlib = is_qt_library(generator, "qtmt") + bedlib = is_qt_library(generator, "qtmtedu") + bevlib = is_qt_library(generator, "qtmteval") + + names = [] + + if stlib: + opt_qtlib = "qt" + names.append(opt_qtlib) + + if mtlib: + opt_qtlib = "qt-mt" + names.append(opt_qtlib) + + if edlib: + opt_qtlib = "qt-mtedu" + names.append(opt_qtlib) + + if evlib: + opt_qtlib = "qt-mteval" + names.append(opt_qtlib) + + if emlib: + opt_qtlib = "qte" + names.append(opt_qtlib) + + if etlib: + opt_qtlib = "qte-mt" + names.append(opt_qtlib) + + if bmtlib: + opt_qtlib = "qtmt" + names.append(opt_qtlib) + + if bedlib: + opt_qtlib = "qtmtedu" + names.append(opt_qtlib) + + if bevlib: + opt_qtlib = "qtmteval" + names.append(opt_qtlib) + + if not names: + sipconfig.error("No Qt libraries could be found in %s." % qt_libdir) + + if len(names) > 1: + sipconfig.error("These Qt libraries were found: %s. Use the -y argument to explicitly specify which you want to use." % string.join(names)) + + +def is_qt_library(generator, lib): + """See if a particular Qt library is installed. + + generator is the name of the Makefile generator. + lib is the name of the library. + """ + if generator in ("MSVC", "MSVC.NET", "BMAKE"): + lpatts = [lib + "[0-9]*.lib", lib + ".lib"] + else: + lpatts = ["lib" + lib + ".*"] + + for lpatt in lpatts: + lmatch = glob.glob(os.path.join(qt_libdir, lpatt)) + + if lmatch: + return lmatch + + return [] + + +def main(argv): + """Create the configuration module module. + + argv is the list of command line arguments. + """ + # Check Python isn't too new. + if sipcfg.py_version >= 0x030000: + sipconfig.error("PyQt v3.x does not support Python v3.x") + + # Check SIP is new enough. + if sipcfg.sip_version_str[:8] != "snapshot": + if sipcfg.sip_version < sip_min_version: + sipconfig.error("This version of PyQt requires SIP v%s or later" % sipconfig.version_to_string(sip_min_version)) + + # Parse the command line. + try: + optlist, args = getopt.getopt(argv[1:], "ha:b:cd:fg:ij:kl:m:n:o:q:rsuv:wy:") + except getopt.GetoptError: + usage() + + global qt_dir, opt_qtlib, opt_qconfigdir + global opt_pyqtbindir, opt_pyqtmoddir, opt_pyqtsipdir + global opt_qtpetag, opt_static, opt_debug, opt_concat + global opt_split, opt_tracing, opt_verbose, opt_keepfeatures + global opt_qsciincdir, opt_qscilibdir, qsci_define + global opt_vendorcheck, opt_vendincdir, opt_vendlibdir + + for opt, arg in optlist: + if opt == "-h": + usage(0) + elif opt == "-a": + opt_qtpetag = arg + elif opt == "-b": + opt_pyqtbindir = os.path.abspath(arg) + elif opt == "-c": + opt_concat = 1 + elif opt == "-d": + opt_pyqtmoddir = os.path.abspath(arg) + elif opt == "-f": + opt_keepfeatures = 1 + elif opt == "-g": + opt_qconfigdir = os.path.abspath(arg) + elif opt == "-i": + opt_vendorcheck = 1 + elif opt == "-j": + try: + opt_split = int(arg) + except: + usage() + elif opt == "-k": + opt_static = 1 + elif opt == "-l": + opt_vendincdir = arg + elif opt == "-m": + opt_vendlibdir = arg + elif opt == "-n": + opt_qsciincdir = arg + elif opt == "-o": + opt_qscilibdir = arg + elif opt == "-q": + qt_dir = os.path.abspath(arg) + elif opt == "-r": + opt_tracing = 1 + elif opt == "-s": + qsci_define = "" + elif opt == "-u": + opt_debug = 1 + elif opt == "-v": + opt_pyqtsipdir = os.path.abspath(arg) + elif opt == "-w": + opt_verbose = 1 + elif opt == "-y": + if arg in ("qt", "qt-mt", "qt-mtedu", "qt-mteval", "qte", "qte-mt", "qtmt", "qtmtedu"): + opt_qtlib = arg + else: + usage() + + # Check that we know the name of the Qt root directory. + if not qt_dir: + sipconfig.error("A Qt installation could not be found. Use use the -q argument or the QTDIR environment variable to explicitly specify the correct directory.") + + # When building static libraries, signed interpreter checking makes no + # sense. + if opt_vendorcheck and opt_static: + sipconfig.error("Using the VendorID package when building static libraries makes no sense.") + + # Replace the existing build macros with the ones from the Qt installation. + macros = get_build_macros(args) + + if macros is None: + usage() + + sipcfg.set_build_macros(macros) + + # Check Qt is what we need. + check_qt_installation(macros) + + # Check the licenses are compatible. + check_license() + + # Check for QScintilla. + check_qscintilla() + + # Check which modules to build. + qtmod_lib = pyqt.check_modules() + + # Check for the VendorID package. + check_vendorid() + + # Set the SIP platform, version and feature flags. + set_sip_flags() + + # Tell the user what's been found. + inform_user() + + # Generate the code. + + extra_include_dirs = [] + extra_libs = [] + + if qtmod_lib: + extra_libs.append(qtmod_lib) + + if opt_vendorcheck: + extra_include_dirs.append(opt_vendincdir) + extra_lib_dir = opt_vendlibdir + extra_libs.append("vendorid") + else: + extra_lib_dir = None + + pyqt.code(extra_include_dirs, extra_lib_dir, extra_libs) + + # Create the additional Makefiles. + sipconfig.inform("Creating top level Makefile...") + + sipconfig.ParentMakefile( + configuration=sipcfg, + subdirs=pyqt_modules + pyqt.tools(), + installs=(pyqt.module_installs(), pyqt.module_dir()) + ).generate() + + # Install the configuration module. + create_config("pyqtconfig.py", os.path.join(src_dir, "pyqtconfig.py.in"), macros) + + +############################################################################### +# The script starts here. +############################################################################### + +if __name__ == "__main__": + try: + main(sys.argv) + except SystemExit: + raise + except: + sys.stderr.write( +"""An internal error occured. Please report all the output from the program, +including the following traceback, to support@riverbankcomputing.co.uk. +""") + raise |