From 057c632bee4c1d2ec9e1546229227583ea4fc835 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Fri, 1 Jul 2022 17:43:55 -0500 Subject: Issue #1956 - Allow building with newer MSVC versions. --- build/moz.configure/toolchain.configure | 82 ++++++++++++---------- build/moz.configure/windows.configure | 45 +++++++----- build/win32/vswhere.exe | Bin 0 -> 469952 bytes config/msvc-stl-wrapper.template.h | 6 -- memory/mozalloc/moz.build | 4 -- memory/mozalloc/msvc_raise_wrappers.cpp | 65 ++++------------- memory/mozalloc/msvc_raise_wrappers.h | 41 ----------- memory/mozalloc/throw_msvc.h | 17 ----- old-configure.in | 32 +-------- python/mozbuild/mozbuild/test/configure/common.py | 4 +- 10 files changed, 90 insertions(+), 206 deletions(-) create mode 100644 build/win32/vswhere.exe delete mode 100644 memory/mozalloc/msvc_raise_wrappers.h delete mode 100644 memory/mozalloc/throw_msvc.h diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index ee14ce009e..e1df749456 100644 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -383,57 +383,63 @@ 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)']): + version = Version(install['installationVersion']) + # Skip anything older than VS2015. + if version < '14': + continue + path = install['installationPath'] + + yield (Version(install['installationVersion']), { + 'x64': [os.path.join(path, r'VC\bin\amd64')], + # The x64->x86 cross toolchain requires DLLs from the native x64 toolchain. + 'x86': [os.path.join(path, r'VC\bin\amd64_x86'), os.path.join (path, r'VC\bin\amd64')], + }) + # 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') -def get_vc_paths(base): - 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(_from='operator', _import='itemgetter') @imports('platform') -def vc_compiler_path(host): +def vc_compiler_path(host, target, env): if host.kernel != 'WINNT': return - vc_host = { - 'x86': 'x86', - 'AMD64': 'x64', - }.get(platform.machine()) - if vc_host is None: - return vc_target = { 'x86': 'x86', 'x86_64': 'x64', 'arm': 'arm', - }.get(host.cpu) + }.get(target.cpu) if vc_target is None: return - - base_key = r'HKEY_LOCAL_MACHINE\SOFTWARE' - data = get_vc_paths(base_key) - if not data: - data = get_vc_paths(base_key + r'\Wow6432Node') - if not data: + all_versions = sorted(get_vc_paths(env.topsrcdir), key=itemgetter(0)) + if not all_versions: return - 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: + # Choose the newest version. + data = all_versions[-1][1] + paths = data.get(vc_target) + if not paths: 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,) + return paths @depends(vc_compiler_path) diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure index 1ad2cd3eb6..f139013aeb 100644 --- a/build/moz.configure/windows.configure +++ b/build/moz.configure/windows.configure @@ -261,13 +261,17 @@ def vc_path(c_compiler): break return result - -@depends_win(vc_path) +@depends_win(vc_path, c_compiler) @checking('for the Debug Interface Access SDK', lambda x: x or 'not found') @imports(_from='os.path', _import='isdir') -def dia_sdk_dir(vc_path): +def dia_sdk_dir(vc_path, c_compiler): 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): return path @@ -309,28 +313,35 @@ def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir): set_config('INCLUDE', include_path) -@depends_win(target, vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir) +@depends_win(target, c_compiler, vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir) @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: return - vc_target = { + sdk_target = { + 'x86': 'x86', + 'x86_64': 'x64', + 'arm': 'arm', + }.get(target.cpu) + + old_target = { 'x86': '', 'x86_64': 'amd64', 'arm': 'arm', }.get(target.cpu) - if vc_target is None: + if old_target is None: return - # As vc_target can be '', and os.path.join will happily use the empty + # 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. - vc_target = (vc_target,) if vc_target else () - sdk_target = { - 'x86': 'x86', - 'x86_64': 'x64', - 'arm': 'arm', - }.get(target.cpu) + 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) if not os.path.isdir(atlmfc_dir): @@ -349,7 +360,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), )) 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 libs = os.pathsep.join(libs) os.environ['LIB'] = libs diff --git a/build/win32/vswhere.exe b/build/win32/vswhere.exe new file mode 100644 index 0000000000..ab3c7f3fce Binary files /dev/null and b/build/win32/vswhere.exe differ diff --git a/config/msvc-stl-wrapper.template.h b/config/msvc-stl-wrapper.template.h index ed9d98b0dd..24f02023c5 100644 --- a/config/msvc-stl-wrapper.template.h +++ b/config/msvc-stl-wrapper.template.h @@ -19,12 +19,6 @@ # define MOZ_INCLUDE_MOZALLOC_H_FROM_${HEADER} #endif -// Code built with !_HAS_EXCEPTIONS calls std::_Throw(), but the win2k -// CRT doesn't export std::_Throw(). So we define it. -#ifndef mozilla_Throw_h -# include "mozilla/throw_msvc.h" -#endif - #ifdef _DEBUG // From // http://msdn.microsoft.com/en-us/library/aa985982%28VS.80%29.aspx diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build index 9afcefc032..5a6228069e 100644 --- a/memory/mozalloc/moz.build +++ b/memory/mozalloc/moz.build @@ -16,10 +16,6 @@ if CONFIG['WRAP_STL_INCLUDES']: elif CONFIG['_MSC_VER']: DEFINES['_HAS_EXCEPTIONS'] = 0 if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']: - EXPORTS.mozilla += [ - 'msvc_raise_wrappers.h', - 'throw_msvc.h', - ] SOURCES += [ 'msvc_raise_wrappers.cpp', ] diff --git a/memory/mozalloc/msvc_raise_wrappers.cpp b/memory/mozalloc/msvc_raise_wrappers.cpp index 820663f63b..a9f844986c 100644 --- a/memory/mozalloc/msvc_raise_wrappers.cpp +++ b/memory/mozalloc/msvc_raise_wrappers.cpp @@ -5,59 +5,18 @@ * 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/. */ -#include - +#include #include "mozalloc_abort.h" -__declspec(noreturn) static void abort_from_exception(const char* const which, - const char* const what); -static void -abort_from_exception(const char* const which, const char* const what) -{ - fprintf(stderr, "fatal: STL threw %s: ", which); - mozalloc_abort(what); -} - -namespace std { - -// NB: user code is not supposed to touch the std:: namespace. We're -// doing this after careful review because we want to define our own -// exception throwing semantics. Don't try this at home! - -MFBT_API __declspec(noreturn) void -moz_Xinvalid_argument(const char* what) -{ - abort_from_exception("invalid_argument", what); -} - -MFBT_API __declspec(noreturn) void -moz_Xlength_error(const char* what) -{ - abort_from_exception("length_error", what); -} - -MFBT_API __declspec(noreturn) void -moz_Xout_of_range(const char* what) -{ - abort_from_exception("out_of_range", what); -} - -MFBT_API __declspec(noreturn) void -moz_Xoverflow_error(const char* what) -{ - abort_from_exception("overflow_error", what); -} - -MFBT_API __declspec(noreturn) void -moz_Xruntime_error(const char* what) -{ - abort_from_exception("runtime_error", what); -} - -MFBT_API __declspec(noreturn) void -moz_Xbad_function_call() -{ +static void __cdecl +RaiseHandler(const std::exception& e) + { abort_from_exception("bad_function_call", "bad function call"); -} - -} // namespace std + mozalloc_abort(e.what()); + } + +static struct StaticScopeStruct final { + StaticScopeStruct() { + std::exception::_Set_raise_handler(RaiseHandler); + } +} StaticScopeInvoke; diff --git a/memory/mozalloc/msvc_raise_wrappers.h b/memory/mozalloc/msvc_raise_wrappers.h deleted file mode 100644 index 91b77f453b..0000000000 --- a/memory/mozalloc/msvc_raise_wrappers.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* 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/. */ - -#ifndef mozilla_msvc_raise_wrappers_h -#define mozilla_msvc_raise_wrappers_h - -#ifdef _XSTDDEF_ -# error "Unable to wrap _RAISE(); CRT _RAISE() already defined" -#endif -#ifdef _XUTILITY_ -# error "Unable to wrap _X[exception](); CRT versions already declared" -#endif -#ifdef _FUNCTIONAL_ -# error "Unable to wrap _Xbad_function_call(); CRT version already declared" -#endif - -#include "mozilla/mozalloc_abort.h" - -// xutility will declare the following functions in the std namespace. -// We #define them to be named differently so we can ensure the exception -// throwing semantics of these functions work exactly the way we want, by -// defining our own versions in msvc_raise_wrappers.cpp. -# define _Xinvalid_argument moz_Xinvalid_argument -# define _Xlength_error moz_Xlength_error -# define _Xout_of_range moz_Xout_of_range -# define _Xoverflow_error moz_Xoverflow_error -# define _Xruntime_error moz_Xruntime_error -// used by -# define _Xbad_function_call moz_Xbad_function_call - -# include -# include - -# undef _RAISE -# define _RAISE(x) mozalloc_abort((x).what()) - -#endif // ifndef mozilla_msvc_raise_wrappers_h diff --git a/memory/mozalloc/throw_msvc.h b/memory/mozalloc/throw_msvc.h deleted file mode 100644 index e6ebf46dc4..0000000000 --- a/memory/mozalloc/throw_msvc.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: sw=4 ts=4 et : - */ -/* 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/. */ - -#ifndef mozilla_throw_msvc_h -#define mozilla_throw_msvc_h - -#if defined(MOZ_MSVC_STL_WRAP_RAISE) -# include "msvc_raise_wrappers.h" -#else -# error "Unknown STL wrapper tactic" -#endif - -#endif // mozilla_throw_msvc_h diff --git a/old-configure.in b/old-configure.in index e575f65fa5..0ed6984ca9 100644 --- a/old-configure.in +++ b/old-configure.in @@ -258,35 +258,8 @@ case "$target" in unset _MSVC_VER_FILTER - AC_CACHE_CHECK(for overridable _RAISE, - ac_cv_have__RAISE, - [ - AC_LANG_SAVE - AC_LANG_CPLUSPLUS - _SAVE_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="${CXXFLAGS} -D_HAS_EXCEPTIONS=0" - AC_TRY_COMPILE([#include - #undef _RAISE - #define _RAISE(x) externallyDefinedFunction((x).what()) - #include - ], - [std::vector v; return v.at(1);], - ac_cv_have__RAISE="no", - ac_cv_have__RAISE="yes") - CXXFLAGS="$_SAVE_CXXFLAGS" - AC_LANG_RESTORE - ]) - if test "$ac_cv_have__RAISE" = "yes"; then - WRAP_STL_INCLUDES=1 - MOZ_MSVC_STL_WRAP_RAISE=1 - AC_DEFINE(MOZ_MSVC_STL_WRAP_RAISE) - else - AC_MSG_ERROR([Gecko exception wrapping doesn't understand your your MSVC/SDK. Please file a bug describing this error and your build configuration.]) - fi - - if test "$WRAP_STL_INCLUDES" = "1"; then - STL_FLAGS="-I${DIST}/stl_wrappers" - fi + WRAP_STL_INCLUDES=1 + STL_FLAGS="-I${DIST}/stl_wrappers" CFLAGS="$CFLAGS -D_HAS_EXCEPTIONS=0" CXXFLAGS="$CXXFLAGS -D_HAS_EXCEPTIONS=0" else @@ -373,7 +346,6 @@ AC_SUBST(GNU_CXX) AC_SUBST(STL_FLAGS) AC_SUBST(WRAP_STL_INCLUDES) -AC_SUBST(MOZ_MSVC_STL_WRAP_RAISE) dnl ======================================================== dnl Checks for programs. diff --git a/python/mozbuild/mozbuild/test/configure/common.py b/python/mozbuild/mozbuild/test/configure/common.py index 089d61a0d1..5ce04e6091 100644 --- a/python/mozbuild/mozbuild/test/configure/common.py +++ b/python/mozbuild/mozbuild/test/configure/common.py @@ -89,7 +89,7 @@ class ConfigureTestSandbox(ConfigureSandbox): self._subprocess_paths[environ['CONFIG_SHELL']] = self.shell paths.append(environ['CONFIG_SHELL']) self._environ = copy.copy(environ) - + self._subprocess_paths[mozpath.join(topsrcdir, 'build/win32/vswhere.exe')] = self.vswhere vfs = ConfigureTestVFS(paths) os_path = { @@ -215,6 +215,8 @@ class ConfigureTestSandbox(ConfigureSandbox): return self._subprocess_paths[script](stdin, args[1:]) return 127, '', 'File not found' + def vswhere(self, stdin, args): + return 0, '[]', '' class BaseConfigureTest(unittest.TestCase): HOST = 'x86_64-pc-linux-gnu' -- cgit v1.2.3