4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 # * supported arch for versions: for old versions of batch file without
26 # argument, giving bogus argument cannot be detected, so we have to hardcode
28 # * print warning when msvc version specified but not found
29 # * find out why warning do not print
30 # * test on 64 bits XP + VS 2005 (and VS 6 if possible)
33 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
35 __doc__ = """Module for Visual C/C++ detection and configuration.
47 class VisualCException(Exception):
50 class UnsupportedVersion(VisualCException):
53 class MissingConfiguration(VisualCException):
56 class NoVersionFound(VisualCException):
59 class BatchFileExecutionError(VisualCException):
62 # Dict to 'canonalize' the arch
63 _ARCH_TO_CANONICAL = {
73 # Given a (host, target) tuple, return the argument for the bat file. Both host
74 # and targets should be canonalized.
75 _HOST_TARGET_ARCH_TO_BAT_ARCH = {
76 ("x86", "x86"): "x86",
77 ("x86", "amd64"): "x86_amd64",
78 ("amd64", "amd64"): "amd64",
79 ("amd64", "x86"): "x86",
80 ("x86", "ia64"): "x86_ia64"
83 def get_host_target(env):
84 host_platform = env.get('HOST_ARCH')
86 host_platform = platform.machine()
87 target_platform = env.get('TARGET_ARCH')
88 if not target_platform:
89 target_platform = host_platform
92 host = _ARCH_TO_CANONICAL[host_platform]
94 raise ValueError("Unrecognized host architecture %s" % host_platform)
97 target = _ARCH_TO_CANONICAL[target_platform]
99 raise ValueError("Unrecognized target architecture %s" % target_platform)
101 return (host, target)
103 _VCVER = ["10.0", "9.0", "8.0", "7.1", "7.0", "6.0"]
105 _VCVER_TO_PRODUCT_DIR = {
107 r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
109 r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',
110 r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
112 r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir',
113 r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
115 r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
117 r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
119 r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
122 def find_vc_pdir(msvc_version):
123 """Try to find the product directory for the given
128 If for some reason the requested version could not be found, an
129 exception which inherits from VisualCException will be raised."""
131 if common.is_win64():
132 root = root + 'Wow6432Node\\'
134 hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
136 debug("Unknown version of MSVC: %s" % msvc_version)
137 raise UnsupportedVersion("Unknown version %s" % msvc_version)
142 comps = common.read_reg(key)
143 except WindowsError, e:
144 debug('find_vc_dir(): no VC registry key %s' % repr(key))
146 debug('find_vc_dir(): found VC in registry: %s' % comps)
147 if os.path.exists(comps):
150 debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
152 raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
155 def find_batch_file(msvc_version):
156 pdir = find_vc_pdir(msvc_version)
158 raise NoVersionFound("No version of Visual Studio found")
160 vernum = float(msvc_version)
162 pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
163 batfilename = os.path.join(pdir, "vsvars32.bat")
165 pdir = os.path.join(pdir, "Bin")
166 batfilename = os.path.join(pdir, "vcvars32.bat")
168 batfilename = os.path.join(pdir, "vcvarsall.bat")
170 if os.path.exists(batfilename):
173 debug("Not found: %s" % batfilename)
177 def get_installed_vcs():
178 installed_versions = []
180 debug('trying to find VC %s' % ver)
182 if find_vc_pdir(ver):
183 debug('found VC %s' % ver)
184 installed_versions.append(ver)
186 debug('find_vc_pdir return None for ver %s' % ver)
187 except VisualCException, e:
188 debug('did not find VC %s: caught exception %s' % (ver, str(e)))
189 return installed_versions
191 def script_env(script, args=None):
192 stdout = common.get_output(script, args)
193 # Stupid batch files do not set return code: we take a look at the
194 # beginning of the output for an error message instead
195 olines = stdout.splitlines()
196 if olines[0].startswith("The specified configuration type is missing"):
197 raise BatchFileExecutionError("\n".join(olines[:2]))
199 return common.parse_output(stdout)
201 def get_default_version(env):
202 debug('get_default_version()')
204 msvc_version = env.get('MSVC_VERSION')
205 msvs_version = env.get('MSVS_VERSION')
207 if msvs_version and not msvc_version:
209 SCons.Warnings.DeprecatedWarning,
210 "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
212 elif msvc_version and msvs_version:
213 if not msvc_version == msvs_version:
215 SCons.Warnings.VisualVersionMismatch,
216 "Requested msvc version (%s) and msvs version (%s) do " \
217 "not match: please use MSVC_VERSION only to request a " \
218 "visual studio version, MSVS_VERSION is deprecated" \
219 % (msvc_version, msvs_version))
222 installed_vcs = get_installed_vcs()
223 debug('installed_vcs:%s' % installed_vcs)
224 if not installed_vcs:
225 msg = 'No installed VCs'
226 debug('msv %s\n' % repr(msg))
227 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
229 msvc_version = installed_vcs[0]
230 debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
234 def msvc_setup_env_once(env):
236 has_run = env["MSVC_SETUP_RUN"]
242 env["MSVC_SETUP_RUN"] = True
244 def msvc_setup_env(env):
245 debug('msvc_setup_env()')
247 version = get_default_version(env)
249 warn_msg = "No version of Visual Studio compiler found - C/C++ " \
250 "compilers most likely not set correctly"
251 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
254 host_platform, target_platform = get_host_target(env)
255 debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
257 # XXX: we set-up both MSVS version for backward
258 # compatibility with the msvs tool
259 env['MSVC_VERSION'] = version
260 env['MSVS_VERSION'] = version
264 script = find_batch_file(version)
265 except VisualCException, e:
267 debug('Caught exception while looking for batch file (%s)' % msg)
268 warn_msg = "VC version %s not installed - C/C++ compilers most " \
269 "likely not set correctly" % version
270 warn_msg += " \n Install versions are: %s" % get_installed_vcs()
271 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
274 use_script = env.get('MSVC_USE_SCRIPT', True)
275 if SCons.Util.is_String(use_script):
276 debug('use_script 1 %s\n' % repr(use_script))
277 d = script_env(use_script)
279 host_target = (host_platform, target_platform)
280 arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
281 debug('use_script 2 %s, args:%s\n' % (repr(script), arg))
283 d = script_env(script, args=arg)
284 except BatchFileExecutionError, e:
285 msg = "MSVC error while executing %s with args %s (error was %s)" % \
286 (script, arg, str(e))
287 raise SCons.Errors.UserError(msg)
289 debug('MSVC_USE_SCRIPT set to False')
290 warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
292 SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
295 for k, v in d.items():
296 env.PrependENVPath(k, v, delete_existing=True)
298 def msvc_exists(version=None):
299 vcs = get_installed_vcs()
302 return version in vcs