16
16
17
17
"""Dependency finders for the Qt framework."""
18
18
19
+ import abc
19
20
import collections
20
21
import re
21
22
import os
30
31
from ..programs import NonExistingExternalProgram , find_external_program
31
32
32
33
if T .TYPE_CHECKING :
34
+ from ..compilers import Compiler
35
+ from ..environment import Environment
36
+ from ..interpreter import Interpreter
33
37
from ..programs import ExternalProgram
34
38
35
39
36
- def _qt_get_private_includes (mod_inc_dir , module , mod_version ) :
40
+ def _qt_get_private_includes (mod_inc_dir : str , module : str , mod_version : str ) -> T . List [ str ] :
37
41
# usually Qt5 puts private headers in /QT_INSTALL_HEADERS/module/VERSION/module/private
38
42
# except for at least QtWebkit and Enginio where the module version doesn't match Qt version
39
43
# as an example with Qt 5.10.1 on linux you would get:
@@ -44,28 +48,26 @@ def _qt_get_private_includes(mod_inc_dir, module, mod_version):
44
48
# on Qt4 when available private folder is directly in module folder
45
49
# like /usr/include/QtCore/private/
46
50
if int (mod_version .split ('.' )[0 ]) < 5 :
47
- return tuple ()
51
+ return []
48
52
49
53
private_dir = os .path .join (mod_inc_dir , mod_version )
50
54
# fallback, let's try to find a directory with the latest version
51
55
if not os .path .exists (private_dir ):
52
56
dirs = [filename for filename in os .listdir (mod_inc_dir )
53
57
if os .path .isdir (os .path .join (mod_inc_dir , filename ))]
54
- dirs .sort (reverse = True )
55
58
56
- for dirname in dirs :
59
+ for dirname in sorted ( dirs , reverse = True ) :
57
60
if len (dirname .split ('.' )) == 3 :
58
61
private_dir = dirname
59
62
break
60
- return (private_dir ,
61
- os .path .join (private_dir , 'Qt' + module ))
63
+ return [private_dir , os .path .join (private_dir , 'Qt' + module )]
62
64
63
65
class QtExtraFrameworkDependency (ExtraFrameworkDependency ):
64
- def __init__ (self , name , env , kwargs , language : T .Optional [str ] = None ):
66
+ def __init__ (self , name : str , env : 'Environment' , kwargs : T . Dict [ str , T . Any ] , language : T .Optional [str ] = None ):
65
67
super ().__init__ (name , env , kwargs , language = language )
66
68
self .mod_name = name [2 :]
67
69
68
- def get_compile_args (self , with_private_headers = False , qt_version = "0" ):
70
+ def get_compile_args (self , with_private_headers : bool = False , qt_version : str = "0" ) -> T . List [ str ] :
69
71
if self .found ():
70
72
mod_inc_dir = os .path .join (self .framework_path , 'Headers' )
71
73
args = ['-I' + mod_inc_dir ]
@@ -74,8 +76,12 @@ def get_compile_args(self, with_private_headers=False, qt_version="0"):
74
76
return args
75
77
return []
76
78
77
- class QtBaseDependency (ExternalDependency ):
78
- def __init__ (self , name , env , kwargs ):
79
+
80
+ class QtBaseDependency (ExternalDependency , metaclass = abc .ABCMeta ):
81
+
82
+ version : T .Optional [str ]
83
+
84
+ def __init__ (self , name : str , env : 'Environment' , kwargs : T .Dict [str , T .Any ]):
79
85
super ().__init__ (name , env , kwargs , language = 'cpp' )
80
86
self .qtname = name .capitalize ()
81
87
self .qtver = name [- 1 ]
@@ -84,20 +90,20 @@ def __init__(self, name, env, kwargs):
84
90
else :
85
91
self .qtpkgname = self .qtname
86
92
self .root = '/usr'
87
- self .bindir = None
88
- self .private_headers = kwargs .get ('private_headers' , False )
89
- mods = mesonlib .extract_as_list (kwargs , 'modules' )
93
+ self .bindir : T . Optional [ str ] = None
94
+ self .private_headers = T . cast ( bool , kwargs .get ('private_headers' , False ) )
95
+ mods = mesonlib .stringlistify ( mesonlib . extract_as_list (kwargs , 'modules' ) )
90
96
self .requested_modules = mods
91
97
if not mods :
92
98
raise DependencyException ('No ' + self .qtname + ' modules specified.' )
93
99
self .from_text = 'pkg-config'
94
100
95
- self .qtmain = kwargs .get ('main' , False )
101
+ self .qtmain = T . cast ( bool , kwargs .get ('main' , False ) )
96
102
if not isinstance (self .qtmain , bool ):
97
103
raise DependencyException ('"main" argument must be a boolean' )
98
104
99
105
# Keep track of the detection methods used, for logging purposes.
100
- methods = []
106
+ methods : T . List [ str ] = []
101
107
# Prefer pkg-config, then fallback to `qmake -query`
102
108
if DependencyMethods .PKGCONFIG in self .methods :
103
109
mlog .debug ('Trying to find qt with pkg-config' )
@@ -115,16 +121,20 @@ def __init__(self, name, env, kwargs):
115
121
self .from_text = mlog .format_list (methods )
116
122
self .version = None
117
123
118
- def compilers_detect (self , interp_obj ):
119
- "Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"
124
+ @abc .abstractmethod
125
+ def get_pkgconfig_host_bins (self , core : PkgConfigDependency ) -> T .Optional [str ]:
126
+ pass
127
+
128
+ def compilers_detect (self , interp_obj : 'Interpreter' ) -> T .Tuple ['ExternalProgram' , 'ExternalProgram' , 'ExternalProgram' , 'ExternalProgram' ]:
129
+ """Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"""
120
130
# It is important that this list does not change order as the order of
121
131
# the returned ExternalPrograms will change as well
122
132
bins = ['moc' , 'uic' , 'rcc' , 'lrelease' ]
123
133
found = {b : NonExistingExternalProgram (name = f'{ b } -{ self .name } ' )
124
134
for b in bins }
125
135
wanted = f'== { self .version } '
126
136
127
- def gen_bins ():
137
+ def gen_bins () -> T . Generator [ T . Tuple [ str , str ], None , None ] :
128
138
for b in bins :
129
139
if self .bindir :
130
140
yield os .path .join (self .bindir , b ), b
@@ -145,7 +155,7 @@ def gen_bins():
145
155
arg = ['-v' ]
146
156
147
157
# Ensure that the version of qt and each tool are the same
148
- def get_version (p ) :
158
+ def get_version (p : 'ExternalProgram' ) -> str :
149
159
_ , out , err = mesonlib .Popen_safe (p .get_command () + arg )
150
160
if b .startswith ('lrelease' ) or not self .version .startswith ('4' ):
151
161
care = out
@@ -159,13 +169,18 @@ def get_version(p):
159
169
if p .found ():
160
170
found [name ] = p
161
171
162
- return tuple ([found [b ] for b in bins ])
172
+ # Since we're converting from a list (no size constraints) to a tuple
173
+ # (size constrained), we have to cast. We can impsect the code to see
174
+ # that obviously this is correct since `len(bins) == 4`, but static
175
+ # type checkers can't
176
+ return T .cast (T .Tuple ['ExternalProgram' , 'ExternalProgram' , 'ExternalProgram' , 'ExternalProgram' ],
177
+ tuple ([found [b ] for b in bins ]))
163
178
164
- def _pkgconfig_detect (self , mods , kwargs ) :
179
+ def _pkgconfig_detect (self , mods : T . List [ str ] , kwargs : T . Dict [ str , T . Any ]) -> None :
165
180
# We set the value of required to False so that we can try the
166
181
# qmake-based fallback if pkg-config fails.
167
182
kwargs ['required' ] = False
168
- modules = collections .OrderedDict ()
183
+ modules : T . MutableMapping [ str , PkgConfigDependency ] = collections .OrderedDict ()
169
184
for module in mods :
170
185
modules [module ] = PkgConfigDependency (self .qtpkgname + module , self .env ,
171
186
kwargs , language = self .language )
@@ -226,7 +241,7 @@ def search_qmake(self) -> T.Generator['ExternalProgram', None, None]:
226
241
for qmake in ('qmake-' + self .name , 'qmake' ):
227
242
yield from find_external_program (self .env , self .for_machine , qmake , 'QMake' , [qmake ])
228
243
229
- def _qmake_detect (self , mods , kwargs ) :
244
+ def _qmake_detect (self , mods : T . List [ str ] , kwargs : T . Dict [ str , T . Any ]) -> T . Optional [ str ] :
230
245
for qmake in self .search_qmake ():
231
246
if not qmake .found ():
232
247
continue
@@ -243,7 +258,7 @@ def _qmake_detect(self, mods, kwargs):
243
258
else :
244
259
# Didn't find qmake :(
245
260
self .is_found = False
246
- return
261
+ return None
247
262
self .version = re .search (self .qtver + r'(\.\d+)+' , stdo ).group (0 )
248
263
# Query library path, header path, and binary path
249
264
mlog .log ("Found qmake:" , mlog .bold (self .qmake .get_path ()), '(%s)' % self .version )
@@ -297,11 +312,11 @@ def _qmake_detect(self, mods, kwargs):
297
312
priv_inc = self .get_private_includes (mincdir , module )
298
313
for directory in priv_inc :
299
314
self .compile_args .append ('-I' + directory )
300
- libfile = self .clib_compiler .find_library (self . qtpkgname + module + modules_lib_suffix ,
301
- self .env ,
302
- libdir )
303
- if libfile :
304
- libfile = libfile [0 ]
315
+ libfiles = self .clib_compiler .find_library (
316
+ self . qtpkgname + module + modules_lib_suffix , self .env ,
317
+ mesonlib . listify ( libdir )) # TODO: shouldn't be necissary
318
+ if libfiles :
319
+ libfile = libfiles [0 ]
305
320
else :
306
321
mlog .log ("Could not find:" , module ,
307
322
self .qtpkgname + module + modules_lib_suffix ,
@@ -316,7 +331,7 @@ def _qmake_detect(self, mods, kwargs):
316
331
317
332
return self .qmake .name
318
333
319
- def _get_modules_lib_suffix (self , is_debug ) :
334
+ def _get_modules_lib_suffix (self , is_debug : bool ) -> str :
320
335
suffix = ''
321
336
if self .env .machines [self .for_machine ].is_windows ():
322
337
if is_debug :
@@ -342,15 +357,16 @@ def _get_modules_lib_suffix(self, is_debug):
342
357
'module detection may not work' .format (cpu_family ))
343
358
return suffix
344
359
345
- def _link_with_qtmain (self , is_debug , libdir ):
360
+ def _link_with_qtmain (self , is_debug : bool , libdir : T .Union [str , T .List [str ]]) -> bool :
361
+ libdir = mesonlib .listify (libdir ) # TODO: shouldn't be necessary
346
362
base_name = 'qtmaind' if is_debug else 'qtmain'
347
363
qtmain = self .clib_compiler .find_library (base_name , self .env , libdir )
348
364
if qtmain :
349
365
self .link_args .append (qtmain [0 ])
350
366
return True
351
367
return False
352
368
353
- def _framework_detect (self , qvars , modules , kwargs ) :
369
+ def _framework_detect (self , qvars : T . Dict [ str , str ], modules : T . List [ str ] , kwargs : T . Dict [ str , T . Any ]) -> None :
354
370
libdir = qvars ['QT_INSTALL_LIBS' ]
355
371
356
372
# ExtraFrameworkDependency doesn't support any methods
@@ -374,19 +390,20 @@ def _framework_detect(self, qvars, modules, kwargs):
374
390
# Used by self.compilers_detect()
375
391
self .bindir = self .get_qmake_host_bins (qvars )
376
392
377
- def get_qmake_host_bins (self , qvars ):
393
+ @staticmethod
394
+ def get_qmake_host_bins (qvars : T .Dict [str , str ]) -> str :
378
395
# Prefer QT_HOST_BINS (qt5, correct for cross and native compiling)
379
396
# but fall back to QT_INSTALL_BINS (qt4)
380
397
if 'QT_HOST_BINS' in qvars :
381
398
return qvars ['QT_HOST_BINS' ]
382
- else :
383
- return qvars ['QT_INSTALL_BINS' ]
399
+ return qvars ['QT_INSTALL_BINS' ]
384
400
385
401
@staticmethod
386
- def get_methods ():
402
+ def get_methods () -> T . List [ DependencyMethods ] :
387
403
return [DependencyMethods .PKGCONFIG , DependencyMethods .QMAKE ]
388
404
389
- def get_exe_args (self , compiler ):
405
+ @staticmethod
406
+ def get_exe_args (compiler : 'Compiler' ) -> T .List [str ]:
390
407
# Originally this was -fPIE but nowadays the default
391
408
# for upstream and distros seems to be -reduce-relocations
392
409
# which requires -fPIC. This may cause a performance
@@ -395,25 +412,26 @@ def get_exe_args(self, compiler):
395
412
# for you, patches are welcome.
396
413
return compiler .get_pic_args ()
397
414
398
- def get_private_includes (self , mod_inc_dir , module ) :
399
- return tuple ()
415
+ def get_private_includes (self , mod_inc_dir : str , module : str ) -> T . List [ str ] :
416
+ return []
400
417
401
- def log_details (self ):
418
+ def log_details (self ) -> str :
402
419
module_str = ', ' .join (self .requested_modules )
403
420
return 'modules: ' + module_str
404
421
405
- def log_info (self ):
422
+ def log_info (self ) -> str :
406
423
return f'{ self .from_text } '
407
424
408
- def log_tried (self ):
425
+ def log_tried (self ) -> str :
409
426
return self .from_text
410
427
411
428
412
429
class Qt4Dependency (QtBaseDependency ):
413
- def __init__ (self , env , kwargs ):
430
+ def __init__ (self , env : 'Environment' , kwargs : T . Dict [ str , T . Any ] ):
414
431
QtBaseDependency .__init__ (self , 'qt4' , env , kwargs )
415
432
416
- def get_pkgconfig_host_bins (self , core ):
433
+ @staticmethod
434
+ def get_pkgconfig_host_bins (core : PkgConfigDependency ) -> T .Optional [str ]:
417
435
# Only return one bins dir, because the tools are generally all in one
418
436
# directory for Qt4, in Qt5, they must all be in one directory. Return
419
437
# the first one found among the bin variables, in case one tool is not
@@ -424,25 +442,28 @@ def get_pkgconfig_host_bins(self, core):
424
442
return os .path .dirname (core .get_pkgconfig_variable ('%s_location' % application , {}))
425
443
except mesonlib .MesonException :
426
444
pass
445
+ return None
427
446
428
447
429
448
class Qt5Dependency (QtBaseDependency ):
430
- def __init__ (self , env , kwargs ):
449
+ def __init__ (self , env : 'Environment' , kwargs : T . Dict [ str , T . Any ] ):
431
450
QtBaseDependency .__init__ (self , 'qt5' , env , kwargs )
432
451
433
- def get_pkgconfig_host_bins (self , core ):
452
+ @staticmethod
453
+ def get_pkgconfig_host_bins (core : PkgConfigDependency ) -> str :
434
454
return core .get_pkgconfig_variable ('host_bins' , {})
435
455
436
- def get_private_includes (self , mod_inc_dir , module ) :
456
+ def get_private_includes (self , mod_inc_dir : str , module : str ) -> T . List [ str ] :
437
457
return _qt_get_private_includes (mod_inc_dir , module , self .version )
438
458
439
459
440
460
class Qt6Dependency (QtBaseDependency ):
441
- def __init__ (self , env , kwargs ):
461
+ def __init__ (self , env : 'Environment' , kwargs : T . Dict [ str , T . Any ] ):
442
462
QtBaseDependency .__init__ (self , 'qt6' , env , kwargs )
443
463
444
- def get_pkgconfig_host_bins (self , core ):
464
+ @staticmethod
465
+ def get_pkgconfig_host_bins (core : PkgConfigDependency ) -> str :
445
466
return core .get_pkgconfig_variable ('host_bins' , {})
446
467
447
- def get_private_includes (self , mod_inc_dir , module ) :
468
+ def get_private_includes (self , mod_inc_dir : str , module : str ) -> T . List [ str ] :
448
469
return _qt_get_private_includes (mod_inc_dir , module , self .version )
0 commit comments