summaryrefslogtreecommitdiff
path: root/lib/spack/spack/compilers/msvc.py
blob: d0ae6921eaa295bf31026fcc7f903ad07f07cc06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import os
import subprocess
import sys
from typing import List  # novm

import spack.operating_systems.windows_os
import spack.util.executable
from spack.compiler import Compiler


class Msvc(Compiler):
    # Subclasses use possible names of C compiler
    cc_names = ['cl.exe']

    # Subclasses use possible names of C++ compiler
    cxx_names = ['cl.exe']

    # Subclasses use possible names of Fortran 77 compiler
    f77_names = ['ifx.exe']  # type: List[str]

    # Subclasses use possible names of Fortran 90 compiler
    fc_names = ['ifx.exe']  # type: List[str]

    # Named wrapper links within build_env_path
    link_paths = {'cc': '',
                  'cxx': '',
                  'f77': '',
                  'fc': ''}

    #: Compiler argument that produces version information
    version_argument = ''

    # For getting ifx's version, call it with version_argument
    # and ignore the error code
    ignore_version_errors = [1]

    #: 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)
        if os.getenv("ONEAPI_ROOT"):
            # If this found, it sets all the vars
            self.setvarsfile = os.path.join(
                os.getenv("ONEAPI_ROOT"), "setvars.bat")
        else:
            self.setvarsfile = os.path.abspath(
                os.path.join(self.cc, '../../../../../../..'))
            self.setvarsfile = os.path.join(
                self.setvarsfile, 'Auxiliary', 'Build', 'vcvars64.bat')

    @property
    def verbose_flag(self):
        return ""

    @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):
            # Set the build environment variables for spack. Just using
            # subprocess.call() doesn't work since that operates in its own
            # environment which is destroyed (along with the adjusted variables)
            # once the process terminates. So go the long way around: examine
            # output, sort into dictionary, use that to make the build
            # environment.
            out = subprocess.check_output(  # novermin
                'cmd /u /c "{}" {} && set'.format(self.setvarsfile, 'amd64'),
                stderr=subprocess.STDOUT)
            if sys.version_info[0] >= 3:
                out = out.decode('utf-16le', errors='replace')  # novermin

            int_env = {  # novermin
                key.lower(): value
                for key, _, value in
                (line.partition('=') for line in out.splitlines())
                if key and value
            }

            if 'path' in int_env:
                env.set_path('PATH', int_env['path'].split(';'))
            env.set_path('INCLUDE', int_env.get('include', '').split(';'))
            env.set_path('LIB', int_env.get('lib', '').split(';'))
        else:
            # Should not this be an exception?
            print("Cannot pull msvc compiler information in Python 2.6 or below")

    # fc_version only loads the ifx compiler into the first MSVC stanza;
    # if there are other versions of Microsoft VS installed and detected, they
    # will only have cl.exe as the C/C++ 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 os.getenv("ONEAPI_ROOT"):
            try:
                sps = spack.operating_systems.windows_os.WindowsOs.compiler_search_paths
            except Exception:
                print("sps not found.")
                raise
            try:
                clp = spack.util.executable.which_string("cl", path=sps)
            except Exception:
                print("cl not found.")
                raise
            ver = cls.default_version(clp)
            return ver
        else:
            return cls.default_version(fc)

    @classmethod
    def f77_version(cls, f77):
        return cls.fc_version(f77)