bug 1318143 - add support for detecting Visual Studio 2017 to configure. r=gps

This patch adds a copy of vswhere.exe to build/win32, downloaded from the
current latest release (1.0.62):
https://github.com/Microsoft/vswhere/releases/download/1.0.62/vswhere.exe

It changes toolchain.configure to invoke vswhere.exe instead of reading
the registry, since that no longer works for VS2017 (but vswhere can locate
VS2015). It also removes a layer of complexity in that code by dropping
support for non-64-bit host systems, since we don't really support building
on 32-bit Windows anymore anyway.

There's a little bit of fixup in windows.configure where some LIB paths
have changed in 2017.

MozReview-Commit-ID: 5XLWjidS6W4

--HG--
extra : rebase_source : 15c69aeca3295a1811c85a9cf4c2793312dcd122
This commit is contained in:
Ted Mielczarek 2017-04-25 06:29:30 -04:00
Родитель 0956db6c55
Коммит aaf6f64815
3 изменённых файлов: 69 добавлений и 63 удалений

Просмотреть файл

@ -410,57 +410,53 @@ def check_compiler(compiler, language, target):
) )
@imports(_from='collections', _import='defaultdict') @imports(_from='__builtin__', _import='open')
@imports('json')
@imports('subprocess')
def get_vc_paths(topsrcdir):
def vswhere(args):
return json.loads(subprocess.check_output([os.path.join(topsrcdir, 'build/win32/vswhere.exe'), '-format', 'json'] + args))
# Can't pass -requires with -legacy, so query each separately.
# Legacy versions first (VS2015)
for install in vswhere(['-legacy', '-version', '[14.0,15.0)']):
path = install['installationPath']
yield (Version(install['installationVersion']), {
'x64': [os.path.join(path, r'VC\bin\amd64')],
'x86': [os.path.join(path, r'VC\bin\amd64_x86')],
})
# Then VS2017 and newer.
for install in vswhere(['-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64']):
path = install['installationPath']
tools_version = open(os.path.join(path, r'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt'), 'rb').read().strip()
tools_path = os.path.join(path, r'VC\Tools\MSVC', tools_version, r'bin\HostX64')
yield (Version(install['installationVersion']), {
'x64': [os.path.join(tools_path, 'x64')],
# The x64->x86 cross toolchain requires DLLs from the native x64 toolchain.
'x86': [os.path.join(tools_path, 'x86'), os.path.join(tools_path, 'x64')],
})
@depends(host, target, check_build_environment)
@imports(_from='__builtin__', _import='sorted') @imports(_from='__builtin__', _import='sorted')
def get_vc_paths(base): @imports(_from='operator', _import='itemgetter')
vc = defaultdict(lambda: defaultdict(dict))
subkey = r'Microsoft\VisualStudio\VC\*\*\*\Compiler'
for v, h, t, p in get_registry_values(base + '\\' + subkey):
vc[v][h][t] = p
if not vc:
return
version, data = sorted(vc.iteritems(), key=lambda x: Version(x[0]))[-1]
return data
@depends(host)
@imports('platform') @imports('platform')
def vc_compiler_path(host): def vc_compiler_path(host, target, env):
if host.kernel != 'WINNT': if host.kernel != 'WINNT':
return return
vc_host = {
'x86': 'x86',
'AMD64': 'x64',
}.get(platform.machine())
if vc_host is None:
return
vc_target = { vc_target = {
'x86': 'x86', 'x86': 'x86',
'x86_64': 'x64', 'x86_64': 'x64',
'arm': 'arm', 'arm': 'arm',
}.get(host.cpu) }.get(target.cpu)
if vc_target is None: if vc_target is None:
return return
base_key = r'HKEY_LOCAL_MACHINE\SOFTWARE' version, data = sorted(get_vc_paths(env.topsrcdir), key=itemgetter(0))[-1]
data = get_vc_paths(base_key) paths = data.get(vc_target)
if not data: if not paths:
data = get_vc_paths(base_key + r'\Wow6432Node')
if not data:
return return
return paths
path = data.get(vc_host, {}).get(vc_target)
if not path and vc_host == 'x64':
vc_host = 'x86'
path = data.get(vc_host, {}).get(vc_target)
if not path:
return
path = os.path.dirname(path)
if vc_host != vc_target:
other_path = data.get(vc_host, {}).get(vc_host)
if other_path:
return (path, os.path.dirname(other_path))
return (path,)
@depends(vc_compiler_path) @depends(vc_compiler_path)

