File: qt4.py

package info (click to toggle)
lv2fil 2.0%2B20100312.git18130f5a%2Bdfsg0-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 888 kB
  • sloc: python: 10,590; ansic: 1,180; makefile: 27; sh: 11
file content (472 lines) | stat: -rw-r--r-- 14,094 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
#! /usr/bin/env python
# encoding: utf-8

#! /usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2006 (ita)

"""
Qt4 support

If QT4_ROOT is given (absolute path), the configuration will look in it first

This module also demonstrates how to add tasks dynamically (when the build has started)
"""

import os, sys
import ccroot, cxx
import Action, Params, Object, Task, Utils, Runner
from Object import taskgen, feature, after, extension
from Params import error, fatal

MOC_H = ['.h', '.hpp', '.hxx', '.hh']
EXT_RCC = ['.qrc']
EXT_UI  = ['.ui']
EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C', '.c']

class MTask(Task.Task):
	"A cpp task that may create a moc task dynamically"
	def __init__(self, action_name, env, parent, priority=10):
		Task.Task.__init__(self, action_name, env, priority)
		self.moc_done = 0
		self.parent = parent

	def may_start(self):

		if self.moc_done:
			# if there is a moc task, delay the computation of the file signature
			for t in self.get_run_after():
				if not t.m_hasrun:
					return 0
			# we need to recompute the signature as the moc task has finally run
			# unfortunately, the moc file enters in the dependency calculation TODO
			delattr(self, 'sign_all')
			self.signature()
			return Task.Task.may_start(self)

		tree = Params.g_build
		parn = self.parent
		node = self.m_inputs[0]

		# to know if there is a moc file to create
		self.signature()

		moctasks=[]
		mocfiles=[]
		variant = node.variant(parn.env)
		try:
			tmp_lst = tree.m_raw_deps[variant][node]
			tree.m_raw_deps[variant][node] = []
		except KeyError:
			tmp_lst = []
		for d in tmp_lst:
			if not d.endswith('.moc'): continue
			# paranoid check
			if d in mocfiles:
				error("paranoia owns")
				continue
			# process that base.moc only once
			mocfiles.append(d)

			# find the extension - this search is done only once
			ext = ''
			try: ext = Params.g_options.qt_header_ext
			except AttributeError: pass

			if not ext:
				base2 = d[:-4]
				path = node.m_parent.srcpath(parn.env)
				for i in MOC_H:
					try:
						# TODO we could use find_source
						os.stat(os.path.join(path, base2+i))
					except OSError:
						pass
					else:
						ext = i
						break
				if not ext: fatal("no header found for %s which is a moc file" % str(d))

			# next time we will not search for the extension (look at the 'for' loop below)
			h_node = node.m_parent.find_source(base2+i)
			m_node = h_node.change_ext('.moc')
			tree.m_depends_on[variant][m_node] = h_node

			# create the task
			task = Task.Task('moc', parn.env, normal=0)
			task.set_inputs(h_node)
			task.set_outputs(m_node)

			generator = Params.g_build.generator
			generator.outstanding.insert(0, task)
			generator.total += 1

			moctasks.append(task)

		# remove raw deps except the moc files to save space (optimization)
		tmp_lst = tree.m_raw_deps[variant][node] = mocfiles

		# look at the file inputs, it is set right above
		try: lst = tree.m_depends_on[variant][node]
		except KeyError: lst=[]
		for d in lst:
			name = d.m_name
			if name.endswith('.moc'):
				task = Task.Task('moc', parn.env, normal=0)
				task.set_inputs(tree.m_depends_on[variant][d])
				task.set_outputs(d)

				generator = Params.g_build.generator
				generator.outstanding.insert(0, task)
				generator.total += 1

				moctasks.append(task)
				break
		# simple scheduler dependency: run the moc task before others
		self.m_run_after = moctasks
		self.moc_done = 1
		return 0

def translation_update(task):
	outs=[a.abspath(task.env) for a in task.m_outputs]
	outs=" ".join(outs)
	lupdate = task.env['QT_LUPDATE']

	for x in task.m_inputs:
		file = x.abspath(task.env)
		cmd = "%s %s -ts %s" % (lupdate, file, outs)
		Params.pprint('BLUE', cmd)
		Runner.exec_command(cmd)

