2016-07-22 11:08:53 +03:00
|
|
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
|
|
# vim: set filetype=python:
|
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
option('--with-windows-version', nargs=1, default='603',
|
|
|
|
help='Windows SDK version to target. Win 8.1 (603) is currently'
|
|
|
|
'the minimum supported version.')
|
|
|
|
|
|
|
|
@depends(target)
|
|
|
|
def is_windows(target):
|
|
|
|
return target.kernel == 'WINNT'
|
|
|
|
|
|
|
|
|
2016-07-22 13:10:04 +03:00
|
|
|
@template
|
|
|
|
def depends_win(*args):
|
|
|
|
return depends_when(*args, when=is_windows)
|
|
|
|
|
|
|
|
|
|
|
|
@depends_win('--with-windows-version')
|
2016-07-22 11:08:53 +03:00
|
|
|
@imports(_from='__builtin__', _import='ValueError')
|
|
|
|
def valid_windows_version(value):
|
|
|
|
if not value:
|
|
|
|
die('Cannot build with --without-windows-version')
|
|
|
|
try:
|
|
|
|
version = int(value[0], 16)
|
|
|
|
if version in (0x603,):
|
|
|
|
return version
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
die('Invalid value for --with-windows-version (%s)', value[0])
|
|
|
|
|
2016-07-22 13:10:04 +03:00
|
|
|
|
|
|
|
option(env='WINDOWSSDKDIR', nargs=1,
|
|
|
|
help='Directory containing the Windows SDK')
|
|
|
|
|
|
|
|
@depends_win('WINDOWSSDKDIR', host)
|
|
|
|
def windows_sdk_dir(value, host):
|
|
|
|
if value:
|
|
|
|
return value
|
|
|
|
if host.kernel != 'WINNT':
|
|
|
|
return ()
|
|
|
|
|
|
|
|
return tuple(x[1] for x in get_registry_values(
|
|
|
|
r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots'
|
|
|
|
r'\KitsRoot*'))
|
|
|
|
|
2016-07-27 09:37:54 +03:00
|
|
|
# The Windows SDK 8.1 and 10 have different layouts. The former has
|
|
|
|
# $SDK/include/$subdir, while the latter has $SDK/include/$version/$subdir.
|
|
|
|
# The vcvars* scripts don't actually care about the version, they just take
|
2016-08-01 10:12:36 +03:00
|
|
|
# the last.
|
2016-07-27 09:37:54 +03:00
|
|
|
@imports('os')
|
|
|
|
@imports('re')
|
|
|
|
@imports(_from='__builtin__', _import='sorted')
|
|
|
|
@imports(_from='__builtin__', _import='WindowsError')
|
2016-08-01 10:12:36 +03:00
|
|
|
def get_include_dir(sdk, subdir):
|
|
|
|
base = os.path.join(sdk, 'include')
|
|
|
|
try:
|
|
|
|
subdirs = [d for d in os.listdir(base)
|
|
|
|
if os.path.isdir(os.path.join(base, d))]
|
|
|
|
except WindowsError:
|
|
|
|
subdirs = []
|
|
|
|
if not subdirs:
|
|
|
|
return None
|
|
|
|
if subdir in subdirs:
|
|
|
|
return os.path.join(base, subdir)
|
|
|
|
# At this point, either we have an incomplete or invalid SDK directory,
|
|
|
|
# or we exclusively have version numbers in subdirs.
|
|
|
|
versions = sorted((Version(d) for d in subdirs), reverse=True)
|
|
|
|
# Version('non-number').major is 0, so if the biggest version we have is
|
|
|
|
# 0, we have a problem.
|
|
|
|
if versions[0].major == 0:
|
|
|
|
return None
|
|
|
|
path = os.path.join(base, str(versions[0]), subdir)
|
|
|
|
return path if os.path.isdir(path) else None
|
2016-07-27 09:37:54 +03:00
|
|
|
|
|
|
|
|
2016-07-22 13:10:04 +03:00
|
|
|
@imports(_from='mozbuild.shellutil', _import='quote')
|
|
|
|
def valid_windows_sdk_dir_result(value):
|
|
|
|
if value:
|
|
|
|
return '0x%04x in %s' % (value.version, quote(value.path))
|
|
|
|
|
|
|
|
@depends_win(c_compiler, windows_sdk_dir, valid_windows_version,
|
|
|
|
'WINDOWSSDKDIR')
|
|
|
|
@checking('for Windows SDK', valid_windows_sdk_dir_result)
|
|
|
|
@imports(_from='__builtin__', _import='sorted')
|
|
|
|
@imports(_from='textwrap', _import='dedent')
|
|
|
|
def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
|
|
|
|
windows_sdk_dir_env):
|
|
|
|
if windows_sdk_dir_env:
|
|
|
|
windows_sdk_dir_env = windows_sdk_dir_env[0]
|
|
|
|
sdks = {}
|
|
|
|
for d in windows_sdk_dir:
|
2016-08-01 10:12:36 +03:00
|
|
|
um_dir = get_include_dir(d, 'um')
|
|
|
|
shared_dir = get_include_dir(d, 'shared')
|
|
|
|
if um_dir and shared_dir:
|
2016-07-22 13:10:04 +03:00
|
|
|
check = dedent('''\
|
|
|
|
#include <winsdkver.h>
|
|
|
|
WINVER_MAXVER
|
|
|
|
''')
|
|
|
|
result = try_preprocess(compiler.wrapper + [compiler.compiler] +
|
|
|
|
compiler.flags +
|
|
|
|
['-I', um_dir, '-I', shared_dir], 'C',
|
|
|
|
check)
|
|
|
|
if result:
|
|
|
|
maxver = result.splitlines()[-1]
|
|
|
|
try:
|
|
|
|
maxver = int(maxver, 0)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
else:
|
2016-08-01 10:12:36 +03:00
|
|
|
sdks[d] = maxver
|
2016-07-22 13:10:04 +03:00
|
|
|
continue
|
|
|
|
if d == windows_sdk_dir_env:
|
|
|
|
raise FatalCheckError(
|
|
|
|
'Error while checking the version of the SDK in '
|
|
|
|
'WINDOWSSDKDIR (%s). Please verify it contains a valid and '
|
|
|
|
'complete SDK installation.' % windows_sdk_dir_env)
|
|
|
|
|
2016-08-01 10:12:36 +03:00
|
|
|
valid_sdks = sorted(sdks, key=lambda x: sdks[x], reverse=True)
|
2016-07-22 13:10:04 +03:00
|
|
|
if valid_sdks:
|
2016-08-01 10:12:36 +03:00
|
|
|
biggest_version = sdks[valid_sdks[0]]
|
2016-07-22 13:10:04 +03:00
|
|
|
if not valid_sdks or biggest_version < target_version:
|
|
|
|
if windows_sdk_dir_env:
|
|
|
|
raise FatalCheckError(
|
|
|
|
'You are targeting Windows version 0x%04x, but your SDK only '
|
|
|
|
'supports up to version 0x%04x. Install and use an updated SDK, '
|
|
|
|
'or target a lower version using --with-windows-version. '
|
|
|
|
'Alternatively, try running the Windows SDK Configuration Tool '
|
|
|
|
'and selecting a newer SDK. See '
|
|
|
|
'https://developer.mozilla.org/En/Windows_SDK_versions for '
|
|
|
|
'details on fixing this.' % (target_version, biggest_version))
|
|
|
|
|
|
|
|
raise FatalCheckError(
|
|
|
|
'Cannot find a Windows SDK for version >= 0x%04x.' % target_version)
|
|
|
|
|
|
|
|
return namespace(
|
2016-08-01 10:12:36 +03:00
|
|
|
path=valid_sdks[0],
|
2016-07-22 13:10:04 +03:00
|
|
|
version=biggest_version,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
add_old_configure_assignment(
|
|
|
|
'WINDOWSSDKDIR',
|
|
|
|
delayed_getattr(valid_windows_sdk_dir, 'path'))
|
2016-07-22 11:08:53 +03:00
|
|
|
add_old_configure_assignment(
|
2016-07-22 13:10:04 +03:00
|
|
|
'MOZ_WINSDK_MAXVER',
|
|
|
|
depends(valid_windows_sdk_dir)(
|
|
|
|
lambda x: '0x%04X0000' % x.version if x else None))
|
2016-07-26 09:15:08 +03:00
|
|
|
|
|
|
|
|
2016-07-27 11:03:09 +03:00
|
|
|
@imports(_from='mozbuild.shellutil', _import='quote')
|
|
|
|
def valid_ucrt_sdk_dir_result(value):
|
|
|
|
if value:
|
|
|
|
return '%s in %s' % (value.version, quote(value.path))
|
|
|
|
|
|
|
|
@depends_win(windows_sdk_dir, 'WINDOWSSDKDIR')
|
|
|
|
@checking('for Universal CRT SDK', valid_ucrt_sdk_dir_result)
|
|
|
|
@imports(_from='__builtin__', _import='sorted')
|
|
|
|
def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
|
|
|
|
if windows_sdk_dir_env:
|
|
|
|
windows_sdk_dir_env = windows_sdk_dir_env[0]
|
|
|
|
sdks = {}
|
|
|
|
for d in windows_sdk_dir:
|
|
|
|
ucrt_dir = get_include_dir(d, 'ucrt')
|
|
|
|
if ucrt_dir:
|
|
|
|
version = os.path.basename(os.path.dirname(ucrt_dir))
|
|
|
|
# We're supposed to always find a version in the directory, because
|
|
|
|
# the 8.1 SDK, which doesn't have a version in the directory, doesn't
|
|
|
|
# contain the Universal CRT SDK. When the main SDK is 8.1, there
|
|
|
|
# is, however, supposed to be a reduced install of the SDK 10
|
|
|
|
# with the UCRT.
|
|
|
|
if version != 'include':
|
|
|
|
sdks[d] = Version(version)
|
|
|
|
continue
|
|
|
|
if d == windows_sdk_dir_env:
|
|
|
|
raise FatalCheckError(
|
|
|
|
'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal '
|
|
|
|
'CRT.' % windows_sdk_dir_env)
|
|
|
|
|
|
|
|
valid_sdks = sorted(sdks, key=lambda x: sdks[x], reverse=True)
|
|
|
|
if not valid_sdks:
|
|
|
|
raise FatalCheckError('Cannot find the Universal CRT SDK. '
|
|
|
|
'Please install it.')
|
|
|
|
|
|
|
|
return namespace(
|
|
|
|
path=valid_sdks[0],
|
|
|
|
version=sdks[valid_sdks[0]],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@depends_win(c_compiler)
|
|
|
|
@imports('os')
|
|
|
|
def vc_path(c_compiler):
|
|
|
|
if c_compiler.type != 'msvc':
|
|
|
|
return
|
|
|
|
# Normally, we'd start from c_compiler.compiler, but for now, it's not the
|
|
|
|
# ideal full path to the compiler. At least, we're guaranteed find_program
|
|
|
|
# will get us the one we found in toolchain.configure.
|
|
|
|
cl = find_program(c_compiler.compiler)
|
|
|
|
result = os.path.dirname(cl)
|
|
|
|
while True:
|
|
|
|
next, p = os.path.split(result)
|
|
|
|
if next == result:
|
|
|
|
die('Cannot determine the Visual C++ directory the compiler (%s) '
|
|
|
|
'is in' % cl)
|
|
|
|
result = next
|
|
|
|
if p.lower() == 'bin':
|
|
|
|
break
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
@depends_win(vc_path)
|
|
|
|
@checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
|
|
|
|
def dia_sdk_dir(vc_path):
|
|
|
|
if vc_path:
|
|
|
|
path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')
|
|
|
|
if os.path.isdir(path):
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
@depends_win(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
|
|
|
|
@imports('os')
|
|
|
|
def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
|
|
|
|
if not vc_path:
|
|
|
|
return
|
|
|
|
atlmfc_dir = os.path.join(vc_path, 'atlmfc', 'include')
|
|
|
|
if not os.path.isdir(atlmfc_dir):
|
|
|
|
die('Cannot find the ATL/MFC headers in the Visual C++ directory (%s). '
|
|
|
|
'Please install them.' % vc_path)
|
|
|
|
|
|
|
|
winrt_dir = get_include_dir(windows_sdk_dir.path, 'winrt')
|
|
|
|
if not os.path.isdir(winrt_dir):
|
|
|
|
die('Cannot find the WinRT headers in the Windows SDK directory (%s). '
|
|
|
|
'Please install them.' % windows_sdk_dir.path)
|
|
|
|
|
|
|
|
includes = []
|
|
|
|
include_env = os.environ.get('INCLUDE')
|
|
|
|
if include_env:
|
|
|
|
includes.append(include_env)
|
|
|
|
includes.extend((
|
|
|
|
os.path.join(vc_path, 'include'),
|
|
|
|
atlmfc_dir,
|
|
|
|
get_include_dir(windows_sdk_dir.path, 'shared'),
|
|
|
|
get_include_dir(windows_sdk_dir.path, 'um'),
|
|
|
|
winrt_dir,
|
|
|
|
get_include_dir(ucrt_sdk_dir.path, 'ucrt'),
|
|
|
|
))
|
|
|
|
if dia_sdk_dir:
|
|
|
|
includes.append(os.path.join(dia_sdk_dir, 'include'))
|
|
|
|
# Set in the environment for old-configure
|
|
|
|
includes = os.pathsep.join(includes)
|
|
|
|
os.environ['INCLUDE'] = includes
|
|
|
|
return includes
|
|
|
|
|
|
|
|
set_config('INCLUDE', include_path)
|
|
|
|
|
|
|
|
|
2016-07-26 09:15:08 +03:00
|
|
|
option(env='MT', nargs=1, help='Path to the Microsoft Manifest Tool')
|
|
|
|
|
|
|
|
@depends_win(valid_windows_sdk_dir)
|
|
|
|
@imports(_from='os', _import='environ')
|
|
|
|
@imports('platform')
|
|
|
|
def sdk_bin_path(valid_windows_sdk_dir):
|
|
|
|
if not valid_windows_sdk_dir:
|
|
|
|
return
|
|
|
|
|
|
|
|
vc_host = {
|
|
|
|
'x86': 'x86',
|
|
|
|
'AMD64': 'x64',
|
|
|
|
}.get(platform.machine())
|
|
|
|
|
|
|
|
result = [
|
|
|
|
environ['PATH'],
|
|
|
|
os.path.join(valid_windows_sdk_dir.path, 'bin', vc_host)
|
|
|
|
]
|
|
|
|
if vc_host == 'x64':
|
|
|
|
result.append(
|
|
|
|
os.path.join(valid_windows_sdk_dir.path, 'bin', 'x86'))
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
# Normally, we'd use `MT` instead of `_MT`, but for now, we want MT to only contain
|
|
|
|
# mt.exe.
|
|
|
|
mt = check_prog('_MT', depends_win()(lambda: ('mt.exe',)), what='mt',
|
|
|
|
input='MT', paths=sdk_bin_path)
|
|
|
|
|
|
|
|
|
|
|
|
# Check that MT is not something unexpected like "magnetic tape manipulation
|
|
|
|
# utility".
|
|
|
|
@depends_win(mt)
|
|
|
|
@checking('whether MT is really Microsoft Manifest Tool', lambda x: bool(x))
|
|
|
|
@imports('subprocess')
|
|
|
|
def valid_mt(path):
|
|
|
|
try:
|
|
|
|
out = subprocess.check_output([path]).splitlines()
|
|
|
|
out = '\n'.join(l for l in out
|
|
|
|
if 'Microsoft (R) Manifest Tool' in l)
|
|
|
|
if out:
|
2016-07-28 12:29:49 +03:00
|
|
|
return path
|
2016-07-26 09:15:08 +03:00
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
pass
|
|
|
|
raise FatalCheckError('%s is not Microsoft Manifest Tool')
|
|
|
|
|
|
|
|
|
2016-07-28 12:29:49 +03:00
|
|
|
set_config('MT', depends_if(valid_mt)(lambda x: os.path.basename(x)))
|
2016-07-26 09:15:08 +03:00
|
|
|
set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
|
|
|
|
|
|
|
|
|
|
|
|
# Normally, we'd just have CC, etc. set to absolute paths, but the build system
|
|
|
|
# doesn't currently handle properly the case where the paths contain spaces.
|
|
|
|
# Additionally, there's the issue described in toolchain.configure, in
|
|
|
|
# valid_compiler().
|
|
|
|
@depends_win(sdk_bin_path)
|
|
|
|
@imports('os')
|
|
|
|
def alter_path(sdk_bin_path):
|
|
|
|
path = os.pathsep.join(sdk_bin_path)
|
|
|
|
os.environ['PATH'] = path
|
|
|
|
return path
|
|
|
|
|
|
|
|
set_config('PATH', alter_path)
|