From a7101db39de6aa754a3cce8f6e39231ababc6f67 Mon Sep 17 00:00:00 2001 From: Betsy McPhail Date: Fri, 22 Oct 2021 16:24:48 -0400 Subject: MSVC Compiler Find and vcvars env integration (#22856) Made the vcvars batch script location a member variable of the msvc compiler subclass, initialized from the compiler executable path. Added a setup_custom_environment() method to the msvc subclass that sources the vcvars script, dumps the environment, and copies the relevant environment variables to the Spack environment. Added class variables to the Windows OS and MSVC compiler subclasses to enable finding the compiler executables and determining their versions. --- lib/spack/spack/compiler.py | 8 +++-- lib/spack/spack/compilers/msvc.py | 47 +++++++++++++++++++++++++ lib/spack/spack/operating_systems/windows_os.py | 33 +++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py index 976699702b..cf903c129c 100644 --- a/lib/spack/spack/compiler.py +++ b/lib/spack/spack/compiler.py @@ -37,8 +37,12 @@ def _get_compiler_version_output(compiler_path, version_arg, ignore_errors=()): version_arg (str): the argument used to extract version information """ compiler = spack.util.executable.Executable(compiler_path) - output = compiler( - version_arg, output=str, error=str, ignore_errors=ignore_errors) + if version_arg: + output = compiler( + version_arg, output=str, error=str, ignore_errors=ignore_errors) + else: + output = compiler( + output=str, error=str, ignore_errors=ignore_errors) return output diff --git a/lib/spack/spack/compilers/msvc.py b/lib/spack/spack/compilers/msvc.py index ac5da84705..a613d02d36 100644 --- a/lib/spack/spack/compilers/msvc.py +++ b/lib/spack/spack/compilers/msvc.py @@ -3,7 +3,11 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os +import subprocess +import sys from typing import List # novm + from spack.compiler import Compiler @@ -26,6 +30,22 @@ class Msvc(Compiler): 'f77': '', 'fc': ''} + #: Compiler argument that produces version information + version_argument = '' + + #: Regex used to extract version from compiler's output + version_regex = r'([1-9][0-9]*\.[0-9]*\.[0-9]*)' + + # Initialize, deferring to base class but then adding the vcvarsallfile + # file based on compiler executable path. + + def __init__(self, *args, **kwargs): + super(Msvc, self).__init__(*args, **kwargs) + self.vcvarsallfile = os.path.abspath( + os.path.join(self.cc, '../../../../../../..')) + self.vcvarsallfile = os.path.join( + self.vcvarsallfile, 'Auxiliary', 'Build', 'vcvarsall.bat') + @property def verbose_flag(self): return "" @@ -33,3 +53,30 @@ class Msvc(Compiler): @property def pic_flag(self): return "" + + def setup_custom_environment(self, pkg, env): + """Set environment variables for MSVC using the Microsoft-provided + script.""" + if sys.version_info[:2] > (2, 6): + # Capture output from batch script and DOS environment dump + out = subprocess.check_output( # novermin + 'cmd /u /c "{0}" {1} && set'.format(self.vcvarsallfile, 'amd64'), + stderr=subprocess.STDOUT) + if sys.version_info[0] >= 3: + out = out.decode('utf-16le', errors='replace') + else: + print("Cannot pull msvc compiler information in Python 2.6 or below") + + # Process in to nice Python dictionary + vc_env = { # novermin + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + + # Request setting environment variables + if 'path' in vc_env: + env.set_path('PATH', vc_env['path'].split(';')) + env.set_path('INCLUDE', vc_env.get('include', '').split(';')) + env.set_path('LIB', vc_env.get('lib', '').split(';')) diff --git a/lib/spack/spack/operating_systems/windows_os.py b/lib/spack/spack/operating_systems/windows_os.py index c4f8fa7f84..a9132c7bce 100755 --- a/lib/spack/spack/operating_systems/windows_os.py +++ b/lib/spack/spack/operating_systems/windows_os.py @@ -3,6 +3,10 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import sys +import os +import subprocess +import glob from spack.architecture import OperatingSystem from spack.version import Version @@ -22,6 +26,35 @@ class WindowsOs(OperatingSystem): using the major version operating system number, e.g. 10. """ + # Find MSVC directories using vswhere + compSearchPaths = [] + root = os.environ.get('ProgramFiles(x86)') or os.environ.get('ProgramFiles') + if root: + try: + extra_args = {} + if sys.version_info[:3] >= (3, 6, 0): + extra_args = {'encoding': 'mbcs', 'errors': 'strict'} + paths = subprocess.check_output([ + os.path.join(root, "Microsoft Visual Studio", "Installer", + "vswhere.exe"), + "-prerelease", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath", + "-products", "*", + ], **extra_args).strip() + if (3, 0) <= sys.version_info[:2] <= (3, 5): + paths = paths.decode() + msvcPaths = paths.split('\n') + msvcPaths = [os.path.join(path, "VC", "Tools", "MSVC") + for path in msvcPaths] + for p in msvcPaths: + compSearchPaths.extend( + glob.glob(os.path.join(p, '*', 'bin', 'Hostx64', 'x64'))) + except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): + pass + if compSearchPaths: + compiler_search_paths = compSearchPaths + def __init__(self): super(WindowsOs, self).__init__('Windows10', '10') -- cgit v1.2.3-70-g09d2