aboutsummaryrefslogtreecommitdiffstats
path: root/python/servo/visual_studio.py
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2024-01-17 11:53:34 +0100
committerGitHub <noreply@github.com>2024-01-17 10:53:34 +0000
commitd86e713a9cb5be2555d63bd477d47d440fa8c832 (patch)
treee7bbc0783b19f4b4500fb350e60654c276ad0b1d /python/servo/visual_studio.py
parentf76982e2e7f411e2e2fd8e6dbfe92a080acefc54 (diff)
downloadservo-d86e713a9cb5be2555d63bd477d47d440fa8c832.tar.gz
servo-d86e713a9cb5be2555d63bd477d47d440fa8c832.zip
build: Clean up post-build copy of Windows DLLs (#31092)
* build: Clean up post-build copy of Windows DLLs - No longer use vcvarsall.bat at all. Instead find the Windows SDK directory by looking in the registry. - Split logic for copying Windows dependencies into its own function and do some minor clean up, such as collecting all MSVC functionality into visual_studio.py. - Remove support for Visual Studio 2015 and Visual Studio 2017. This is a preparatory change in order to support Visual Studio 2022. * More cleanup of the code
Diffstat (limited to 'python/servo/visual_studio.py')
-rw-r--r--python/servo/visual_studio.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/python/servo/visual_studio.py b/python/servo/visual_studio.py
new file mode 100644
index 00000000000..4149076a396
--- /dev/null
+++ b/python/servo/visual_studio.py
@@ -0,0 +1,149 @@
+# Copyright 2024 The Servo Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import dataclasses
+import json
+import os
+import subprocess
+import sys
+from typing import List
+
+import servo.platform
+
+
+@dataclasses.dataclass(kw_only=True)
+class VisualStudioInstallation:
+ version_number: str
+ installation_path: str
+ vc_install_path: str
+
+
+def find_highest_msvc_version_ext():
+ """Try to find the MSVC installation with the `vswhere.exe` tool. The results
+ are sorted with newer versions first."""
+ def vswhere(args):
+ program_files = (os.environ.get('PROGRAMFILES(X86)')
+ or os.environ.get('PROGRAMFILES'))
+ if not program_files:
+ return []
+ vswhere = os.path.join(program_files, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe')
+ if not os.path.exists(vswhere):
+ return []
+ output = subprocess.check_output([vswhere, '-format', 'json'] + args).decode(errors='ignore')
+ return json.loads(output)
+
+ for install in vswhere(['-products', '*',
+ '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+ '-requires', 'Microsoft.VisualStudio.Component.Windows10SDK']):
+ version = install['installationVersion'].split('.')[0] + '.0'
+ yield (install['installationPath'], version)
+
+
+def find_highest_msvc_version():
+ prog_files = os.environ.get("ProgramFiles(x86)")
+
+ # TODO(mrobinson): Add support for Visual Studio 2022.
+ vs_versions = {
+ "2019": "16.0",
+ }
+
+ for (version, version_number) in vs_versions.items():
+ for edition in ["Enterprise", "Professional", "Community", "BuildTools"]:
+ vsinstalldir = os.path.join(prog_files, "Microsoft Visual Studio", version, edition)
+ if os.path.exists(vsinstalldir):
+ return (vsinstalldir, version_number)
+
+ versions = sorted(find_highest_msvc_version_ext(), key=lambda tup: float(tup[1]))
+ if not versions:
+ print("Can't find a Visual Studio installation. "
+ "Please set the VSINSTALLDIR and VisualStudioVersion environment variables")
+ sys.exit(1)
+ return versions[0]
+
+
+def find_msvc() -> VisualStudioInstallation:
+ vsinstalldir = os.environ.get('VSINSTALLDIR')
+ version_number = os.environ.get('VisualStudioVersion')
+ if not vsinstalldir or not version_number:
+ (vsinstalldir, version_number) = find_highest_msvc_version()
+
+ vc_install_path = os.environ.get("VCINSTALLDIR", os.path.join(vsinstalldir, "VC"))
+ if not os.path.exists(vc_install_path):
+ print(f"Can't find Visual C++ {version_number} installation at {vc_install_path}")
+ sys.exit(1)
+
+ return VisualStudioInstallation(
+ version_number=version_number,
+ installation_path=vsinstalldir,
+ vc_install_path=vc_install_path,
+ )
+
+
+def find_windows_sdk_installation_path(vs_platform: str) -> str:
+ """Try to find the Windows SDK installation path using the Windows registry.
+ Raises an Exception if the path cannot be found in the registry."""
+
+ # This module must be imported here, because other platforms also
+ # load this file and the module is platform-specific.
+ import winreg
+
+ # This is based on the advice from
+ # https://stackoverflow.com/questions/35119223/how-to-programmatically-detect-and-locate-the-windows-10-sdk
+ key_path = r'SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0'
+ try:
+ with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, key_path) as key:
+ path = str(winreg.QueryValueEx(key, "InstallationFolder")[0])
+ return os.path.join(path, "Redist", "ucrt", "DLLs", vs_platform)
+ except FileNotFoundError:
+ raise Exception(f"Couldn't find Windows SDK installation path in registry at path ({key_path})")
+
+
+def find_msvc_redist_dirs(target: str) -> List[str]:
+ assert 'windows' in servo.platform.host_triple()
+
+ installation = find_msvc()
+ msvc_redist_dir = None
+ vs_platforms = {
+ "x86_64": "x64",
+ "i686": "x86",
+ "aarch64": "arm64",
+ }
+ target_arch = target.split('-')[0]
+ vs_platform = vs_platforms[target_arch]
+
+ redist_dir = os.path.join(installation.vc_install_path, "Redist", "MSVC")
+ if not os.path.isdir(redist_dir):
+ raise Exception(f"Couldn't locate MSVC redistributable directory {redist_dir}")
+
+ for p in os.listdir(redist_dir)[::-1]:
+ redist_path = os.path.join(redist_dir, p)
+ for v in ["VC141", "VC142", "VC150", "VC160"]:
+ # there are two possible paths
+ # `x64\Microsoft.VC*.CRT` or `onecore\x64\Microsoft.VC*.CRT`
+ redist1 = os.path.join(redist_path, vs_platform, "Microsoft.{}.CRT".format(v))
+ redist2 = os.path.join(redist_path, "onecore", vs_platform, "Microsoft.{}.CRT".format(v))
+ if os.path.isdir(redist1):
+ msvc_redist_dir = redist1
+ break
+ elif os.path.isdir(redist2):
+ msvc_redist_dir = redist2
+ break
+ if msvc_redist_dir:
+ break
+
+ if not msvc_redist_dir:
+ print("Couldn't locate MSVC redistributable directory")
+ sys.exit(1)
+
+ redist_dirs = [
+ msvc_redist_dir,
+ find_windows_sdk_installation_path(vs_platform)
+ ]
+
+ return redist_dirs