Followon to PR #4348: more bool fixes
[scons.git] / SCons / Tool / MSCommon / MSVC / Util.py
blobf0e47e2956cbb57b47a32591f72b64ed2f70a570
1 # MIT License
3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """
25 Helper functions for Microsoft Visual C/C++.
26 """
28 import os
29 import re
31 from collections import (
32 namedtuple,
35 from . import Config
37 # path utilities
39 def listdir_dirs(p):
40 """
41 Return a list of tuples for each subdirectory of the given directory path.
42 Each tuple is comprised of the subdirectory name and the qualified subdirectory path.
44 Args:
45 p: str
46 directory path
48 Returns:
49 list[tuple[str,str]]: a list of tuples
51 """
52 dirs = []
53 if p and os.path.exists(p) and os.path.isdir(p):
54 for dir_name in os.listdir(p):
55 dir_path = os.path.join(p, dir_name)
56 if os.path.isdir(dir_path):
57 dirs.append((dir_name, dir_path))
58 return dirs
60 def process_path(p):
61 """
62 Normalize a system path
64 Args:
65 p: str
66 system path
68 Returns:
69 str: normalized system path
71 """
72 if p:
73 p = os.path.normpath(p)
74 p = os.path.realpath(p)
75 p = os.path.normcase(p)
76 return p
78 # msvc version and msvc toolset version regexes
80 re_version_prefix = re.compile('^(?P<version>[0-9]+(?:[.][0-9]+)*)(?![.]).*$')
82 re_msvc_version_prefix = re.compile(r'^(?P<version>[1-9][0-9]?[.][0-9]).*$')
84 re_msvc_version = re.compile(r'^(?P<msvc_version>[1-9][0-9]?[.][0-9])(?P<suffix>[A-Z]+)*$', re.IGNORECASE)
86 re_extended_version = re.compile(r'''^
87 (?P<version>(?:
88 ([1-9][0-9]?[.][0-9]{1,2})| # XX.Y - XX.YY
89 ([1-9][0-9][.][0-9]{2}[.][0-9]{1,5})| # XX.YY.Z - XX.YY.ZZZZZ
90 ([1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}) # XX.YY.AA.B - XX.YY.AA.BB
92 (?P<suffix>[A-Z]+)*
93 $''', re.IGNORECASE | re.VERBOSE)
95 re_toolset_full = re.compile(r'''^(?:
96 (?:[1-9][0-9][.][0-9]{1,2})| # XX.Y - XX.YY
97 (?:[1-9][0-9][.][0-9]{2}[.][0-9]{1,5}) # XX.YY.Z - XX.YY.ZZZZZ
98 )$''', re.VERBOSE)
100 re_toolset_140 = re.compile(r'''^(?:
101 (?:14[.]0{1,2})| # 14.0 - 14.00
102 (?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
103 )$''', re.VERBOSE)
105 re_toolset_sxs = re.compile(
106 r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$' # MM.mm.VV.vv format
109 # msvc sdk version regexes
111 re_msvc_sdk_version = re.compile(r'''^
112 (?P<version>(?:
113 ([1-9][0-9]?[.][0-9])| # XX.Y
114 ([1-9][0-9][.][0-9]{1}[.][0-9]{5}[.][0-9]{1,2}) # XX.Y.ZZZZZ.A - XX.Y.ZZZZZ.AA
116 $''', re.IGNORECASE | re.VERBOSE)
118 # version prefix utilities
120 def get_version_prefix(version):
122 Get the version number prefix from a string.
124 Args:
125 version: str
126 version specification
128 Returns:
129 str: the version number prefix
132 rval = ''
133 if version:
134 m = re_version_prefix.match(version)
135 if m:
136 rval = m.group('version')
137 return rval
139 def get_msvc_version_prefix(version):
141 Get the msvc version number prefix from a string.
143 Args:
144 version: str
145 version specification
147 Returns:
148 str: the msvc version number prefix
151 rval = ''
152 if version:
153 m = re_msvc_version_prefix.match(version)
154 if m:
155 rval = m.group('version')
156 return rval
158 # toolset version query utilities
160 def is_toolset_full(toolset_version) -> bool:
161 rval = False
162 if toolset_version:
163 if re_toolset_full.match(toolset_version):
164 rval = True
165 return rval
167 def is_toolset_140(toolset_version) -> bool:
168 rval = False
169 if toolset_version:
170 if re_toolset_140.match(toolset_version):
171 rval = True
172 return rval
174 def is_toolset_sxs(toolset_version) -> bool:
175 rval = False
176 if toolset_version:
177 if re_toolset_sxs.match(toolset_version):
178 rval = True
179 return rval
181 # msvc version and msvc toolset version decomposition utilties
183 _MSVC_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCVersionComponentsDefinition', [
184 'msvc_version', # msvc version (e.g., '14.1Exp')
185 'msvc_verstr', # msvc version numeric string (e.g., '14.1')
186 'msvc_suffix', # msvc version component type (e.g., 'Exp')
187 'msvc_vernum', # msvc version floating point number (e.g, 14.1)
188 'msvc_major', # msvc major version integer number (e.g., 14)
189 'msvc_minor', # msvc minor version integer number (e.g., 1)
190 'msvc_comps', # msvc version components tuple (e.g., ('14', '1'))
193 def msvc_version_components(vcver):
195 Decompose an msvc version into components.
197 Tuple fields:
198 msvc_version: msvc version (e.g., '14.1Exp')
199 msvc_verstr: msvc version numeric string (e.g., '14.1')
200 msvc_suffix: msvc version component type (e.g., 'Exp')
201 msvc_vernum: msvc version floating point number (e.g., 14.1)
202 msvc_major: msvc major version integer number (e.g., 14)
203 msvc_minor: msvc minor version integer number (e.g., 1)
204 msvc_comps: msvc version components tuple (e.g., ('14', '1'))
206 Args:
207 vcver: str
208 msvc version specification
210 Returns:
211 None or MSVCVersionComponents namedtuple:
214 if not vcver:
215 return None
217 m = re_msvc_version.match(vcver)
218 if not m:
219 return None
221 vs_def = Config.MSVC_VERSION_SUFFIX.get(vcver)
222 if not vs_def:
223 return None
225 msvc_version = vcver
226 msvc_verstr = m.group('msvc_version')
227 msvc_suffix = m.group('suffix') if m.group('suffix') else ''
228 msvc_vernum = float(msvc_verstr)
230 msvc_comps = tuple(msvc_verstr.split('.'))
231 msvc_major, msvc_minor = [int(x) for x in msvc_comps]
233 msvc_version_components_def = _MSVC_VERSION_COMPONENTS_DEFINITION(
234 msvc_version = msvc_version,
235 msvc_verstr = msvc_verstr,
236 msvc_suffix = msvc_suffix,
237 msvc_vernum = msvc_vernum,
238 msvc_major = msvc_major,
239 msvc_minor = msvc_minor,
240 msvc_comps = msvc_comps,
243 return msvc_version_components_def
245 _MSVC_EXTENDED_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCExtendedVersionComponentsDefinition', [
246 'msvc_version', # msvc version (e.g., '14.1Exp')
247 'msvc_verstr', # msvc version numeric string (e.g., '14.1')
248 'msvc_suffix', # msvc version component type (e.g., 'Exp')
249 'msvc_vernum', # msvc version floating point number (e.g, 14.1)
250 'msvc_major', # msvc major version integer number (e.g., 14)
251 'msvc_minor', # msvc minor version integer number (e.g., 1)
252 'msvc_comps', # msvc version components tuple (e.g., ('14', '1'))
253 'msvc_toolset_version', # msvc toolset version
254 'msvc_toolset_comps', # msvc toolset version components
255 'version', # msvc version or msvc toolset version
258 def msvc_extended_version_components(version):
260 Decompose an msvc version or msvc toolset version into components.
262 Args:
263 version: str
264 version specification
266 Returns:
267 None or MSVCExtendedVersionComponents namedtuple:
270 if not version:
271 return None
273 m = re_extended_version.match(version)
274 if not m:
275 return None
277 msvc_toolset_version = m.group('version')
278 msvc_toolset_comps = tuple(msvc_toolset_version.split('.'))
280 msvc_verstr = get_msvc_version_prefix(msvc_toolset_version)
281 if not msvc_verstr:
282 return None
284 msvc_suffix = m.group('suffix') if m.group('suffix') else ''
285 msvc_version = msvc_verstr + msvc_suffix
287 vs_def = Config.MSVC_VERSION_SUFFIX.get(msvc_version)
288 if not vs_def:
289 return None
291 msvc_vernum = float(msvc_verstr)
293 msvc_comps = tuple(msvc_verstr.split('.'))
294 msvc_major, msvc_minor = [int(x) for x in msvc_comps]
296 msvc_extended_version_components_def = _MSVC_EXTENDED_VERSION_COMPONENTS_DEFINITION(
297 msvc_version = msvc_version,
298 msvc_verstr = msvc_verstr,
299 msvc_suffix = msvc_suffix,
300 msvc_vernum = msvc_vernum,
301 msvc_major = msvc_major,
302 msvc_minor = msvc_minor,
303 msvc_comps = msvc_comps,
304 msvc_toolset_version = msvc_toolset_version,
305 msvc_toolset_comps = msvc_toolset_comps,
306 version = version,
309 return msvc_extended_version_components_def
311 # msvc sdk version decomposition utilties
313 _MSVC_SDK_VERSION_COMPONENTS_DEFINITION = namedtuple('MSVCSDKVersionComponentsDefinition', [
314 'sdk_version', # sdk version (e.g., '10.0.20348.0')
315 'sdk_verstr', # sdk version numeric string (e.g., '10.0')
316 'sdk_vernum', # sdk version floating point number (e.g, 10.0)
317 'sdk_major', # sdk major version integer number (e.g., 10)
318 'sdk_minor', # sdk minor version integer number (e.g., 0)
319 'sdk_comps', # sdk version components tuple (e.g., ('10', '0', '20348', '0'))
322 def msvc_sdk_version_components(version):
324 Decompose an msvc sdk version into components.
326 Tuple fields:
327 sdk_version: sdk version (e.g., '10.0.20348.0')
328 sdk_verstr: sdk version numeric string (e.g., '10.0')
329 sdk_vernum: sdk version floating point number (e.g., 10.0)
330 sdk_major: sdk major version integer number (e.g., 10)
331 sdk_minor: sdk minor version integer number (e.g., 0)
332 sdk_comps: sdk version components tuple (e.g., ('10', '0', '20348', '0'))
334 Args:
335 version: str
336 sdk version specification
338 Returns:
339 None or MSVCSDKVersionComponents namedtuple:
342 if not version:
343 return None
345 m = re_msvc_sdk_version.match(version)
346 if not m:
347 return None
349 sdk_version = version
350 sdk_comps = tuple(sdk_version.split('.'))
351 sdk_verstr = '.'.join(sdk_comps[:2])
352 sdk_vernum = float(sdk_verstr)
354 sdk_major, sdk_minor = [int(x) for x in sdk_comps[:2]]
356 msvc_sdk_version_components_def = _MSVC_SDK_VERSION_COMPONENTS_DEFINITION(
357 sdk_version = sdk_version,
358 sdk_verstr = sdk_verstr,
359 sdk_vernum = sdk_vernum,
360 sdk_major = sdk_major,
361 sdk_minor = sdk_minor,
362 sdk_comps = sdk_comps,
365 return msvc_sdk_version_components_def