3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Determine if and/or when an error/warning should be issued when there
26 are no versions of msvc installed. If there is at least one version of
27 msvc installed, these routines do (almost) nothing.
30 * When msvc is the default compiler because there are no compilers
31 installed, a build may fail due to the cl.exe command not being
32 recognized. Currently, there is no easy way to detect during
33 msvc initialization if the default environment will be used later
34 to build a program and/or library. There is no error/warning
35 as there are legitimate SCons uses that do not require a c compiler.
36 * An error is indicated by returning a non-empty tool list from the
37 function register_iserror.
42 from .. common
import (
46 from . import Dispatcher
47 Dispatcher
.register_modulename(__name__
)
57 def reset(cls
) -> None:
58 debug('msvc default:init')
59 cls
.n_setup
= 0 # number of calls to msvc_setup_env_once
60 cls
.default_ismsvc
= False # is msvc the default compiler
61 cls
.default_tools_re_list
= [] # list of default tools regular expressions
62 cls
.msvc_tools_init
= set() # tools registered via msvc_exists
63 cls
.msvc_tools
= None # tools registered via msvc_setup_env_once
64 cls
.msvc_installed
= False # is msvc installed (vcs_installed > 0)
65 cls
.msvc_nodefault
= False # is there a default version of msvc
66 cls
.need_init
= True # reset initialization indicator
68 def _initialize(env
, msvc_exists_func
) -> None:
71 _Data
.need_init
= False
72 _Data
.msvc_installed
= msvc_exists_func(env
)
73 debug('msvc default:msvc_installed=%s', _Data
.msvc_installed
)
75 def register_tool(env
, tool
, msvc_exists_func
):
77 _initialize(env
, msvc_exists_func
)
78 if _Data
.msvc_installed
:
82 if _Data
.n_setup
== 0:
83 if tool
not in _Data
.msvc_tools_init
:
84 _Data
.msvc_tools_init
.add(tool
)
85 debug('msvc default:tool=%s, msvc_tools_init=%s', tool
, _Data
.msvc_tools_init
)
87 if tool
not in _Data
.msvc_tools
:
88 _Data
.msvc_tools
.add(tool
)
89 debug('msvc default:tool=%s, msvc_tools=%s', tool
, _Data
.msvc_tools
)
91 def register_setup(env
, msvc_exists_func
) -> None:
93 _initialize(env
, msvc_exists_func
)
95 if not _Data
.msvc_installed
:
96 _Data
.msvc_tools
= set(_Data
.msvc_tools_init
)
97 if _Data
.n_setup
== 1:
98 tool_list
= env
.get('TOOLS', None)
99 if tool_list
and tool_list
[0] == 'default':
100 if len(tool_list
) > 1 and tool_list
[1] in _Data
.msvc_tools
:
101 # msvc tools are the default compiler
102 _Data
.default_ismsvc
= True
103 _Data
.msvc_nodefault
= False
105 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
106 _Data
.n_setup
, _Data
.msvc_installed
, _Data
.default_ismsvc
109 def set_nodefault() -> None:
110 # default msvc version, msvc not installed
111 _Data
.msvc_nodefault
= True
112 debug('msvc default:msvc_nodefault=%s', _Data
.msvc_nodefault
)
114 def register_iserror(env
, tool
, msvc_exists_func
):
116 register_tool(env
, tool
, msvc_exists_func
)
118 if _Data
.msvc_installed
:
122 if not _Data
.msvc_nodefault
:
123 # msvc version specified
126 tool_list
= env
.get('TOOLS', None)
132 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
133 _Data
.n_setup
, _Data
.default_ismsvc
, _Data
.msvc_tools
, tool_list
136 if not _Data
.default_ismsvc
:
139 # * msvc is not installed
140 # * msvc version not specified (default)
141 # * msvc is not the default compiler
143 # construct tools set
144 tools_set
= set(tool_list
)
148 if _Data
.n_setup
== 1:
149 # first setup and msvc is default compiler:
150 # build default tools regex for current tool state
151 tools
= _Data
.separator
.join(tool_list
)
152 tools_nchar
= len(tools
)
153 debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar
, tools
)
154 re_default_tools
= re
.compile(re
.escape(tools
))
155 _Data
.default_tools_re_list
.insert(0, (tools_nchar
, re_default_tools
))
156 # early exit: no error for default environment when msvc is not installed
160 # * msvc is not installed
161 # * msvc version not specified (default)
162 # * environment tools list is not empty
163 # * default tools regex list constructed
164 # * msvc tools set constructed
166 # Algorithm using tools string and sets:
167 # * convert environment tools list to a string
168 # * iteratively remove default tools sequences via regex
169 # substition list built from longest sequence (first)
170 # to shortest sequence (last)
171 # * build environment tools set with remaining tools
172 # * compute intersection of environment tools and msvc tools sets
173 # * if the intersection is:
174 # empty - no error: default tools and/or no additional msvc tools
175 # not empty - error: user specified one or more msvc tool(s)
177 # This will not produce an error or warning when there are no
178 # msvc installed instances nor any other recognized compilers
179 # and the default environment is needed for a build. The msvc
180 # compiler is forcibly added to the environment tools list when
181 # there are no compilers installed on win32. In this case, cl.exe
182 # will not be found on the path resulting in a failed build.
184 # construct tools string
185 tools
= _Data
.separator
.join(tool_list
)
186 tools_nchar
= len(tools
)
188 debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar
, tools
)
190 # iteratively remove default tool sequences (longest to shortest)
191 if not _Data
.default_tools_re_list
:
192 debug('default_tools_re_list=%s', _Data
.default_tools_re_list
)
194 re_nchar_min
, re_tools_min
= _Data
.default_tools_re_list
[-1]
195 if tools_nchar
>= re_nchar_min
and re_tools_min
.search(tools
):
196 # minimum characters satisfied and minimum pattern exists
197 for re_nchar
, re_default_tool
in _Data
.default_tools_re_list
:
198 if tools_nchar
< re_nchar
:
199 # not enough characters for pattern
201 tools
= re_default_tool
.sub('', tools
).strip(_Data
.separator
)
202 tools_nchar
= len(tools
)
203 debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar
, tools
)
204 if tools_nchar
< re_nchar_min
or not re_tools_min
.search(tools
):
205 # less than minimum characters or minimum pattern does not exist
208 # construct non-default list(s) tools set
209 tools_set
= {msvc_tool
for msvc_tool
in tools
.split(_Data
.separator
) if msvc_tool
}
211 debug('msvc default:tools=%s', tools_set
)
215 # compute intersection of remaining tools set and msvc tools set
216 tools_found
= _Data
.msvc_tools
.intersection(tools_set
)
217 debug('msvc default:tools_exist=%s', tools_found
)
221 # construct in same order as tools list
222 tools_found_list
= []
224 for tool
in tool_list
:
225 if tool
not in seen_tool
:
227 if tool
in tools_found
:
228 tools_found_list
.append(tool
)
230 # return tool list in order presented
231 return tools_found_list