# @file WindowsVsToolChain.py | |
# Plugin to configures paths for the VS2017 and VS2019 tool chain | |
## | |
# This plugin works in conjuncture with the tools_def | |
# | |
# Copyright (c) Microsoft Corporation | |
# SPDX-License-Identifier: BSD-2-Clause-Patent | |
## | |
import os | |
import logging | |
from edk2toolext.environment.plugintypes.uefi_build_plugin import IUefiBuildPlugin | |
import edk2toollib.windows.locate_tools as locate_tools | |
from edk2toollib.windows.locate_tools import FindWithVsWhere | |
from edk2toolext.environment import shell_environment | |
from edk2toolext.environment import version_aggregator | |
from edk2toollib.utility_functions import GetHostInfo | |
class WindowsVsToolChain(IUefiBuildPlugin): | |
def do_post_build(self, thebuilder): | |
return 0 | |
def do_pre_build(self, thebuilder): | |
self.Logger = logging.getLogger("WindowsVsToolChain") | |
interesting_keys = ["ExtensionSdkDir", "INCLUDE", "LIB", "LIBPATH", "UniversalCRTSdkDir", | |
"UCRTVersion", "WindowsLibPath", "WindowsSdkBinPath", "WindowsSdkDir", "WindowsSdkVerBinPath", | |
"WindowsSDKVersion", "VCToolsInstallDir", "Path"] | |
# | |
# VS2017 - Follow VS2017 where there is potential for many versions of the tools. | |
# If a specific version is required then the user must set both env variables: | |
# VS150INSTALLPATH: base install path on system to VC install dir. Here you will find the VC folder, etc | |
# VS150TOOLVER: version number for the VC compiler tools | |
# VS2017_PREFIX: path to MSVC compiler folder with trailing slash (can be used instead of two vars above) | |
# VS2017_HOST: set the host architecture to use for host tools, and host libs, etc | |
if thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "VS2017": | |
# check to see if host is configured | |
# HostType for VS2017 should be (defined in tools_def): | |
# x86 == 32bit Intel | |
# x64 == 64bit Intel | |
# arm == 32bit Arm | |
# arm64 == 64bit Arm | |
# | |
HostType = shell_environment.GetEnvironment().get_shell_var("VS2017_HOST") | |
if HostType is not None: | |
HostType = HostType.lower() | |
self.Logger.info( | |
f"HOST TYPE defined by environment. Host Type is {HostType}") | |
else: | |
HostInfo = GetHostInfo() | |
if HostInfo.arch == "x86": | |
if HostInfo.bit == "32": | |
HostType = "x86" | |
elif HostInfo.bit == "64": | |
HostType = "x64" | |
else: | |
raise NotImplementedError() | |
# VS2017_HOST options are not exactly the same as QueryVcVariables. This translates. | |
VC_HOST_ARCH_TRANSLATOR = { | |
"x86": "x86", "x64": "AMD64", "arm": "not supported", "arm64": "not supported"} | |
# check to see if full path already configured | |
if shell_environment.GetEnvironment().get_shell_var("VS2017_PREFIX") != None: | |
self.Logger.info("VS2017_PREFIX is already set.") | |
else: | |
install_path = self._get_vs_install_path( | |
"VS2017".lower(), "VS150INSTALLPATH") | |
vc_ver = self._get_vc_version(install_path, "VS150TOOLVER") | |
if install_path is None or vc_ver is None: | |
self.Logger.error( | |
"Failed to configure environment for VS2017") | |
return -1 | |
version_aggregator.GetVersionAggregator().ReportVersion( | |
"Visual Studio Install Path", install_path, version_aggregator.VersionTypes.INFO) | |
version_aggregator.GetVersionAggregator().ReportVersion( | |
"VC Version", vc_ver, version_aggregator.VersionTypes.TOOL) | |
# make VS2017_PREFIX to align with tools_def.txt | |
prefix = os.path.join(install_path, "VC", | |
"Tools", "MSVC", vc_ver) | |
prefix = prefix + os.path.sep | |
shell_environment.GetEnvironment().set_shell_var("VS2017_PREFIX", prefix) | |
shell_environment.GetEnvironment().set_shell_var("VS2017_HOST", HostType) | |
shell_env = shell_environment.GetEnvironment() | |
# Use the tools lib to determine the correct values for the vars that interest us. | |
vs_vars = locate_tools.QueryVcVariables( | |
interesting_keys, VC_HOST_ARCH_TRANSLATOR[HostType], vs_version="vs2017") | |
for (k, v) in vs_vars.items(): | |
shell_env.set_shell_var(k, v) | |
# now confirm it exists | |
if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("VS2017_PREFIX")): | |
self.Logger.error("Path for VS2017 toolchain is invalid") | |
return -2 | |
# | |
# VS2019 - Follow VS2019 where there is potential for many versions of the tools. | |
# If a specific version is required then the user must set both env variables: | |
# VS160INSTALLPATH: base install path on system to VC install dir. Here you will find the VC folder, etc | |
# VS160TOOLVER: version number for the VC compiler tools | |
# VS2019_PREFIX: path to MSVC compiler folder with trailing slash (can be used instead of two vars above) | |
# VS2017_HOST: set the host architecture to use for host tools, and host libs, etc | |
elif thebuilder.env.GetValue("TOOL_CHAIN_TAG") == "VS2019": | |
# check to see if host is configured | |
# HostType for VS2019 should be (defined in tools_def): | |
# x86 == 32bit Intel | |
# x64 == 64bit Intel | |
# arm == 32bit Arm | |
# arm64 == 64bit Arm | |
# | |
HostType = shell_environment.GetEnvironment().get_shell_var("VS2019_HOST") | |
if HostType is not None: | |
HostType = HostType.lower() | |
self.Logger.info( | |
f"HOST TYPE defined by environment. Host Type is {HostType}") | |
else: | |
HostInfo = GetHostInfo() | |
if HostInfo.arch == "x86": | |
if HostInfo.bit == "32": | |
HostType = "x86" | |
elif HostInfo.bit == "64": | |
HostType = "x64" | |
else: | |
raise NotImplementedError() | |
# VS2019_HOST options are not exactly the same as QueryVcVariables. This translates. | |
VC_HOST_ARCH_TRANSLATOR = { | |
"x86": "x86", "x64": "AMD64", "arm": "not supported", "arm64": "not supported"} | |
# check to see if full path already configured | |
if shell_environment.GetEnvironment().get_shell_var("VS2019_PREFIX") != None: | |
self.Logger.info("VS2019_PREFIX is already set.") | |
else: | |
install_path = self._get_vs_install_path( | |
"VS2019".lower(), "VS160INSTALLPATH") | |
vc_ver = self._get_vc_version(install_path, "VS160TOOLVER") | |
if install_path is None or vc_ver is None: | |
self.Logger.error( | |
"Failed to configure environment for VS2019") | |
return -1 | |
version_aggregator.GetVersionAggregator().ReportVersion( | |
"Visual Studio Install Path", install_path, version_aggregator.VersionTypes.INFO) | |
version_aggregator.GetVersionAggregator().ReportVersion( | |
"VC Version", vc_ver, version_aggregator.VersionTypes.TOOL) | |
# make VS2019_PREFIX to align with tools_def.txt | |
prefix = os.path.join(install_path, "VC", | |
"Tools", "MSVC", vc_ver) | |
prefix = prefix + os.path.sep | |
shell_environment.GetEnvironment().set_shell_var("VS2019_PREFIX", prefix) | |
shell_environment.GetEnvironment().set_shell_var("VS2019_HOST", HostType) | |
shell_env = shell_environment.GetEnvironment() | |
# Use the tools lib to determine the correct values for the vars that interest us. | |
vs_vars = locate_tools.QueryVcVariables( | |
interesting_keys, VC_HOST_ARCH_TRANSLATOR[HostType], vs_version="vs2019") | |
for (k, v) in vs_vars.items(): | |
shell_env.set_shell_var(k, v) | |
# now confirm it exists | |
if not os.path.exists(shell_environment.GetEnvironment().get_shell_var("VS2019_PREFIX")): | |
self.Logger.error("Path for VS2019 toolchain is invalid") | |
return -2 | |
return 0 | |
def _get_vs_install_path(self, vs_version, varname): | |
# check if already specified | |
path = None | |
if varname is not None: | |
path = shell_environment.GetEnvironment().get_shell_var(varname) | |
if(path is None): | |
# Not specified...find latest | |
try: | |
path = FindWithVsWhere(vs_version=vs_version) | |
except (EnvironmentError, ValueError, RuntimeError) as e: | |
self.Logger.error(str(e)) | |
return None | |
if path is not None and os.path.exists(path): | |
self.Logger.debug("Found VS instance for %s", vs_version) | |
else: | |
self.Logger.error( | |
f"VsWhere successfully executed, but could not find VS instance for {vs_version}.") | |
return path | |
def _get_vc_version(self, path, varname): | |
# check if already specified | |
vc_ver = shell_environment.GetEnvironment().get_shell_var(varname) | |
if (path is None): | |
self.Logger.critical( | |
"Failed to find Visual Studio tools. Might need to check for VS install") | |
return vc_ver | |
if(vc_ver is None): | |
# Not specified...find latest | |
p2 = os.path.join(path, "VC", "Tools", "MSVC") | |
if not os.path.isdir(p2): | |
self.Logger.critical( | |
"Failed to find VC tools. Might need to check for VS install") | |
return vc_ver | |
vc_ver = os.listdir(p2)[-1].strip() # get last in list | |
self.Logger.debug("Found VC Tool version is %s" % vc_ver) | |
return vc_ver |