# This script generates the PyQt configuration and generates the Makefiles. # # Copyright (c) 2006 # Riverbank Computing Limited # # 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 sipconfig # Initialise the globals. pyqt_version = 0x040101 pyqt_version_str = "4.1.1" sip_min_version = 0x040501 qt_version = 0 qt_edition = "" qt_dir = None qt_incdir = None qt_libdir = None qt_bindir = None qt_datadir = None qt_xfeatures = None qt_winconfig = "" qt_lib = None qt_framework = 0 qt_sip_flags = [] pyqt_modules = [] # Get the SIP configuration. sipcfg = sipconfig.Configuration() # Command line options. opt_qmake = None opt_pyqtbindir = sipcfg.default_bin_dir opt_pyqtmoddir = os.path.join(sipcfg.default_mod_dir, "PyQt4") opt_pyqtsipdir = os.path.join(sipcfg.default_sip_dir, "PyQt4") opt_static = 0 opt_debug = 0 opt_concat = 0 opt_split = 1 opt_tracing = 0 opt_verbose = 0 opt_api = 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 opt_qmake: def_qmake = opt_qmake else: def_qmake = "none" print "Usage:" print " python configure.py [-h] [-a] [-b dir] [-c] [-d dir] [-i] [-j #] [-k] [-l dir] [-m dir] [-q exe] [-r] [-u] [-v dir] [-w] option=value option+=value ..." print "where:" print " -h display this help message" print " -a install the PyQt API file for QScintilla [default only if QScintilla installed]" print " -b dir where pyuic4, pyrcc4 and pylupdate4 will be installed [default %s]" % opt_pyqtbindir print " -c concatenate each module's C++ source files" print " -d dir where the PyQt4 modules will be installed [default %s]" % opt_pyqtmoddir print " -i enable checking of signed interpreters using the VendorID package [default disabled]" print " -j n split the concatenated C++ source files into n pieces [default 1]" print " -k build the PyQt4 modules as static libraries" print " -l dir the directory containing the VendorID header file [default %s]" % opt_vendincdir print " -m dir the directory containing the VendorID library [default %s]" % opt_vendlibdir print " -q exe the pathname of qmake [default %s]" % def_qmake print " -r generate code with tracing enabled [default disabled]" print " -u build with debugging symbols" print " -v dir where the PyQt4 .sip files will be installed [default %s]" % opt_pyqtsipdir print " -w don't suppress compiler output during configuration" sys.exit(rcode) class ConfigurePyQt4: """This class defines the methods to configure PyQt4. """ def qt_version_tags(self): """Get the versions tags for the configuration. Returns a dictionary of versions and corresponding tags. """ return { 0x040101: None, 0x040102: "Qt_4_1_1", 0x040103: "Qt_4_1_2", 0x040200: "Qt_4_1_3", 0x040202: "Qt_4_2_0", 0x050000: "Qt_4_2_2" } def check_modules(self): pyqt_modules.append("QtCore") check_module("QtGui", "qwidget.h", "new QWidget()") check_module("QtNetwork", "qhostaddress.h", "new QHostAddress()") check_module("QtOpenGL", "qgl.h", "new QGLWidget()") check_module("QtSql", "qsqldatabase.h", "new QSqlDatabase()") check_module("QtSvg", "qsvgwidget.h", "new QSvgWidget()") check_module("QtTest", "QtTest", "QTest::qSleep(0)") check_module("QtXml", "qdom.h", "new QDomDocument()") check_module("QtAssistant", "qassistantclient.h", "new QAssistantClient(\"foo\")") check_module("QAxContainer", "qaxobject.h", "new QAxObject()", "QAxContainer") def code(self): # Note that the order of the dependent modules is important. if opt_vendorcheck: generate_code("QtCore", ["QtCore"], opt_vendincdir, opt_vendlibdir, "vendorid") else: generate_code("QtCore", ["QtCore"]) if "QtGui" in pyqt_modules: generate_code("QtGui", ["QtGui", "QtCore"]) if "QtNetwork" in pyqt_modules: generate_code("QtNetwork", ["QtNetwork", "QtCore"]) if "QtOpenGL" in pyqt_modules: generate_code("QtOpenGL", ["QtOpenGL", "QtGui", "QtCore"]) if "QtSvg" in pyqt_modules: generate_code("QtSvg", ["QtSvg", "QtGui", "QtCore"]) if "QtSql" in pyqt_modules: generate_code("QtSql", ["QtSql", "QtGui", "QtCore"]) if "QtTest" in pyqt_modules: generate_code("QtTest", ["QtTest", "QtGui", "QtCore"]) if "QtXml" in pyqt_modules: generate_code("QtXml", ["QtXml", "QtCore"]) if "QtAssistant" in pyqt_modules: generate_code("QtAssistant", ["QtAssistant", "QtNetwork", "QtGui", "QtCore"]) if "QAxContainer" in pyqt_modules: generate_code("QAxContainer", ["QAxContainer", "QtGui", "QtCore"]) # Generate the consolidated module. sipconfig.inform("Creating Qt consolidated module...") f = open("Qt.py", "w") for m in pyqt_modules: f.write("from PyQt4.%s import *\n" % m) f.close() # Generate the QScintilla API file. sipconfig.inform("Creating QScintilla API file...") f = open("PyQt4.api", "w") for m in pyqt_modules: api = open(m + ".api") for l in api: f.write("PyQt4." + l) api.close() os.remove(m + ".api") f.close() def module_installs(self): return ["__init__.py", "Qt.py", "pyqtconfig.py"] def tools(self): tool = [] # Only include ElementTree for older versions of Python. if sipcfg.py_version < 0x020500: sipconfig.inform("Creating elementtree Makefile...") makefile = sipconfig.PythonModuleMakefile( configuration=sipcfg, dstdir=os.path.join(opt_pyqtmoddir, "elementtree"), dir="elementtree" ) makefile.generate() tool.append("elementtree") # Create the pyuic4 wrapper. Use the GUI version on MacOS (so that # previews work properly and normal console use will work anyway), but # not on Windows (so that normal console use will work). sipconfig.inform("Creating pyuic4 wrapper...") uicdir=os.path.join(opt_pyqtmoddir, "uic") wrapper = sipconfig.create_wrapper(os.path.join(uicdir, "pyuic.py"), os.path.join("pyuic", "pyuic4"), (sys.platform == "darwin")) sipconfig.inform("Creating pyuic4 Makefile...") makefile = sipconfig.PythonModuleMakefile( configuration=sipcfg, dstdir=uicdir, srcdir="uic", dir="pyuic", installs=[[os.path.basename(wrapper), opt_pyqtbindir]] ) makefile.generate() tool.append("pyuic") if "QtXml" in pyqt_modules: sipconfig.inform("Creating pylupdate4 Makefile...") makefile = sipconfig.ProgramMakefile( configuration=sipcfg, build_file="pylupdate.sbf", dir="pylupdate", install_dir=opt_pyqtbindir, console=1, qt=["QtCore", "QtGui", "QtXml"], debug=opt_debug, warnings=1 ) makefile.generate() tool.append("pylupdate") sipconfig.inform("Creating pyrcc4 Makefile...") makefile = sipconfig.ProgramMakefile( configuration=sipcfg, build_file="pyrcc.sbf", dir="pyrcc", install_dir=opt_pyqtbindir, console=1, qt=["QtCore", "QtXml"], debug=opt_debug, warnings=1 ) makefile.generate() tool.append("pyrcc") else: sipconfig.inform("pylupdate4 and pyrcc4 will not be built because the Qt XML module is missing.") return tool 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)) if sys.platform == "darwin" and qt_framework: sipconfig.inform("Qt is built as a framework.") sipconfig.inform("SIP %s is being used." % sipcfg.sip_version_str) sipconfig.inform("The Qt header files are in %s." % qt_incdir) sipconfig.inform("The %s Qt library is in %s." % (qt_lib, qt_libdir)) sipconfig.inform("The Qt binaries are in %s." % qt_bindir) sipconfig.inform("The Qt mkspecs directory is in %s." % qt_datadir) sipconfig.inform("These PyQt modules will be built: %s." % string.join(pyqt_modules)) 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("pyuic4, pyrcc4 and pylupdate4 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_sip_flags": qt_sip_flags, "qt_version": qt_version, "qt_edition": qt_edition, "qt_winconfig": qt_winconfig, "qt_framework": qt_framework, "qt_threaded": 1, "qt_dir": qt_dir, "qt_data_dir": qt_datadir, "qt_inc_dir": qt_incdir, "qt_lib_dir": qt_libdir } sipconfig.create_config_module(module, template, content, macros) def run_command(cmd): """Run a command and display the output if verbose mode is enabled. cmd is the command to run. """ if opt_verbose: sys.stdout.write(cmd + "\n") fin, fout = os.popen4(cmd) # Read stdout and stderr until there is no more output. lout = fout.readline() while lout: if opt_verbose: sys.stdout.write(lout) lout = fout.readline() fin.close() fout.close() try: os.wait() except: pass def remove_file(fname): """Remove a file which may or may not exist. fname is the name of the file. """ try: os.remove(fname) except OSError: pass def compile_qt_program(name, mname, lib=None): """Compile a simple Qt application. name is the name of the single source file. mname is the name of the Qt module. lib is an optional extra library. Returns the name of the executable suitable for running or None if it wasn't created. """ opengl = (mname == "QtOpenGL") makefile = sipconfig.ProgramMakefile(sipcfg, console=1, qt=[mname], warnings=0, opengl=opengl, debug=opt_debug) if lib: makefile.extra_libs.append(lib) exe, build = makefile.build_command(name) # Make sure the executable file doesn't exist. remove_file(exe) run_command(build) if not os.access(exe, os.X_OK): return None if sys.platform != "win32": exe = "./" + exe return exe 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, test, lib=None): """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. test is a C++ statement being used for the test. lib is an optional extra library. """ # Check the module's main .sip file exists. if os.access(os.path.join("sip", mname, mname + "mod.sip"), os.F_OK): sipconfig.inform("Checking to see if the %s module should be built..." % mname) if check_api(incfile, test, mname, lib): pyqt_modules.append(mname) def check_api(incfile, test, mname, lib=None): """Return non-zero if a class is available. incfile is the name of the include file needed for the test. test is a C++ statement being used for the test. mname is the name of the module. lib is an optional extra library. """ # We use a module specific name to avoid a potential problem on Windows # where the operating system doesn't delete previous tests quickly enough. cfgtest = "cfgtest_%s.cpp" % mname f = open(cfgtest, "w") f.write("""#include <%s> int main(int, char **) { %s; } """ % (incfile, test)) f.close() return compile_qt_program(cfgtest, mname, lib) def set_sip_flags(pyqt): """Set the SIP platform, version and feature flags. pyqt is the configuration instance. """ # 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 sys.platform == "win32": plattag = "WS_WIN" elif sys.platform == "darwin": if "__USE_WS_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") # Handle any feature flags. for xf in qt_xfeatures: qt_sip_flags.append("-x") qt_sip_flags.append(xf) if verstag: qt_sip_flags.append("-t") qt_sip_flags.append(verstag) # Handle the version specific Python features. if sipcfg.py_version < 0x020400: qt_sip_flags.append("-x") qt_sip_flags.append("Py_DateTime") def generate_code(mname, qt_mods, extra_include_dir=None, extra_lib_dir=None, extra_lib=None): """Generate the code for a module. mname is the name of the module. qt_mods is the list of Qt modules that are needed. extra_include_dir is an optional directory to add to the list of include directories. extra_lib_dir is an optional directory to add to the list of library directories. extra_lib is an optional library to add to the list of libraries. """ 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 + '"'] argv.extend(qt_sip_flags) if opt_concat: argv.append("-j") argv.append(str(opt_split)) if opt_tracing: argv.append("-r") argv.append("-a") argv.append(mname + ".api") argv.append("-c") argv.append(mname) buildfile = os.path.join(mname, mname + ".sbf") argv.append("-b") argv.append(buildfile) argv.append("-I") argv.append("sip") # SIP assumes POSIX style path separators. argv.append(string.join(["sip", mname, mname + "mod.sip"], "/")) cmd = string.join(argv) if opt_verbose: sys.stdout.write(cmd + "\n") os.system(cmd) # 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("..", "sip", mname, os.path.basename(s))) installs.append([sipfiles, os.path.join(opt_pyqtsipdir, mname)]) opengl = (mname == "QtOpenGL") makefile = sipconfig.SIPModuleMakefile( configuration=sipcfg, build_file=mname + ".sbf", dir=mname, install_dir=opt_pyqtmoddir, installs=installs, qt=qt_mods, opengl=opengl, warnings=1, static=opt_static, debug=opt_debug ) if extra_include_dir: makefile.extra_include_dirs.append(extra_include_dir) if extra_lib_dir: makefile.extra_lib_dirs.append(extra_lib_dir) if extra_lib: makefile.extra_libs.append(extra_lib) 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. 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. print print "Type 'L' to view the license." print "Type 'yes' to accept the terms of the license." print "Type 'no' to decline the terms of the license." print 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.environ["QMAKESPEC"] if not os.path.dirname(fname): fname = os.path.join(qt_datadir, "mkspecs", fname) elif sys.platform == "darwin": # The Qt Mac binary installer defaults to xcode which we don't want. fname = os.path.join(qt_datadir, "mkspecs", "macx-g++") else: fname = os.path.join(qt_datadir, "mkspecs", "default") fname = os.path.join(fname, "qmake.conf") if not os.access(fname, os.F_OK): sipconfig.error("Unable to find the qmake configuration file %s. Use the QMAKESPEC environment variable to specify the correct platform." % 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") properties = { "QT_INSTALL_BINS": qt_bindir, "QT_INSTALL_HEADERS": qt_incdir, "QT_INSTALL_LIBS": qt_libdir } return sipconfig.parse_build_macros(fname, names, overrides, properties) def qt_core_header(incdir, fname): """Find a QtCore header file. incdir is the directory expected to contain the file. fname is the base name of the file. Returns the full path of the file or None if it wasn't found. """ pn = os.path.join(incdir, fname) try: sbuf = os.stat(pn) except OSError: sbuf = None if sbuf: # In some Qt4 installations the public header files just have a single # line that #includes the real file in the src directory. Rather than # parse #include directives we just look at the size of the file and # assume it contains a #include if it seems too small to contain # anything useful. if sbuf.st_size < 100: sn = os.path.join(qt_dir, "src", "corelib", "global", fname) if os.access(sn, os.F_OK): pn = sn else: pn = None return pn def qt_inc_dir(qtmod): """Get the directory containing the header files for a particular Qt module. qtmod is the name of the Qt module. Returns the directory name. """ # QLibraryInfo doesn't report the correct directories when built as a # Darwin framework. if qt_framework: incdir = os.path.join(qt_libdir, qtmod + ".framework", "Headers") else: incdir = os.path.join(qt_incdir, qtmod) return incdir def check_qt_installation(macros): """Check the Qt installation and get the version number and edition and return the configuration instance. macros is the dictionary of build macros. """ # Work out how Qt was built on MacOS. if sys.platform == "darwin": if os.access(os.path.join(qt_libdir, "QtCore.framework"), os.F_OK): global qt_framework qt_framework = 1 # Get the Makefile generator. generator = macros["MAKEFILE_GENERATOR"] # Check the Qt header files have been installed. incdir = qt_inc_dir("QtCore") qglobal = qt_core_header(incdir, "qglobal.h") if not qglobal: sipconfig.error("qglobal.h could not be found in %s." % incdir) # Get the Qt version number. global qt_version qt_version, ignore = sipconfig.read_version(qglobal, "Qt", "QT_VERSION") if qt_version < 0x040100: sipconfig.error("PyQt v4 requires Qt v4.1.0 or later.") # Try and work out which edition it is. global qt_edition # See if it is the open source edition. qconfig = qt_core_header(incdir, "qconfig.h") if not qconfig: sipconfig.error("qconfig.h could not be found in %s." % incdir) f = open(qconfig) l = f.readline() while l: wl = string.split(l) if len(wl) == 3 and wl[0] == "#define": name_val = wl[1:] elif len(wl) == 4 and wl[0] == "#" and wl[1] == "define": name_val = wl[2:] else: name_val = None if name_val and name_val[0] == "QT_EDITION" and name_val[1] == "QT_EDITION_OPENSOURCE": qt_edition = "free" break l = f.readline() f.close() if not qt_edition: # Work out which commercial edition it is. if not os.access(qt_inc_dir("QtGui"), os.F_OK): qt_edition = "Console" elif not os.access(qt_inc_dir("QtXml"), os.F_OK): qt_edition = "Desktop Light" else: qt_edition = "Desktop" 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. resolve_qt4_library(generator) # 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 = qt_framework sipcfg.qt_threaded = 1 sipcfg.qt_dir = qt_dir sipcfg.qt_lib_dir = qt_libdir return ConfigurePyQt4() def resolve_qt4_library(generator): """Check that the Qt v4 library can be found. generator is the name of the Makefile generator. """ global qt_lib qt_lib = "QtCore" if opt_debug and sys.platform != "win32": # Qt v4.2 and later for X11 platforms doesn't have separate debug # libraries. if qt_version < 0x040200 or sys.platform == "darwin": qt_lib = qt_lib + "_debug" if not is_qt_library(generator, qt_lib): sipconfig.error("The %s Qt library could not be found in %s." % (qt_lib, qt_libdir)) 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"] elif generator == "MINGW": lpatts = ["lib" + lib + "[0-9]*.a"] elif sys.platform == "darwin" and qt_framework: lpatts = [lib + ".framework"] else: lpatts = ["lib" + lib + ".*"] for lpatt in lpatts: lmatch = glob.glob(os.path.join(qt_libdir, lpatt)) if lmatch: return lmatch return [] def get_qt_configuration(): """Set the qt_dir, qt_incdir, qt_libdir, qt_bindir, qt_datadir and qt_xfeatures globals for the Qt installation. """ sipconfig.inform("Determining the layout of your Qt installation...") if not opt_qmake: sipconfig.error("Make sure you have a working Qt v4 qmake on your PATH or use the -q argument to explicitly specify a working Qt v4 qmake.") # The file names we will use to get the directory information. app = "qtdirs" pro_file = app + ".pro" make_file = app + ".mk" make_target = "" cpp_file = app + ".cpp" out_file = app + ".out" qmake_args = "-o " + make_file if sys.platform == "win32": exe_file = os.path.join("release", app + ".exe") make_target = " release" elif sys.platform == "darwin": # The Qt binary installer has macx-xcode as the default. qmake_args = "-spec macx-g++ " + qmake_args exe_file = os.path.join(app + ".app", "Contents", "MacOS", app) else: exe_file = os.path.join(".", app) # Generate the qmake project file. f = open(pro_file, "w") f.write( """QT = core TARGET = %s SOURCES = %s """ % (app, cpp_file)) f.close() # Generate the source code. f = open(cpp_file, "w") f.write( """#include #include #include int main(int, char **) { QFile outf("%s"); if (!outf.open(QIODevice::WriteOnly|QIODevice::Truncate|QIODevice::Text)) return 1; QTextStream out(&outf); out << QLibraryInfo::location(QLibraryInfo::PrefixPath) << '\\n'; out << QLibraryInfo::location(QLibraryInfo::HeadersPath) << '\\n'; out << QLibraryInfo::location(QLibraryInfo::LibrariesPath) << '\\n'; out << QLibraryInfo::location(QLibraryInfo::BinariesPath) << '\\n'; out << QLibraryInfo::location(QLibraryInfo::DataPath) << '\\n'; #if defined(QT_NO_ACCESSIBILITY) out << "PyQt_Accessibility\\n"; #endif #if defined(QT_NO_SESSIONMANAGER) out << "PyQt_SessionManager\\n"; #endif #if defined(QT_NO_STATUSTIP) out << "PyQt_StatusTip\\n"; #endif #if defined(QT_NO_TOOLTIP) out << "PyQt_ToolTip\\n"; #endif #if defined(QT_NO_WHATSTHIS) out << "PyQt_WhatsThis\\n"; #endif #if !defined(QT3_SUPPORT) || QT_VERSION >= 0x040200 out << "PyQt_NoPrintRangeBug\\n"; #endif return 0; } """ % out_file) f.close() # Create the makefile, first making sure it doesn't already exist. remove_file(make_file) run_command("%s %s %s" % (opt_qmake, qmake_args, pro_file)) if not os.access(make_file, os.F_OK): sipconfig.error("%s failed to create a makefile. Make sure you have a working Qt v4 qmake on your PATH or use the -q argument to explicitly specify a working Qt v4 qmake." % opt_qmake) # Try and work out the name of make. if sipcfg.platform.startswith("win32-msvc"): make = "nmake" elif sipcfg.platform == "win32-borland": make = "bmake" elif sipcfg.platform == "win32-g++": make = "mingw32-make" else: make = "make" # Create the executable, first making sure it doesn't exist. remove_file(exe_file) run_command("%s -f %s%s" % (make, make_file, make_target)) if not os.access(exe_file, os.X_OK): sipconfig.error("Failed to create %s. Make sure you have a working Qt v4 qmake on your PATH or use the -q argument to explicitly specify a working Qt v4 qmake." % exe_file) # 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)) # Read the directories. f = open(out_file, "r") lines = f.read().strip().split("\n") f.close() global qt_dir, qt_incdir, qt_libdir, qt_bindir, qt_datadir, qt_xfeatures qt_dir = lines[0] qt_incdir = lines[1] qt_libdir = lines[2] qt_bindir = lines[3] qt_datadir = lines[4] qt_xfeatures = lines[5:] def main(argv): """Create the configuration module module. argv is the list of command line arguments. """ # 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)) # The process to find the Qt installation to use is driven by qmake, so # first try and find a default qmake, ie. the first on the path. try: path = os.environ["PATH"] except KeyError: path = "" if sys.platform == "win32": base_qmake = "qmake.exe" else: base_qmake = "qmake" global opt_qmake for d in path.split(os.pathsep): opt_qmake = os.path.join(os.path.abspath(d), base_qmake) if os.access(opt_qmake, os.X_OK): break else: opt_qmake = None # Parse the command line. try: optlist, args = getopt.getopt(argv[1:], "ahb:cd:g:ij:kl:m:q:ruv:w") except getopt.GetoptError: usage() global opt_pyqtbindir, opt_pyqtmoddir, opt_pyqtsipdir, opt_static global opt_debug, opt_concat, opt_split, opt_tracing, opt_verbose global opt_vendorcheck, opt_vendincdir, opt_vendlibdir, opt_api for opt, arg in optlist: if opt == "-h": usage(0) elif opt == "-a": opt_api = 1 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 == "-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 == "-q": opt_qmake = os.path.abspath(arg) elif opt == "-r": opt_tracing = 1 elif opt == "-u": opt_debug = 1 elif opt == "-v": opt_pyqtsipdir = os.path.abspath(arg) elif opt == "-w": opt_verbose = 1 # 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.") # Get the details of the Qt installation. get_qt_configuration() # 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. pyqt = check_qt_installation(macros) # Check the licenses are compatible. check_license() # Check which modules to build. pyqt.check_modules() # Check for the VendorID package. check_vendorid() # Set the SIP platform, version and feature flags. set_sip_flags(pyqt) # Tell the user what's been found. inform_user() # Generate the code. pyqt.code() # Create the additional Makefiles. sipconfig.inform("Creating top level Makefile...") installs=[(pyqt.module_installs(), opt_pyqtmoddir)] scidir = os.path.join(qt_datadir, "qsci") if opt_api or os.path.isdir(scidir): installs.append(("PyQt4.api", os.path.join(scidir, "api", "python"))) sipconfig.ParentMakefile( configuration=sipcfg, subdirs=pyqt_modules + pyqt.tools(), installs=installs ).generate() # Install the configuration module. create_config("pyqtconfig.py", "pyqtconfig.py.in", macros) ############################################################################### # The script starts here. ############################################################################### if __name__ == "__main__": try: main(sys.argv) except SystemExit: raise except: print \ """An internal error occured. Please report all the output from the program, including the following traceback, to support@riverbankcomputing.co.uk. """ raise