You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
21 KiB

6 years ago
  1. #
  2. # Copyright (c) 2001 - 2017 The SCons Foundation
  3. #
  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:
  11. #
  12. # The above copyright notice and this permission notice shall be included
  13. # in all copies or substantial portions of the Software.
  14. #
  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.
  22. #
  23. __revision__ = "src/engine/SCons/Tool/MSCommon/vs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
  24. __doc__ = """Module to detect Visual Studio and/or Visual C/C++
  25. """
  26. import os
  27. import SCons.Errors
  28. import SCons.Util
  29. from .common import debug, \
  30. get_output, \
  31. is_win64, \
  32. normalize_env, \
  33. parse_output, \
  34. read_reg
  35. import SCons.Tool.MSCommon.vc
  36. class VisualStudio(object):
  37. """
  38. An abstract base class for trying to find installed versions of
  39. Visual Studio.
  40. """
  41. def __init__(self, version, **kw):
  42. self.version = version
  43. kw['vc_version'] = kw.get('vc_version', version)
  44. kw['sdk_version'] = kw.get('sdk_version', version)
  45. self.__dict__.update(kw)
  46. self._cache = {}
  47. def find_batch_file(self):
  48. vs_dir = self.get_vs_dir()
  49. if not vs_dir:
  50. debug('find_executable(): no vs_dir')
  51. return None
  52. batch_file = os.path.join(vs_dir, self.batch_file_path)
  53. batch_file = os.path.normpath(batch_file)
  54. if not os.path.isfile(batch_file):
  55. debug('find_batch_file(): %s not on file system' % batch_file)
  56. return None
  57. return batch_file
  58. def find_vs_dir_by_vc(self):
  59. SCons.Tool.MSCommon.vc.get_installed_vcs()
  60. dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version)
  61. if not dir:
  62. debug('find_vs_dir(): no installed VC %s' % self.vc_version)
  63. return None
  64. return dir
  65. def find_vs_dir_by_reg(self):
  66. root = 'Software\\'
  67. if is_win64():
  68. root = root + 'Wow6432Node\\'
  69. for key in self.hkeys:
  70. if key=='use_dir':
  71. return self.find_vs_dir_by_vc()
  72. key = root + key
  73. try:
  74. comps = read_reg(key)
  75. except SCons.Util.WinError as e:
  76. debug('find_vs_dir_by_reg(): no VS registry key {}'.format(repr(key)))
  77. else:
  78. debug('find_vs_dir_by_reg(): found VS in registry: {}'.format(comps))
  79. return comps
  80. return None
  81. def find_vs_dir(self):
  82. """ Can use registry or location of VC to find vs dir
  83. First try to find by registry, and if that fails find via VC dir
  84. """
  85. if True:
  86. vs_dir=self.find_vs_dir_by_reg()
  87. return vs_dir
  88. else:
  89. return self.find_vs_dir_by_vc()
  90. def find_executable(self):
  91. vs_dir = self.get_vs_dir()
  92. if not vs_dir:
  93. debug('find_executable(): no vs_dir ({})'.format(vs_dir))
  94. return None
  95. executable = os.path.join(vs_dir, self.executable_path)
  96. executable = os.path.normpath(executable)
  97. if not os.path.isfile(executable):
  98. debug('find_executable(): {} not on file system'.format(executable))
  99. return None
  100. return executable
  101. def get_batch_file(self):
  102. try:
  103. return self._cache['batch_file']
  104. except KeyError:
  105. batch_file = self.find_batch_file()
  106. self._cache['batch_file'] = batch_file
  107. return batch_file
  108. def get_executable(self):
  109. try:
  110. debug('get_executable using cache:%s'%self._cache['executable'])
  111. return self._cache['executable']
  112. except KeyError:
  113. executable = self.find_executable()
  114. self._cache['executable'] = executable
  115. debug('get_executable not in cache:%s'%executable)
  116. return executable
  117. def get_vs_dir(self):
  118. try:
  119. return self._cache['vs_dir']
  120. except KeyError:
  121. vs_dir = self.find_vs_dir()
  122. self._cache['vs_dir'] = vs_dir
  123. return vs_dir
  124. def get_supported_arch(self):
  125. try:
  126. return self._cache['supported_arch']
  127. except KeyError:
  128. # RDEVE: for the time being use hardcoded lists
  129. # supported_arch = self.find_supported_arch()
  130. self._cache['supported_arch'] = self.supported_arch
  131. return self.supported_arch
  132. def reset(self):
  133. self._cache = {}
  134. # The list of supported Visual Studio versions we know how to detect.
  135. #
  136. # How to look for .bat file ?
  137. # - VS 2008 Express (x86):
  138. # * from registry key productdir, gives the full path to vsvarsall.bat. In
  139. # HKEY_LOCAL_MACHINE):
  140. # Software\Microsoft\VCEpress\9.0\Setup\VC\productdir
  141. # * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC
  142. # relatively to the path given by the variable.
  143. #
  144. # - VS 2008 Express (WoW6432: 32 bits on windows x64):
  145. # Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir
  146. #
  147. # - VS 2005 Express (x86):
  148. # * from registry key productdir, gives the full path to vsvarsall.bat. In
  149. # HKEY_LOCAL_MACHINE):
  150. # Software\Microsoft\VCEpress\8.0\Setup\VC\productdir
  151. # * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC
  152. # relatively to the path given by the variable.
  153. #
  154. # - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a
  155. # productdir ?
  156. #
  157. # - VS 2003 .Net (pro edition ? x86):
  158. # * from registry key productdir. The path is then ..\Common7\Tools\
  159. # relatively to the key. The key is in HKEY_LOCAL_MACHINE):
  160. # Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir
  161. # * from environmnent variable VS71COMNTOOLS: the path is the full path to
  162. # vsvars32.bat
  163. #
  164. # - VS 98 (VS 6):
  165. # * from registry key productdir. The path is then Bin
  166. # relatively to the key. The key is in HKEY_LOCAL_MACHINE):
  167. # Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir
  168. #
  169. # The first version found in the list is the one used by default if
  170. # there are multiple versions installed. Barring good reasons to
  171. # the contrary, this means we should list versions from most recent
  172. # to oldest. Pro versions get listed before Express versions on the
  173. # assumption that, by default, you'd rather use the version you paid
  174. # good money for in preference to whatever Microsoft makes available
  175. # for free.
  176. #
  177. # If you update this list, update _VCVER and _VCVER_TO_PRODUCT_DIR in
  178. # Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
  179. SupportedVSList = [
  180. # Visual Studio 2017
  181. VisualStudio('14.1',
  182. vc_version='14.1',
  183. sdk_version='10.0A',
  184. hkeys=[],
  185. common_tools_var='VS150COMNTOOLS',
  186. executable_path=r'Common7\IDE\devenv.com',
  187. batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat',
  188. supported_arch=['x86', 'amd64', "arm"],
  189. ),
  190. # Visual Studio 2015
  191. VisualStudio('14.0',
  192. vc_version='14.0',
  193. sdk_version='10.0',
  194. hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
  195. common_tools_var='VS140COMNTOOLS',
  196. executable_path=r'Common7\IDE\devenv.com',
  197. batch_file_path=r'Common7\Tools\vsvars32.bat',
  198. supported_arch=['x86', 'amd64', "arm"],
  199. ),
  200. # Visual C++ 2015 Express Edition (for Desktop)
  201. VisualStudio('14.0Exp',
  202. vc_version='14.0',
  203. sdk_version='10.0A',
  204. hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
  205. common_tools_var='VS140COMNTOOLS',
  206. executable_path=r'Common7\IDE\WDExpress.exe',
  207. batch_file_path=r'Common7\Tools\vsvars32.bat',
  208. supported_arch=['x86', 'amd64', "arm"],
  209. ),
  210. # Visual Studio 2013
  211. VisualStudio('12.0',
  212. vc_version='12.0',
  213. sdk_version='8.1A',
  214. hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
  215. common_tools_var='VS120COMNTOOLS',
  216. executable_path=r'Common7\IDE\devenv.com',
  217. batch_file_path=r'Common7\Tools\vsvars32.bat',
  218. supported_arch=['x86', 'amd64'],
  219. ),
  220. # Visual C++ 2013 Express Edition (for Desktop)
  221. VisualStudio('12.0Exp',
  222. vc_version='12.0',
  223. sdk_version='8.1A',
  224. hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
  225. common_tools_var='VS120COMNTOOLS',
  226. executable_path=r'Common7\IDE\WDExpress.exe',
  227. batch_file_path=r'Common7\Tools\vsvars32.bat',
  228. supported_arch=['x86', 'amd64'],
  229. ),
  230. # Visual Studio 2012
  231. VisualStudio('11.0',
  232. sdk_version='8.0A',
  233. hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
  234. common_tools_var='VS110COMNTOOLS',
  235. executable_path=r'Common7\IDE\devenv.com',
  236. batch_file_path=r'Common7\Tools\vsvars32.bat',
  237. supported_arch=['x86', 'amd64'],
  238. ),
  239. # Visual C++ 2012 Express Edition (for Desktop)
  240. VisualStudio('11.0Exp',
  241. vc_version='11.0',
  242. sdk_version='8.0A',
  243. hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
  244. common_tools_var='VS110COMNTOOLS',
  245. executable_path=r'Common7\IDE\WDExpress.exe',
  246. batch_file_path=r'Common7\Tools\vsvars32.bat',
  247. supported_arch=['x86', 'amd64'],
  248. ),
  249. # Visual Studio 2010
  250. VisualStudio('10.0',
  251. sdk_version='7.0A',
  252. hkeys=[r'Microsoft\VisualStudio\10.0\Setup\VS\ProductDir'],
  253. common_tools_var='VS100COMNTOOLS',
  254. executable_path=r'Common7\IDE\devenv.com',
  255. batch_file_path=r'Common7\Tools\vsvars32.bat',
  256. supported_arch=['x86', 'amd64'],
  257. ),
  258. # Visual C++ 2010 Express Edition
  259. VisualStudio('10.0Exp',
  260. vc_version='10.0',
  261. sdk_version='7.0A',
  262. hkeys=[r'Microsoft\VCExpress\10.0\Setup\VS\ProductDir'],
  263. common_tools_var='VS100COMNTOOLS',
  264. executable_path=r'Common7\IDE\VCExpress.exe',
  265. batch_file_path=r'Common7\Tools\vsvars32.bat',
  266. supported_arch=['x86'],
  267. ),
  268. # Visual Studio 2008
  269. VisualStudio('9.0',
  270. sdk_version='6.0A',
  271. hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'],
  272. common_tools_var='VS90COMNTOOLS',
  273. executable_path=r'Common7\IDE\devenv.com',
  274. batch_file_path=r'Common7\Tools\vsvars32.bat',
  275. supported_arch=['x86', 'amd64'],
  276. ),
  277. # Visual C++ 2008 Express Edition
  278. VisualStudio('9.0Exp',
  279. vc_version='9.0',
  280. sdk_version='6.0A',
  281. hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'],
  282. common_tools_var='VS90COMNTOOLS',
  283. executable_path=r'Common7\IDE\VCExpress.exe',
  284. batch_file_path=r'Common7\Tools\vsvars32.bat',
  285. supported_arch=['x86'],
  286. ),
  287. # Visual Studio 2005
  288. VisualStudio('8.0',
  289. sdk_version='6.0A',
  290. hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'],
  291. common_tools_var='VS80COMNTOOLS',
  292. executable_path=r'Common7\IDE\devenv.com',
  293. batch_file_path=r'Common7\Tools\vsvars32.bat',
  294. default_dirname='Microsoft Visual Studio 8',
  295. supported_arch=['x86', 'amd64'],
  296. ),
  297. # Visual C++ 2005 Express Edition
  298. VisualStudio('8.0Exp',
  299. vc_version='8.0Exp',
  300. sdk_version='6.0A',
  301. hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'],
  302. common_tools_var='VS80COMNTOOLS',
  303. executable_path=r'Common7\IDE\VCExpress.exe',
  304. batch_file_path=r'Common7\Tools\vsvars32.bat',
  305. default_dirname='Microsoft Visual Studio 8',
  306. supported_arch=['x86'],
  307. ),
  308. # Visual Studio .NET 2003
  309. VisualStudio('7.1',
  310. sdk_version='6.0',
  311. hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'],
  312. common_tools_var='VS71COMNTOOLS',
  313. executable_path=r'Common7\IDE\devenv.com',
  314. batch_file_path=r'Common7\Tools\vsvars32.bat',
  315. default_dirname='Microsoft Visual Studio .NET 2003',
  316. supported_arch=['x86'],
  317. ),
  318. # Visual Studio .NET
  319. VisualStudio('7.0',
  320. sdk_version='2003R2',
  321. hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
  322. common_tools_var='VS70COMNTOOLS',
  323. executable_path=r'IDE\devenv.com',
  324. batch_file_path=r'Common7\Tools\vsvars32.bat',
  325. default_dirname='Microsoft Visual Studio .NET',
  326. supported_arch=['x86'],
  327. ),
  328. # Visual Studio 6.0
  329. VisualStudio('6.0',
  330. sdk_version='2003R1',
  331. hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir',
  332. 'use_dir'],
  333. common_tools_var='VS60COMNTOOLS',
  334. executable_path=r'Common\MSDev98\Bin\MSDEV.COM',
  335. batch_file_path=r'Common7\Tools\vsvars32.bat',
  336. default_dirname='Microsoft Visual Studio',
  337. supported_arch=['x86'],
  338. ),
  339. ]
  340. SupportedVSMap = {}
  341. for vs in SupportedVSList:
  342. SupportedVSMap[vs.version] = vs
  343. # Finding installed versions of Visual Studio isn't cheap, because it
  344. # goes not only to the registry but also to the disk to sanity-check
  345. # that there is, in fact, a Visual Studio directory there and that the
  346. # registry entry isn't just stale. Find this information once, when
  347. # requested, and cache it.
  348. InstalledVSList = None
  349. InstalledVSMap = None
  350. def get_installed_visual_studios():
  351. global InstalledVSList
  352. global InstalledVSMap
  353. if InstalledVSList is None:
  354. InstalledVSList = []
  355. InstalledVSMap = {}
  356. for vs in SupportedVSList:
  357. debug('trying to find VS %s' % vs.version)
  358. if vs.get_executable():
  359. debug('found VS %s' % vs.version)
  360. InstalledVSList.append(vs)
  361. InstalledVSMap[vs.version] = vs
  362. return InstalledVSList
  363. def reset_installed_visual_studios():
  364. global InstalledVSList
  365. global InstalledVSMap
  366. InstalledVSList = None
  367. InstalledVSMap = None
  368. for vs in SupportedVSList:
  369. vs.reset()
  370. # Need to clear installed VC's as well as they are used in finding
  371. # installed VS's
  372. SCons.Tool.MSCommon.vc.reset_installed_vcs()
  373. # We may be asked to update multiple construction environments with
  374. # SDK information. When doing this, we check on-disk for whether
  375. # the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
  376. # is expensive, cache results by directory.
  377. #SDKEnvironmentUpdates = {}
  378. #
  379. #def set_sdk_by_directory(env, sdk_dir):
  380. # global SDKEnvironmentUpdates
  381. # try:
  382. # env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
  383. # except KeyError:
  384. # env_tuple_list = []
  385. # SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
  386. #
  387. # include_path = os.path.join(sdk_dir, 'include')
  388. # mfc_path = os.path.join(include_path, 'mfc')
  389. # atl_path = os.path.join(include_path, 'atl')
  390. #
  391. # if os.path.exists(mfc_path):
  392. # env_tuple_list.append(('INCLUDE', mfc_path))
  393. # if os.path.exists(atl_path):
  394. # env_tuple_list.append(('INCLUDE', atl_path))
  395. # env_tuple_list.append(('INCLUDE', include_path))
  396. #
  397. # env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
  398. # env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
  399. # env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
  400. #
  401. # for variable, directory in env_tuple_list:
  402. # env.PrependENVPath(variable, directory)
  403. def msvs_exists():
  404. return (len(get_installed_visual_studios()) > 0)
  405. def get_vs_by_version(msvs):
  406. global InstalledVSMap
  407. global SupportedVSMap
  408. debug('vs.py:get_vs_by_version()')
  409. if msvs not in SupportedVSMap:
  410. msg = "Visual Studio version %s is not supported" % repr(msvs)
  411. raise SCons.Errors.UserError(msg)
  412. get_installed_visual_studios()
  413. vs = InstalledVSMap.get(msvs)
  414. debug('InstalledVSMap:%s'%InstalledVSMap)
  415. debug('vs.py:get_vs_by_version: found vs:%s'%vs)
  416. # Some check like this would let us provide a useful error message
  417. # if they try to set a Visual Studio version that's not installed.
  418. # However, we also want to be able to run tests (like the unit
  419. # tests) on systems that don't, or won't ever, have it installed.
  420. # It might be worth resurrecting this, with some configurable
  421. # setting that the tests can use to bypass the check.
  422. #if not vs:
  423. # msg = "Visual Studio version %s is not installed" % repr(msvs)
  424. # raise SCons.Errors.UserError, msg
  425. return vs
  426. def get_default_version(env):
  427. """Returns the default version string to use for MSVS.
  428. If no version was requested by the user through the MSVS environment
  429. variable, query all the available visual studios through
  430. get_installed_visual_studios, and take the highest one.
  431. Return
  432. ------
  433. version: str
  434. the default version.
  435. """
  436. if 'MSVS' not in env or not SCons.Util.is_Dict(env['MSVS']):
  437. # get all versions, and remember them for speed later
  438. versions = [vs.version for vs in get_installed_visual_studios()]
  439. env['MSVS'] = {'VERSIONS' : versions}
  440. else:
  441. versions = env['MSVS'].get('VERSIONS', [])
  442. if 'MSVS_VERSION' not in env:
  443. if versions:
  444. env['MSVS_VERSION'] = versions[0] #use highest version by default
  445. else:
  446. debug('get_default_version: WARNING: no installed versions found, '
  447. 'using first in SupportedVSList (%s)'%SupportedVSList[0].version)
  448. env['MSVS_VERSION'] = SupportedVSList[0].version
  449. env['MSVS']['VERSION'] = env['MSVS_VERSION']
  450. return env['MSVS_VERSION']
  451. def get_default_arch(env):
  452. """Return the default arch to use for MSVS
  453. if no version was requested by the user through the MSVS_ARCH environment
  454. variable, select x86
  455. Return
  456. ------
  457. arch: str
  458. """
  459. arch = env.get('MSVS_ARCH', 'x86')
  460. msvs = InstalledVSMap.get(env['MSVS_VERSION'])
  461. if not msvs:
  462. arch = 'x86'
  463. elif not arch in msvs.get_supported_arch():
  464. fmt = "Visual Studio version %s does not support architecture %s"
  465. raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
  466. return arch
  467. def merge_default_version(env):
  468. version = get_default_version(env)
  469. arch = get_default_arch(env)
  470. def msvs_setup_env(env):
  471. batfilename = msvs.get_batch_file()
  472. msvs = get_vs_by_version(version)
  473. if msvs is None:
  474. return
  475. # XXX: I think this is broken. This will silently set a bogus tool instead
  476. # of failing, but there is no other way with the current scons tool
  477. # framework
  478. if batfilename is not None:
  479. vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE')
  480. msvs_list = get_installed_visual_studios()
  481. vscommonvarnames = [vs.common_tools_var for vs in msvs_list]
  482. save_ENV = env['ENV']
  483. nenv = normalize_env(env['ENV'],
  484. ['COMSPEC'] + vscommonvarnames,
  485. force=True)
  486. try:
  487. output = get_output(batfilename, arch, env=nenv)
  488. finally:
  489. env['ENV'] = save_ENV
  490. vars = parse_output(output, vars)
  491. for k, v in vars.items():
  492. env.PrependENVPath(k, v, delete_existing=1)
  493. def query_versions():
  494. """Query the system to get available versions of VS. A version is
  495. considered when a batfile is found."""
  496. msvs_list = get_installed_visual_studios()
  497. versions = [msvs.version for msvs in msvs_list]
  498. return versions
  499. # Local Variables:
  500. # tab-width:4
  501. # indent-tabs-mode:nil
  502. # End:
  503. # vim: set expandtab tabstop=4 shiftwidth=4: