# Copyright (c) 2007
# Riverbank Computing Limited <info@riverbankcomputing.co.uk>
#
# This file is part of PyTQt.
#
# This copy of PyTQt 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.
#
# PyTQt 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
# PyTQt; see the file LICENSE. If not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# This is the build script for PyTQt. It should be run in the top level
# directory of the source distribution and by the Python interpreter for which
# it is being built. It uses either tqmake or tmake to do the hard work of
# generating the platform specific Makefiles.
import sys
import os
import glob
import tempfile
import shutil
import py_compile
import compileall
import string
# Get the SIP-TQt configuration.
try :
import sip_tqt_config
except :
print ( " Unable to import the sip_tqt_config module. Please make sure you have " )
print ( " SIP-TQt v3.9 or later installed. " )
sys . exit ( 1 )
config = sip_tqt_config . SIPConfig ( " PyTQt 3.18.1 " )
# Initialise the globals.
sipMajorVersion = config . sip_version >> 16
sciIncDir = config . tqt_inc_dir
sciLibDir = config . tqt_lib_dir
sciLib = None
sciVersion = None
binDir = config . default_bin_dir
modDir = config . default_mod_dir
sipDir = config . default_sip_dir
buildModules = [ " tqt " ]
tempBuildDir = None
catCppFiles = 0
catSplit = 1
qpeTag = None
trace = 0
releaseGIL = 0
def usage ( rcode = 2 ) :
""" Display a usage message and exit.
rcode is the return code passed back to the calling process .
"""
print ( " Usage: " )
print ( " %s [-h] [-a version] [-b dir] [-c] [-d dir] [-g] [-j #] [-n dir] [-o dir] [-r] [-v dir] " % sip_tqt_config . script ( ) )
print ( " where: " )
print ( " -h display this help message " )
print ( " -a tag explicitly enable the tqtpe module " )
print ( " -b dir where pyuic and pylupdate will be installed [default %s ] " % config . default_bin_dir )
print ( " -c concatenate each module ' s C++ source files " )
print ( " -d dir where the PyTQt modules will be installed [default %s ] " % config . default_mod_dir )
print ( " -g always release the GIL (SIP-TQt v3.x behaviour) " )
print ( " -j # split the concatenated C++ source files into # pieces [default 1] " )
print ( " -n dir the directory containing the TQScintilla header files [default %s ] " % config . tqt_inc_dir )
print ( " -o dir the directory containing the TQScintilla library [default %s ] " % config . tqt_lib_dir )
print ( " -r generate code with tracing enabled [default disabled] " )
print ( " -v dir where the PyTQt .sip files will be installed [default %s ] " % config . default_sip_dir )
sys . exit ( rcode )
def mkTempBuildDir ( olddir = None ) :
""" Create a temporary build directory for a console application called
tqttest , complete with patched Makefile . The global tempBuildDir is set to
the name of the directory . The temporary directory becomes the current
directory .
olddir is None if the directory should be created , otherwise it is deleted .
Returns the name of the previous current directory .
"""
global tempBuildDir
if olddir is None :
tempBuildDir = tempfile . mktemp ( )
try :
os . mkdir ( tempBuildDir )
except :
sip_tqt_config . error ( " Unable to create temporary directory. " )
prevdir = sip_tqt_config . push_dir ( tempBuildDir )
sip_tqt_config . copy_to_file ( " tqttest.pro.in " ,
""" TEMPLATE = app
TARGET = tqttest
CONFIG + = console warn_off @TEST_OPENGL @ @BLX_CONFIG_APP @
INCLUDEPATH = @BLX_INCLUDEPATH @ @TEST_TQSCINTILLA_INC @
DEFINES = @BLX_DEFINES @
SOURCES = tqttest . cpp
LIBS + = @TEST_TQUI_LIB @ @TEST_TQSCINTILLA_LIB @
""" )
# Disable OpenGL, tqui and TQScintilla support by default.
config . patches [ " @TEST_OPENGL@ " ] = " "
config . patches [ " @TEST_TQUI_LIB@ " ] = " "
config . patches [ " @TEST_TQSCINTILLA_INC@ " ] = " "
config . patches [ " @TEST_TQSCINTILLA_LIB@ " ] = " "
# Create a dummy source file to suppress a tqmake warning.
sip_tqt_config . copy_to_file ( " tqttest.cpp " , " " )
config . create_makefile ( " tqttest.pro " )
else :
sip_tqt_config . pop_dir ( olddir )
prevdir = None
shutil . rmtree ( tempBuildDir , 1 )
return prevdir
def tryModule ( maindir , mname , incfile , ctor ) :
""" See if a PyTQt module should be built and update the buildModules list
accordingly .
maindir is the directory containing this script .
mname is the name of the PyTQt module .
incfile is the C + + header file that defines the class being used for the
test .
ctor is the constructor of the class being used for the test .
"""
# Check for the existence of the module .sip file.
msip = os . path . join ( maindir , " sip " , mname , mname + " mod.sip " )
if not os . access ( msip , os . F_OK ) :
return
sip_tqt_config . copy_to_file ( " tqttest.cpp " ,
""" #include < %s >
int main ( int argc , char * * argv )
{
new % s ;
}
""" % (incfile, ctor))
if sip_tqt_config . run_make ( None , 0 ) == 0 :
buildModules . append ( mname )
sip_tqt_config . inform ( " The %s module will be built. " % mname )
else :
sip_tqt_config . inform ( " The %s module will not be built. " % mname )
sip_tqt_config . run_make ( " clean " )
def checkTQScintilla ( ) :
""" See if TQScintilla can be found and what its version is.
"""
# Find the TQScintilla header files.
sciglobal = os . path . join ( sciIncDir , " tqextscintillaglobal.h " )
if os . access ( sciglobal , os . F_OK ) :
config . patches [ " @PYTQT_TQSCINTILLA_INC@ " ] = sciIncDir
sip_tqt_config . inform ( " %s contains tqextscintillaglobal.h. " % ( sciIncDir ) )
# Get the TQScintilla version number.
global sciVersion
sciVersion , sciversstr = sip_tqt_config . read_version ( sciglobal , " TQScintilla " , " TQSCINTILLA_VERSION " , " TQSCINTILLA_VERSION_STR " )
sip_tqt_config . inform ( " TQScintilla %s is being used. " % ( sciversstr ) )
# If we find a snapshot then set the version number to 0 as a special
# case.
if sciversstr [ : 8 ] == " snapshot " :
sciVersion = 0
# Find the TQScintilla library.
if sys . platform == " win32 " :
lpatt = " tqscintilla.lib "
else :
lpatt = " libtqscintilla.* "
if len ( glob . glob ( os . path . join ( sciLibDir , lpatt ) ) ) :
sip_tqt_config . inform ( " %s contains the TQScintilla library. " % sciLibDir )
global sciLib
if sys . platform == " win32 " :
sciLib = sip_tqt_config . escape ( os . path . join ( sciLibDir , " tqscintilla.lib " ) )
else :
sciLib = sip_tqt_config . escape ( " -L " + sciLibDir ) + " -ltqscintilla "
config . patches [ " @PYTQT_TQSCINTILLA_LIB@ " ] = sciLib
else :
sip_tqt_config . inform ( " The TQScintilla library could not be found in %s and so the tqtext module will not be built. If TQScintilla is installed then use the -o argument to explicitly specify the correct directory. " % ( sciLibDir ) )
sciVersion = - 1
else :
sip_tqt_config . inform ( " tqextscintillaglobal.h could not be found in %s and so the tqtext module will not be built. If TQScintilla is installed then use the -n argument to explicitly specify the correct directory. " % sciIncDir )
sciVersion = - 1
def moduleChecks ( maindir ) :
""" See which PyTQt modules to build.
"""
sip_tqt_config . inform ( " Checking which additional PyTQt modules to build. " ) ;
tryModule ( maindir , " tqtcanvas " , " tqcanvas.h " , " TQCanvas() " )
tryModule ( maindir , " tqtnetwork " , " tqsocket.h " , " TQSocket() " )
tryModule ( maindir , " tqttable " , " tqtable.h " , " TQTable() " )
tryModule ( maindir , " tqtxml " , " tqdom.h " , " TQDomImplementation() " )
tryModule ( maindir , " tqtsql " , " tqsql.h " , " TQSql() " )
# We need a different Makefile for the tqtgl module.
config . patches [ " @TEST_OPENGL@ " ] = " opengl "
config . create_makefile ( " tqttest.pro " )
tryModule ( maindir , " tqtgl " , " tqgl.h " , " TQGLWidget() " )
# Put things back.
config . patches [ " @TEST_OPENGL@ " ] = " "
config . create_makefile ( " tqttest.pro " )
# Check for the tqui library.
if sys . platform == " win32 " :
tquilib = r " $(TQTDIR) \ lib \ tqui.lib "
else :
tquilib = " -ltqui "
config . patches [ " @PYTQT_TQUI_LIB@ " ] = tquilib
config . patches [ " @TEST_TQUI_LIB@ " ] = tquilib
config . create_makefile ( " tqttest.pro " )
tryModule ( maindir , " tqtui " , " tqwidgetfactory.h " , " TQWidgetFactory() " )
# Put things back.
config . patches [ " @TEST_TQUI_LIB@ " ] = " "
config . create_makefile ( " tqttest.pro " )
# Check for the TQScintilla library.
if sciVersion > = 0 :
config . patches [ " @TEST_TQSCINTILLA_INC@ " ] = sciIncDir
config . patches [ " @TEST_TQSCINTILLA_LIB@ " ] = sciLib
config . create_makefile ( " tqttest.pro " )
tryModule ( maindir , " tqtext " , " tqextscintillabase.h " , " TQextScintillaBase() " )
# Put things back.
config . patches [ " @TEST_TQSCINTILLA_INC@ " ] = " "
config . patches [ " @TEST_TQSCINTILLA_LIB@ " ] = " "
config . create_makefile ( " tqttest.pro " )
def generateFeatures ( featfile ) :
""" Generate the header file describing the TQt features that are enabled if
it doesn ' t already exist. (If it already exists then we are probably cross
compiling and generated the file through other means . )
featfile is the name of the features file .
"""
if os . access ( featfile , os . F_OK ) :
sip_tqt_config . inform ( " Using existing features file. " )
return
sip_tqt_config . inform ( " Generating the features file. " )
# The features that a given TQt configuration may or may not support. Note
# that STYLE_WINDOWSXP requires special handling.
flist = [ " ACTION " , " CLIPBOARD " , " CODECS " , " COLORDIALOG " , " DATASTREAM " ,
" DIAL " , " DNS " , " DOM " , " DRAGANDDROP " , " ICONVIEW " , " IMAGE_TEXT " ,
" INPUTDIALOG " , " FILEDIALOG " , " FONTDATABASE " , " FONTDIALOG " ,
" MESSAGEBOX " , " MIMECLIPBOARD " , " NETWORKPROTOCOL " , " PICTURE " ,
" PRINTDIALOG " , " PRINTER " , " PROGRESSDIALOG " , " PROPERTIES " ,
" 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 ( " tqttest.cpp " , " w " )
# Escape the backslashes so that the name can be embedded in a C++ string.
ffstr = string . replace ( featfile , " \\ " , " \\ \\ " )
f . write (
""" #include <stdio.h>
#include <tqglobal.h>
#include <tqapplication.h>
int main ( int argc , char * * argv )
{
FILE * fp ;
TQApplication app ( argc , argv , 0 ) ;
if ( ( fp = fopen ( " %s " , " w " ) ) == NULL )
{
printf ( " Unable to create ' %s ' \\ n " ) ;
return 1 ;
}
#if !defined(TQT_THREAD_SUPPORT)
fprintf ( fp , " -x TQt_THREAD_SUPPORT \\ n " ) ;
#endif
#if (defined(Q_OS_WIN32) || defined(Q_OS_WIN64))
if ( tqWinVersion ( ) != TQt : : WV_XP )
fprintf ( fp , " -x TQt_STYLE_WINDOWSXP \\ n " ) ;
#endif
""" % (ffstr, ffstr))
for feat in flist :
f . write (
"""
#if defined(TQT_NO_%s)
fprintf ( fp , " -x TQt_ %s \\ n " ) ;
#endif
""" % (feat, feat))
f . write (
"""
fclose ( fp ) ;
return 0 ;
}
""" )
f . close ( )
sip_tqt_config . run_make ( )
sip_tqt_config . run_program ( os . path . join ( os . getcwd ( ) , " tqttest " ) )
sip_tqt_config . run_make ( " clean " )
sip_tqt_config . inform ( " Generated the features file. " )
def generateSource ( mname , plattag , tqttag , xtrtag ) :
""" Generate the C++ source code for a particular PyTQt module.
mname is the name of the module .
plattag is the SIP - TQt tag for the platform .
tqttag is the SIP - TQt tag for the TQt version .
xtrtag is an optional extra SIP - TQt tag .
"""
sip_tqt_config . inform ( " Generating the C++ source for the %s module. " % mname )
try :
shutil . rmtree ( mname )
except :
pass
try :
os . mkdir ( mname )
except :
sip_tqt_config . error ( " Unable to create the %s directory. " % mname )
pro = mname + " .pro "
argv = [ " -t " , plattag ,
" -t " , tqttag ,
" -z " , " features " ,
" -I " , " sip " ,
" -m " , mname + " / " + pro + " .in " ,
" -c " , mname ,
" sip/ " + mname + " / " + mname + " mod.sip " ]
if xtrtag :
argv . insert ( 0 , xtrtag )
argv . insert ( 0 , " -t " )
if trace :
argv . insert ( 0 , " -r " )
if releaseGIL :
argv . insert ( 0 , " -g " )
sip_tqt_config . run_program ( config . sip_bin , argv )
# Generate the Makefile.
sip_tqt_config . inform ( " Generating the Makefile for the %s module. " % mname )
olddir = sip_tqt_config . push_dir ( mname )
if catCppFiles :
sip_tqt_config . cat_source_files ( mname , catSplit )
config . create_makefile ( pro , mname )
icmds = [ ]
if sipMajorVersion == 3 :
icmds . append ( ( " copy " , mname + " .py " , modDir ) )
icmds . append ( ( " copy " , mname + " .pyc " , modDir ) )
config . add_install_target ( icmds )
if sipMajorVersion == 3 :
# Compile the Python part of the module.
pyname = mname + " .py "
sip_tqt_config . inform ( " Compiling %s . " % ( pyname ) )
py_compile . compile ( pyname )
sip_tqt_config . pop_dir ( olddir )
def versionToTag ( vers , tags , desc ) :
""" Convert a version number to a tag.
vers is the version number .
tags is the dictionary of tags keyed by version number .
desc is the descriptive name of the package .
Returns the corresponding tag .
"""
tag = None
vl = list ( tags . keys ( ) )
vl . sort ( )
# For a snapshot use the latest tag.
if vers == 0 :
tag = tags [ vl [ - 1 ] ]
else :
for v in vl :
if vers < v :
tag = tags [ v ]
break
if tag is None :
sip_tqt_config . error ( " Invalid %s version: 0x %06x . " % ( desc , vers ) )
return tag
def main ( argv ) :
""" The main function of the script.
argv is the list of command line arguments .
"""
import getopt
# Parse the command line.
try :
optlist , args = getopt . getopt ( argv [ 1 : ] , " ha:b:cd:gj:n:o:rv: " )
except getopt . GetoptError :
usage ( )
for opt , arg in optlist :
if opt == " -h " :
usage ( 0 )
elif opt == " -a " :
global tqpeTag
tqpeTag = arg
elif opt == " -b " :
global binDir
binDir = arg
elif opt == " -c " :
global catCppFiles
catCppFiles = 1
elif opt == " -d " :
global modDir
modDir = arg
elif opt == " -g " :
global releaseGIL
releaseGIL = 1
elif opt == " -j " :
global catSplit
try :
catSplit = int ( arg )
except :
catSplit = 0
if catSplit < 1 :
usage ( )
elif opt == " -n " :
global sciIncDir
sciIncDir = arg
elif opt == " -o " :
global sciLibDir
sciLibDir = arg
elif opt == " -r " :
global trace
trace = 1
elif opt == " -v " :
global sipDir
sipDir = arg
# Confirm the license.
sip_tqt_config . confirm_license ( )
# If there should be a license file then check it is where it should be.
if config . license_file :
if os . access ( os . path . join ( " sip " , config . license_file ) , os . F_OK ) :
sip_tqt_config . inform ( " Found the license file %s . \n " % config . license_file )
else :
sip_tqt_config . error ( " Please copy the license file %s to the sip directory. \n " % config . license_file )
# Check the TQt version.
if config . tqt_version == 0 :
sip_tqt_config . error ( " SIP-TQt has been built with TQt support disabled. \n " )
# Check the installation directory is valid and add it as a patch.
if not os . access ( modDir , os . F_OK ) :
sip_tqt_config . error ( " The %s PyTQt destination directory does not seem to exist. Use the -d argument to set the correct directory. " % ( modDir ) )
config . patches [ " @PYTQT_MODDIR@ " ] = sip_tqt_config . escape ( modDir )
sip_tqt_config . inform ( " %s is the PyTQt installation directory. " % ( modDir ) )
# Enable warnings for SIP v4 generated code.
if sipMajorVersion > = 4 :
warn = " warn_on "
else :
warn = " warn_off "
config . patches [ " @PYTQT_WARN@ " ] = warn
# Create patches to allow some modules to link against others.
if sipMajorVersion > = 4 :
modlink = " "
elif sys . platform == " win32 " :
modlink = sip_tqt_config . escape ( os . path . join ( modDir , " libtqtc.lib " ) )
else :
modlink = sip_tqt_config . escape ( " -L " + modDir ) + " -ltqtcmodule "
config . patches [ " @PYTQT_TQT_MODULE@ " ] = modlink
if sipMajorVersion > = 4 :
modlink = " "
elif sys . platform == " win32 " :
modlink = sip_tqt_config . escape ( os . path . join ( modDir , " libtqttablec.lib " ) ) + " " + sip_tqt_config . escape ( os . path . join ( modDir , " libtqtc.lib " ) )
else :
modlink = sip_tqt_config . escape ( " -L " + modDir ) + " -ltqttablecmodule -ltqtcmodule "
config . patches [ " @PYTQT_TQTTABLE_MODULE@ " ] = modlink
# The professional edition needs special handling if XML support is needed.
if config . tqt_edition == " professional " :
rbprof = " rbprof "
else :
rbprof = " "
config . patches [ " @PYTQT_RBPROF@ " ] = rbprof
# Link in the tqassistantclient library for TQt v3.1+.
tqaclib = " "
if sys . platform == " win32 " :
tqaclib = r " $(TQTDIR) \ lib \ tqassistantclient.lib "
else :
tqaclib = " -ltqassistantclient "
config . patches [ " @PYTQT_TQASSISTANTCLIENT_LIB@ " ] = tqaclib
# Check for TQScintilla.
checkTQScintilla ( )
# Create a build directory that we can compile test programs.
maindir = mkTempBuildDir ( )
# Check what additional modules to build.
moduleChecks ( maindir )
# Work out the platform and TQt version tags to pass to SIP-TQt to generate the
# code we need.
if config . tqt_lib == " tqte " :
plattag = " WS_QWS "
elif sys . platform == " win32 " :
plattag = " WS_WIN "
elif sys . platform == " darwin " :
plattag = " WS_MACX "
else :
plattag = " WS_X11 "
tqttags = {
0x020000 : " TQt_1_43 " ,
0x020100 : " TQt_2_00 " ,
0x020200 : " TQt_2_1_0 " ,
0x020300 : " TQt_2_2_0 " ,
0x020301 : " TQt_2_3_0 " ,
0x030000 : " TQt_2_3_1 " ,
0x030001 : " TQt_3_0_0 " ,
0x030002 : " TQt_3_0_1 " ,
0x030004 : " TQt_3_0_2 " ,
0x030005 : " TQt_3_0_4 " ,
0x030006 : " TQt_3_0_5 " ,
0x030100 : " TQt_3_0_6 " ,
0x030101 : " TQt_3_1_0 " ,
0x030102 : " TQt_3_1_1 " ,
0x030200 : " TQt_3_1_2 " ,
0x030300 : " TQt_3_2_0 " ,
0x040000 : " TQt_3_3_0 "
}
tqttag = versionToTag ( config . tqt_version , tqttags , " TQt " )
# Work out the TQScintilla tag.
if sciVersion > = 0 :
scitags = {
0x010100 : " TQScintilla_1_0 " ,
0x010200 : " TQScintilla_1_1 " ,
0x020000 : " TQScintilla_1_2 "
}
scitag = versionToTag ( sciVersion , scitags , " TQScintilla " )
else :
scitag = None
# Generate the features file.
generateFeatures ( os . path . join ( maindir , " features " ) )
# We don't need the temporary build directory anymore.
mkTempBuildDir ( maindir )
subdirs = [ ]
for mname in buildModules :
if mname == " tqtext " :
xtratag = scitag
else :
xtratag = None
generateSource ( mname , plattag , tqttag , xtratag )
subdirs . append ( mname )
# We handle the tqtpe module explicitly rather than auto-detect. This is
# because it does things a bit differently and I'm too lazy to deal with it
# properly at the moment.
if tqpeTag :
generateSource ( " tqtpe " , plattag , tqttag , tqpeTag )
subdirs . append ( " tqtpe " )
# Install the .sip files.
sip_tqt_config . inform ( " Creating Makefile for .sip files. " )
olddir = sip_tqt_config . push_dir ( " sip " )
sip_tqt_config . copy_to_file ( " Makefile " , " all: \n " )
icmds = [ ]
for mname in buildModules :
dstdir = os . path . join ( sipDir , mname )
icmds . append ( ( " mkdir " , dstdir , None ) )
for sf in os . listdir ( os . path . join ( olddir , " sip " , mname ) ) :
icmds . append ( ( " copy " , os . path . join ( mname , sf ) , os . path . join ( dstdir , sf ) ) )
config . add_install_target ( icmds )
sip_tqt_config . pop_dir ( olddir )
subdirs . append ( " sip " )
# See which version of pyuic to build.
config . patches [ " @PYTQT_BINDIR@ " ] = sip_tqt_config . escape ( binDir )
sip_tqt_config . inform ( " Creating Makefile for pytquic3. " )
subdirs . append ( " pytquic3 " )
olddir = sip_tqt_config . push_dir ( " pytquic3 " )
config . create_makefile ( " pytquic.pro " , [ ] )
sip_tqt_config . pop_dir ( olddir )
# Build pylupdate.
sip_tqt_config . inform ( " Creating Makefile for pytqlupdate3. " )
subdirs . append ( " pytqlupdate3 " )
olddir = sip_tqt_config . push_dir ( " pytqlupdate3 " )
config . create_makefile ( " pytqlupdate.pro " , [ ] )
sip_tqt_config . pop_dir ( olddir )
# Generate the top-level Makefile.
sip_tqt_config . inform ( " Creating top level Makefile. " )
sip_tqt_config . copy_to_file ( " PyTQt.pro.in " , " TEMPLATE = subdirs \n SUBDIRS = " + string . join ( subdirs ) + " \n " )
config . create_makefile ( " PyTQt.pro " )
# Tell the user what to do next.
msg = " The build of the PyTQt source code for your system is now complete. To compile and install PyTQt run \" %s \" and \" %s install \" with appropriate user privileges. " % ( config . make_bin , config . make_bin )
sip_tqt_config . inform ( msg )
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