summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJohn W. Parent <45471568+johnwparent@users.noreply.github.com>2024-04-18 17:53:56 -0400
committerGitHub <noreply@github.com>2024-04-18 21:53:56 +0000
commit6fba31ce3427a6e3985c37543c0f946d1c7c01e4 (patch)
tree7f2a45aabecd517f605446080a314fd6dc9434de /lib
parent112cead00b5cadbf20dec3dbc2cb20651427883b (diff)
downloadspack-6fba31ce3427a6e3985c37543c0f946d1c7c01e4.tar.gz
spack-6fba31ce3427a6e3985c37543c0f946d1c7c01e4.tar.bz2
spack-6fba31ce3427a6e3985c37543c0f946d1c7c01e4.tar.xz
spack-6fba31ce3427a6e3985c37543c0f946d1c7c01e4.zip
Windows: Update MSVC + oneAPI detection and integration (#43646)
* Later versions of oneAPI have moved, so update detection to find it in both old and new location * Remove reliance on ONEAPI_ROOT env variable when determining Fortran compiler version for %msvc * When finding a Fortran compiler for MSVC, there was logic enforcing a maximum MSVC version for a given oneAPI Fortran version. This mapping was out of date and excluding valid combinations, so has been removed (the logic now just picks the latest available oneAPI Fortran compiler for any given MSVC version).
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/compilers/msvc.py87
-rwxr-xr-xlib/spack/spack/operating_systems/windows_os.py15
2 files changed, 58 insertions, 44 deletions
diff --git a/lib/spack/spack/compilers/msvc.py b/lib/spack/spack/compilers/msvc.py
index d34ef83c3e..9914e5242a 100644
--- a/lib/spack/spack/compilers/msvc.py
+++ b/lib/spack/spack/compilers/msvc.py
@@ -8,7 +8,7 @@ import re
import subprocess
import sys
import tempfile
-from typing import Dict, List, Set
+from typing import Dict, List
import archspec.cpu
@@ -20,15 +20,7 @@ from spack.compiler import Compiler
from spack.error import SpackError
from spack.version import Version, VersionRange
-avail_fc_version: Set[str] = set()
-fc_path: Dict[str, str] = dict()
-
-fortran_mapping = {
- "2021.3.0": "19.29.30133",
- "2021.2.1": "19.28.29913",
- "2021.2.0": "19.28.29334",
- "2021.1.0": "19.28.29333",
-}
+FC_PATH: Dict[str, str] = dict()
class CmdCall:
@@ -115,15 +107,13 @@ class VCVarsInvocation(VarsInvocation):
return f"{script} {self.arch} {self.sdk_ver} {self.vcvars_ver}"
-def get_valid_fortran_pth(comp_ver):
- cl_ver = str(comp_ver)
+def get_valid_fortran_pth():
+ """Assign maximum available fortran compiler version"""
+ # TODO (johnwparent): validate compatibility w/ try compiler
+ # functionality when added
sort_fn = lambda fc_ver: Version(fc_ver)
- sort_fc_ver = sorted(list(avail_fc_version), key=sort_fn)
- for ver in sort_fc_ver:
- if ver in fortran_mapping:
- if Version(cl_ver) <= Version(fortran_mapping[ver]):
- return fc_path[ver]
- return None
+ sort_fc_ver = sorted(list(FC_PATH.keys()), key=sort_fn)
+ return FC_PATH[sort_fc_ver[-1]] if sort_fc_ver else None
class Msvc(Compiler):
@@ -167,11 +157,9 @@ class Msvc(Compiler):
# This positional argument "paths" is later parsed and process by the base class
# via the call to `super` later in this method
paths = args[3]
- # This positional argument "cspec" is also parsed and handled by the base class
- # constructor
- cspec = args[0]
- new_pth = [pth if pth else get_valid_fortran_pth(cspec.version) for pth in paths]
- paths[:] = new_pth
+ latest_fc = get_valid_fortran_pth()
+ new_pth = [pth if pth else latest_fc for pth in paths[2:]]
+ paths[2:] = new_pth
# Initialize, deferring to base class but then adding the vcvarsallfile
# file based on compiler executable path.
super().__init__(*args, **kwargs)
@@ -183,7 +171,7 @@ class Msvc(Compiler):
# and stores their path, but their respective VCVARS
# file must be invoked before useage.
env_cmds = []
- compiler_root = os.path.join(self.cc, "../../../../../../..")
+ compiler_root = os.path.join(os.path.dirname(self.cc), "../../../../../..")
vcvars_script_path = os.path.join(compiler_root, "Auxiliary", "Build", "vcvars64.bat")
# get current platform architecture and format for vcvars argument
arch = spack.platforms.real_host().default.lower()
@@ -198,11 +186,34 @@ class Msvc(Compiler):
# paths[2] refers to the fc path and is a generic check
# for a fortran compiler
if paths[2]:
+
+ def get_oneapi_root(pth: str):
+ """From within a prefix known to be a oneAPI path
+ determine the oneAPI root path from arbitrary point
+ under root
+
+ Args:
+ pth: path prefixed within oneAPI root
+ """
+ if not pth:
+ return ""
+ while os.path.basename(pth) and os.path.basename(pth) != "oneAPI":
+ pth = os.path.dirname(pth)
+ return pth
+
# If this found, it sets all the vars
- oneapi_root = os.path.join(self.cc, "../../..")
+ oneapi_root = get_oneapi_root(self.fc)
+ if not oneapi_root:
+ raise RuntimeError(f"Non-oneAPI Fortran compiler {self.fc} assigned to MSVC")
oneapi_root_setvars = os.path.join(oneapi_root, "setvars.bat")
+ # some oneAPI exes return a version more precise than their
+ # install paths specify, so we determine path from
+ # the install path rather than the fc executable itself
+ numver = r"\d+\.\d+(?:\.\d+)?"
+ pattern = f"((?:{numver})|(?:latest))"
+ version_from_path = re.search(pattern, self.fc).group(1)
oneapi_version_setvars = os.path.join(
- oneapi_root, "compiler", str(self.ifx_version), "env", "vars.bat"
+ oneapi_root, "compiler", version_from_path, "env", "vars.bat"
)
# order matters here, the specific version env must be invoked first,
# otherwise it will be ignored if the root setvars sets up the oneapi
@@ -314,23 +325,19 @@ class Msvc(Compiler):
@classmethod
def fc_version(cls, fc):
- # We're using intel for the Fortran compilers, which exist if
- # ONEAPI_ROOT is a meaningful variable
if not sys.platform == "win32":
return "unknown"
fc_ver = cls.default_version(fc)
- avail_fc_version.add(fc_ver)
- fc_path[fc_ver] = fc
- if os.getenv("ONEAPI_ROOT"):
- try:
- sps = spack.operating_systems.windows_os.WindowsOs().compiler_search_paths
- except AttributeError:
- raise SpackError("Windows compiler search paths not established")
- clp = spack.util.executable.which_string("cl", path=sps)
- ver = cls.default_version(clp)
- else:
- ver = fc_ver
- return ver
+ FC_PATH[fc_ver] = fc
+ try:
+ sps = spack.operating_systems.windows_os.WindowsOs().compiler_search_paths
+ except AttributeError:
+ raise SpackError(
+ "Windows compiler search paths not established, "
+ "please report this behavior to github.com/spack/spack"
+ )
+ clp = spack.util.executable.which_string("cl", path=sps)
+ return cls.default_version(clp) if clp else fc_ver
@classmethod
def f77_version(cls, f77):
diff --git a/lib/spack/spack/operating_systems/windows_os.py b/lib/spack/spack/operating_systems/windows_os.py
index 6ce25bb8de..3d3d44175f 100755
--- a/lib/spack/spack/operating_systems/windows_os.py
+++ b/lib/spack/spack/operating_systems/windows_os.py
@@ -74,16 +74,23 @@ class WindowsOs(OperatingSystem):
return [os.path.join(path, "VC", "Tools", "MSVC") for path in self.vs_install_paths]
@property
+ def oneapi_root(self):
+ root = os.environ.get("ONEAPI_ROOT", "") or os.path.join(
+ os.environ.get("ProgramFiles(x86)", ""), "Intel", "oneAPI"
+ )
+ if os.path.exists(root):
+ return root
+
+ @property
def compiler_search_paths(self):
# First Strategy: Find MSVC directories using vswhere
_compiler_search_paths = []
for p in self.msvc_paths:
_compiler_search_paths.extend(glob.glob(os.path.join(p, "*", "bin", "Hostx64", "x64")))
- if os.getenv("ONEAPI_ROOT"):
+ oneapi_root = self.oneapi_root
+ if oneapi_root:
_compiler_search_paths.extend(
- glob.glob(
- os.path.join(str(os.getenv("ONEAPI_ROOT")), "compiler", "*", "windows", "bin")
- )
+ glob.glob(os.path.join(oneapi_root, "compiler", "**", "bin"), recursive=True)
)
# Second strategy: Find MSVC via the registry