def create_rcc_task(self, node):
	"hook for rcc files"
	# run rcctask with one of the highest priority
	# TODO add the dependency on the files listed in .qrc
	rcnode = node.change_ext('_rc.cpp')

	rcctask = self.create_task('rcc', self.env)
	rcctask.m_inputs = [node]
	rcctask.m_outputs = [rcnode]

	cpptask = self.create_task('cpp', self.env)
	cpptask.m_inputs  = [rcnode]
	cpptask.m_outputs = [rcnode.change_ext('.o')]

	self.compiled_tasks.append(cpptask)

	return cpptask

def create_uic_task(self, node):
	"hook for uic tasks"
	uictask = self.create_task('ui4', self.env)
	uictask.m_inputs    = [node]
	uictask.m_outputs   = [node.change_ext('.h')]

class qt4obj(cxx.cpp_taskgen):
	def __init__(self, type='program', subtype=None):
		cxx.cpp_taskgen.__init__(self, type, subtype)
		self.link_task = None
		self.lang = ''
		self.langname = ''
		self.update = 0
		self.features.append('qt4')

def apply_qt4(self):
	if self.lang:
		lst=[]
		trans=[]
		for l in self.to_list(self.lang):
			t = Task.Task('ts2qm', self.env, 4)
			t.set_inputs(self.path.find_build(l+'.ts'))
			t.set_outputs(t.m_inputs[0].change_ext('.qm'))
			lst.append(t.m_outputs[0])

			if self.update:
				trans.append(t.m_inputs[0])

		if self.update and Params.g_options.trans_qt4:
			# we need the cpp files given, except the rcc task we create after
			u = Task.TaskCmd(translation_update, self.env, 2)
			u.m_inputs = [a.m_inputs[0] for a in self.compiled_tasks]
			u.m_outputs = trans

		if self.langname:
			t = Task.Task('qm2rcc', self.env, 40)
			t.set_inputs(lst)
			t.set_outputs(self.path.find_build(self.langname+'.qrc'))
			t.path = self.path
			k = create_rcc_task(self, t.m_outputs[0])
			self.link_task.m_inputs.append(k.m_outputs[0])

	lst = []
	for flag in self.to_list(self.env['CXXFLAGS']):
		if len(flag) < 2: continue
		if flag[0:2] == '-D' or flag[0:2] == '-I':
			lst.append(flag)
	self.env['MOC_FLAGS'] = lst

def find_sources_in_dirs(self, dirnames, excludes=[], exts=[]):
	"the .ts files are added to self.lang"
	lst=[]
	excludes = self.to_list(excludes)
	#make sure dirnames is a list helps with dirnames with spaces
	dirnames = self.to_list(dirnames)

	ext_lst = exts or self.mappings.keys() + Object.task_gen.mappings.keys()

	for name in dirnames:
		#print "name is ", name
		anode = self.path.ensure_node_from_lst(Utils.split_path(name))
		#print "anode ", anode.m_name, " ", anode.files()
		Params.g_build.rescan(anode)
		#print "anode ", anode.m_name, " ", anode.files()

		for file in anode.files():
			#print "file found ->", file
			(base, ext) = os.path.splitext(file.m_name)
			if ext in ext_lst:
				s = file.relpath(self.path)
				if not s in lst:
					if s in excludes: continue
					lst.append(s)
			elif ext == '.ts':
				self.lang += ' '+base

	lst.sort()
	self.source = self.source+' '+(" ".join(lst))
setattr(qt4obj, 'find_sources_in_dirs', find_sources_in_dirs)

def cxx_hook(self, node):
	# create the compilation task: cpp or cc
	task = MTask('cpp', self.env, self)
	self.m_tasks.append(task)
	try: obj_ext = self.obj_ext
	except AttributeError: obj_ext = '_%s.o' % self.m_type[:2]

	task.m_scanner = ccroot.g_c_scanner
	task.path_lst = self.inc_paths
	task.defines  = self.scanner_defines

	task.m_inputs = [node]
	task.m_outputs = [node.change_ext(obj_ext)]
	self.compiled_tasks.append(task)

