~yade-dev/yade/0.80

« back to all changes in this revision

Viewing changes to site_scons/site_tools/qt4/__init__.py

  • Committer: Anton Gladky
  • Date: 2012-05-02 21:50:42 UTC
  • Revision ID: gladky.anton@gmail.com-20120502215042-v1fa9r65usqe7kfk
0.80.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
"""SCons.Tool.qt4
 
3
 
 
4
Tool-specific initialization for Qt4.
 
5
 
 
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()
 
8
selection method.
 
9
 
 
10
"""
 
11
 
 
12
#
 
13
# Copyright (c) 2001-7,2010 The SCons Foundation
 
14
#
 
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:
 
22
#
 
23
# The above copyright notice and this permission notice shall be included
 
24
# in all copies or substantial portions of the Software.
 
25
#
 
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.
 
33
#
 
34
 
 
35
import os.path
 
36
import re
 
37
 
 
38
import SCons.Action
 
39
import SCons.Builder
 
40
import SCons.Defaults
 
41
import SCons.Scanner
 
42
import SCons.Tool
 
43
import SCons.Util
 
44
 
 
45
class ToolQt4Warning(SCons.Warnings.Warning):
 
46
    pass
 
47
 
 
48
class GeneratedMocFileNotIncluded(ToolQt4Warning):
 
49
    pass
 
50
 
 
51
class QtdirNotFound(ToolQt4Warning):
 
52
    pass
 
53
 
 
54
SCons.Warnings.enableWarningClass(ToolQt4Warning)
 
55
 
 
56
try:
 
57
    sorted
 
58
except NameError:
 
59
    # Pre-2.4 Python has no sorted() function.
 
60
    #
 
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):
 
66
        if key is not None:
 
67
            result = [(key(x), x) for x in iterable]
 
68
        else:
 
69
            result = iterable[:]
 
70
        if cmp is None:
 
71
            # Pre-2.3 Python does not support list.sort(None).
 
72
            result.sort()
 
73
        else:
 
74
            result.sort(cmp)
 
75
        if key is not None:
 
76
            result = [t1 for t0,t1 in result]
 
77
        if reverse:
 
78
            result.reverse()
 
79
        return result
 
80
 
 
81
qrcinclude_re = re.compile(r'<file[^>]*>([^<]*)</file>', re.M)
 
82
 
 
83
def transformToWinePath(path) :
 
84
    return os.popen('winepath -w "%s"'%path).read().strip().replace('\\','/')
 
85
 
 
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"]
 
94
 
 
95
def checkMocIncluded(target, source, env):
 
96
    moc = target[0]
 
97
    cpp = source[0]
 
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:
 
103
        SCons.Warnings.warn(
 
104
            GeneratedMocFileNotIncluded,
 
105
            "Generated moc file '%s' is not included by '%s'" %
 
106
            (str(moc), str(cpp)))
 
107
 
 
108
def find_file(filename, paths, node_factory):
 
109
    for dir in paths:
 
110
        node = node_factory(filename, dir)
 
111
        if node.rexists():
 
112
            return node
 
113
    return None
 
114
 
 
115
class _Automoc:
 
116
    """
 
117
    Callable class, which works as an emitter for Programs, SharedLibraries and
 
118
    StaticLibraries.
 
119
    """
 
120
 
 
121
    def __init__(self, objBuilderName):
 
122
        self.objBuilderName = objBuilderName
 
123
        # some regular expressions:
 
124
        # Q_OBJECT detection
 
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]*"')
 
131
        
 
132
    def create_automoc_options(self, env):
 
133
        """
 
134
        Create a dictionary with variables related to Automocing,
 
135
        based on the current environment.
 
136
        Is executed once in the __call__ routine.  
 
137
        """
 
138
        moc_options = {'auto_scan' : True,
 
139
                       'auto_scan_strategy' : 0,
 
140
                       'gobble_comments' : 0,
 
141
                       'debug' : 0,
 
142
                       'auto_cpppath' : True,
 
143
                       'cpppaths' : []}
 
144
        try:
 
145
            if int(env.subst('$QT4_AUTOSCAN')) == 0:
 
146
                moc_options['auto_scan'] = False
 
