00001 import re
00002 import os.path
00003
00004 import SCons.Defaults
00005 import SCons.Tool
00006 import SCons.Util
00007
00008
00009 class ToolQtWarning(SCons.Warnings.Warning):
00010 pass
00011 class GeneratedMocFileNotIncluded(ToolQtWarning):
00012 pass
00013 class QtdirNotFound(ToolQtWarning):
00014 pass
00015 SCons.Warnings.enableWarningClass(ToolQtWarning)
00016
00017 qrcinclude_re = re.compile(r'<file>([^<]*)</file>', re.M)
00018
00019
00020 header_extensions = [".h", ".hxx", ".hpp", ".hh"]
00021 if SCons.Util.case_sensitive_suffixes('.h', '.H'):
00022 header_extensions.append('.H')
00023
00024
00025 cxx_suffixes = [".c", ".cxx", ".cpp", ".cc"]
00026
00027 def _checkMocIncluded(target, source, env):
00028 moc = target[0]
00029 cpp = source[0]
00030
00031
00032 path = SCons.Defaults.CScan.path_function(env, moc.cwd)
00033 includes = SCons.Defaults.CScan(cpp, env, path)
00034 if not moc in includes:
00035 SCons.Warnings.warn(
00036 GeneratedMocFileNotIncluded,
00037 "Generated moc file '%s' is not included by '%s'" %
00038 (str(moc), str(cpp)))
00039
00040 def _find_file(filename, paths, node_factory):
00041 retval = None
00042 for dir in paths:
00043 node = node_factory(filename, dir)
00044 if node.rexists():
00045 return node
00046 return None
00047
00048 class _Automoc:
00049 """
00050 Callable class, which works as an emitter for Programs, SharedLibraries and
00051 StaticLibraries.
00052 """
00053
00054 def __init__(self, objBuilderName):
00055 self.objBuilderNameobjBuilderName = objBuilderName
00056
00057 def __call__(self, target, source, env):
00058 """
00059 Smart autoscan function. Gets the list of objects for the Program
00060 or Lib. Adds objects and builders for the special qt files.
00061 """
00062 try:
00063 if int(env.subst('$QT_AUTOSCAN')) == 0:
00064 return target, source
00065 except ValueError:
00066 pass
00067 try:
00068 debug = int(env.subst('$QT_DEBUG'))
00069 except ValueError:
00070 debug = 0
00071
00072
00073 FS = SCons.Node.FS.default_fs
00074 splitext = SCons.Util.splitext
00075 objBuilder = getattr(env, self.objBuilderNameobjBuilderName)
00076
00077
00078
00079 q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]')
00080
00081
00082
00083
00084
00085
00086 objBuilderEnv = objBuilder.env
00087 objBuilder.env = env
00088 mocBuilderEnv = env.Moc4.env
00089 env.Moc4.env = env
00090
00091
00092 out_sources = source[:]
00093
00094 for obj in source:
00095 if not obj.has_builder():
00096
00097 if debug:
00098 print "scons: qt: '%s' seems to be a binary. Discarded." % str(obj)
00099 continue
00100 cpp = obj.sources[0]
00101 if not splitext(str(cpp))[1] in cxx_suffixes:
00102 if debug:
00103 print "scons: qt: '%s' is no cxx file. Discarded." % str(cpp)
00104
00105 continue
00106
00107 cpp_contents = cpp.get_contents()
00108 h=None
00109 for h_ext in header_extensions:
00110
00111
00112 hname = splitext(cpp.name)[0] + h_ext
00113 h = _find_file(hname,
00114 (cpp.get_dir(),),
00115 FS.File)
00116 if h:
00117 if debug:
00118 print "scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp))
00119
00120 h_contents = h.get_contents()
00121 break
00122 if not h and debug:
00123 print "scons: qt: no header for '%s'." % (str(cpp))
00124 if h and q_object_search.search(h_contents):
00125
00126 moc_cpp = env.Moc4(h)
00127 moc_o = objBuilder(moc_cpp)
00128 out_sources.append(moc_o)
00129
00130 if debug:
00131 print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))
00132 if cpp and q_object_search.search(cpp_contents):
00133
00134
00135 moc = env.Moc4(cpp)
00136 env.Ignore(moc, moc)
00137 if debug:
00138 print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
00139
00140
00141 objBuilder.env = objBuilderEnv
00142 env.Moc4.env = mocBuilderEnv
00143
00144 return (target, out_sources)
00145
00146 AutomocShared = _Automoc('SharedObject')
00147 AutomocStatic = _Automoc('StaticObject')
00148
00149 def _detect(env):
00150 """Not really safe, but fast method to detect the QT library"""
00151
00152 QTDIR = env.get('QTDIR',None)
00153 if QTDIR!=None : return QTDIR
00154
00155 QTDIR = os.environ.get('QTDIR',None)
00156 if QTDIR!=None : return QTDIR
00157
00158 moc = env.WhereIs('moc-qt4') or env.WhereIs('moc')
00159 if moc:
00160 SCons.Warnings.warn(
00161 QtdirNotFound,
00162 "QTDIR variable is not defined, using moc executable as a hint (QTDIR=%s)" % QTDIR)
00163 return os.path.dirname(os.path.dirname(moc))
00164
00165 SCons.Warnings.warn(
00166 QtdirNotFound,
00167 "Could not detect qt, using empty QTDIR")
00168 return None
00169
00170 def generate(env):
00171 """Add Builders and construction variables for qt to an Environment."""
00172
00173 print "Loading qt4 tool..."
00174
00175 def locateQt4Command(env, command, qtdir) :
00176 fullpath = env.Detect([command+'-qt4', command])
00177 if not (fullpath is None) : return fullpath
00178 fullpath1 = os.path.join(qtdir,'bin',command +'-qt4')
00179 if os.access(fullpath1, os.X_OK) or \
00180 os.access(fullpath1+".exe", os.X_OK):
00181 return fullpath1
00182 fullpath2 = os.path.join(qtdir,'bin',command)
00183 if os.access(fullpath2, os.X_OK) or \
00184 os.access(fullpath2+".exe", os.X_OK):
00185 return fullpath2
00186 raise "Qt4 command '" + command + "' not found. Tried: " + fullpath1 + " and "+ fullpath2
00187
00188
00189 CLVar = SCons.Util.CLVar
00190 Action = SCons.Action.Action
00191 Builder = SCons.Builder.Builder
00192 splitext = SCons.Util.splitext
00193
00194
00195 env['QTDIR'] = _detect(env)
00196 env['QT4_MOC'] = locateQt4Command(env,'moc', env['QTDIR'])
00197 env['QT4_UIC'] = locateQt4Command(env,'uic', env['QTDIR'])
00198 env['QT4_RCC'] = locateQt4Command(env,'rcc', env['QTDIR'])
00199 env['QT4_LUPDATE'] = locateQt4Command(env,'lupdate', env['QTDIR'])
00200 env['QT4_LRELEASE'] = locateQt4Command(env,'lrelease', env['QTDIR'])
00201
00202
00203 env['QT4_AUTOSCAN'] = 1
00204
00205
00206
00207 env['QT4_UICDECLFLAGS'] = CLVar('')
00208 env['QT4_MOCFROMHFLAGS'] = CLVar('')
00209 env['QT4_MOCFROMCXXFLAGS'] = CLVar('-i')
00210 env['QT4_QRCFLAGS'] = ''
00211
00212
00213 env['QT4_MOCHPREFIX'] = 'moc_'
00214 env['QT4_MOCHSUFFIX'] = '$CXXFILESUFFIX'
00215 env['QT4_MOCCXXPREFIX'] = 'moc_'
00216 env['QT4_MOCCXXSUFFIX'] = '.moc'
00217 env['QT4_UISUFFIX'] = '.ui'
00218 env['QT4_UICDECLPREFIX'] = 'ui_'
00219 env['QT4_UICDECLSUFFIX'] = '.h'
00220 env['QT4_QRCSUFFIX'] = '.qrc',
00221 env['QT4_QRCCXXSUFFIX'] = '$CXXFILESUFFIX'
00222 env['QT4_QRCCXXPREFIX'] = 'qrc_'
00223
00224 env['QT4_LIB'] = ''
00225
00226
00227 tsbuilder = Builder(
00228 action ='$QT4_LUPDATE $SOURCES -ts $TARGETS',
00229 multi=1
00230 )
00231 env.Append( BUILDERS = { 'Ts': tsbuilder } )
00232 qmbuilder = Builder(
00233 action =[
00234 '$QT4_LRELEASE $SOURCE',
00235 ],
00236 src_suffix = '.ts',
00237 suffix = '.qm',
00238 single_source = True
00239 )
00240 env.Append( BUILDERS = { 'Qm': qmbuilder } )
00241
00242
00243 def scanResources(node, env, path, arg):
00244 contents = node.get_contents()
00245 includes = qrcinclude_re.findall(contents)
00246 return includes
00247 qrcscanner = env.Scanner(name = 'qrcfile',
00248 function = scanResources,
00249 argument = None,
00250 skeys = ['.qrc'])
00251 qrcbuilder = Builder(
00252 action ='$QT4_RCC $QT4_QRCFLAGS $SOURCE -o $TARGET',
00253 source_scanner = qrcscanner,
00254 src_suffix = '$QT4_QRCSUFFIX',
00255 suffix = '$QT4_QRCCXXSUFFIX',
00256 prefix = '$QT4_QRCCXXPREFIX',
00257 single_source = True
00258 )
00259 env.Append( BUILDERS = { 'Qrc': qrcbuilder } )
00260
00261
00262 env['QT4_UIC4COM'] = [
00263 CLVar('$QT4_UIC $QT4_UICDECLFLAGS -o ${TARGETS[0]} $SOURCE'),
00264 ]
00265 uic4builder = Builder(
00266 action='$QT4_UIC4COM',
00267 src_suffix='$QT4_UISUFFIX',
00268 suffix='$QT4_UICDECLSUFFIX',
00269 prefix='$QT4_UICDECLPREFIX',
00270 single_source = True
00271 )
00272 env.Append( BUILDERS = { 'Uic4': uic4builder } )
00273
00274
00275 env['QT4_MOCFROMHCOM'] = (
00276 '$QT4_MOC $QT4_MOCFROMHFLAGS -o ${TARGETS[0]} $SOURCE')
00277 env['QT4_MOCFROMCXXCOM'] = [
00278 CLVar('$QT4_MOC $QT4_MOCFROMCXXFLAGS -o ${TARGETS[0]} $SOURCE'),
00279 Action(_checkMocIncluded,None)]
00280 mocBld = Builder(action={}, prefix={}, suffix={})
00281 for h in header_extensions:
00282 mocBld.add_action(h, '$QT4_MOCFROMHCOM')
00283 mocBld.prefix[h] = '$QT4_MOCHPREFIX'
00284 mocBld.suffix[h] = '$QT4_MOCHSUFFIX'
00285 for cxx in cxx_suffixes:
00286 mocBld.add_action(cxx, '$QT4_MOCFROMCXXCOM')
00287 mocBld.prefix[cxx] = '$QT4_MOCCXXPREFIX'
00288 mocBld.suffix[cxx] = '$QT4_MOCCXXSUFFIX'
00289 env.Append( BUILDERS = { 'Moc4': mocBld } )
00290
00291
00292 static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
00293 static_obj.src_builder.append('Uic4')
00294 shared_obj.src_builder.append('Uic4')
00295
00296
00297
00298
00299
00300
00301 env.AppendUnique(PROGEMITTER =[AutomocStatic],
00302 SHLIBEMITTER=[AutomocShared],
00303 LIBEMITTER =[AutomocStatic],
00304
00305 CPPPATH=[os.path.join('$QTDIR', 'include')],
00306 LIBPATH=[os.path.join('$QTDIR', 'lib')],
00307 LIBS=['$QT4_LIB'])
00308
00309 import new
00310 method = new.instancemethod(enable_modules, env, SCons.Environment)
00311 env.EnableQt4Modules=method
00312
00313 def enable_modules(self, modules, debug=False) :
00314 import sys
00315
00316 validModules = [
00317 'QtCore',
00318 'QtGui',
00319 'QtOpenGL',
00320 'Qt3Support',
00321
00322
00323 'QtSql',
00324 'QtNetwork',
00325 'QtSvg',
00326 'QtTest',
00327 'QtXml',
00328 'QtUiTools',
00329 ]
00330 pclessModules = [
00331 'QtUiTools',
00332 'QtUiTools_debug',
00333 ]
00334 invalidModules=[]
00335 for module in modules:
00336 if module not in validModules :
00337 invalidModules.append(module)
00338 if invalidModules :
00339 raise "Modules %s are not Qt4 modules. Valid Qt4 modules are: %s"% \
00340 (str(invalidModules),str(validModules))
00341
00342
00343 if 'QtGui' in modules:
00344 self.AppendUnique(CPPFLAGS='-DQT_GUI_LIB')
00345
00346 if sys.platform == "linux2" :
00347 if debug : modules = [module+"_debug" for module in modules]
00348 for module in modules :
00349 if module in pclessModules :
00350
00351 self.AppendUnique(LIBPATH=[os.path.join(self["QTDIR"],"lib",module)])
00352 self.AppendUnique(CPPPATH=[os.path.join(self["QTDIR"],"include","qt4",module)])
00353 modules.remove(module)
00354 self.ParseConfig('PKG_CONFIG_PATH=%s/lib/pkgconfig pkg-config %s --libs --cflags'%
00355 (
00356 self['QTDIR'],
00357 ' '.join(modules)))
00358 return
00359 if sys.platform == "win32" :
00360 if debug : debugSuffix = 'd'
00361 else : debugSuffix = ''
00362 self.AppendUnique(LIBS=[lib+'4'+debugSuffix for lib in modules])
00363 if 'QtOpenGL' in modules:
00364 self.AppendUnique(LIBS=['opengl32'])
00365 self.AppendUnique(CPPPATH=[ '$QTDIR/include/'+module
00366 for module in modules])
00367 self.AppendUnique(LIBPATH=['$QTDIR/lib'])
00368
00369
00370 def exists(env):
00371 return _detect(env)
00372