qt4.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. # Thomas Nagy, 2006-2010 (ita)
  4. """
  5. Tool Description
  6. ================
  7. This tool helps with finding Qt4 tools and libraries,
  8. and also provides syntactic sugar for using Qt4 tools.
  9. The following snippet illustrates the tool usage::
  10. def options(opt):
  11. opt.load('compiler_cxx qt4')
  12. def configure(conf):
  13. conf.load('compiler_cxx qt4')
  14. def build(bld):
  15. bld(
  16. features = 'qt4 cxx cxxprogram',
  17. uselib = 'QTCORE QTGUI QTOPENGL QTSVG',
  18. source = 'main.cpp textures.qrc aboutDialog.ui',
  19. target = 'window',
  20. )
  21. Here, the UI description and resource files will be processed
  22. to generate code.
  23. Usage
  24. =====
  25. Load the "qt4" tool.
  26. You also need to edit your sources accordingly:
  27. - the normal way of doing things is to have your C++ files
  28. include the .moc file.
  29. This is regarded as the best practice (and provides much faster
  30. compilations).
  31. It also implies that the include paths have beenset properly.
  32. - to have the include paths added automatically, use the following::
  33. from waflib.TaskGen import feature, before_method, after_method
  34. @feature('cxx')
  35. @after_method('process_source')
  36. @before_method('apply_incpaths')
  37. def add_includes_paths(self):
  38. incs = set(self.to_list(getattr(self, 'includes', '')))
  39. for x in self.compiled_tasks:
  40. incs.add(x.inputs[0].parent.path_from(self.path))
  41. self.includes = sorted(incs)
  42. Note: another tool provides Qt processing that does not require
  43. .moc includes, see 'playground/slow_qt/'.
  44. A few options (--qt{dir,bin,...}) and environment variables
  45. (QT4_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool,
  46. tool path selection, etc; please read the source for more info.
  47. """
  48. try:
  49. from xml.sax import make_parser
  50. from xml.sax.handler import ContentHandler
  51. except ImportError:
  52. has_xml = False
  53. ContentHandler = object
  54. else:
  55. has_xml = True
  56. import os, sys
  57. from waflib.Tools import cxx
  58. from waflib import Task, Utils, Options, Errors, Context
  59. from waflib.TaskGen import feature, after_method, extension
  60. from waflib.Configure import conf
  61. from waflib import Logs
  62. MOC_H = ['.h', '.hpp', '.hxx', '.hh']
  63. """
  64. File extensions associated to the .moc files
  65. """
  66. EXT_RCC = ['.qrc']
  67. """
  68. File extension for the resource (.qrc) files
  69. """
  70. EXT_UI = ['.ui']
  71. """
  72. File extension for the user interface (.ui) files
  73. """
  74. EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C']
  75. """
  76. File extensions of C++ files that may require a .moc processing
  77. """
  78. QT4_LIBS = "QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative QtDesigner"
  79. class qxx(Task.classes['cxx']):
  80. """
  81. Each C++ file can have zero or several .moc files to create.
  82. They are known only when the files are scanned (preprocessor)
  83. To avoid scanning the c++ files each time (parsing C/C++), the results
  84. are retrieved from the task cache (bld.node_deps/bld.raw_deps).
  85. The moc tasks are also created *dynamically* during the build.
  86. """
  87. def __init__(self, *k, **kw):
  88. Task.Task.__init__(self, *k, **kw)
  89. self.moc_done = 0
  90. def runnable_status(self):
  91. """
  92. Compute the task signature to make sure the scanner was executed. Create the
  93. moc tasks by using :py:meth:`waflib.Tools.qt4.qxx.add_moc_tasks` (if necessary),
  94. then postpone the task execution (there is no need to recompute the task signature).
  95. """
  96. if self.moc_done:
  97. return Task.Task.runnable_status(self)
  98. else:
  99. for t in self.run_after:
  100. if not t.hasrun:
  101. return Task.ASK_LATER
  102. self.add_moc_tasks()
  103. return Task.Task.runnable_status(self)
  104. def create_moc_task(self, h_node, m_node):
  105. """
  106. If several libraries use the same classes, it is possible that moc will run several times (Issue 1318)
  107. It is not possible to change the file names, but we can assume that the moc transformation will be identical,
  108. and the moc tasks can be shared in a global cache.
  109. The defines passed to moc will then depend on task generator order. If this is not acceptable, then
  110. use the tool slow_qt4 instead (and enjoy the slow builds... :-( )
  111. """
  112. try:
  113. moc_cache = self.generator.bld.moc_cache
  114. except AttributeError:
  115. moc_cache = self.generator.bld.moc_cache = {}
  116. try:
  117. return moc_cache[h_node]
  118. except KeyError:
  119. tsk = moc_cache[h_node] = Task.classes['moc'](env=self.env, generator=self.generator)
  120. tsk.set_inputs(h_node)
  121. tsk.set_outputs(m_node)
  122. if self.generator:
  123. self.generator.tasks.append(tsk)
  124. # direct injection in the build phase (safe because called from the main thread)
  125. gen = self.generator.bld.producer
  126. gen.outstanding.append(tsk)
  127. gen.total += 1
  128. return tsk
  129. def moc_h_ext(self):
  130. ext = []
  131. try:
  132. ext = Options.options.qt_header_ext.split()
  133. except AttributeError:
  134. pass
  135. if not ext:
  136. ext = MOC_H
  137. return ext
  138. def add_moc_tasks(self):
  139. """
  140. Create the moc tasks by looking in ``bld.raw_deps[self.uid()]``
  141. """
  142. node = self.inputs[0]
  143. bld = self.generator.bld
  144. try:
  145. # compute the signature once to know if there is a moc file to create
  146. self.signature()
  147. except KeyError:
  148. # the moc file may be referenced somewhere else
  149. pass
  150. else:
  151. # remove the signature, it must be recomputed with the moc task
  152. delattr(self, 'cache_sig')
  153. include_nodes = [node.parent] + self.generator.includes_nodes
  154. moctasks = []
  155. mocfiles = set()
  156. for d in bld.raw_deps.get(self.uid(), []):
  157. if not d.endswith('.moc'):
  158. continue
  159. # process that base.moc only once
  160. if d in mocfiles:
  161. continue
  162. mocfiles.add(d)
  163. # find the source associated with the moc file
  164. h_node = None
  165. base2 = d[:-4]
  166. for x in include_nodes:
  167. for e in self.moc_h_ext():
  168. h_node = x.find_node(base2 + e)
  169. if h_node:
  170. break
  171. if h_node:
  172. m_node = h_node.change_ext('.moc')
  173. break
  174. else:
  175. # foo.cpp -> foo.cpp.moc
  176. for k in EXT_QT4:
  177. if base2.endswith(k):
  178. for x in include_nodes:
  179. h_node = x.find_node(base2)
  180. if h_node:
  181. break
  182. if h_node:
  183. m_node = h_node.change_ext(k + '.moc')
  184. break
  185. if not h_node:
  186. raise Errors.WafError('No source found for %r which is a moc file' % d)
  187. # create the moc task
  188. task = self.create_moc_task(h_node, m_node)
  189. moctasks.append(task)
  190. # simple scheduler dependency: run the moc task before others
  191. self.run_after.update(set(moctasks))
  192. self.moc_done = 1
  193. class trans_update(Task.Task):
  194. """Update a .ts files from a list of C++ files"""
  195. run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}'
  196. color = 'BLUE'
  197. class XMLHandler(ContentHandler):
  198. """
  199. Parser for *.qrc* files
  200. """
  201. def __init__(self):
  202. self.buf = []
  203. self.files = []
  204. def startElement(self, name, attrs):
  205. if name == 'file':
  206. self.buf = []
  207. def endElement(self, name):
  208. if name == 'file':
  209. self.files.append(str(''.join(self.buf)))
  210. def characters(self, cars):
  211. self.buf.append(cars)
  212. @extension(*EXT_RCC)
  213. def create_rcc_task(self, node):
  214. "Create rcc and cxx tasks for *.qrc* files"
  215. rcnode = node.change_ext('_rc.cpp')
  216. self.create_task('rcc', node, rcnode)
  217. cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o'))
  218. try:
  219. self.compiled_tasks.append(cpptask)
  220. except AttributeError:
  221. self.compiled_tasks = [cpptask]
  222. return cpptask
  223. @extension(*EXT_UI)
  224. def create_uic_task(self, node):
  225. "hook for uic tasks"
  226. uictask = self.create_task('ui4', node)
  227. uictask.outputs = [self.path.find_or_declare(self.env['ui_PATTERN'] % node.name[:-3])]
  228. @extension('.ts')
  229. def add_lang(self, node):
  230. """add all the .ts file into self.lang"""
  231. self.lang = self.to_list(getattr(self, 'lang', [])) + [node]
  232. @feature('qt4')
  233. @after_method('apply_link')
  234. def apply_qt4(self):
  235. """
  236. Add MOC_FLAGS which may be necessary for moc::
  237. def build(bld):
  238. bld.program(features='qt4', source='main.cpp', target='app', use='QTCORE')
  239. The additional parameters are:
  240. :param lang: list of translation files (\*.ts) to process
  241. :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension
  242. :param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**)
  243. :type update: bool
  244. :param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file
  245. :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension
  246. """
  247. if getattr(self, 'lang', None):
  248. qmtasks = []
  249. for x in self.to_list(self.lang):
  250. if isinstance(x, str):
  251. x = self.path.find_resource(x + '.ts')
  252. qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))
  253. if getattr(self, 'update', None) and Options.options.trans_qt4:
  254. cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [
  255. a.inputs[0] for a in self.tasks if getattr(a, 'inputs', None) and a.inputs[0].name.endswith('.ui')]
  256. for x in qmtasks:
  257. self.create_task('trans_update', cxxnodes, x.inputs)
  258. if getattr(self, 'langname', None):
  259. qmnodes = [x.outputs[0] for x in qmtasks]
  260. rcnode = self.langname
  261. if isinstance(rcnode, str):
  262. rcnode = self.path.find_or_declare(rcnode + '.qrc')
  263. t = self.create_task('qm2rcc', qmnodes, rcnode)
  264. k = create_rcc_task(self, t.outputs[0])
  265. self.link_task.inputs.append(k.outputs[0])
  266. lst = []
  267. for flag in self.to_list(self.env['CXXFLAGS']):
  268. if len(flag) < 2:
  269. continue
  270. f = flag[0:2]
  271. if f in ('-D', '-I', '/D', '/I'):
  272. if (f[0] == '/'):
  273. lst.append('-' + flag[1:])
  274. else:
  275. lst.append(flag)
  276. self.env.append_value('MOC_FLAGS', lst)
  277. @extension(*EXT_QT4)
  278. def cxx_hook(self, node):
  279. """
  280. Re-map C++ file extensions to the :py:class:`waflib.Tools.qt4.qxx` task.
  281. """
  282. return self.create_compiled_task('qxx', node)
  283. class rcc(Task.Task):
  284. """
  285. Process *.qrc* files
  286. """
  287. color = 'BLUE'
  288. run_str = '${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'
  289. ext_out = ['.h']
  290. def rcname(self):
  291. return os.path.splitext(self.inputs[0].name)[0]
  292. def scan(self):
  293. """Parse the *.qrc* files"""
  294. if not has_xml:
  295. Logs.error('no xml support was found, the rcc dependencies will be incomplete!')
  296. return ([], [])
  297. parser = make_parser()
  298. curHandler = XMLHandler()
  299. parser.setContentHandler(curHandler)
  300. fi = open(self.inputs[0].abspath(), 'r')
  301. try:
  302. parser.parse(fi)
  303. finally:
  304. fi.close()
  305. nodes = []
  306. names = []
  307. root = self.inputs[0].parent
  308. for x in curHandler.files:
  309. nd = root.find_resource(x)
  310. if nd:
  311. nodes.append(nd)
  312. else:
  313. names.append(x)
  314. return (nodes, names)
  315. class moc(Task.Task):
  316. """
  317. Create *.moc* files
  318. """
  319. color = 'BLUE'
  320. run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'
  321. def keyword(self):
  322. return "Creating"
  323. def __str__(self):
  324. return self.outputs[0].path_from(self.generator.bld.launch_node())
  325. class ui4(Task.Task):
  326. """
  327. Process *.ui* files
  328. """
  329. color = 'BLUE'
  330. run_str = '${QT_UIC} ${SRC} -o ${TGT}'
  331. ext_out = ['.h']
  332. class ts2qm(Task.Task):
  333. """
  334. Create *.qm* files from *.ts* files
  335. """
  336. color = 'BLUE'
  337. run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'
  338. class qm2rcc(Task.Task):
  339. """
  340. Transform *.qm* files into *.rc* files
  341. """
  342. color = 'BLUE'
  343. after = 'ts2qm'
  344. def run(self):
  345. """Create a qrc file including the inputs"""
  346. txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])
  347. code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt
  348. self.outputs[0].write(code)
  349. def configure(self):
  350. """
  351. Besides the configuration options, the environment variable QT4_ROOT may be used
  352. to give the location of the qt4 libraries (absolute path).
  353. The detection will use the program *pkg-config* through :py:func:`waflib.Tools.config_c.check_cfg`
  354. """
  355. self.find_qt4_binaries()
  356. self.set_qt4_libs_to_check()
  357. self.set_qt4_defines()
  358. self.find_qt4_libraries()
  359. self.add_qt4_rpath()
  360. self.simplify_qt4_libs()
  361. @conf
  362. def find_qt4_binaries(self):
  363. env = self.env
  364. opt = Options.options
  365. qtdir = getattr(opt, 'qtdir', '')
  366. qtbin = getattr(opt, 'qtbin', '')
  367. paths = []
  368. if qtdir:
  369. qtbin = os.path.join(qtdir, 'bin')
  370. # the qt directory has been given from QT4_ROOT - deduce the qt binary path
  371. if not qtdir:
  372. qtdir = os.environ.get('QT4_ROOT', '')
  373. qtbin = os.environ.get('QT4_BIN') or os.path.join(qtdir, 'bin')
  374. if qtbin:
  375. paths = [qtbin]
  376. # no qtdir, look in the path and in /usr/local/Trolltech
  377. if not qtdir:
  378. paths = os.environ.get('PATH', '').split(os.pathsep)
  379. paths.append('/usr/share/qt4/bin/')
  380. try:
  381. lst = Utils.listdir('/usr/local/Trolltech/')
  382. except OSError:
  383. pass
  384. else:
  385. if lst:
  386. lst.sort()
  387. lst.reverse()
  388. # keep the highest version
  389. qtdir = '/usr/local/Trolltech/%s/' % lst[0]
  390. qtbin = os.path.join(qtdir, 'bin')
  391. paths.append(qtbin)
  392. # at the end, try to find qmake in the paths given
  393. # keep the one with the highest version
  394. cand = None
  395. prev_ver = ['4', '0', '0']
  396. for qmk in ('qmake-qt4', 'qmake4', 'qmake'):
  397. try:
  398. qmake = self.find_program(qmk, path_list=paths)
  399. except self.errors.ConfigurationError:
  400. pass
  401. else:
  402. try:
  403. version = self.cmd_and_log(qmake + ['-query', 'QT_VERSION']).strip()
  404. except self.errors.WafError:
  405. pass
  406. else:
  407. if version:
  408. new_ver = version.split('.')
  409. if new_ver > prev_ver:
  410. cand = qmake
  411. prev_ver = new_ver
  412. if cand:
  413. self.env.QMAKE = cand
  414. else:
  415. self.fatal('Could not find qmake for qt4')
  416. qtbin = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_BINS']).strip() + os.sep
  417. def find_bin(lst, var):
  418. if var in env:
  419. return
  420. for f in lst:
  421. try:
  422. ret = self.find_program(f, path_list=paths)
  423. except self.errors.ConfigurationError:
  424. pass
  425. else:
  426. env[var]=ret
  427. break
  428. find_bin(['uic-qt3', 'uic3'], 'QT_UIC3')
  429. find_bin(['uic-qt4', 'uic'], 'QT_UIC')
  430. if not env.QT_UIC:
  431. self.fatal('cannot find the uic compiler for qt4')
  432. self.start_msg('Checking for uic version')
  433. uicver = self.cmd_and_log(env.QT_UIC + ["-version"], output=Context.BOTH)
  434. uicver = ''.join(uicver).strip()
  435. uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '')
  436. self.end_msg(uicver)
  437. if uicver.find(' 3.') != -1:
  438. self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')
  439. find_bin(['moc-qt4', 'moc'], 'QT_MOC')
  440. find_bin(['rcc-qt4', 'rcc'], 'QT_RCC')
  441. find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE')
  442. find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE')
  443. env['UIC3_ST']= '%s -o %s'
  444. env['UIC_ST'] = '%s -o %s'
  445. env['MOC_ST'] = '-o'
  446. env['ui_PATTERN'] = 'ui_%s.h'
  447. env['QT_LRELEASE_FLAGS'] = ['-silent']
  448. env.MOCCPPPATH_ST = '-I%s'
  449. env.MOCDEFINES_ST = '-D%s'
  450. @conf
  451. def find_qt4_libraries(self):
  452. qtlibs = getattr(Options.options, 'qtlibs', None) or os.environ.get("QT4_LIBDIR")
  453. if not qtlibs:
  454. try:
  455. qtlibs = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_LIBS']).strip()
  456. except Errors.WafError:
  457. qtdir = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_PREFIX']).strip() + os.sep
  458. qtlibs = os.path.join(qtdir, 'lib')
  459. self.msg('Found the Qt4 libraries in', qtlibs)
  460. qtincludes = os.environ.get("QT4_INCLUDES") or self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_HEADERS']).strip()
  461. env = self.env
  462. if not 'PKG_CONFIG_PATH' in os.environ:
  463. os.environ['PKG_CONFIG_PATH'] = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs)
  464. try:
  465. if os.environ.get("QT4_XCOMPILE"):
  466. raise self.errors.ConfigurationError()
  467. self.check_cfg(atleast_pkgconfig_version='0.1')
  468. except self.errors.ConfigurationError:
  469. for i in self.qt4_vars:
  470. uselib = i.upper()
  471. if Utils.unversioned_sys_platform() == "darwin":
  472. # Since at least qt 4.7.3 each library locates in separate directory
  473. frameworkName = i + ".framework"
  474. qtDynamicLib = os.path.join(qtlibs, frameworkName, i)
  475. if os.path.exists(qtDynamicLib):
  476. env.append_unique('FRAMEWORK_' + uselib, i)
  477. self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
  478. else:
  479. self.msg('Checking for %s' % i, False, 'YELLOW')
  480. env.append_unique('INCLUDES_' + uselib, os.path.join(qtlibs, frameworkName, 'Headers'))
  481. elif env.DEST_OS != "win32":
  482. qtDynamicLib = os.path.join(qtlibs, "lib" + i + ".so")
  483. qtStaticLib = os.path.join(qtlibs, "lib" + i + ".a")
  484. if os.path.exists(qtDynamicLib):
  485. env.append_unique('LIB_' + uselib, i)
  486. self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')
  487. elif os.path.exists(qtStaticLib):
  488. env.append_unique('LIB_' + uselib, i)
  489. self.msg('Checking for %s' % i, qtStaticLib, 'GREEN')
  490. else:
  491. self.msg('Checking for %s' % i, False, 'YELLOW')
  492. env.append_unique('LIBPATH_' + uselib, qtlibs)
  493. env.append_unique('INCLUDES_' + uselib, qtincludes)
  494. env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
  495. else:
  496. # Release library names are like QtCore4
  497. for k in ("lib%s.a", "lib%s4.a", "%s.lib", "%s4.lib"):
  498. lib = os.path.join(qtlibs, k % i)
  499. if os.path.exists(lib):
  500. env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
  501. self.msg('Checking for %s' % i, lib, 'GREEN')
  502. break
  503. else:
  504. self.msg('Checking for %s' % i, False, 'YELLOW')
  505. env.append_unique('LIBPATH_' + uselib, qtlibs)
  506. env.append_unique('INCLUDES_' + uselib, qtincludes)
  507. env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
  508. # Debug library names are like QtCore4d
  509. uselib = i.upper() + "_debug"
  510. for k in ("lib%sd.a", "lib%sd4.a", "%sd.lib", "%sd4.lib"):
  511. lib = os.path.join(qtlibs, k % i)
  512. if os.path.exists(lib):
  513. env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])
  514. self.msg('Checking for %s' % i, lib, 'GREEN')
  515. break
  516. else:
  517. self.msg('Checking for %s' % i, False, 'YELLOW')
  518. env.append_unique('LIBPATH_' + uselib, qtlibs)
  519. env.append_unique('INCLUDES_' + uselib, qtincludes)
  520. env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))
  521. else:
  522. for i in self.qt4_vars_debug + self.qt4_vars:
  523. self.check_cfg(package=i, args='--cflags --libs', mandatory=False)
  524. @conf
  525. def simplify_qt4_libs(self):
  526. # the libpaths make really long command-lines
  527. # remove the qtcore ones from qtgui, etc
  528. env = self.env
  529. def process_lib(vars_, coreval):
  530. for d in vars_:
  531. var = d.upper()
  532. if var == 'QTCORE':
  533. continue
  534. value = env['LIBPATH_'+var]
  535. if value:
  536. core = env[coreval]
  537. accu = []
  538. for lib in value:
  539. if lib in core:
  540. continue
  541. accu.append(lib)
  542. env['LIBPATH_'+var] = accu
  543. process_lib(self.qt4_vars, 'LIBPATH_QTCORE')
  544. process_lib(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
  545. @conf
  546. def add_qt4_rpath(self):
  547. # rpath if wanted
  548. env = self.env
  549. if getattr(Options.options, 'want_rpath', False):
  550. def process_rpath(vars_, coreval):
  551. for d in vars_:
  552. var = d.upper()
  553. value = env['LIBPATH_'+var]
  554. if value:
  555. core = env[coreval]
  556. accu = []
  557. for lib in value:
  558. if var != 'QTCORE':
  559. if lib in core:
  560. continue
  561. accu.append('-Wl,--rpath='+lib)
  562. env['RPATH_'+var] = accu
  563. process_rpath(self.qt4_vars, 'LIBPATH_QTCORE')
  564. process_rpath(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')
  565. @conf
  566. def set_qt4_libs_to_check(self):
  567. if not hasattr(self, 'qt4_vars'):
  568. self.qt4_vars = QT4_LIBS
  569. self.qt4_vars = Utils.to_list(self.qt4_vars)
  570. if not hasattr(self, 'qt4_vars_debug'):
  571. self.qt4_vars_debug = [a + '_debug' for a in self.qt4_vars]
  572. self.qt4_vars_debug = Utils.to_list(self.qt4_vars_debug)
  573. @conf
  574. def set_qt4_defines(self):
  575. if sys.platform != 'win32':
  576. return
  577. for x in self.qt4_vars:
  578. y = x[2:].upper()
  579. self.env.append_unique('DEFINES_%s' % x.upper(), 'QT_%s_LIB' % y)
  580. self.env.append_unique('DEFINES_%s_DEBUG' % x.upper(), 'QT_%s_LIB' % y)
  581. def options(opt):
  582. """
  583. Command-line options
  584. """
  585. opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries')
  586. opt.add_option('--header-ext',
  587. type='string',
  588. default='',
  589. help='header extension for moc files',
  590. dest='qt_header_ext')
  591. for i in 'qtdir qtbin qtlibs'.split():
  592. opt.add_option('--'+i, type='string', default='', dest=i)
  593. opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False)