3 # Thomas Nagy, 2006-2018 (ita)
6 This tool helps with finding Qt5 tools and libraries,
7 and also provides syntactic sugar for using Qt5 tools.
9 The following snippet illustrates the tool usage::
12 opt.load('compiler_cxx qt5')
15 conf.load('compiler_cxx qt5')
19 features = 'qt5 cxx cxxprogram',
20 uselib = 'QT5CORE QT5GUI QT5OPENGL QT5SVG',
21 source = 'main.cpp textures.qrc aboutDialog.ui',
25 Here, the UI description and resource files will be processed
33 You also need to edit your sources accordingly:
35 - the normal way of doing things is to have your C++ files
36 include the .moc file.
37 This is regarded as the best practice (and provides much faster
39 It also implies that the include paths have beenset properly.
41 - to have the include paths added automatically, use the following::
43 from waflib.TaskGen import feature, before_method, after_method
45 @after_method('process_source')
46 @before_method('apply_incpaths')
47 def add_includes_paths(self):
48 incs = set(self.to_list(getattr(self, 'includes', '')))
49 for x in self.compiled_tasks:
50 incs.add(x.inputs[0].parent.path_from(self.path))
51 self.includes = sorted(incs)
53 Note: another tool provides Qt processing that does not require
54 .moc includes, see 'playground/slow_qt/'.
56 A few options (--qt{dir,bin,...}) and environment variables
57 (QT5_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool,
58 tool path selection, etc; please read the source for more info.
60 The detection uses pkg-config on Linux by default. The list of
61 libraries to be requested to pkg-config is formulated by scanning
62 in the QTLIBS directory (that can be passed via --qtlibs or by
63 setting the environment variable QT5_LIBDIR otherwise is derived
64 by querying qmake for QT_INSTALL_LIBS directory) for shared/static
66 Alternatively the list of libraries to be requested via pkg-config
67 can be set using the qt5_vars attribute, ie:
69 conf.qt5_vars = ['Qt5Core', 'Qt5Gui', 'Qt5Widgets', 'Qt5Test'];
71 This can speed up configuration phase if needed libraries are
72 known beforehand, can improve detection on systems with a
73 sparse QT5 libraries installation (ie. NIX) and can improve
74 detection of some header-only Qt modules (ie. Qt5UiPlugin).
76 To force static library detection use:
77 QT5_XCOMPILE=1 QT5_FORCE_STATIC=1 waf configure
80 from __future__
import with_statement
83 from xml
.sax
import make_parser
84 from xml
.sax
.handler
import ContentHandler
87 ContentHandler
= object
92 from waflib
.Tools
import cxx
93 from waflib
import Build
, Task
, Utils
, Options
, Errors
, Context
94 from waflib
.TaskGen
import feature
, after_method
, extension
, before_method
95 from waflib
.Configure
import conf
96 from waflib
import Logs
98 MOC_H
= ['.h', '.hpp', '.hxx', '.hh']
100 File extensions associated to .moc files
105 File extension for the resource (.qrc) files
110 File extension for the user interface (.ui) files
113 EXT_QT5
= ['.cpp', '.cc', '.cxx', '.C']
115 File extensions of C++ files that may require a .moc processing
118 class qxx(Task
.classes
['cxx']):
120 Each C++ file can have zero or several .moc files to create.
121 They are known only when the files are scanned (preprocessor)
122 To avoid scanning the c++ files each time (parsing C/C++), the results
123 are retrieved from the task cache (bld.node_deps/bld.raw_deps).
124 The moc tasks are also created *dynamically* during the build.
127 def __init__(self
, *k
, **kw
):
128 Task
.Task
.__init
__(self
, *k
, **kw
)
131 def runnable_status(self
):
133 Compute the task signature to make sure the scanner was executed. Create the
134 moc tasks by using :py:meth:`waflib.Tools.qt5.qxx.add_moc_tasks` (if necessary),
135 then postpone the task execution (there is no need to recompute the task signature).
138 return Task
.Task
.runnable_status(self
)
140 for t
in self
.run_after
:
142 return Task
.ASK_LATER
144 return Task
.Task
.runnable_status(self
)
146 def create_moc_task(self
, h_node
, m_node
):
148 If several libraries use the same classes, it is possible that moc will run several times (Issue 1318)
149 It is not possible to change the file names, but we can assume that the moc transformation will be identical,
150 and the moc tasks can be shared in a global cache.
153 moc_cache
= self
.generator
.bld
.moc_cache
154 except AttributeError:
155 moc_cache
= self
.generator
.bld
.moc_cache
= {}
158 return moc_cache
[h_node
]
160 tsk
= moc_cache
[h_node
] = Task
.classes
['moc'](env
=self
.env
, generator
=self
.generator
)
161 tsk
.set_inputs(h_node
)
162 tsk
.set_outputs(m_node
)
163 tsk
.env
.append_unique('MOC_FLAGS', '-i')
166 self
.generator
.tasks
.append(tsk
)
168 # direct injection in the build phase (safe because called from the main thread)
169 gen
= self
.generator
.bld
.producer
170 gen
.outstanding
.append(tsk
)
176 # remove the signature, it must be recomputed with the moc task
177 delattr(self
, 'cache_sig')
179 def add_moc_tasks(self
):
181 Creates moc tasks by looking in the list of file dependencies ``bld.raw_deps[self.uid()]``
183 node
= self
.inputs
[0]
184 bld
= self
.generator
.bld
186 # skip on uninstall due to generated files
187 if bld
.is_install
== Build
.UNINSTALL
:
191 # compute the signature once to know if there is a moc file to create
194 # the moc file may be referenced somewhere else
197 # remove the signature, it must be recomputed with the moc task
198 delattr(self
, 'cache_sig')
200 include_nodes
= [node
.parent
] + self
.generator
.includes_nodes
204 for d
in bld
.raw_deps
.get(self
.uid(), []):
205 if not d
.endswith('.moc'):
208 # process that base.moc only once
213 # find the source associated with the moc file
217 # foo.moc from foo.cpp
218 prefix
= node
.name
[:node
.name
.rfind('.')]
222 # this deviates from the standard
223 # if bar.cpp includes foo.moc, then assume it is from foo.h
224 for x
in include_nodes
:
226 h_node
= x
.find_node(base2
+ e
)
233 m_node
= h_node
.change_ext('.moc')
235 raise Errors
.WafError('No source found for %r which is a moc file' % d
)
237 # create the moc task
238 task
= self
.create_moc_task(h_node
, m_node
)
239 moctasks
.append(task
)
241 # simple scheduler dependency: run the moc task before others
242 self
.run_after
.update(set(moctasks
))
245 class trans_update(Task
.Task
):
246 """Updates a .ts files from a list of C++ files"""
247 run_str
= '${QT_LUPDATE} ${SRC} -ts ${TGT}'
250 class XMLHandler(ContentHandler
):
252 Parses ``.qrc`` files
255 ContentHandler
.__init
__(self
)
258 def startElement(self
, name
, attrs
):
261 def endElement(self
, name
):
263 self
.files
.append(str(''.join(self
.buf
)))
264 def characters(self
, cars
):
265 self
.buf
.append(cars
)
268 def create_rcc_task(self
, node
):
269 "Creates rcc and cxx tasks for ``.qrc`` files"
270 rcnode
= node
.change_ext('_rc.%d.cpp' % self
.idx
)
271 self
.create_task('rcc', node
, rcnode
)
272 cpptask
= self
.create_task('cxx', rcnode
, rcnode
.change_ext('.o'))
274 self
.compiled_tasks
.append(cpptask
)
275 except AttributeError:
276 self
.compiled_tasks
= [cpptask
]
280 def create_uic_task(self
, node
):
281 "Create uic tasks for user interface ``.ui`` definition files"
284 If UIC file is used in more than one bld, we would have a conflict in parallel execution
285 It is not possible to change the file names (like .self.idx. as for objects) as they have
286 to be referenced by the source file, but we can assume that the transformation will be identical
287 and the tasks can be shared in a global cache.
290 uic_cache
= self
.bld
.uic_cache
291 except AttributeError:
292 uic_cache
= self
.bld
.uic_cache
= {}
294 if node
not in uic_cache
:
295 uictask
= uic_cache
[node
] = self
.create_task('ui5', node
)
296 uictask
.outputs
= [node
.parent
.find_or_declare(self
.env
.ui_PATTERN
% node
.name
[:-3])]
299 def add_lang(self
, node
):
300 """Adds all the .ts file into ``self.lang``"""
301 self
.lang
= self
.to_list(getattr(self
, 'lang', [])) + [node
]
304 @before_method('process_source')
305 def process_mocs(self
):
307 Processes MOC files included in headers::
310 bld.program(features='qt5', source='main.cpp', target='app', use='QT5CORE', moc='foo.h')
312 The build will run moc on foo.h to create moc_foo.n.cpp. The number in the file name
313 is provided to avoid name clashes when the same headers are used by several targets.
315 lst
= self
.to_nodes(getattr(self
, 'moc', []))
316 self
.source
= self
.to_list(getattr(self
, 'source', []))
318 prefix
= x
.name
[:x
.name
.rfind('.')] # foo.h -> foo
319 moc_target
= 'moc_%s.%d.cpp' % (prefix
, self
.idx
)
320 moc_node
= x
.parent
.find_or_declare(moc_target
)
321 self
.source
.append(moc_node
)
323 self
.create_task('moc', x
, moc_node
)
326 @after_method('apply_link')
329 Adds MOC_FLAGS which may be necessary for moc::
332 bld.program(features='qt5', source='main.cpp', target='app', use='QT5CORE')
334 The additional parameters are:
336 :param lang: list of translation files (\\*.ts) to process
337 :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
338 :param update: whether to process the C++ files to update the \\*.ts files (use **waf --translate**)
340 :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file
341 :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
343 if getattr(self
, 'lang', None):
345 for x
in self
.to_list(self
.lang
):
346 if isinstance(x
, str):
347 x
= self
.path
.find_resource(x
+ '.ts')
348 qmtasks
.append(self
.create_task('ts2qm', x
, x
.change_ext('.%d.qm' % self
.idx
)))
350 if getattr(self
, 'update', None) and Options
.options
.trans_qt5
:
351 cxxnodes
= [a
.inputs
[0] for a
in self
.compiled_tasks
] + [
352 a
.inputs
[0] for a
in self
.tasks
if a
.inputs
and a
.inputs
[0].name
.endswith('.ui')]
354 self
.create_task('trans_update', cxxnodes
, x
.inputs
)
356 if getattr(self
, 'langname', None):
357 qmnodes
= [x
.outputs
[0] for x
in qmtasks
]
358 rcnode
= self
.langname
359 if isinstance(rcnode
, str):
360 rcnode
= self
.path
.find_or_declare(rcnode
+ ('.%d.qrc' % self
.idx
))
361 t
= self
.create_task('qm2rcc', qmnodes
, rcnode
)
362 k
= create_rcc_task(self
, t
.outputs
[0])
363 self
.link_task
.inputs
.append(k
.outputs
[0])
366 for flag
in self
.to_list(self
.env
.CXXFLAGS
):
370 if f
in ('-D', '-I', '/D', '/I'):
372 lst
.append('-' + flag
[1:])
375 self
.env
.append_value('MOC_FLAGS', lst
)
378 def cxx_hook(self
, node
):
380 Re-maps C++ file extensions to the :py:class:`waflib.Tools.qt5.qxx` task.
382 return self
.create_compiled_task('qxx', node
)
384 class rcc(Task
.Task
):
386 Processes ``.qrc`` files
389 run_str
= '${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
393 return os
.path
.splitext(self
.inputs
[0].name
)[0]
396 """Parse the *.qrc* files"""
398 Logs
.error('No xml.sax support was found, rcc dependencies will be incomplete!')
401 parser
= make_parser()
402 curHandler
= XMLHandler()
403 parser
.setContentHandler(curHandler
)
404 with
open(self
.inputs
[0].abspath(), 'r') as f
:
409 root
= self
.inputs
[0].parent
410 for x
in curHandler
.files
:
411 nd
= root
.find_resource(x
)
416 return (nodes
, names
)
418 def quote_flag(self
, x
):
420 Override Task.quote_flag. QT parses the argument files
421 differently than cl.exe and link.exe
431 class moc(Task
.Task
):
433 Creates ``.moc`` files
436 run_str
= '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
438 def quote_flag(self
, x
):
440 Override Task.quote_flag. QT parses the argument files
441 differently than cl.exe and link.exe
451 class ui5(Task
.Task
):
453 Processes ``.ui`` files
456 run_str
= '${QT_UIC} ${SRC} -o ${TGT}'
459 class ts2qm(Task
.Task
):
461 Generates ``.qm`` files from ``.ts`` files
464 run_str
= '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
466 class qm2rcc(Task
.Task
):
468 Generates ``.qrc`` files from ``.qm`` files
473 """Create a qrc file including the inputs"""
474 txt
= '\n'.join(['<file>%s</file>' % k
.path_from(self
.outputs
[0].parent
) for k
in self
.inputs
])
475 code
= '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
476 self
.outputs
[0].write(code
)
480 Besides the configuration options, the environment variable QT5_ROOT may be used
481 to give the location of the qt5 libraries (absolute path).
483 The detection uses the program ``pkg-config`` through :py:func:`waflib.Tools.config_c.check_cfg`
485 if 'COMPILER_CXX' not in self
.env
:
486 self
.fatal('No CXX compiler defined: did you forget to configure compiler_cxx first?')
488 self
.find_qt5_binaries()
489 self
.set_qt5_libs_dir()
490 self
.set_qt5_libs_to_check()
491 self
.set_qt5_defines()
492 self
.find_qt5_libraries()
494 self
.simplify_qt5_libs()
496 # warn about this during the configuration too
498 Logs
.error('No xml.sax support was found, rcc dependencies will be incomplete!')
500 # Qt5 may be compiled with '-reduce-relocations' which requires dependent programs to have -fPIE or -fPIC?
501 frag
= '#include <QMap>\nint main(int argc, char **argv) {QMap<int,int> m;return m.keys().size();}\n'
503 for flag
in [[], '-fPIE', '-fPIC', '-std=c++11' , ['-std=c++11', '-fPIE'], ['-std=c++11', '-fPIC']]:
504 msg
= 'See if Qt files compile '
506 msg
+= 'with %s' % flag
508 self
.check(features
='qt5 cxx', use
=uses
, uselib_store
='qt5', cxxflags
=flag
, fragment
=frag
, msg
=msg
)
509 except self
.errors
.ConfigurationError
:
514 self
.fatal('Could not build a simple Qt application')
516 # FreeBSD does not add /usr/local/lib and the pkg-config files do not provide it either :-/
517 if Utils
.unversioned_sys_platform() == 'freebsd':
518 frag
= '#include <QMap>\nint main(int argc, char **argv) {QMap<int,int> m;return m.keys().size();}\n'
520 self
.check(features
='qt5 cxx cxxprogram', use
=uses
, fragment
=frag
, msg
='Can we link Qt programs on FreeBSD directly?')
521 except self
.errors
.ConfigurationError
:
522 self
.check(features
='qt5 cxx cxxprogram', use
=uses
, uselib_store
='qt5', libpath
='/usr/local/lib', fragment
=frag
, msg
='Is /usr/local/lib required?')
525 def find_qt5_binaries(self
):
527 Detects Qt programs such as qmake, moc, uic, lrelease
530 opt
= Options
.options
532 qtdir
= getattr(opt
, 'qtdir', '')
533 qtbin
= getattr(opt
, 'qtbin', '')
538 qtbin
= os
.path
.join(qtdir
, 'bin')
540 # the qt directory has been given from QT5_ROOT - deduce the qt binary path
542 qtdir
= self
.environ
.get('QT5_ROOT', '')
543 qtbin
= self
.environ
.get('QT5_BIN') or os
.path
.join(qtdir
, 'bin')
548 # no qtdir, look in the path and in /usr/local/Trolltech
550 paths
= self
.environ
.get('PATH', '').split(os
.pathsep
)
551 paths
.extend(['/usr/share/qt5/bin', '/usr/local/lib/qt5/bin'])
553 lst
= Utils
.listdir('/usr/local/Trolltech/')
561 # keep the highest version
562 qtdir
= '/usr/local/Trolltech/%s/' % lst
[0]
563 qtbin
= os
.path
.join(qtdir
, 'bin')
566 # at the end, try to find qmake in the paths given
567 # keep the one with the highest version
569 prev_ver
= ['0', '0', '0']
570 for qmk
in ('qmake-qt5', 'qmake5', 'qmake'):
572 qmake
= self
.find_program(qmk
, path_list
=paths
)
573 except self
.errors
.ConfigurationError
:
577 version
= self
.cmd_and_log(qmake
+ ['-query', 'QT_VERSION']).strip()
578 except self
.errors
.WafError
:
582 new_ver
= version
.split('.')
583 if new_ver
[0] == '5' and new_ver
> prev_ver
:
587 # qmake could not be found easily, rely on qtchooser
590 self
.find_program('qtchooser')
591 except self
.errors
.ConfigurationError
:
594 cmd
= self
.env
.QTCHOOSER
+ ['-qt=5', '-run-tool=qmake']
596 version
= self
.cmd_and_log(cmd
+ ['-query', 'QT_VERSION'])
597 except self
.errors
.WafError
:
603 self
.env
.QMAKE
= cand
605 self
.fatal('Could not find qmake for qt5')
607 self
.env
.QT_HOST_BINS
= qtbin
= self
.cmd_and_log(self
.env
.QMAKE
+ ['-query', 'QT_HOST_BINS']).strip()
608 paths
.insert(0, qtbin
)
610 def find_bin(lst
, var
):
615 ret
= self
.find_program(f
, path_list
=paths
)
616 except self
.errors
.ConfigurationError
:
622 find_bin(['uic-qt5', 'uic'], 'QT_UIC')
624 self
.fatal('cannot find the uic compiler for qt5')
626 self
.start_msg('Checking for uic version')
627 uicver
= self
.cmd_and_log(env
.QT_UIC
+ ['-version'], output
=Context
.BOTH
)
628 uicver
= ''.join(uicver
).strip()
629 uicver
= uicver
.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '')
631 if uicver
.find(' 3.') != -1 or uicver
.find(' 4.') != -1:
632 self
.fatal('this uic compiler is for qt3 or qt4, add uic for qt5 to your path')
634 find_bin(['moc-qt5', 'moc'], 'QT_MOC')
635 find_bin(['rcc-qt5', 'rcc'], 'QT_RCC')
636 find_bin(['lrelease-qt5', 'lrelease'], 'QT_LRELEASE')
637 find_bin(['lupdate-qt5', 'lupdate'], 'QT_LUPDATE')
639 env
.UIC_ST
= '%s -o %s'
641 env
.ui_PATTERN
= 'ui_%s.h'
642 env
.QT_LRELEASE_FLAGS
= ['-silent']
643 env
.MOCCPPPATH_ST
= '-I%s'
644 env
.MOCDEFINES_ST
= '-D%s'
647 def set_qt5_libs_dir(self
):
649 qtlibs
= getattr(Options
.options
, 'qtlibs', None) or self
.environ
.get('QT5_LIBDIR')
652 qtlibs
= self
.cmd_and_log(env
.QMAKE
+ ['-query', 'QT_INSTALL_LIBS']).strip()
653 except Errors
.WafError
:
654 qtdir
= self
.cmd_and_log(env
.QMAKE
+ ['-query', 'QT_INSTALL_PREFIX']).strip()
655 qtlibs
= os
.path
.join(qtdir
, 'lib')
656 self
.msg('Found the Qt5 library path', qtlibs
)
660 def find_single_qt5_lib(self
, name
, uselib
, qtlibs
, qtincludes
, force_static
):
663 exts
= ('.a', '.lib')
666 exts
= ('.so', '.lib')
671 for k
in ('', '5') if Utils
.is_win32
else ['']:
672 for p
in ('lib', ''):
673 yield (p
, name
, k
, x
)
675 for tup
in lib_names():
677 path
= os
.path
.join(qtlibs
, k
)
678 if os
.path
.exists(path
):
679 if env
.DEST_OS
== 'win32':
680 libval
= ''.join(tup
[:-1])
683 env
.append_unique(prefix
+ '_' + uselib
, libval
)
684 env
.append_unique('%sPATH_%s' % (prefix
, uselib
), qtlibs
)
685 env
.append_unique('INCLUDES_' + uselib
, qtincludes
)
686 env
.append_unique('INCLUDES_' + uselib
, os
.path
.join(qtincludes
, name
.replace('Qt5', 'Qt')))
691 def find_qt5_libraries(self
):
694 qtincludes
= self
.environ
.get('QT5_INCLUDES') or self
.cmd_and_log(env
.QMAKE
+ ['-query', 'QT_INSTALL_HEADERS']).strip()
695 force_static
= self
.environ
.get('QT5_FORCE_STATIC')
697 if self
.environ
.get('QT5_XCOMPILE'):
698 self
.fatal('QT5_XCOMPILE Disables pkg-config detection')
699 self
.check_cfg(atleast_pkgconfig_version
='0.1')
700 except self
.errors
.ConfigurationError
:
701 for i
in self
.qt5_vars
:
703 if Utils
.unversioned_sys_platform() == 'darwin':
704 # Since at least qt 4.7.3 each library locates in separate directory
705 fwk
= i
.replace('Qt5', 'Qt')
706 frameworkName
= fwk
+ '.framework'
708 qtDynamicLib
= os
.path
.join(env
.QTLIBS
, frameworkName
, fwk
)
709 if os
.path
.exists(qtDynamicLib
):
710 env
.append_unique('FRAMEWORK_' + uselib
, fwk
)
711 env
.append_unique('FRAMEWORKPATH_' + uselib
, env
.QTLIBS
)
712 self
.msg('Checking for %s' % i
, qtDynamicLib
, 'GREEN')
714 self
.msg('Checking for %s' % i
, False, 'YELLOW')
715 env
.append_unique('INCLUDES_' + uselib
, os
.path
.join(env
.QTLIBS
, frameworkName
, 'Headers'))
717 ret
= self
.find_single_qt5_lib(i
, uselib
, env
.QTLIBS
, qtincludes
, force_static
)
718 if not force_static
and not ret
:
719 ret
= self
.find_single_qt5_lib(i
, uselib
, env
.QTLIBS
, qtincludes
, True)
720 self
.msg('Checking for %s' % i
, ret
, 'GREEN' if ret
else 'YELLOW')
722 path
= '%s:%s:%s/pkgconfig:/usr/lib/qt5/lib/pkgconfig:/opt/qt5/lib/pkgconfig:/usr/lib/qt5/lib:/opt/qt5/lib' % (
723 self
.environ
.get('PKG_CONFIG_PATH', ''), env
.QTLIBS
, env
.QTLIBS
)
724 for i
in self
.qt5_vars
:
725 self
.check_cfg(package
=i
, args
='--cflags --libs', mandatory
=False, force_static
=force_static
, pkg_config_path
=path
)
728 def simplify_qt5_libs(self
):
730 Since library paths make really long command-lines,
731 and since everything depends on qtcore, remove the qtcore ones from qtgui, etc
734 def process_lib(vars_
, coreval
):
740 value
= env
['LIBPATH_'+var
]
748 env
['LIBPATH_'+var
] = accu
749 process_lib(self
.qt5_vars
, 'LIBPATH_QTCORE')
752 def add_qt5_rpath(self
):
754 Defines rpath entries for Qt libraries
757 if getattr(Options
.options
, 'want_rpath', False):
758 def process_rpath(vars_
, coreval
):
761 value
= env
['LIBPATH_' + var
]
769 accu
.append('-Wl,--rpath='+lib
)
770 env
['RPATH_' + var
] = accu
771 process_rpath(self
.qt5_vars
, 'LIBPATH_QTCORE')
774 def set_qt5_libs_to_check(self
):
775 self
.qt5_vars
= Utils
.to_list(getattr(self
, 'qt5_vars', []))
776 if not self
.qt5_vars
:
777 dirlst
= Utils
.listdir(self
.env
.QTLIBS
)
779 pat
= self
.env
.cxxshlib_PATTERN
781 pat
= pat
.replace('.dll', '.lib')
782 if self
.environ
.get('QT5_FORCE_STATIC'):
783 pat
= self
.env
.cxxstlib_PATTERN
784 if Utils
.unversioned_sys_platform() == 'darwin':
785 pat
= r
"%s\.framework"
786 re_qt
= re
.compile(pat
% 'Qt5?(?P<name>\\w+)' + '$')
787 for x
in sorted(dirlst
):
790 self
.qt5_vars
.append("Qt5%s" % m
.group('name'))
791 if not self
.qt5_vars
:
792 self
.fatal('cannot find any Qt5 library (%r)' % self
.env
.QTLIBS
)
794 qtextralibs
= getattr(Options
.options
, 'qtextralibs', None)
796 self
.qt5_vars
.extend(qtextralibs
.split(','))
799 def set_qt5_defines(self
):
800 if sys
.platform
!= 'win32':
802 for x
in self
.qt5_vars
:
803 y
=x
.replace('Qt5', 'Qt')[2:].upper()
804 self
.env
.append_unique('DEFINES_%s' % x
.upper(), 'QT_%s_LIB' % y
)
810 opt
.add_option('--want-rpath', action
='store_true', default
=False, dest
='want_rpath', help='enable the rpath for qt libraries')
811 for i
in 'qtdir qtbin qtlibs'.split():
812 opt
.add_option('--'+i
, type='string', default
='', dest
=i
)
814 opt
.add_option('--translate', action
='store_true', help='collect translation strings', dest
='trans_qt5', default
=False)
815 opt
.add_option('--qtextralibs', type='string', default
='', dest
='qtextralibs', help='additional qt libraries on the system to add to default ones, comma separated')