def process_qm2rcc(task):
	outfile = task.m_outputs[0].abspath(task.env())
	f = open(outfile, 'w')
	f.write('<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n')
	for k in task.m_inputs:
		f.write(' <file>')
		#f.write(k.m_name)
		f.write(k.relpath(task.path))
		f.write('</file>\n')
	f.write('</qresource>\n</RCC>')
	f.close()

Action.simple_action('moc', '${QT_MOC} ${MOC_FLAGS} ${SRC} ${MOC_ST} ${TGT}', color='BLUE', vars=['QT_MOC', 'MOC_FLAGS'], prio=100)
Action.simple_action('rcc', '${QT_RCC} -name ${SRC[0].m_name} ${SRC} ${RCC_ST} -o ${TGT}', color='BLUE', prio=60)
Action.simple_action('ui4', '${QT_UIC} ${SRC} -o ${TGT}', color='BLUE', prio=60)
Action.simple_action('ts2qm', '${QT_LRELEASE} ${SRC} -qm ${TGT}', color='BLUE', prio=40)

Action.Action('qm2rcc', vars=[], func=process_qm2rcc, color='BLUE', prio=60)

def detect_qt4(conf):
	env = conf.env
	opt = Params.g_options

	qtlibs = getattr(opt, 'qtlibs', '')
	qtincludes = getattr(opt, 'qtincludes', '')
	qtbin = getattr(opt, 'qtbin', '')
	useframework = getattr(opt, 'use_qt4_osxframework', True)
	qtdir = getattr(opt, 'qtdir', '')

	if not qtdir: qtdir = os.environ.get('QT4_ROOT', '')

	if not qtdir:
		try:
			lst = os.listdir('/usr/local/Trolltech/')
			lst.sort()
			lst.reverse()
			qtdir = '/usr/local/Trolltech/%s/' % lst[0]

		except OSError:
			pass

	if not qtdir:
		try:
			path = os.environ['PATH'].split(':')
			for qmk in ['qmake-qt4', 'qmake4', 'qmake']:
				qmake = conf.find_program(qmk, path)
				if qmake:
					version = os.popen(qmake+" -query QT_VERSION").read().strip().split('.')
					if version[0] == "4":
						qtincludes = os.popen(qmake+" -query QT_INSTALL_HEADERS").read().strip()
						qtdir = os.popen(qmake + " -query QT_INSTALL_PREFIX").read().strip()+"/"
						qtbin = os.popen(qmake + " -query QT_INSTALL_BINS").read().strip()+"/"
						break
		except OSError:
			pass

	# check for the qt includes first
	if not qtincludes: qtincludes = qtdir + 'include/'
	env['QTINCLUDEPATH']=qtincludes

	lst = [qtincludes, '/usr/share/qt4/include/', '/opt/qt4/include']
	test = conf.create_header_enumerator()
	test.name = 'QtGui/QFont'
	test.path = lst
	test.mandatory = 1
	ret = test.run()


	# check for the qtbinaries
	if not qtbin: qtbin = qtdir + 'bin/'

	binpath = [qtbin, '/usr/share/qt4/bin/'] + os.environ['PATH'].split(':')
	def find_bin(lst, var):
		for f in lst:
			ret = conf.find_program(f, path_list=binpath)
			if ret:
				env[var]=ret
				break

	find_bin(['uic-qt3', 'uic3'], 'QT_UIC3')

	find_bin(['uic-qt4', 'uic'], 'QT_UIC')
	version = os.popen(env['QT_UIC'] + " -version 2>&1").read().strip()
	version = version.replace('Qt User Interface Compiler ','')
	version = version.replace('User Interface Compiler for Qt', '')
	if version.find(" 3.") != -1:
		conf.check_message('uic version', '(too old)', 0, option='(%s)'%version)
		sys.exit(1)
	conf.check_message('uic version', '', 1, option='(%s)'%version)

	find_bin(['moc-qt4', 'moc'], 'QT_MOC')
	find_bin(['rcc'], 'QT_RCC')
	find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE')
	find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE')

	env['UIC3_ST']= '%s -o %s'
	env['UIC_ST'] = '%s -o %s'
	env['MOC_ST'] = '-o'


	# check for the qt libraries
	if not qtlibs: qtlibs = qtdir + 'lib'

	vars = "Qt3Support QtCore QtGui QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtWebKit".split()

	framework_ok = False
	if sys.platform == "darwin" and useframework:
		for i in vars:
			e = conf.create_framework_configurator()
			e.path = [qtlibs]
			e.name = i
			e.remove_dot_h = 1
			e.run()

			if not i == 'QtCore':
				# strip -F flag so it don't get reduant
				for r in env['CCFLAGS_' + i.upper()]:
					if r.startswith('-F'):
						env['CCFLAGS_' + i.upper()].remove(r)
						break

			incflag = '-I%s' % os.path.join(qtincludes, i)
			if not incflag in env["CCFLAGS_" + i.upper ()]:
				env['CCFLAGS_' + i.upper ()] += [incflag]
			if not incflag in env["CXXFLAGS_" + i.upper ()]:
				env['CXXFLAGS_' + i.upper ()] += [incflag]

		# now we add some static depends.
		if conf.is_defined("HAVE_QTOPENGL"):
			if not '-framework OpenGL' in env["LINKFLAGS_QTOPENGL"]:
				env["LINKFLAGS_QTOPENGL"] += ['-framework OpenGL']

		if conf.is_defined("HAVE_QTGUI"):
			if not '-framework AppKit' in env["LINKFLAGS_QTGUI"]:
				env["LINKFLAGS_QTGUI"] += ['-framework AppKit']
			if not '-framework ApplicationServices' in env["LINKFLAGS_QTGUI"]:
				env["LINKFLAGS_QTGUI"] += ['-framework ApplicationServices']

		framework_ok = True

	if not framework_ok: # framework_ok is false either when the platform isn't OSX, Qt4 shall not be used as framework, or Qt4 could not be found as framework
		vars_debug = [a+'_debug' for a in vars]

		for i in vars_debug+vars:
			#conf.check_pkg(i, pkgpath=qtlibs)
			pkgconf = conf.create_pkgconfig_configurator()
			pkgconf.name = i
			pkgconf.pkgpath = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs)
			pkgconf.run()


		# the libpaths are set nicely, unfortunately they make really long command-lines
		# remove the qtcore ones from qtgui, etc
		def process_lib(vars_, coreval):
			for d in vars_:
				var = d.upper()
				if var == 'QTCORE': continue

				value = env['LIBPATH_'+var]
				if value:
					core = env[coreval]
					accu = []
					for lib in value:
						if lib in core: continue
						accu.append(lib)
					env['LIBPATH_'+var] = accu

		process_lib(vars, 'LIBPATH_QTCORE')
		process_lib(vars_debug, 'LIBPATH_QTCORE_DEBUG')

		# rpath if wanted
		if Params.g_options.want_rpath:
			def process_rpath(vars_, coreval):
				for d in vars_:
					var = d.upper()
					value = env['LIBPATH_'+var]
					if value:
						core = env[coreval]
						accu = []
						for lib in value:
							if var != 'QTCORE':
								if lib in core:
									continue
							accu.append('-Wl,--rpath='+lib)
						env['RPATH_'+var] = accu
			process_rpath(vars, 'LIBPATH_QTCORE')
			process_rpath(vars_debug, 'LIBPATH_QTCORE_DEBUG')

	env['QTLOCALE'] = str(env['PREFIX'])+'/share/locale'

def detect(conf):
	if sys.platform=='win32': fatal('Qt4.py will not work on win32 for now - ask the author')
	detect_qt4(conf)

def set_options(opt):
	try: opt.add_option('--want-rpath', type='int', default=1, dest='want_rpath', help='set rpath to 1 or 0 [Default 1]')
	except Exception: pass

	opt.add_option('--header-ext',
		type='string',
		default='',
		help='header extension for moc files',
		dest='qt_header_ext')

	for i in "qtdir qtincludes qtlibs qtbin".split():
		opt.add_option('--'+i, type='string', default='', dest=i)

	if sys.platform == "darwin":
		opt.add_option('--no-qt4-framework', action="store_false", help='do not use the framework version of Qt4 in OS X', dest='use_qt4_osxframework',default=True)

	opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False)


extension(EXT_RCC)(create_rcc_task)
extension(EXT_UI)(create_uic_task)
taskgen(apply_qt4)
feature('qt4')(apply_qt4)
after('apply_link')(apply_qt4)
extension(EXT_QT4)(cxx_hook)