initial comit
[qtscons.git] / qt4.py
1 # -*- coding: utf-8 -*-
2 """SCons.Tool.qt
3
4 Tool-specific initialization for Qt.
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, 2002, 2003, 2004, 2005, 2006, 2007 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 __revision__ = "/home/scons/scons/branch.0/branch.96/baseline/src/engine/SCons/Tool/qt.py 0.96.92.D001 2006/04/10 23:13:27 knight"
36
37 import os.path
38 import re
39
40 import SCons.Action
41 import SCons.Builder
42 import SCons.Defaults
43 import SCons.Scanner
44 import SCons.Tool
45 import SCons.Util
46
47 class ToolQtWarning(SCons.Warnings.Warning):
48         pass
49
50 class GeneratedMocFileNotIncluded(ToolQtWarning):
51         pass
52
53 class QtdirNotFound(ToolQtWarning):
54         pass
55
56 SCons.Warnings.enableWarningClass(ToolQtWarning)
57
58 qrcinclude_re = re.compile(r'<file>([^<]*)</file>', re.M)
59
60 def transformToWinePath(path) :
61         return os.popen('winepath -w "%s"'%path).read().strip().replace('\\','/')
62
63 header_extensions = [".h", ".hxx", ".hpp", ".hh"]
64 if SCons.Util.case_sensitive_suffixes('.h', '.H'):
65         header_extensions.append('.H')
66 # TODO: The following two lines will work when integrated back to SCons
67 # TODO: Meanwhile the third line will do the work
68 #cplusplus = __import__('c++', globals(), locals(), [])
69 #cxx_suffixes = cplusplus.CXXSuffixes
70 cxx_suffixes = [".c", ".cxx", ".cpp", ".cc"]
71
72 def checkMocIncluded(target, source, env):
73         moc = target[0]
74         cpp = source[0]
75         # looks like cpp.includes is cleared before the build stage :-(
76         # not really sure about the path transformations (moc.cwd? cpp.cwd?) :-/
77         path = SCons.Defaults.CScan.path_function(env, moc.cwd)
78         includes = SCons.Defaults.CScan(cpp, env, path)
79         if not moc in includes:
80                 SCons.Warnings.warn(
81                         GeneratedMocFileNotIncluded,
82                         "Generated moc file '%s' is not included by '%s'" %
83                         (str(moc), str(cpp)))
84
85 def find_file(filename, paths, node_factory):
86         for dir in paths:
87                 node = node_factory(filename, dir)
88                 if node.rexists():
89                         return node
90         return None
91
92 class _Automoc:
93         """
94         Callable class, which works as an emitter for Programs, SharedLibraries and
95         StaticLibraries.
96         """
97
98         def __init__(self, objBuilderName):
99                 self.objBuilderName = objBuilderName
100                 
101         def __call__(self, target, source, env):
102                 """
103                 Smart autoscan function. Gets the list of objects for the Program
104                 or Lib. Adds objects and builders for the special qt files.
105                 """
106                 try:
107                         if int(env.subst('$QT4_AUTOSCAN')) == 0:
108                                 return target, source
109                 except ValueError:
110                         pass
111                 try:
112                         debug = int(env.subst('$QT4_DEBUG'))
113                 except ValueError:
114                         debug = 0
115                 
116                 # some shortcuts used in the scanner
117                 splitext = SCons.Util.splitext
118                 objBuilder = getattr(env, self.objBuilderName)
119
120                 # some regular expressions:
121                 # Q_OBJECT detection
122                 q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]') 
123                 # cxx and c comment 'eater'
124                 #comment = re.compile(r'(//.*)|(/\*(([^*])|(\*[^/]))*\*/)')
125                 # CW: something must be wrong with the regexp. See also bug #998222
126                 #        CURRENTLY THERE IS NO TEST CASE FOR THAT
127                 
128                 # The following is kind of hacky to get builders working properly (FIXME)
129                 objBuilderEnv = objBuilder.env
130                 objBuilder.env = env
131                 mocBuilderEnv = env.Moc4.env
132                 env.Moc4.env = env
133                 
134                 # make a deep copy for the result; MocH objects will be appended
135                 out_sources = source[:]
136
137                 for obj in source:
138                         if isinstance(obj,basestring):  # big kludge!
139                                 print "scons: qt4: '%s' MAYBE USING AN OLD SCONS VERSION AND NOT CONVERTED TO 'File'. Discarded." % str(obj)
140                                 continue
141                         if not obj.has_builder():
142                                 # binary obj file provided
143                                 if debug:
144                                         print "scons: qt: '%s' seems to be a binary. Discarded." % str(obj)
145                                 continue
146                         cpp = obj.sources[0]
147                         if not splitext(str(cpp))[1] in cxx_suffixes:
148                                 if debug:
149                                         print "scons: qt: '%s' is no cxx file. Discarded." % str(cpp) 
150                                 # c or fortran source
151                                 continue
152                         #cpp_contents = comment.sub('', cpp.get_contents())
153                         try:
154                                 cpp_contents = cpp.get_contents()
155                         except: continue # may be an still not generated source
156                         h=None
157                         for h_ext in header_extensions:
158                                 # try to find the header file in the corresponding source
159                                 # directory
160                                 hname = splitext(cpp.name)[0] + h_ext
161                                 h = find_file(hname, (cpp.get_dir(),), env.File)
162                                 if h:
163                                         if debug:
164                                                 print "scons: qt: Scanning '%s' (header of '%s')" % (str(h), str(cpp))
165                                         #h_contents = comment.sub('', h.get_contents())
166                                         h_contents = h.get_contents()
167                                         break
168                         if not h and debug:
169                                 print "scons: qt: no header for '%s'." % (str(cpp))
170                         if h and q_object_search.search(h_contents):
171                                 # h file with the Q_OBJECT macro found -> add moc_cpp
172                                 moc_cpp = env.Moc4(h)
173                                 moc_o = objBuilder(moc_cpp)
174                                 out_sources.append(moc_o)
175                                 #moc_cpp.target_scanner = SCons.Defaults.CScan
176                                 if debug:
177                                         print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(h), str(moc_cpp))
178                         if cpp and q_object_search.search(cpp_contents):
179                                 # cpp file with Q_OBJECT macro found -> add moc
180                                 # (to be included in cpp)
181                                 moc = env.Moc4(cpp)
182                                 env.Ignore(moc, moc)
183                                 if debug:
184                                         print "scons: qt: found Q_OBJECT macro in '%s', moc'ing to '%s'" % (str(cpp), str(moc))
185                                 #moc.source_scanner = SCons.Defaults.CScan
186                 # restore the original env attributes (FIXME)
187                 objBuilder.env = objBuilderEnv
188                 env.Moc4.env = mocBuilderEnv
189
190                 return (target, out_sources)
191
192 AutomocShared = _Automoc('SharedObject')
193 AutomocStatic = _Automoc('StaticObject')
194
195 def _detect(env):
196         """Not really safe, but fast method to detect the QT library"""
197         try: return env['QTDIR']
198         except KeyError: pass
199
200         try: return os.environ['QTDIR']
201         except KeyError: pass
202
203         moc = env.WhereIs('moc-qt4') or env.WhereIs('moc4') or env.WhereIs('moc')
204         if moc:
205                 QTDIR = os.path.dirname(os.path.dirname(moc))
206                 SCons.Warnings.warn(
207                         QtdirNotFound,
208                         "QTDIR variable is not defined, using moc executable as a hint (QTDIR=%s)" % QTDIR)
209                 return QTDIR
210
211         raise SCons.Errors.StopError(
212                 QtdirNotFound,
213                 "Could not detect Qt 4 installation")
214         return None
215
216 def generate(env):
217         """Add Builders and construction variables for qt to an Environment."""
218
219         def locateQt4Command(env, command, qtdir) :
220                 suffixes = [
221                         '-qt4',
222                         '-qt4.exe',
223                         '4',
224                         '4.exe',
225                         '',
226                         '.exe',
227                 ]
228                 triedPaths = []
229                 for suffix in suffixes :
230                         fullpath = os.path.join(qtdir,'bin',command + suffix)
231                         if os.access(fullpath, os.X_OK) :
232                                 return fullpath
233                         triedPaths.append(fullpath)
234
235                 fullpath = env.Detect([command+'-qt4', command+'4', command])
236                 if not (fullpath is None) : return fullpath
237
238                 raise Exception("Qt4 command '" + command + "' not found. Tried: " + ', '.join(triedPaths))
239                 
240
241         CLVar = SCons.Util.CLVar
242         Action = SCons.Action.Action
243         Builder = SCons.Builder.Builder
244         splitext = SCons.Util.splitext
245
246         env['QTDIR']  = _detect(env)
247         # TODO: 'Replace' should be 'SetDefault'
248 #       env.SetDefault(
249         env.Replace(
250                 QTDIR  = _detect(env),
251                 QT4_BINPATH = os.path.join('$QTDIR', 'bin'),
252                 # TODO: This is not reliable to QTDIR value changes but needed in order to support '-qt4' variants
253                 QT4_MOC = locateQt4Command(env,'moc', env['QTDIR']),
254                 QT4_UIC = locateQt4Command(env,'uic', env['QTDIR']),
255                 QT4_RCC = locateQt4Command(env,'rcc', env['QTDIR']),
256                 QT4_LUPDATE = locateQt4Command(env,'lupdate', env['QTDIR']),
257                 QT4_LRELEASE = locateQt4Command(env,'lrelease', env['QTDIR']),
258
259                 QT4_AUTOSCAN = 1, # Should the qt tool try to figure out, which sources are to be moc'ed?
260
261                 # Some QT specific flags. I don't expect someone wants to
262                 # manipulate those ...
263                 QT4_UICFLAGS = CLVar(''),
264                 QT4_MOCFROMHFLAGS = CLVar(''),
265                 QT4_MOCFROMCXXFLAGS = CLVar('-i'),
266                 QT4_QRCFLAGS = '',
267
268                 # suffixes/prefixes for the headers / sources to generate
269                 QT4_UISUFFIX = '.ui',
270                 QT4_UICDECLPREFIX = 'ui_',
271                 QT4_UICDECLSUFFIX = '.h',
272                 QT4_MOCINCPREFIX = '-I',
273                 QT4_MOCHPREFIX = 'moc_',
274                 QT4_MOCHSUFFIX = '$CXXFILESUFFIX',
275                 QT4_MOCCXXPREFIX = '',
276                 QT4_MOCCXXSUFFIX = '.moc',
277                 QT4_QRCSUFFIX = '.qrc',
278                 QT4_QRCCXXSUFFIX = '$CXXFILESUFFIX',
279                 QT4_QRCCXXPREFIX = 'qrc_',
280                 QT4_MOCCPPPATH = [],
281                 QT4_MOCINCFLAGS = '$( ${_concat(QT4_MOCINCPREFIX, QT4_MOCCPPPATH, INCSUFFIX, __env__, RDirs)} $)',
282
283                 # Commands for the qt support ...
284                 QT4_UICCOM = '$QT4_UIC $QT4_UICFLAGS -o $TARGET $SOURCE',
285                 QT4_MOCFROMHCOM = '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
286                 QT4_MOCFROMCXXCOM = [
287                         '$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
288                         Action(checkMocIncluded,None)],
289                 QT4_LUPDATECOM = '$QT4_LUPDATE $SOURCE -ts $TARGET',
290                 QT4_LRELEASECOM = '$QT4_LRELEASE $SOURCE',
291                 QT4_RCCCOM = '$QT4_RCC $QT4_QRCFLAGS -name ${SOURCE.filebase} $SOURCE -o $TARGET',
292                 )
293
294         # Translation builder
295         tsbuilder = Builder(
296                 action = SCons.Action.Action('$QT4_LUPDATECOM'), #,'$QT4_LUPDATECOMSTR'),
297                 multi=1
298                 )
299         env.Append( BUILDERS = { 'Ts': tsbuilder } )
300         qmbuilder = Builder(
301                 action = SCons.Action.Action('$QT4_LRELEASECOM'),# , '$QT4_LRELEASECOMSTR'),
302                 src_suffix = '.ts',
303                 suffix = '.qm',
304                 single_source = True
305                 )
306         env.Append( BUILDERS = { 'Qm': qmbuilder } )
307
308         # Resource builder
309         def scanResources(node, env, path, arg):
310                 # I've being careful on providing names relative to the qrc file
311                 # If that was not needed that code could be simplified a lot
312                 def recursiveFiles(basepath, path) :
313                         result = []
314                         for item in os.listdir(os.path.join(basepath, path)) :
315                                 itemPath = os.path.join(path, item)
316                                 if os.path.isdir(os.path.join(basepath, itemPath)) :
317                                         result += recursiveFiles(basepath, itemPath)
318                                 else:
319                                         result.append(itemPath)
320                         return result
321                 contents = node.get_contents()
322                 includes = qrcinclude_re.findall(contents)
323                 qrcpath = os.path.dirname(node.path)
324                 dirs = [included for included in includes if os.path.isdir(os.path.join(qrcpath,included))]
325                 # dirs need to include files recursively
326                 for dir in dirs :
327                         includes.remove(dir)
328                         includes+=recursiveFiles(qrcpath,dir)
329                 return includes
330         qrcscanner = SCons.Scanner.Scanner(name = 'qrcfile',
331                 function = scanResources,
332                 argument = None,
333                 skeys = ['.qrc'])
334         qrcaction = SCons.Action.Action('$QT4_RCCCOM', '$QT4_RCCCOMSTR')
335         qrcbuilder = Builder(
336                 action = qrcaction,
337                 source_scanner = qrcscanner,
338                 src_suffix = '$QT4_QRCSUFFIX',
339                 suffix = '$QT4_QRCCXXSUFFIX',
340                 prefix = '$QT4_QRCCXXPREFIX',
341                 single_source = True
342                 )
343         env.Append( BUILDERS = { 'Qrc': qrcbuilder } )
344
345         #c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
346         #cxx_file.add_action('.qrc', qrcaction)
347
348         # Interface builder
349         uic4builder = Builder(
350                 action = SCons.Action.Action('$QT4_UICCOM', '$QT4_UICCOMSTR'),
351                 src_suffix='$QT4_UISUFFIX',
352                 suffix='$QT4_UICDECLSUFFIX',
353                 prefix='$QT4_UICDECLPREFIX',
354                 single_source = True
355                 #TODO: Consider the uiscanner on new scons version
356                 )
357         env['BUILDERS']['Uic4'] = uic4builder
358
359         # Metaobject builder
360         mocBld = Builder(action={}, prefix={}, suffix={})
361         for h in header_extensions:
362                 act = SCons.Action.Action('$QT4_MOCFROMHCOM', '$QT4_MOCFROMHCOMSTR')
363                 mocBld.add_action(h, act)
364                 mocBld.prefix[h] = '$QT4_MOCHPREFIX'
365                 mocBld.suffix[h] = '$QT4_MOCHSUFFIX'
366         for cxx in cxx_suffixes:
367                 act = SCons.Action.Action('$QT4_MOCFROMCXXCOM', '$QT4_MOCFROMCXXCOMSTR')
368                 mocBld.add_action(cxx, act)
369                 mocBld.prefix[cxx] = '$QT4_MOCCXXPREFIX'
370                 mocBld.suffix[cxx] = '$QT4_MOCCXXSUFFIX'
371         env['BUILDERS']['Moc4'] = mocBld
372
373         # er... no idea what that was for
374         # Answer: This lets the Object (and therefore the Program builder) automatically
375         #         recognize and build uic and qrc files
376         static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
377         static_obj.src_builder.append('Uic4')
378         shared_obj.src_builder.append('Uic4')
379         static_obj.src_builder.append('Qrc')
380         shared_obj.src_builder.append('Qrc')
381
382         # We use the emitters of Program / StaticLibrary / SharedLibrary
383         # to scan for moc'able files
384         # We can't refer to the builders directly, we have to fetch them
385         # as Environment attributes because that sets them up to be called
386         # correctly later by our emitter.
387         env.AppendUnique( PROGEMITTER =[AutomocStatic],
388                           SHLIBEMITTER=[AutomocShared],
389                           LIBEMITTER  =[AutomocStatic] )
390
391         # TODO: Does dbusxml2cpp need an adapter
392         env.AddMethod(enable_modules, "EnableQt4Modules")
393
394 def enable_modules(self, modules, debug=False, crosscompiling=False) :
395         import sys
396
397         validModules = [
398                 'QtCore',
399                 'QtGui',
400                 'QtOpenGL',
401                 'Qt3Support',
402                 'QtAssistant', # deprecated
403                 'QtAssistantClient',
404                 'QtScript',
405                 'QtDBus',
406                 'QtSql',
407                 'QtSvg',
408                 # The next modules have not been tested yet so, please
409                 # maybe they require additional work on non Linux platforms
410                 'QtNetwork',
411                 'QtTest',
412                 'QtXml',
413                 'QtXmlPatterns',
414                 'QtUiTools',
415                 'QtDesigner',
416                 'QtDesignerComponents',
417                 'QtWebKit',
418                 'QtHelp',
419                 'QtScript',
420                 'QtScriptTools',
421                 'QtMultimedia',
422                 ]
423         pclessModules = [
424 # in qt <= 4.3 designer and designerComponents are pcless, on qt4.4 they are not, so removed.   
425 #               'QtDesigner',
426 #               'QtDesignerComponents',
427         ]
428         staticModules = [
429                 'QtUiTools',
430         ]
431         invalidModules=[]
432         for module in modules:
433                 if module not in validModules :
434                         invalidModules.append(module)
435         if invalidModules :
436                 raise Exception("Modules %s are not Qt4 modules. Valid Qt4 modules are: %s"% (
437                         str(invalidModules),str(validModules)))
438
439         moduleDefines = {
440                 'QtScript'   : ['QT_SCRIPT_LIB'],
441                 'QtSvg'      : ['QT_SVG_LIB'],
442                 'Qt3Support' : ['QT_QT3SUPPORT_LIB','QT3_SUPPORT'],
443                 'QtSql'      : ['QT_SQL_LIB'],
444                 'QtXml'      : ['QT_XML_LIB'],
445                 'QtOpenGL'   : ['QT_OPENGL_LIB'],
446                 'QtGui'      : ['QT_GUI_LIB'],
447                 'QtNetwork'  : ['QT_NETWORK_LIB'],
448                 'QtCore'     : ['QT_CORE_LIB'],
449         }
450         for module in modules :
451                 try : self.AppendUnique(CPPDEFINES=moduleDefines[module])
452                 except: pass
453         debugSuffix = ''
454         if sys.platform in ["darwin", "linux2"] and not crosscompiling :
455                 if debug : debugSuffix = '_debug'
456                 for module in modules :
457                         if module not in pclessModules : continue
458                         self.AppendUnique(LIBS=[module+debugSuffix])
459                         self.AppendUnique(LIBPATH=[os.path.join("$QTDIR","lib")])
460                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4")])
461                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4",module)])
462                 pcmodules = [module+debugSuffix for module in modules if module not in pclessModules ]
463                 if 'QtDBus' in pcmodules:
464                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4","QtDBus")])
465                 if "QtAssistant" in pcmodules:
466                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4","QtAssistant")])
467                         pcmodules.remove("QtAssistant")
468                         pcmodules.append("QtAssistantClient")
469                 self.ParseConfig('pkg-config %s --libs --cflags'% ' '.join(pcmodules))
470                 self["QT4_MOCCPPPATH"] = self["CPPPATH"]
471                 return
472         if sys.platform == "win32" or crosscompiling :
473                 if crosscompiling:
474                         transformedQtdir = transformToWinePath(self['QTDIR'])
475                         self['QT4_MOC'] = "QTDIR=%s %s"%( transformedQtdir, self['QT4_MOC'])
476                 self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include")])
477                 try: modules.remove("QtDBus")
478                 except: pass
479                 if debug : debugSuffix = 'd'
480                 if "QtAssistant" in modules:
481                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","QtAssistant")])
482                         modules.remove("QtAssistant")
483                         modules.append("QtAssistantClient")
484                 self.AppendUnique(LIBS=[lib+'4'+debugSuffix for lib in modules if lib not in staticModules])
485                 self.PrependUnique(LIBS=[lib+debugSuffix for lib in modules if lib in staticModules])
486                 if 'QtOpenGL' in modules:
487                         self.AppendUnique(LIBS=['opengl32'])
488                 self.AppendUnique(CPPPATH=[ '$QTDIR/include/'])
489                 self.AppendUnique(CPPPATH=[ '$QTDIR/include/'+module for module in modules])
490                 if crosscompiling :
491                         self["QT4_MOCCPPPATH"] = [
492                                 path.replace('$QTDIR', transformedQtdir)
493                                         for path in self['CPPPATH'] ]
494                 else :
495                         self["QT4_MOCCPPPATH"] = self["CPPPATH"]
496                 self.AppendUnique(LIBPATH=[os.path.join('$QTDIR','lib')])
497                 return
498         """
499         if sys.platform=="darwin" :
500                 # TODO: Test debug version on Mac
501                 self.AppendUnique(LIBPATH=[os.path.join('$QTDIR','lib')])
502                 self.AppendUnique(LINKFLAGS="-F$QTDIR/lib")
503                 self.AppendUnique(LINKFLAGS="-L$QTDIR/lib") #TODO clean!
504                 if debug : debugSuffix = 'd'
505                 for module in modules :
506 #                       self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include")])
507 #                       self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include",module)])
508 # port qt4-mac:
509                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include", "qt4")])
510                         self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include", "qt4", module)])
511                         if module in staticModules :
512                                 self.AppendUnique(LIBS=[module+debugSuffix]) # TODO: Add the debug suffix
513                                 self.AppendUnique(LIBPATH=[os.path.join("$QTDIR","lib")])
514                         else :
515 #                               self.Append(LINKFLAGS=['-framework', module])
516 # port qt4-mac:
517                                 self.Append(LIBS=module)
518                 if 'QtOpenGL' in modules:
519                         self.AppendUnique(LINKFLAGS="-F/System/Library/Frameworks")
520                         self.Append(LINKFLAGS=['-framework', 'AGL']) #TODO ughly kludge to avoid quotes
521                         self.Append(LINKFLAGS=['-framework', 'OpenGL'])
522                 self["QT4_MOCCPPPATH"] = self["CPPPATH"]
523                 return
524 # This should work for mac but doesn't
525 #       env.AppendUnique(FRAMEWORKPATH=[os.path.join(env['QTDIR'],'lib')])
526 #       env.AppendUnique(FRAMEWORKS=['QtCore','QtGui','QtOpenGL', 'AGL'])
527         """
528
529
530 def exists(env):
531         return _detect(env)