147
        except ValueError:
 
148
            pass
 
149
        try:
 
150
            moc_options['auto_scan_strategy'] = int(env.subst('$QT4_AUTOSCAN_STRATEGY'))
 
151
        except ValueError:
 
152
            pass
 
153
        try:
 
154
            moc_options['gobble_comments'] = int(env.subst('$QT4_GOBBLECOMMENTS'))
 
155
        except ValueError:
 
156
            pass
 
157
        try:
 
158
            moc_options['debug'] = int(env.subst('$QT4_DEBUG'))
 
159
        except ValueError:
 
160
            pass
 
161
        try:
 
162
            if int(env.subst('$QT4_AUTOMOC_SCANCPPPATH')) == 0:
 
163
                moc_options['auto_cpppath'] = False
 
164
        except ValueError:
 
165
            pass
 
166
        if moc_options['auto_cpppath']:
 
167
            paths = env.get('QT4_AUTOMOC_CPPPATH', [])
 
168
            if not paths:
 
169
                paths = env.get('CPPPATH', [])
 
170
            moc_options['cpppaths'].extend(paths)
 
171
        
 
172
        return moc_options
 
173
 
 
174
    def __automoc_strategy_simple(self, env, moc_options, 
 
175
                                  cpp, cpp_contents, out_sources):
 
176
        """
 
177
        Default Automoc strategy (Q_OBJECT driven): detect a header file
 
178
        (alongside the current cpp/cxx) that contains a Q_OBJECT
 
179
        macro...and MOC it.
 
180
        If a Q_OBJECT macro is also found in the cpp/cxx itself,
 
181
        it gets MOCed too.
 
182
        """
 
183
        
 
184
        h=None
 
185
        for h_ext in header_extensions:
 
186
            # try to find the header file in the corresponding source
 
187
            # directory
 
188
            hname = self.splitext(cpp.name)[0] + h_ext
 
189
            h = find_file(hname, [cpp.get_dir()]+moc_options['cpppaths'], env.File)
 
190
            if h:
 
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)
 
198
                break
 
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)
 
211
            moc = env.Moc4(cpp)
 
212
            env.Ignore(moc, moc)
 
213
            if moc_options['debug']:
 
214
                print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
 
215
 
 
216
    def __automoc_strategy_include_driven(self, env, moc_options,
 
217
                                          cpp, cpp_contents, out_sources):
 
218
        """
 
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...
 
223
        """
 
224
        if self.splitext(str(cpp))[1] in cxx_suffixes:
 
225
            added = False
 
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
 
234
            
 
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
 
238
                
 
239
                # Try to find header file                    
 
240
                h=None
 
241
                hname=""
 
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)
 
247
                    if h:
 
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)
 
255
                        break
 
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)
 
262
                    added = True
 
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:
 
268
                                out_sources.pop(idx)
 
269
                                break
 
270
                    if moc_options['debug']:
 
271
                        print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(h_moc))
 
272
                else:
 
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)
 
275
 
 
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)
 
280
                    env.Ignore(moc, moc)
 
281
                    added = True
 
282
                    if moc_options['debug']:
 
283
                        print "scons: qt4: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
 
284
                else:
 
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)
 
287
 
 
288
            if not added:
 
289
                # Fallback to default Automoc strategy (Q_OBJECT driven)
 
290
               self.__automoc_strategy_simple(env, moc_options, cpp,
 
291
                                              cpp_contents, out_sources)
 
292
        
 
293
    def __call__(self, target, source, env):
 
294
        """
 
295
        Smart autoscan function. Gets the list of objects for the Program
 
296
        or Lib. Adds objects and builders for the special qt4 files.
 
297
        """
 
298
        moc_options = self.create_automoc_options(env)
 
299
        
 
300
        # some shortcuts used in the scanner
 
301
        self.splitext = SCons.Util.splitext
 
302
        self.objBuilder = getattr(env, self.objBuilderName)
 
303
 
 
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
 
308
        env.Moc4.env = env
 
309
        xMocBuilderEnv = env.XMoc4.env
 
310
        env.XMoc4.env = env
 
311
        
 
312
        # make a deep copy for the result; MocH objects will be appended
 
313
        out_sources = source[:]
 
314
 
 
315
        for obj in source:
 
316
            if not moc_options['auto_scan']:
 
317
                break
 
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)
 
320
                continue
 
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)
 
325
                continue
 
326
            cpp = obj.sources[0]
 
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
 
331
                continue
 
332
            try:
 
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
 
339
            
 
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)
 
344
            else:
 
345
                # Automoc strategy #1 (include driven)
 
346
                self.__automoc_strategy_include_driven(env, moc_options,
 
347
                                                       cpp, cpp_contents, out_sources)
 
348
 
 
349
        # restore the original env attributes (FIXME)
 
350
        self.objBuilder.env = objBuilderEnv
 
351
        env.Moc4.env = mocBuilderEnv
 
352
        env.XMoc4.env = xMocBuilderEnv
 
353
 
 
354
        return (target, sorted(set(out_sources)))
 
355
 
 
356
AutomocShared = _Automoc('SharedObject')
 
357
AutomocStatic = _Automoc('StaticObject')
 
358
 
 
359
def _detect(env):
 
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
 
364
 
 
365
    try: return env['QTDIR']
 
366
    except KeyError: pass
 
367
 
 
368
    try: return os.environ['QT4DIR']
 
369
    except KeyError: pass
 
370
 
 
371
    try: return os.environ['QTDIR']
 
372
    except KeyError: pass
 
373
 
 
374
    moc = env.WhereIs('moc-qt4') or env.WhereIs('moc4') or env.WhereIs('moc')
 
375
    if moc:
 
376
        QT4DIR = os.path.dirname(os.path.dirname(moc))
 
377
        SCons.Warnings.warn(
 
378
            QtdirNotFound,
 
379
            "QT4DIR variable is not defined, using moc executable as a hint (QT4DIR=%s)" % QT4DIR)
 
380
        return QT4DIR
 
381
 
 
382
    raise SCons.Errors.StopError(
 
383
        QtdirNotFound,
 
384
        "Could not detect Qt 4 installation")
 
385
    return None
 
386
 
 
387
 
 
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) :
 
393
        result = []
 
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)
 
398
            else:
 
399
                result.append(itemPath)
 
400
        return result
 
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
 
406
    for dir in dirs :
 
407
        includes.remove(dir)
 
408
        includes+=recursiveFiles(qrcpath,dir)
 
409
    return includes
 
410
 
 
411
#
 
412
# Scanners
 
413
#
 
414
__qrcscanner = SCons.Scanner.Scanner(name = 'qrcfile',
 
415
    function = __scanResources,
 
416
    argument = None,
 
417
    skeys = ['.qrc'])
 
418
 
 
419
#
 
420
# Emitters
 
421
#
 
422
def __qrc_path(head, prefix, tail, suffix):
 
423
    if head:
 
424
        if tail:
 
425
            return os.path.join(head, "%s%s%s" % (prefix, tail, suffix))
 
426
        else:
 
427
            return "%s%s%s" % (prefix, head, suffix)
 
428
    else:
 
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]))
 
432
    sHead = None
 
433
    sTail = sourceBase
 
434
    if sourceBase:
 
435
        sHead, sTail = os.path.split(sourceBase)
 
436
 
 
437
    t = __qrc_path(sHead, env.subst('$QT4_QRCCXXPREFIX'),
 
438
                   sTail, env.subst('$QT4_QRCCXXSUFFIX'))
 
439
 
 
440
    return t, source
 
441
 
 
442
#
 
443
# Action generators
 
444
#
 
445
def __moc_generator_from_h(source, target, env, for_signature):
 
446
    pass_defines = False
 
447
    try:
 
448
        if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
 
449
            pass_defines = True
 
450
    except ValueError:
 
451
        pass
 
452
    
 
453
    if pass_defines:
 
454
        return '$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
 
455
    else:
 
456
        return '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
 
457
 
 
458
def __moc_generator_from_cxx(source, target, env, for_signature):
 
459
    pass_defines = False
 
460
    try:
 
461
        if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
 
462
            pass_defines = True
 
463
    except ValueError:
 
464
        pass
 
465
    
 
466
    if pass_defines:
 
467
        return ['$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
 
468
                SCons.Action.Action(checkMocIncluded,None)]
 
469
    else:
 
470
        return ['$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
 
471
                SCons.Action.Action(checkMocIncluded,None)]
 
472
 
 
473
def __mocx_generator_from_h(source, target, env, for_signature):
 
474
    pass_defines = False
 
475
    try:
 
476
        if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
 
477
            pass_defines = True
 
478
    except ValueError:
 
479
        pass
 
480
    
 
481
    if pass_defines:
 
482
        return '$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
 
483
    else:
 
484
        return '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE'
 
485
 
 
486
def __mocx_generator_from_cxx(source, target, env, for_signature):
 
487
    pass_defines = False
 
488
    try:
 
489
        if int(env.subst('$QT4_CPPDEFINES_PASSTOMOC')) == 1:
 
490
            pass_defines = True
 
491
    except ValueError:
 
492
        pass
 
493
    
 
494
    if pass_defines:
 
495
        return ['$QT4_MOC $QT4_MOCDEFINES $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
 
496
                SCons.Action.Action(checkMocIncluded,None)]
 
497
    else:
 
498
        return ['$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
 
499
                SCons.Action.Action(checkMocIncluded,None)]
 
500
 
 
501
def __qrc_generator(source, target, env, for_signature):
 
502
    name_defined = False
 
503
    try:
 
504
        if env.subst('$QT4_QRCFLAGS').find('-name') >= 0:
 
505
            name_defined = True
 
506
    except ValueError:
 
507
        pass
 
508
    
 
509
    if name_defined:
 
510
        return '$QT4_RCC $QT4_QRCFLAGS $SOURCE -o $TARGET'
 
511
    else:
 
512
        qrc_suffix = env.subst('$QT4_QRCSUFFIX')
 
513
        src = str(source[0])
 
514
        head, tail = os.path.split(src)
 
515
        if tail:
 
516
            src = tail
 
517
        qrc_suffix = env.subst('$QT4_QRCSUFFIX')
 
518
        if src.endswith(qrc_suffix):
 
519
            qrc_stem = src[:-len(qrc_suffix)]
 
520
        else:
 
521
            qrc_stem = src
 
522
        return '$QT4_RCC $QT4_QRCFLAGS -name %s $SOURCE -o $TARGET' % qrc_stem
 
523
 
 
524
#
 
525
# Builders
 
526
#
 
527
__ts_builder = SCons.Builder.Builder(        
 
528
        action = SCons.Action.Action('$QT4_LUPDATECOM','$QT4_LUPDATECOMSTR'),
 
529
        suffix = '.ts',
 
530
        source_factory = SCons.Node.FS.Entry)
 
531
__qm_builder = SCons.Builder.Builder(
 
532
        action = SCons.Action.Action('$QT4_LRELEASECOM','$QT4_LRELEASECOMSTR'),
 
533
        src_suffix = '.ts',
 
534
        suffix = '.qm')
 
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',
 
541
        single_source = 1)
 
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'),
 
546
        src_suffix = '.ui')
 
547
 
 
548
 
 
549
#
 
550
# Wrappers (pseudo-Builders)
 
551
#
 
552
def Ts4(env, target, source=None, *args, **kw):
 
553
    """
 
554
    A pseudo-Builder wrapper around the LUPDATE executable of Qt4.
 
555
        lupdate [options] [source-file|path]... -ts ts-files
 
556
    """
 
557
    if not SCons.Util.is_List(target):
 
558
        target = [target]
 
559
    if not source:
 
560
        source = target[:]
 
561
    if not SCons.Util.is_List(source):
 
562
        source = [source]
 
563
 
 
564
    # Check QT4_CLEAN_TS and use NoClean() function
 
565
    clean_ts = False
 
566
    try:
 
567
        if int(env.subst('$QT4_CLEAN_TS')) == 1:
 
568
            clean_ts = True
 
569
    except ValueError:
 
570
        pass
 
571
    
 
572
    result = []
 
573
    for t in target:
 
574
        obj = __ts_builder.__call__(env, t, source, **kw)
 
575
        # Prevent deletion of the .ts file, unless explicitly specified
 
576
        if not clean_ts:
 
