2e02775a3134e0712daecfe3134f7f2436d6c541
[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: return env['QTDIR']
203     except KeyError: pass
204
205     try: return os.environ['QTDIR']
206     except KeyError: pass
207
208     moc = env.WhereIs('moc-qt4') or env.WhereIs('moc4') or env.WhereIs('moc')
209     if moc:
210         QTDIR = os.path.dirname(os.path.dirname(moc))
211         # SCons.Warnings.warn(
212         #   QtdirNotFound,
213         #   "QTDIR variable is not defined, using moc executable as a hint (QTDIR=%s)" % QTDIR)
214         return QTDIR
215
216     raise SCons.Errors.StopError(
217         QtdirNotFound,
218         "Could not detect Qt 4 installation")
219     return None
220
221 def generate(env):
222     """Add Builders and construction variables for qt to an Environment."""
223
224     def locateQt4Command(env, command, qtdir) :
225         suffixes = [
226             '-qt4',
227             '-qt4.exe',
228             '4',
229             '4.exe',
230             '',
231             '.exe',
232         ]
233         triedPaths = []
234         for suffix in suffixes :
235             fullpath = os.path.join(qtdir,'bin',command + suffix)
236             if os.access(fullpath, os.X_OK) :
237                 return fullpath
238             triedPaths.append(fullpath)
239
240         fullpath = env.Detect([command+'-qt4', command+'4', command])
241         if not (fullpath is None) : return fullpath
242
243         raise Exception("Qt4 command '" + command + "' not found. Tried: " + ', '.join(triedPaths))
244
245
246     CLVar = SCons.Util.CLVar
247     Action = SCons.Action.Action
248     Builder = SCons.Builder.Builder
249     splitext = SCons.Util.splitext
250
251     env['QTDIR']  = _detect(env)
252     # TODO: 'Replace' should be 'SetDefault'
253     #env.SetDefault(
254     env.Replace(
255         QTDIR  = _detect(env),
256         QT4_BINPATH = os.path.join('$QTDIR', 'bin'),
257         # TODO: This is not reliable to QTDIR value changes but needed in order to support '-qt4'
258         # variants
259         QT4_MOC = locateQt4Command(env,'moc', env['QTDIR']),
260         QT4_UIC = locateQt4Command(env,'uic', env['QTDIR']),
261         QT4_RCC = locateQt4Command(env,'rcc', env['QTDIR']),
262         QT4_LUPDATE = locateQt4Command(env,'lupdate', env['QTDIR']),
263         QT4_LRELEASE = locateQt4Command(env,'lrelease', env['QTDIR']),
264
265         QT4_AUTOSCAN = 1, # Should the qt tool try to figure out, which sources are to be moc'ed?
266
267         # Some QT specific flags. I don't expect someone wants to
268         # manipulate those ...
269         QT4_UICFLAGS = CLVar(''),
270         QT4_MOCFROMHFLAGS = CLVar(''),
271         QT4_MOCFROMCXXFLAGS = CLVar('-i'),
272         QT4_QRCFLAGS = '',
273
274         # suffixes/prefixes for the headers / sources to generate
275         QT4_UISUFFIX = '.ui',
276         QT4_UICDECLPREFIX = 'ui_',
277         QT4_UICDECLSUFFIX = '.h',
278         QT4_MOCINCPREFIX = '-I',
279         QT4_MOCHPREFIX = 'moc_',
280         QT4_MOCHSUFFIX = '$CXXFILESUFFIX',
281         QT4_MOCCXXPREFIX = '',
282         QT4_MOCCXXSUFFIX = '.moc',
283         QT4_QRCSUFFIX = '.qrc',
284         QT4_QRCCXXSUFFIX = '$CXXFILESUFFIX',
285         QT4_QRCCXXPREFIX = 'qrc_',
286         QT4_MOCCPPPATH = [],
287         QT4_MOCINCFLAGS = \
288                 '$( ${_concat(QT4_MOCINCPREFIX, QT4_MOCCPPPATH, INCSUFFIX, __env__, RDirs)} $)',
289
290         # Commands for the qt support ...
291         QT4_UICCOM = '$QT4_UIC $QT4_UICFLAGS -o $TARGET $SOURCE',
292         QT4_MOCFROMHCOM = '$QT4_MOC $QT4_MOCFROMHFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
293         QT4_MOCFROMCXXCOM = [
294             '$QT4_MOC $QT4_MOCFROMCXXFLAGS $QT4_MOCINCFLAGS -o $TARGET $SOURCE',
295             Action(checkMocIncluded,None)],
296         QT4_LUPDATECOM = '$QT4_LUPDATE $SOURCE -ts $TARGET',
297         QT4_LRELEASECOM = '$QT4_LRELEASE $SOURCE',
298         QT4_RCCCOM = '$QT4_RCC $QT4_QRCFLAGS -name ${SOURCE.filebase} $SOURCE -o $TARGET',
299         )
300
301     # Translation builder
302     tsbuilder = Builder(
303         action = SCons.Action.Action('$QT4_LUPDATECOM'), #,'$QT4_LUPDATECOMSTR'),
304         multi=1
305         )
306     env.Append( BUILDERS = { 'Ts': tsbuilder } )
307     qmbuilder = Builder(
308         action = SCons.Action.Action('$QT4_LRELEASECOM'),# , '$QT4_LRELEASECOMSTR'),
309         src_suffix = '.ts',
310         suffix = '.qm',
311         single_source = True
312         )
313     env.Append( BUILDERS = { 'Qm': qmbuilder } )
314
315     # Resource builder
316     def scanResources(node, env, path, arg):
317         # I've being careful on providing names relative to the qrc file
318         # If that was not needed that code could be simplified a lot
319         def recursiveFiles(basepath, path) :
320             result = []
321             for item in os.listdir(os.path.join(basepath, path)) :
322                 itemPath = os.path.join(path, item)
323                 if os.path.isdir(os.path.join(basepath, itemPath)) :
324                     result += recursiveFiles(basepath, itemPath)
325                 else:
326                     result.append(itemPath)
327             return result
328         contents = node.get_contents()
329         includes = qrcinclude_re.findall(contents)
330         qrcpath = os.path.dirname(node.path)
331         dirs = [included for included in includes if os.path.isdir(os.path.join(qrcpath,included))]
332         # dirs need to include files recursively
333         for dir in dirs :
334             includes.remove(dir)
335             includes+=recursiveFiles(qrcpath,dir)
336         return includes
337     qrcscanner = SCons.Scanner.Scanner(name = 'qrcfile',
338         function = scanResources,
339         argument = None,
340         skeys = ['.qrc'])
341     qrcaction = SCons.Action.Action('$QT4_RCCCOM', '$QT4_RCCCOMSTR')
342     qrcbuilder = Builder(
343         action = qrcaction,
344         source_scanner = qrcscanner,
345         src_suffix = '$QT4_QRCSUFFIX',
346         suffix = '$QT4_QRCCXXSUFFIX',
347         prefix = '$QT4_QRCCXXPREFIX',
348         single_source = True
349         )
350     env.Append( BUILDERS = { 'Qrc': qrcbuilder } )
351
352     #c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
353     #cxx_file.add_action('.qrc', qrcaction)
354
355     # Interface builder
356     uic4builder = Builder(
357         action = SCons.Action.Action('$QT4_UICCOM', '$QT4_UICCOMSTR'),
358         src_suffix='$QT4_UISUFFIX',
359         suffix='$QT4_UICDECLSUFFIX',
360         prefix='$QT4_UICDECLPREFIX',
361         single_source = True
362         #TODO: Consider the uiscanner on new scons version
363         )
364     env['BUILDERS']['Uic4'] = uic4builder
365
366     # Metaobject builder
367     mocBld = Builder(action={}, prefix={}, suffix={})
368     for h in header_extensions:
369         act = SCons.Action.Action('$QT4_MOCFROMHCOM', '$QT4_MOCFROMHCOMSTR')
370         mocBld.add_action(h, act)
371         mocBld.prefix[h] = '$QT4_MOCHPREFIX'
372         mocBld.suffix[h] = '$QT4_MOCHSUFFIX'
373     for cxx in cxx_suffixes:
374         act = SCons.Action.Action('$QT4_MOCFROMCXXCOM', '$QT4_MOCFROMCXXCOMSTR')
375         mocBld.add_action(cxx, act)
376         mocBld.prefix[cxx] = '$QT4_MOCCXXPREFIX'
377         mocBld.suffix[cxx] = '$QT4_MOCCXXSUFFIX'
378     env['BUILDERS']['Moc4'] = mocBld
379
380     # er... no idea what that was for
381     # Answer: This lets the Object (and therefore the Program builder) automatically
382     #         recognize and build uic and qrc files
383     static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
384     static_obj.src_builder.append('Uic4')
385     shared_obj.src_builder.append('Uic4')
386     static_obj.src_builder.append('Qrc')
387     shared_obj.src_builder.append('Qrc')
388
389     # We use the emitters of Program / StaticLibrary / SharedLibrary
390     # to scan for moc'able files
391     # We can't refer to the builders directly, we have to fetch them
392     # as Environment attributes because that sets them up to be called
393     # correctly later by our emitter.
394     env.AppendUnique( PROGEMITTER =[AutomocStatic],
395               SHLIBEMITTER=[AutomocShared],
396               LIBEMITTER  =[AutomocStatic] )
397
398     # TODO: Does dbusxml2cpp need an adapter
399     env.AddMethod(enable_modules, "EnableQt4Modules")
400
401     resourceDirectoryBuilder = Builder(
402         action = Action(resourceDirectory),
403         source_factory = env.Dir)
404     env.Append( BUILDERS = { 'Qt4ResourceFromDirectory' : resourceDirectoryBuilder } )
405
406     # Utilities
407     env.AddMethod(qt4glob, "Qt4Glob")
408
409 def enable_modules(self, modules, debug=False, crosscompiling=False) :
410     import sys
411
412     validModules = [
413         'QtCore',
414         'QtGui',
415         'QtOpenGL',
416         'Qt3Support',
417         'QtAssistant', # deprecated
418         'QtAssistantClient',
419         'QtScript',
420         'QtDBus',
421         'QtSql',
422         'QtSvg',
423         # The next modules have not been tested yet so, please
424         # maybe they require additional work on non Linux platforms
425         'QtNetwork',
426         'QtTest',
427         'QtXml',
428         'QtXmlPatterns',
429         'QtUiTools',
430         'QtDesigner',
431         'QtDesignerComponents',
432         'QtWebKit',
433         'QtHelp',
434         'QtScript',
435         'QtScriptTools',
436         'QtMultimedia',
437         ]
438     pclessModules = [
439 # in qt <= 4.3 designer and designerComponents are pcless, on qt4.4 they are not, so removed.
440 #       'QtDesigner',
441 #       'QtDesignerComponents',
442     ]
443     staticModules = [
444         'QtUiTools',
445     ]
446     invalidModules=[]
447     for module in modules:
448         if module not in validModules :
449             invalidModules.append(module)
450     if invalidModules :
451         raise Exception("Modules %s are not Qt4 modules. Valid Qt4 modules are: %s"% (
452             str(invalidModules),str(validModules)))
453
454     moduleDefines = {
455         'QtScript'   : ['QT_SCRIPT_LIB'],
456         'QtSvg'      : ['QT_SVG_LIB'],
457         'Qt3Support' : ['QT_QT3SUPPORT_LIB','QT3_SUPPORT'],
458         'QtSql'      : ['QT_SQL_LIB'],
459         'QtXml'      : ['QT_XML_LIB'],
460         'QtOpenGL'   : ['QT_OPENGL_LIB'],
461         'QtGui'      : ['QT_GUI_LIB'],
462         'QtNetwork'  : ['QT_NETWORK_LIB'],
463         'QtCore'     : ['QT_CORE_LIB'],
464     }
465     for module in modules :
466         try : self.AppendUnique(CPPDEFINES=moduleDefines[module])
467         except: pass
468     debugSuffix = ''
469     if sys.platform in ["darwin", "linux2"] and not crosscompiling :
470         if debug : debugSuffix = '_debug'
471         for module in modules :
472             if module not in pclessModules : continue
473             self.AppendUnique(LIBS=[module+debugSuffix])
474             self.AppendUnique(LIBPATH=[os.path.join("$QTDIR","lib")])
475             self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4")])
476             self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4",module)])
477         pcmodules = [module+debugSuffix for module in modules if module not in pclessModules ]
478         if 'QtDBus' in pcmodules:
479             self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4","QtDBus")])
480         if "QtAssistant" in pcmodules:
481             self.AppendUnique(CPPPATH=[os.path.join("$QTDIR","include","qt4","QtAssistant")])
482             pcmodules.remove("QtAssistant")
483             pcmodules.append("QtAssistantClient")
484         self.ParseConfig('pkg-config %s --libs --cflags'% ' '.join(pcmodules))
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, 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>' % (f, os.path.join(base, f)))
560         rv.append("'</qresource>'")
561     rv.append('</RCC>\n')
562     return '\n'.join(rv)
563
564 def resourceDirectory(env, target, source):
565     file(str(target[0]), 'w').write(scanResourceDirectory(
566             source[0], prefix=env.get('RESOURCE_PREFIX', ''), exclude=env.get('EXCLUDE', [])))
567
568 def exists(env):
569     return _detect(env)