4
Tool-specific initialization for Qt4.
6
There normally shouldn't be any need to import this module directly.
7
It will usually be imported through the generic SCons.Tool.Tool()
13
# Copyright (c) 2001-7,2010 The SCons Foundation
15
# Permission is hereby granted, free of charge, to any person obtaining
16
# a copy of this software and associated documentation files (the
17
# "Software"), to deal in the Software without restriction, including
18
# without limitation the rights to use, copy, modify, merge, publish,
19
# distribute, sublicense, and/or sell copies of the Software, and to
20
# permit persons to whom the Software is furnished to do so, subject to
21
# the following conditions:
23
# The above copyright notice and this permission notice shall be included
24
# in all copies or substantial portions of the Software.
26
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
class ToolQt4Warning(SCons.Warnings.Warning):
48
class GeneratedMocFileNotIncluded(ToolQt4Warning):
51
class QtdirNotFound(ToolQt4Warning):
54
SCons.Warnings.enableWarningClass(ToolQt4Warning)
59
# Pre-2.4 Python has no sorted() function.
61
# The pre-2.4 Python list.sort() method does not support
62
# list.sort(key=) nor list.sort(reverse=) keyword arguments, so
63
# we must implement the functionality of those keyword arguments
64
# by hand instead of passing them to list.sort().
65
def sorted(iterable, cmp=None, key=None, reverse=0):
67
result = [(key(x), x) for x in iterable]
71
# Pre-2.3 Python does not support list.sort(None).
76
result = [t1 for t0,t1 in result]
81
qrcinclude_re = re.compile(r'<file[^>]*>([^<]*)</file>', re.M)
83
def transformToWinePath(path) :
84
return os.popen('winepath -w "%s"'%path).read().strip().replace('\\','/')
86
header_extensions = [".h", ".hxx", ".hpp", ".hh"]
87
if SCons.Util.case_sensitive_suffixes('.h', '.H'):
88
header_extensions.append('.H')
89
# TODO: The following two lines will work when integrated back to SCons
90
# TODO: Meanwhile the third line will do the work
91
#cplusplus = __import__('c++', globals(), locals(), [])
92
#cxx_suffixes = cplusplus.CXXSuffixes
93
cxx_suffixes = [".c", ".cxx", ".cpp", ".cc"]
95
def checkMocIncluded(target, source, env):
98
# looks like cpp.includes is cleared before the build stage :-(
99
# not really sure about the path transformations (moc.cwd? cpp.cwd?) :-/
100
path = SCons.Defaults.CScan.path_function(env, moc.cwd)
101
includes = SCons.Defaults.CScan(cpp, env, path)
102
if not moc in includes:
104
GeneratedMocFileNotIncluded,
105
"Generated moc file '%s' is not included by '%s'" %
106
(str(moc), str(cpp)))
108
def find_file(filename, paths, node_factory):
110
node = node_factory(filename, dir)
117
Callable class, which works as an emitter for Programs, SharedLibraries and
121
def __init__(self, objBuilderName):
122
self.objBuilderName = objBuilderName
123
# some regular expressions:
125
self.qo_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]')
126
# cxx and c comment 'eater'
127
self.ccomment = re.compile(r'/\*(.*?)\*/',re.S)
128
self.cxxcomment = re.compile(r'//.*$',re.M)
129
# we also allow Q_OBJECT in a literal string
130
self.literal_qobject = re.compile(r'"[^\n]*Q_OBJECT[^\n]*"')
132
def create_automoc_options(self, env):
134
Create a dictionary with variables related to Automocing,
135
based on the current environment.
136
Is executed once in the __call__ routine.
138
moc_options = {'auto_scan' : True,
139
'auto_scan_strategy' : 0,
140
'gobble_comments' : 0,
142
'auto_cpppath' : True,
145
if int(env.subst('$QT4_AUTOSCAN')) == 0:
146
moc_options['auto_scan'] = False
150
moc_options['auto_scan_strategy'] = int(env.subst('$QT4_AUTOSCAN_STRATEGY'))
154
moc_options['gobble_comments'] = int(env.subst('$QT4_GOBBLECOMMENTS'))
158
moc_options['debug'] = int(env.subst('$QT4_DEBUG'))
162
if int(env.subst('$QT4_AUTOMOC_SCANCPPPATH')) == 0:
163
moc_options['auto_cpppath'] = False
166
if moc_options['auto_cpppath']:
167
paths = env.get('QT4_AUTOMOC_CPPPATH', [])
169
paths = env.get('CPPPATH', [])
170
moc_options['cpppaths'].extend(paths)
174
def __automoc_strategy_simple(self, env, moc_options,
175
cpp, cpp_contents, out_sources):
177
Default Automoc strategy (Q_OBJECT driven): detect a header file
178
(alongside the current cpp/cxx) that contains a Q_OBJECT
180
If a Q_OBJECT macro is also found in the cpp/cxx itself,
185
for h_ext in header_extensions:
186
# try to find the header file in the corresponding source
188
hname = self.splitext(cpp.name)[0] + h_ext
189
h = find_file(hname, [cpp.get_dir()]+moc_options['cpppaths'], env.File)
191
if moc_options['debug']:
192
print "scons: qt4: Scanning '%s' (header of '%s')" % (str(h), str(cpp))
193
h_contents = h.get_contents()
194
if moc_options['gobble_comments']:
195
h_contents = self.ccomment.sub('', h_contents)
196
h_contents = self.cxxcomment.sub('', h_contents)
197
h_contents = self.literal_qobject.sub('""', h_contents)
199
if not h and moc_options['debug']:
200
print "scons: qt4: no header for '%s'." % (str(cpp))
201
if h and self.qo_search.search(h_contents):
202
# h file with the Q_OBJECT macro found -> add moc_cpp
203
moc_cpp = env.Moc4(h)
204
moc_o = self.objBuilder(moc_cpp)
205
out_sources.extend(moc_o)
206
if moc_options['debug']:
207
print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))
208
if cpp and self.qo_search.search(cpp_contents):
209
# cpp file with Q_OBJECT macro found -> add moc
210
# (to be included in cpp)
213
if moc_options['debug']:
214
print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
216
def __automoc_strategy_include_driven(self, env, moc_options,
217
cpp, cpp_contents, out_sources):
219
Automoc strategy #1 (include driven): searches for "include"
220
statements of MOCed files in the current cpp/cxx file.
221
This strategy tries to add support for the compilation
222
of the qtsolutions...
224
if self.splitext(str(cpp))[1] in cxx_suffixes:
226
h_moc = "%s%s%s" % (env.subst('$QT4_XMOCHPREFIX'),
227
self.splitext(cpp.name)[0],
228
env.subst('$QT4_XMOCHSUFFIX'))
229
cxx_moc = "%s%s%s" % (env.subst('$QT4_XMOCCXXPREFIX'),
230
self.splitext(cpp.name)[0],
231
env.subst('$QT4_XMOCCXXSUFFIX'))
232
inc_h_moc = r'#include\s+"%s"' % h_moc
233
inc_cxx_moc = r'#include\s+"%s"' % cxx_moc
235
# Search for special includes in qtsolutions style
236
if cpp and re.search(inc_h_moc, cpp_contents):
237
# cpp file with #include directive for a MOCed header found -> add moc
239
# Try to find header file
242
for h_ext in header_extensions:
243
# Try to find the header file in the
244
# corresponding source directory
245
hname = self.splitext(cpp.name)[0] + h_ext
246
h = find_file(hname, [cpp.get_dir()]+moc_options['cpppaths'], env.File)
248
if moc_options['debug']:
249
print "scons: qt4: Scanning '%s' (header of '%s')" % (str(h), str(cpp))
250
h_contents = h.get_contents()
251
if moc_options['gobble_comments']:
252
h_contents = self.ccomment.sub('', h_contents)
253
h_contents = self.cxxcomment.sub('', h_contents)
254
h_contents = self.literal_qobject.sub('""', h_contents)
256
if not h and moc_options['debug']:
257
print "scons: qt4: no header for '%s'." % (str(cpp))
258
if h and self.qo_search.search(h_contents):
259
# h file with the Q_OBJECT macro found -> add moc_cpp
260
moc_cpp = env.XMoc4(h)
261
env.Ignore(moc_cpp, moc_cpp)
263
# Removing file from list of sources, because it is not to be
264
# compiled but simply included by the cpp/cxx file.
265
for idx, s in enumerate(out_sources):
266
if hasattr(s, "sources") and len(s.sources) > 0:
267
if str(s.sources[0]) == h_moc:
270
if moc_options['debug']:
271
print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(h_moc))
273
if moc_options['debug']:
274
print "scons: qt4: found no Q_OBJECT macro in '%s', but a moc'ed version '%s' gets included in '%s'" % (str(h), inc_h_moc, cpp.name)
276
if cpp and re.search(inc_cxx_moc, cpp_contents):
277
# cpp file with #include directive for a MOCed cxx file found -> add moc
278
if self.qo_search.search(cpp_contents):
279
moc = env.XMoc4(target=cxx_moc, source=cpp)
282
if moc_options['debug']:
283
print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
285
if moc_options['debug']:
286
print "scons: qt4: found no Q_OBJECT macro in '%s', although a moc'ed version '%s' of itself gets included" % (cpp.name, inc_cxx_moc)
289
# Fallback to default Automoc strategy (Q_OBJECT driven)
290
self.__automoc_strategy_simple(env, moc_options, cpp,
291
cpp_contents, out_sources)
293
def __call__(self, target, source, env):
295
Smart autoscan function. Gets the list of objects for the Program
296
or Lib. Adds objects and builders for the special qt4 files.
298
moc_options = self.create_automoc_options(env)
300
# some shortcuts used in the scanner
301
self.splitext = SCons.Util.splitext
302
self.objBuilder = getattr(env, self.objBuilderName)
304
# The following is kind of hacky to get builders working properly (FIXME)
305
objBuilderEnv = self.objBuilder.env
306
self.objBuilder.env = env
307
mocBuilderEnv = env.Moc4.env
309
xMocBuilderEnv = env.XMoc4.env
312
# make a deep copy for the result; MocH objects will be appended
313
out_sources = source[:]
316
if not moc_options['auto_scan']:
318
if isinstance(obj,basestring): # big kludge!
319
print "scons: qt4: '%s' MAYBE USING AN OLD SCONS VERSION AND NOT CONVERTED TO 'File'. Discarded." % str(obj)
321
if not obj.has_builder():
322
# binary obj file provided
323
if moc_options['debug']:
324
print "scons: qt4: '%s' seems to be a binary. Discarded." % str(obj)
327
if not self.splitext(str(cpp))[1] in cxx_suffixes:
328
if moc_options['debug']:
329
print "scons: qt4: '%s' is no cxx file. Discarded." % str(cpp)
330
# c or fortran source
333
cpp_contents = cpp.get_contents()
334
if moc_options['gobble_comments']:
335
cpp_contents = self.ccomment.sub('', cpp_contents)
336
cpp_contents = self.cxxcomment.sub('', cpp_contents)
337
cpp_contents = self.literal_qobject.sub('""', cpp_contents)
338
except: continue # may be an still not generated source
340
if moc_options['auto_scan_strategy'] == 0:
341
# Default Automoc strategy (Q_OBJECT driven)
342
self.__automoc_strategy_simple(env, moc_options,
343
cpp, cpp_contents, out_sources)
345
# Automoc strategy #1 (include driven)
346
self.__automoc_strategy_include_driven(env, moc_options,
347
cpp, cpp_contents, out_sources)
349
# restore the original env attributes (FIXME)
350
self.objBuilder.env = objBuilderEnv
351
env.Moc4.env = mocBuilderEnv
352
env.XMoc4.env = xMocBuilderEnv
354
return (target, sorted(set(out_sources)))
356
AutomocShared = _Automoc('SharedObject')
357
AutomocStatic = _Automoc('StaticObject')
360
"""Not really safe, but fast method to detect the Qt4 library"""
361
# TODO: check output of "moc -v" for correct version >= 4.0.0
362
try: return env['QT4DIR']
363
except KeyError: pass
365
try: return env['QTDIR']
366
except KeyError: pass
368
try: return os.environ['QT4DIR']
369
except KeyError: pass
371
try: return os.environ['QTDIR']
372
except KeyError: pass
374
moc = env.WhereIs('moc-qt4') or env.WhereIs('moc4') or env.WhereIs('moc')
376
QT4DIR = os.path.dirname(os.path.dirname(moc))
379
"QT4DIR variable is not defined, using moc executable as a hint (QT4DIR=%s)" % QT4DIR)
382
raise SCons.Errors.StopError(
384
"Could not detect Qt 4 installation")
388
def __scanResources(node, env, path, arg):
389
# Helper function for scanning .qrc resource files
390
# I've been careful on providing names relative to the qrc file
391
# If that was not needed this code could be simplified a lot
392
def recursiveFiles(basepath, path) :
394
for item in os.listdir(os.path.join(basepath, path)) :
395
itemPath = os.path.join(path, item)
396
if os.path.isdir(os.path.join(basepath, itemPath)) :
397
result += recursiveFiles(basepath, itemPath)
399
result.append(itemPath)
401
contents = node.get_contents()
402
includes = qrcinclude_re.findall(contents)
403
qrcpath = os.path.dirname(node.path)
404
dirs = [included for included in includes if os.path.isdir(os.path.join(qrcpath,included))]
405
# dirs need to include files recursively
408
includes+=recursiveFiles(qrcpath,dir)
414
__qrcscanner = SCons.Scanner.Scanner(name = 'qrcfile',
415
function = __scanResources,
422
def __qrc_path(head, prefix, tail, suffix):
425
return os.path.join(head, "%s%s%s" % (prefix, tail, suffix))
427
return "%s%s%s" % (prefix, head, suffix)
429
return "%s%s%s" % (prefix, tail, suffix)
430
def __qrc_emitter(target, source, env):
431
sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0]))
435
sHead, sTail = os.path.split(sourceBase)
437
t = __qrc_path(sHead, env.subst('$QT4_QRCCXXPREFIX'),
438
sTail, env.subst('$QT4_QRCCXXSUFFIX'))
445
def __moc_generator_from_h(source, target, env, for_signature):
448
if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
454
return '$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
456
return '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
458
def __moc_generator_from_cxx(source, target, env, for_signature):
461
if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
467
return ['$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
468
SCons.Action.Action(checkMocIncluded,None)]
470
return ['$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
471
SCons.Action.Action(checkMocIncluded,None)]
473
def __mocx_generator_from_h(source, target, env, for_signature):
476
if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
482
return '$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
484
return '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
486
def __mocx_generator_from_cxx(source, target, env, for_signature):
489
if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
495
return ['$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
496
SCons.Action.Action(checkMocIncluded,None)]
498
return ['$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
499
SCons.Action.Action(checkMocIncluded,None)]
501
def __qrc_generator(source, target, env, for_signature):
504
if env.subst('$QT4_QRCFLAGS').find('-name') >= 0:
510
return '$QT4_RCC $QT4_QRCFLAGS $SOURCE -o $TARGET'
512
qrc_suffix = env.subst('$QT4_QRCSUFFIX')
514
head, tail = os.path.split(src)
517
qrc_suffix = env.subst('$QT4_QRCSUFFIX')
518
if src.endswith(qrc_suffix):
519
qrc_stem = src[:-len(qrc_suffix)]
522
return '$QT4_RCC $QT4_QRCFLAGS -name %s $SOURCE -o $TARGET' % qrc_stem
527
__ts_builder = SCons.Builder.Builder(
528
action = SCons.Action.Action('$QT4_LUPDATECOM','$QT4_LUPDATECOMSTR'),
530
source_factory = SCons.Node.FS.Entry)
531
__qm_builder = SCons.Builder.Builder(
532
action = SCons.Action.Action('$QT4_LRELEASECOM','$QT4_LRELEASECOMSTR'),
535
__qrc_builder = SCons.Builder.Builder(
536
action = SCons.Action.CommandGeneratorAction(__qrc_generator, {}),
537
source_scanner = __qrcscanner,
538
src_suffix = '$QT4_QRCSUFFIX',
539
suffix = '$QT4_QRCCXXSUFFIX',
540
prefix = '$QT4_QRCCXXPREFIX',
542
__ex_moc_builder = SCons.Builder.Builder(
543
action = SCons.Action.CommandGeneratorAction(__moc_generator_from_h, {}))
544
__ex_uic_builder = SCons.Builder.Builder(
545
action = SCons.Action.Action('$QT4_UICCOM', '$QT4_UICCOMSTR'),
550
# Wrappers (pseudo-Builders)
552
def Ts4(env, target, source=None, *args, **kw):
554
A pseudo-Builder wrapper around the LUPDATE executable of Qt4.
555
lupdate [options] [source-file|path]... -ts ts-files
557
if not SCons.Util.is_List(target):
561
if not SCons.Util.is_List(source):
564
# Check QT4_CLEAN_TS and use NoClean() function
567
if int(env.subst('$QT4_CLEAN_TS')) == 1:
574
obj = __ts_builder.__call__(env, t, source, **kw)
575
# Prevent deletion of the .ts file, unless explicitly specified
578
# Always make our target "precious", such that it is not deleted
581
# Add to resulting target list
586
def Qm4(env, target, source=None, *args, **kw):
588
A pseudo-Builder wrapper around the LRELEASE executable of Qt4.
589
lrelease [options] ts-files [-qm qm-file]
591
if not SCons.Util.is_List(target):
595
if not SCons.Util.is_List(source):
600
result.extend(__qm_builder.__call__(env, t, source, **kw))
604
def Qrc4(env, target, source=None, *args, **kw):
606
A pseudo-Builder wrapper around the RCC executable of Qt4.
607
rcc [options] qrc-files -o out-file
609
if not SCons.Util.is_List(target):
613
if not SCons.Util.is_List(source):
617
for t, s in zip(target, source):
618
result.extend(__qrc_builder.__call__(env, t, s, **kw))
622
def ExplicitMoc4(env, target, source, *args, **kw):
624
A pseudo-Builder wrapper around the MOC executable of Qt4.
625
moc [options] <header-file>
627
if not SCons.Util.is_List(target):
629
if not SCons.Util.is_List(source):
634
# Is it a header or a cxx file?
635
result.extend(__ex_moc_builder.__call__(env, t, source, **kw))
639
def ExplicitUic4(env, target, source, *args, **kw):
641
A pseudo-Builder wrapper around the UIC executable of Qt4.
642
uic [options] <uifile>
644
if not SCons.Util.is_List(target):
646
if not SCons.Util.is_List(source):
651
result.extend(__ex_uic_builder.__call__(env, t, source, **kw))
656
"""Add Builders and construction variables for qt4 to an Environment."""
658
def locateQt4Command(env, command, qtdir) :
668
for suffix in suffixes :
669
fullpath = os.path.join(qtdir,'bin',command + suffix)
670
if os.access(fullpath, os.X_OK) :
672
triedPaths.append(fullpath)
674
fullpath = env.Detect([command+'-qt4', command+'4', command])
675
if not (fullpath is None) : return fullpath
677
raise Exception("Qt4 command '" + command + "' not found. Tried: " + ', '.join(triedPaths))
679
CLVar = SCons.Util.CLVar
680
Action = SCons.Action.Action
681
Builder = SCons.Builder.Builder
683
env['QT4DIR'] = _detect(env)
684
# TODO: 'Replace' should be 'SetDefault'
687
QT4DIR = _detect(env),
688
QT4_BINPATH = os.path.join('$QT4DIR', 'bin'),
689
# TODO: This is not reliable to QT4DIR value changes but needed in order to support '-qt4' variants
690
QT4_MOC = locateQt4Command(env,'moc', env['QT4DIR']),
691
QT4_UIC = locateQt4Command(env,'uic', env['QT4DIR']),
692
QT4_RCC = locateQt4Command(env,'rcc', env['QT4DIR']),
693
QT4_LUPDATE = locateQt4Command(env,'lupdate', env['QT4DIR']),
694
QT4_LRELEASE = locateQt4Command(env,'lrelease', env['QT4DIR']),
696
QT4_AUTOSCAN = 1, # Should the qt4 tool try to figure out, which sources are to be moc'ed?
697
QT4_AUTOSCAN_STRATEGY = 0, # While scanning for files to moc, should we search for includes in qtsolutions style?
698
QT4_GOBBLECOMMENTS = 0, # If set to 1, comments are removed before scanning cxx/h files.
699
QT4_CPPDEFINES_PASSTOMOC = 1, # If set to 1, all CPPDEFINES get passed to the moc executable.
700
QT4_CLEAN_TS = 0, # If set to 1, translation files (.ts) get cleaned on 'scons -c'
701
QT4_AUTOMOC_SCANCPPPATH = 1, # If set to 1, the CPPPATHs (or QT4_AUTOMOC_CPPPATH) get scanned for moc'able files
702
QT4_AUTOMOC_CPPPATH = [], # Alternative paths that get scanned for moc files
704
# Some Qt4 specific flags. I don't expect someone wants to
705
# manipulate those ...
706
QT4_UICFLAGS = CLVar(''),
707
QT4_MOCFROMHFLAGS = CLVar(''),
708
QT4_MOCFROMCXXFLAGS = CLVar('-i'),
710
QT4_LUPDATEFLAGS = '',
711
QT4_LRELEASEFLAGS = '',
713
# suffixes/prefixes for the headers / sources to generate
714
QT4_UISUFFIX = '.ui',
715
QT4_UICDECLPREFIX = 'ui_',
716
QT4_UICDECLSUFFIX = '.h',
717
QT4_MOCINCPREFIX = '-I',
718
QT4_MOCHPREFIX = 'moc_',
719
QT4_MOCHSUFFIX = '$CXXFILESUFFIX',
720
QT4_MOCCXXPREFIX = '',
721
QT4_MOCCXXSUFFIX = '.moc',
722
QT4_QRCSUFFIX = '.qrc',
723
QT4_QRCCXXSUFFIX = '$CXXFILESUFFIX',
724
QT4_QRCCXXPREFIX = 'qrc_',
725
QT4_MOCDEFPREFIX = '-D',
726
QT4_MOCDEFSUFFIX = '',
727
QT4_MOCDEFINES = '${_defines(QT4_MOCDEFPREFIX, CPPDEFINES, QT4_MOCDEFSUFFIX, __env__)}',
729
QT4_MOCINCFLAGS = '$( ${_concat(QT4_MOCINCPREFIX, QT4_MOCCPPPATH, INCSUFFIX, __env__, RDirs)} $)',
731
# Commands for the qt4 support ...
732
QT4_UICCOM = '$QT4_UIC $QT4_UICFLAGS -o $TARGET $SOURCE',
733
QT4_LUPDATECOM = '$QT4_LUPDATE $QT4_LUPDATEFLAGS $SOURCES -ts $TARGET',
734
QT4_LRELEASECOM = '$QT4_LRELEASE $QT4_LRELEASEFLAGS -qm $TARGET $SOURCES',
736
# Specialized variables for the Extended Automoc support
737
# (Strategy #1 for qtsolutions)
738
QT4_XMOCHPREFIX = 'moc_',
739
QT4_XMOCHSUFFIX = '.cpp',
740
QT4_XMOCCXXPREFIX = '',
741
QT4_XMOCCXXSUFFIX = '.moc',
746
env.AddMethod(Ts4, "Ts4")
747
env.AddMethod(Qm4, "Qm4")
748
env.AddMethod(Qrc4, "Qrc4")
749
env.AddMethod(ExplicitMoc4, "ExplicitMoc4")
750
env.AddMethod(ExplicitUic4, "ExplicitUic4")
751
except AttributeError:
752
# Looks like we use a pre-0.98 version of SCons...
753
from SCons.Script.SConscript import SConsEnvironment
754
SConsEnvironment.Ts4 = Ts4
755
SConsEnvironment.Qm4 = Qm4
756
SConsEnvironment.Qrc4 = Qrc4
757
SConsEnvironment.ExplicitMoc4 = ExplicitMoc4
758
SConsEnvironment.ExplicitUic4 = ExplicitUic4
761
uic4builder = Builder(
762
action = SCons.Action.Action('$QT4_UICCOM', '$QT4_UICCOMSTR'),
763
src_suffix='$QT4_UISUFFIX',
764
suffix='$QT4_UICDECLSUFFIX',
765
prefix='$QT4_UICDECLPREFIX',
767
#TODO: Consider the uiscanner on new scons version
769
env['BUILDERS']['Uic4'] = uic4builder
772
mocBld = Builder(action={}, prefix={}, suffix={})
773
for h in header_extensions:
774
act = SCons.Action.CommandGeneratorAction(__moc_generator_from_h, {})
775
mocBld.add_action(h, act)
776
mocBld.prefix[h] = '$QT4_MOCHPREFIX'
777
mocBld.suffix[h] = '$QT4_MOCHSUFFIX'
778
for cxx in cxx_suffixes:
779
act = SCons.Action.CommandGeneratorAction(__moc_generator_from_cxx, {})
780
mocBld.add_action(cxx, act)
781
mocBld.prefix[cxx] = '$QT4_MOCCXXPREFIX'
782
mocBld.suffix[cxx] = '$QT4_MOCCXXSUFFIX'
783
env['BUILDERS']['Moc4'] = mocBld
785
# Metaobject builder for the extended auto scan feature
786
# (Strategy #1 for qtsolutions)
787
xMocBld = Builder(action={}, prefix={}, suffix={})
788
for h in header_extensions:
789
act = SCons.Action.CommandGeneratorAction(__mocx_generator_from_h, {})
790
xMocBld.add_action(h, act)
791
xMocBld.prefix[h] = '$QT4_XMOCHPREFIX'
792
xMocBld.suffix[h] = '$QT4_XMOCHSUFFIX'
793
for cxx in cxx_suffixes:
794
act = SCons.Action.CommandGeneratorAction(__mocx_generator_from_cxx, {})
795
xMocBld.add_action(cxx, act)
796
xMocBld.prefix[cxx] = '$QT4_XMOCCXXPREFIX'
797
xMocBld.suffix[cxx] = '$QT4_XMOCCXXSUFFIX'
798
env['BUILDERS']['XMoc4'] = xMocBld
800
# Add the Qrc4 action to the CXX file builder (registers the
801
# *.qrc extension with the Environment)
802
cfile_builder, cxxfile_builder = SCons.Tool.createCFileBuilders(env)
803
qrc_act = SCons.Action.CommandGeneratorAction(__qrc_generator, {})
804
cxxfile_builder.add_action('$QT4_QRCSUFFIX', qrc_act)
805
cxxfile_builder.add_emitter('$QT4_QRCSUFFIX', __qrc_emitter)
807
# We use the emitters of Program / StaticLibrary / SharedLibrary
808
# to scan for moc'able files
809
# We can't refer to the builders directly, we have to fetch them
810
# as Environment attributes because that sets them up to be called
811
# correctly later by our emitter.
812
env.AppendUnique(PROGEMITTER =[AutomocStatic],
813
SHLIBEMITTER=[AutomocShared],
814
LIBEMITTER =[AutomocStatic],
817
# TODO: Does dbusxml2cpp need an adapter
819
env.AddMethod(enable_modules, "EnableQt4Modules")
820
except AttributeError:
821
# Looks like we use a pre-0.98 version of SCons...
822
from SCons.Script.SConscript import SConsEnvironment
823
SConsEnvironment.EnableQt4Modules = enable_modules
825
def enable_modules(self, modules, debug=False, crosscompiling=False) :
833
'QtAssistant', # deprecated
839
# The next modules have not been tested yet so, please
840
# maybe they require additional work on non Linux platforms
847
'QtDesignerComponents',
855
# in qt <= 4.3 designer and designerComponents are pcless, on qt4.4 they are not, so removed.
857
# 'QtDesignerComponents',
863
for module in modules:
864
if module not in validModules :
865
invalidModules.append(module)
867
raise Exception("Modules %s are not Qt4 modules. Valid Qt4 modules are: %s"% (
868
str(invalidModules),str(validModules)))
871
'QtScript' : ['QT_SCRIPT_LIB'],
872
'QtSvg' : ['QT_SVG_LIB'],
873
'Qt3Support' : ['QT_QT3SUPPORT_LIB','QT3_SUPPORT'],
874
'QtSql' : ['QT_SQL_LIB'],
875
'QtXml' : ['QT_XML_LIB'],
876
'QtOpenGL' : ['QT_OPENGL_LIB'],
877
'QtGui' : ['QT_GUI_LIB'],
878
'QtNetwork' : ['QT_NETWORK_LIB'],
879
'QtCore' : ['QT_CORE_LIB'],
881
for module in modules :
882
try : self.AppendUnique(CPPDEFINES=moduleDefines[module])
885
if sys.platform in ["darwin", "linux2"] and not crosscompiling :
886
if debug : debugSuffix = '_debug'
887
for module in modules :
888
if module not in pclessModules : continue
889
self.AppendUnique(LIBS=[module+debugSuffix])
890
self.AppendUnique(LIBPATH=[os.path.join("$QT4DIR","lib")])
891
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include","qt4")])
892
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include","qt4",module)])
893
pcmodules = [module+debugSuffix for module in modules if module not in pclessModules ]
894
if 'QtDBus' in pcmodules:
895
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include","qt4","QtDBus")])
896
if "QtAssistant" in pcmodules:
897
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include","qt4","QtAssistant")])
898
pcmodules.remove("QtAssistant")
899
pcmodules.append("QtAssistantClient")
900
self.ParseConfig('pkg-config %s --libs --cflags'% ' '.join(pcmodules))
901
self["QT4_MOCCPPPATH"] = self["CPPPATH"]
903
if sys.platform == "win32" or crosscompiling :
905
transformedQtdir = transformToWinePath(self['QT4DIR'])
906
self['QT4_MOC'] = "QT4DIR=%s %s"%( transformedQtdir, self['QT4_MOC'])
907
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include")])
908
try: modules.remove("QtDBus")
910
if debug : debugSuffix = 'd'
911
if "QtAssistant" in modules:
912
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include","QtAssistant")])
913
modules.remove("QtAssistant")
914
modules.append("QtAssistantClient")
915
self.AppendUnique(LIBS=['qtmain'+debugSuffix])
916
self.AppendUnique(LIBS=[lib+debugSuffix+'4' for lib in modules if lib not in staticModules])
917
self.PrependUnique(LIBS=[lib+debugSuffix for lib in modules if lib in staticModules])
918
if 'QtOpenGL' in modules:
919
self.AppendUnique(LIBS=['opengl32'])
920
self.AppendUnique(CPPPATH=[ '$QT4DIR/include/'])
921
self.AppendUnique(CPPPATH=[ '$QT4DIR/include/'+module for module in modules])
923
self["QT4_MOCCPPPATH"] = [
924
path.replace('$QT4DIR', transformedQtdir)
925
for path in self['CPPPATH'] ]
927
self["QT4_MOCCPPPATH"] = self["CPPPATH"]
928
self.AppendUnique(LIBPATH=[os.path.join('$QT4DIR','lib')])
931
if sys.platform=="darwin" :
932
# TODO: Test debug version on Mac
933
self.AppendUnique(LIBPATH=[os.path.join('$QT4DIR','lib')])
934
self.AppendUnique(LINKFLAGS="-F$QT4DIR/lib")
935
self.AppendUnique(LINKFLAGS="-L$QT4DIR/lib") #TODO clean!
936
if debug : debugSuffix = 'd'
937
for module in modules :
938
# self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include")])
939
# self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include",module)])
941
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include", "qt4")])
942
self.AppendUnique(CPPPATH=[os.path.join("$QT4DIR","include", "qt4", module)])
943
if module in staticModules :
944
self.AppendUnique(LIBS=[module+debugSuffix]) # TODO: Add the debug suffix
945
self.AppendUnique(LIBPATH=[os.path.join("$QT4DIR","lib")])
947
# self.Append(LINKFLAGS=['-framework', module])
949
self.Append(LIBS=module)
950
if 'QtOpenGL' in modules:
951
self.AppendUnique(LINKFLAGS="-F/System/Library/Frameworks")
952
self.Append(LINKFLAGS=['-framework', 'AGL']) #TODO ughly kludge to avoid quotes
953
self.Append(LINKFLAGS=['-framework', 'OpenGL'])
954
self["QT4_MOCCPPPATH"] = self["CPPPATH"]
956
# This should work for mac but doesn't
957
# env.AppendUnique(FRAMEWORKPATH=[os.path.join(env['QT4DIR'],'lib')])
958
# env.AppendUnique(FRAMEWORKS=['QtCore','QtGui','QtOpenGL', 'AGL'])