577
            env.NoClean(obj)
 
578
        # Always make our target "precious", such that it is not deleted
 
579
        # prior to a rebuild
 
580
        env.Precious(obj)
 
581
        # Add to resulting target list        
 
582
        result.extend(obj)
 
583
 
 
584
    return result
 
585
 
 
586
def Qm4(env, target, source=None, *args, **kw):
 
587
    """
 
588
    A pseudo-Builder wrapper around the LRELEASE executable of Qt4.
 
589
        lrelease [options] ts-files [-qm qm-file]
 
590
    """
 
591
    if not SCons.Util.is_List(target):
 
592
        target = [target]
 
593
    if not source:
 
594
        source = target[:]
 
595
    if not SCons.Util.is_List(source):
 
596
        source = [source]
 
597
 
 
598
    result = []    
 
599
    for t in target:
 
600
        result.extend(__qm_builder.__call__(env, t, source, **kw))
 
601
 
 
602
    return result
 
603
 
 
604
def Qrc4(env, target, source=None, *args, **kw):
 
605
    """
 
606
    A pseudo-Builder wrapper around the RCC executable of Qt4.
 
607
        rcc [options] qrc-files -o out-file
 
608
    """
 
609
    if not SCons.Util.is_List(target):
 
610
        target = [target]
 
611
    if not source:
 
612
        source = target[:]
 
613
    if not SCons.Util.is_List(source):
 
614
        source = [source]
 
615
 
 
616
    result = []
 
617
    for t, s in zip(target, source):
 
618
        result.extend(__qrc_builder.__call__(env, t, s, **kw))
 
619
 
 
620
    return result
 
621
 
 
622
def ExplicitMoc4(env, target, source, *args, **kw):
 
623
    """
 
624
    A pseudo-Builder wrapper around the MOC executable of Qt4.
 
625
        moc [options] <header-file>
 
626
    """
 
627
    if not SCons.Util.is_List(target):
 
628
        target = [target]
 
629
    if not SCons.Util.is_List(source):
 
630
        source = [source]
 
631
 
 
632
    result = []
 
633
    for t in target:
 
634
        # Is it a header or a cxx file?
 
635
        result.extend(__ex_moc_builder.__call__(env, t, source, **kw))
 
636
 
 
637
    return result
 
638
 
 
639
def ExplicitUic4(env, target, source, *args, **kw):
 
640
    """
 
641
    A pseudo-Builder wrapper around the UIC executable of Qt4.
 
642
        uic [options] <uifile>
 
643
    """
 
644
    if not SCons.Util.is_List(target):
 
645
        target = [target]
 
646
    if not SCons.Util.is_List(source):
 
647
        source = [source]
 
648
 
 
649
    result = []
 
650
    for t in target:
 
651
        result.extend(__ex_uic_builder.__call__(env, t, source, **kw))
 
652
 
 
653
    return result
 
654
 
 
655
def generate(env):
 
656
    """Add Builders and construction variables for qt4 to an Environment."""
 
657
 
 
658
    def locateQt4Command(env, command, qtdir) :
 
659
        suffixes = [
 
660
            '-qt4',
 
661
            '-qt4.exe',
 
662
            '4',
 
663
            '4.exe',
 
664
            '',
 
665
            '.exe',
 
666
        ]
 
667
        triedPaths = []
 
668
        for suffix in suffixes :
 
669
            fullpath = os.path.join(qtdir,'bin',command + suffix)
 
670
            if os.access(fullpath, os.X_OK) :
 
671
                return fullpath
 
672
            triedPaths.append(fullpath)
 
673
 
 
674
        fullpath = env.Detect([command+'-qt4', command+'4', command])
 
675
        if not (fullpath is None) : return fullpath
 
676
 
 
677
        raise Exception("Qt4 command '" + command + "' not found. Tried: " + ', '.join(triedPaths))
 
678
 
 
679
    CLVar = SCons.Util.CLVar
 
680
    Action = SCons.Action.Action
 
681
    Builder = SCons.Builder.Builder
 
682
 
 
683
    env['QT4DIR']  = _detect(env)
 
684
    # TODO: 'Replace' should be 'SetDefault'
 
685
#    env.SetDefault(
 