Просмотреть файл

@ -252,12 +252,17 @@ def vc_path(c_compiler):
return result return result
@depends(vc_path) @depends(vc_path, c_compiler)
@checking('for the Debug Interface Access SDK', lambda x: x or 'not found') @checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
@imports(_from='os.path', _import='isdir') @imports(_from='os.path', _import='isdir')
def dia_sdk_dir(vc_path): def dia_sdk_dir(vc_path, c_compiler):
if vc_path: if vc_path:
path = os.path.join(os.path.dirname(vc_path), 'DIA SDK') if c_compiler.version < '19.10':
path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')
else:
# This would be easier if we had the installationPath that
# get_vc_paths works with, since 'DIA SDK' is relative to that.
path = os.path.normpath(os.path.join(vc_path, r'..\..\..\..\..\..\..\DIA SDK'))
if isdir(path): if isdir(path):
return path return path
@ -299,37 +304,40 @@ def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
set_config('INCLUDE', include_path) set_config('INCLUDE', include_path)
@depends(target, vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir) @depends(target, c_compiler, vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
@imports('os') @imports('os')
def lib_path(target, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir): def lib_path(target, c_compiler, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
if not vc_path: if not vc_path:
return return
vc_target = {
'x86': '',
'x86_64': 'amd64',
'arm': 'arm',
}.get(target.cpu)
if vc_target is None:
return
# As vc_target can be '', and os.path.join will happily use the empty
# string, leading to a string ending with a backslash, that Make will
# interpret as a "string continues on next line" indicator, use variable
# args.
vc_target = (vc_target,) if vc_target else ()
sdk_target = { sdk_target = {
'x86': 'x86', 'x86': 'x86',
'x86_64': 'x64', 'x86_64': 'x64',
'arm': 'arm', 'arm': 'arm',
}.get(target.cpu) }.get(target.cpu)
old_target = {
'x86': '',
'x86_64': 'amd64',
'arm': 'arm',
}.get(target.cpu)
if old_target is None:
return
# As old_target can be '', and os.path.join will happily use the empty
# string, leading to a string ending with a backslash, that Make will
# interpret as a "string continues on next line" indicator, use variable
# args.
old_target = (old_target,) if old_target else ()
if c_compiler.version < '19.10':
# MSVC2015
vc_target = old_target
else:
# MSVC2017 switched to use the same target naming as the sdk.
vc_target = (sdk_target,)
atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'lib', *vc_target) atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'lib', *vc_target)
if not os.path.isdir(atlmfc_dir): if not os.path.isdir(atlmfc_dir):
# For Visual Studio 2017 die('Cannot find the ATL/MFC libraries in the Visual C++ directory '
atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'lib', sdk_target) '(%s). Please install them.' % vc_path)
if not os.path.isdir(atlmfc_dir):
die('Cannot find the ATL/MFC libraries in the Visual C++ directory '
'(%s). Please install them.' % vc_path)
libs = [] libs = []
lib_env = os.environ.get('LIB') lib_env = os.environ.get('LIB')
@ -342,7 +350,9 @@ def lib_path(target, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
os.path.join(ucrt_sdk_dir.lib, 'ucrt', sdk_target), os.path.join(ucrt_sdk_dir.lib, 'ucrt', sdk_target),
)) ))
if dia_sdk_dir: if dia_sdk_dir:
libs.append(os.path.join(dia_sdk_dir, 'lib', *vc_target)) # For some reason the DIA SDK still uses the old-style targets
# even in a newer MSVC.
libs.append(os.path.join(dia_sdk_dir, 'lib', *old_target))
# Set in the environment for old-configure # Set in the environment for old-configure
libs = os.pathsep.join(libs) libs = os.pathsep.join(libs)
os.environ['LIB'] = libs os.environ['LIB'] = libs

Двоичные данные
build/win32/vswhere.exe Normal file

Двоичный файл не отображается.