summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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