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