686
    env.Replace(
 
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']),
 
695
 
 
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
 
703
 
 
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'),
 
709
        QT4_QRCFLAGS = '',
 
710
        QT4_LUPDATEFLAGS = '',
 
711
        QT4_LRELEASEFLAGS = '',
 
712
 
 
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__)}',
 
728
        QT4_MOCCPPPATH = [],
 
729
        QT4_MOCINCFLAGS = '$( ${_concat(QT4_MOCINCPREFIX, QT4_MOCCPPPATH, INCSUFFIX, __env__, RDirs)} $)',
 
730
 
 
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',
 
735
        
 
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',
 
742
                
 
743
        )
 
744
 
 
745
    try:
 
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
 
759
 
 
760
    # Interface builder
 
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',
 
766
        single_source = True
 
767
        #TODO: Consider the uiscanner on new scons version
 
768
        )
 
769
    env['BUILDERS']['Uic4'] = uic4builder
 
770
 
 
771
    # Metaobject builder
 
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
 
784
 
 
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
 
799
 
 
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)    
 
806
 
 
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],
 
815
                    )
 
816
 
 
817
    # TODO: Does dbusxml2cpp need an adapter
 
818
    try:
 
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
 
824
 
 
825
def enable_modules(self, modules, debug=False, crosscompiling=False) :
 
826
    import sys
 
827
 
 
828
    validModules = [
 
829
        'QtCore',
 
830
        'QtGui',
 
831
        'QtOpenGL',
 
832
        'Qt3Support',
 
833
        'QtAssistant', # deprecated
 
834
        'QtAssistantClient',
 
835
        'QtScript',
 
836
        'QtDBus',
 
837
        'QtSql',
 
838
        'QtSvg',
 
839
        # The next modules have not been tested yet so, please
 
840
        # maybe they require additional work on non Linux platforms
 
841
        'QtNetwork',
 
842
        'QtTest',
 
843
        'QtXml',
 
844
        'QtXmlPatterns',
 
845
        'QtUiTools',
 
846
        'QtDesigner',
 
847
        'QtDesignerComponents',
 
848
        'QtWebKit',
 
849
        'QtHelp',
 
850
        'QtScript',
 
851
        'QtScriptTools',
 
852
        'QtMultimedia',
 
853
        ]
 
854
    pclessModules = [
 
855
# in qt <= 4.3 designer and designerComponents are pcless, on qt4.4 they are not, so removed.    
 
856
#        'QtDesigner',
 
857
#        'QtDesignerComponents',
 
858
    ]
 
859
    staticModules = [
 
860
        'QtUiTools',
 
861
    ]
 
862
    invalidModules=[]
 
863
    for module in modules:
 
864
        if module not in validModules :
 
865
            invalidModules.append(module)
 
866
    if invalidModules :
 
867
        raise Exception("Modules %s are not Qt4 modules. Valid Qt4 modules are: %s"% (
 
868
            str(invalidModules),str(validModules)))
 
869
 
 
870
    moduleDefines = {
 
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'],
 
880
    }
 
881
    for module in modules :
 
882
        try : self.AppendUnique(CPPDEFINES=moduleDefines[module])
 
883
        except: pass
 
884
    debugSuffix = ''
 
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"]
 
902
        return
 
903
    if sys.platform == "win32" or crosscompiling :
 
904
        if 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")
 
909
        except: pass
 
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])
 
922
        if crosscompiling :
 
923
            self["QT4_MOCCPPPATH"] = [
 
924
                path.replace('$QT4DIR', transformedQtdir)
 
925
                    for path in self['CPPPATH'] ]
 
926
        else :
 
927
            self["QT4_MOCCPPPATH"] = self["CPPPATH"]
 
928
        self.AppendUnique(LIBPATH=[os.path.join('$QT4DIR','lib')])
 
929
        return
 
930
    """
 
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)])
 
940
# port qt4-mac:
 
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")])
 
946
            else :
 
947
#                self.Append(LINKFLAGS=['-framework', module])
 
948
# port qt4-mac:
 
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"]
 
955
        return
 
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'])
 
959
    """
 
960
 
 
961
 
 
962
def exists(env):
 
963
    return _detect(env)