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.

403 lines
15 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. __revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
  23. __doc__ = """Module to detect the Platform/Windows SDK
  24. PSDK 2003 R1 is the earliest version detected.
  25. """
  26. import os
  27. import SCons.Errors
  28. import SCons.Util
  29. from . import common
  30. debug = common.debug
  31. # SDK Checks. This is of course a mess as everything else on MS platforms. Here
  32. # is what we do to detect the SDK:
  33. #
  34. # For Windows SDK >= 6.0: just look into the registry entries:
  35. # HKLM\Software\Microsoft\Microsoft SDKs\Windows
  36. # All the keys in there are the available versions.
  37. #
  38. # For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not
  39. # seem to be any sane registry key, so the precise location is hardcoded.
  40. #
  41. # For versions below 2003R1, it seems the PSDK is included with Visual Studio?
  42. #
  43. # Also, per the following:
  44. # http://benjamin.smedbergs.us/blog/tag/atl/
  45. # VC++ Professional comes with the SDK, VC++ Express does not.
  46. # Location of the SDK (checked for 6.1 only)
  47. _CURINSTALLED_SDK_HKEY_ROOT = \
  48. r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
  49. class SDKDefinition(object):
  50. """
  51. An abstract base class for trying to find installed SDK directories.
  52. """
  53. def __init__(self, version, **kw):
  54. self.version = version
  55. self.__dict__.update(kw)
  56. def find_sdk_dir(self):
  57. """Try to find the MS SDK from the registry.
  58. Return None if failed or the directory does not exist.
  59. """
  60. if not SCons.Util.can_read_reg:
  61. debug('find_sdk_dir(): can not read registry')
  62. return None
  63. hkey = self.HKEY_FMT % self.hkey_data
  64. debug('find_sdk_dir(): checking registry:{}'.format(hkey))
  65. try:
  66. sdk_dir = common.read_reg(hkey)
  67. except SCons.Util.WinError as e:
  68. debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
  69. return None
  70. debug('find_sdk_dir(): Trying SDK Dir: {}'.format(sdk_dir))
  71. if not os.path.exists(sdk_dir):
  72. debug('find_sdk_dir(): {} not on file system'.format(sdk_dir))
  73. return None
  74. ftc = os.path.join(sdk_dir, self.sanity_check_file)
  75. if not os.path.exists(ftc):
  76. debug("find_sdk_dir(): sanity check {} not found".format(ftc))
  77. return None
  78. return sdk_dir
  79. def get_sdk_dir(self):
  80. """Return the MSSSDK given the version string."""
  81. try:
  82. return self._sdk_dir
  83. except AttributeError:
  84. sdk_dir = self.find_sdk_dir()
  85. self._sdk_dir = sdk_dir
  86. return sdk_dir
  87. def get_sdk_vc_script(self,host_arch, target_arch):
  88. """ Return the script to initialize the VC compiler installed by SDK
  89. """
  90. if (host_arch == 'amd64' and target_arch == 'x86'):
  91. # No cross tools needed compiling 32 bits on 64 bit machine
  92. host_arch=target_arch
  93. arch_string=target_arch
  94. if (host_arch != target_arch):
  95. arch_string='%s_%s'%(host_arch,target_arch)
  96. debug("sdk.py: get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
  97. host_arch,
  98. target_arch))
  99. file=self.vc_setup_scripts.get(arch_string,None)
  100. debug("sdk.py: get_sdk_vc_script():file:%s"%file)
  101. return file
  102. class WindowsSDK(SDKDefinition):
  103. """
  104. A subclass for trying to find installed Windows SDK directories.
  105. """
  106. HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder'
  107. def __init__(self, *args, **kw):
  108. SDKDefinition.__init__(self, *args, **kw)
  109. self.hkey_data = self.version
  110. class PlatformSDK(SDKDefinition):
  111. """
  112. A subclass for trying to find installed Platform SDK directories.
  113. """
  114. HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir'
  115. def __init__(self, *args, **kw):
  116. SDKDefinition.__init__(self, *args, **kw)
  117. self.hkey_data = self.uuid
  118. #
  119. # The list of VC initialization scripts installed by the SDK
  120. # These should be tried if the vcvarsall.bat TARGET_ARCH fails
  121. preSDK61VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
  122. 'amd64' : r'bin\vcvarsamd64.bat',
  123. 'x86_amd64': r'bin\vcvarsx86_amd64.bat',
  124. 'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
  125. 'ia64' : r'bin\vcvarsia64.bat'}
  126. SDK61VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
  127. 'amd64' : r'bin\amd64\vcvarsamd64.bat',
  128. 'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
  129. 'x86_ia64' : r'bin\x86_ia64\vcvarsx86_ia64.bat',
  130. 'ia64' : r'bin\ia64\vcvarsia64.bat'}
  131. SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
  132. 'amd64' : r'bin\vcvars64.bat',
  133. 'x86_amd64': r'bin\vcvarsx86_amd64.bat',
  134. 'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
  135. 'ia64' : r'bin\vcvarsia64.bat'}
  136. SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
  137. 'amd64' : r'bin\vcvars64.bat',
  138. 'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
  139. 'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'}
  140. # The list of support SDKs which we know how to detect.
  141. #
  142. # The first SDK found in the list is the one used by default if there
  143. # are multiple SDKs installed. Barring good reasons to the contrary,
  144. # this means we should list SDKs from most recent to oldest.
  145. #
  146. # If you update this list, update the documentation in Tool/mssdk.xml.
  147. SupportedSDKList = [
  148. WindowsSDK('10.0',
  149. sanity_check_file=r'bin\SetEnv.Cmd',
  150. include_subdir='include',
  151. lib_subdir={
  152. 'x86' : ['lib'],
  153. 'x86_64' : [r'lib\x64'],
  154. 'ia64' : [r'lib\ia64'],
  155. },
  156. vc_setup_scripts = SDK70VCSetupScripts,
  157. ),
  158. WindowsSDK('7.1',
  159. sanity_check_file=r'bin\SetEnv.Cmd',
  160. include_subdir='include',
  161. lib_subdir={
  162. 'x86' : ['lib'],
  163. 'x86_64' : [r'lib\x64'],
  164. 'ia64' : [r'lib\ia64'],
  165. },
  166. vc_setup_scripts = SDK70VCSetupScripts,
  167. ),
  168. WindowsSDK('7.0A',
  169. sanity_check_file=r'bin\SetEnv.Cmd',
  170. include_subdir='include',
  171. lib_subdir={
  172. 'x86' : ['lib'],
  173. 'x86_64' : [r'lib\x64'],
  174. 'ia64' : [r'lib\ia64'],
  175. },
  176. vc_setup_scripts = SDK70VCSetupScripts,
  177. ),
  178. WindowsSDK('7.0',
  179. sanity_check_file=r'bin\SetEnv.Cmd',
  180. include_subdir='include',
  181. lib_subdir={
  182. 'x86' : ['lib'],
  183. 'x86_64' : [r'lib\x64'],
  184. 'ia64' : [r'lib\ia64'],
  185. },
  186. vc_setup_scripts = SDK70VCSetupScripts,
  187. ),
  188. WindowsSDK('6.1',
  189. sanity_check_file=r'bin\SetEnv.Cmd',
  190. include_subdir='include',
  191. lib_subdir={
  192. 'x86' : ['lib'],
  193. 'x86_64' : [r'lib\x64'],
  194. 'ia64' : [r'lib\ia64'],
  195. },
  196. vc_setup_scripts = SDK61VCSetupScripts,
  197. ),
  198. WindowsSDK('6.0A',
  199. sanity_check_file=r'include\windows.h',
  200. include_subdir='include',
  201. lib_subdir={
  202. 'x86' : ['lib'],
  203. 'x86_64' : [r'lib\x64'],
  204. 'ia64' : [r'lib\ia64'],
  205. },
  206. vc_setup_scripts = preSDK61VCSetupScripts,
  207. ),
  208. WindowsSDK('6.0',
  209. sanity_check_file=r'bin\gacutil.exe',
  210. include_subdir='include',
  211. lib_subdir='lib',
  212. vc_setup_scripts = preSDK61VCSetupScripts,
  213. ),
  214. PlatformSDK('2003R2',
  215. sanity_check_file=r'SetEnv.Cmd',
  216. uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1",
  217. vc_setup_scripts = preSDK61VCSetupScripts,
  218. ),
  219. PlatformSDK('2003R1',
  220. sanity_check_file=r'SetEnv.Cmd',
  221. uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3",
  222. vc_setup_scripts = preSDK61VCSetupScripts,
  223. ),
  224. ]
  225. SupportedSDKMap = {}
  226. for sdk in SupportedSDKList:
  227. SupportedSDKMap[sdk.version] = sdk
  228. # Finding installed SDKs isn't cheap, because it goes not only to the
  229. # registry but also to the disk to sanity-check that there is, in fact,
  230. # an SDK installed there and that the registry entry isn't just stale.
  231. # Find this information once, when requested, and cache it.
  232. InstalledSDKList = None
  233. InstalledSDKMap = None
  234. def get_installed_sdks():
  235. global InstalledSDKList
  236. global InstalledSDKMap
  237. debug('sdk.py:get_installed_sdks()')
  238. if InstalledSDKList is None:
  239. InstalledSDKList = []
  240. InstalledSDKMap = {}
  241. for sdk in SupportedSDKList:
  242. debug('MSCommon/sdk.py: trying to find SDK %s' % sdk.version)
  243. if sdk.get_sdk_dir():
  244. debug('MSCommon/sdk.py:found SDK %s' % sdk.version)
  245. InstalledSDKList.append(sdk)
  246. InstalledSDKMap[sdk.version] = sdk
  247. return InstalledSDKList
  248. # We may be asked to update multiple construction environments with
  249. # SDK information. When doing this, we check on-disk for whether
  250. # the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
  251. # is expensive, cache results by directory.
  252. SDKEnvironmentUpdates = {}
  253. def set_sdk_by_directory(env, sdk_dir):
  254. global SDKEnvironmentUpdates
  255. debug('set_sdk_by_directory: Using dir:%s'%sdk_dir)
  256. try:
  257. env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
  258. except KeyError:
  259. env_tuple_list = []
  260. SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
  261. include_path = os.path.join(sdk_dir, 'include')
  262. mfc_path = os.path.join(include_path, 'mfc')
  263. atl_path = os.path.join(include_path, 'atl')
  264. if os.path.exists(mfc_path):
  265. env_tuple_list.append(('INCLUDE', mfc_path))
  266. if os.path.exists(atl_path):
  267. env_tuple_list.append(('INCLUDE', atl_path))
  268. env_tuple_list.append(('INCLUDE', include_path))
  269. env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
  270. env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
  271. env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
  272. for variable, directory in env_tuple_list:
  273. env.PrependENVPath(variable, directory)
  274. def get_sdk_by_version(mssdk):
  275. if mssdk not in SupportedSDKMap:
  276. raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk)))
  277. get_installed_sdks()
  278. return InstalledSDKMap.get(mssdk)
  279. def get_default_sdk():
  280. """Set up the default Platform/Windows SDK."""
  281. get_installed_sdks()
  282. if not InstalledSDKList:
  283. return None
  284. return InstalledSDKList[0]
  285. def mssdk_setup_env(env):
  286. debug('sdk.py:mssdk_setup_env()')
  287. if 'MSSDK_DIR' in env:
  288. sdk_dir = env['MSSDK_DIR']
  289. if sdk_dir is None:
  290. return
  291. sdk_dir = env.subst(sdk_dir)
  292. debug('sdk.py:mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
  293. elif 'MSSDK_VERSION' in env:
  294. sdk_version = env['MSSDK_VERSION']
  295. if sdk_version is None:
  296. msg = "SDK version is specified as None"
  297. raise SCons.Errors.UserError(msg)
  298. sdk_version = env.subst(sdk_version)
  299. mssdk = get_sdk_by_version(sdk_version)
  300. if mssdk is None:
  301. msg = "SDK version %s is not installed" % sdk_version
  302. raise SCons.Errors.UserError(msg)
  303. sdk_dir = mssdk.get_sdk_dir()
  304. debug('sdk.py:mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
  305. elif 'MSVS_VERSION' in env:
  306. msvs_version = env['MSVS_VERSION']
  307. debug('sdk.py:mssdk_setup_env:Getting MSVS_VERSION from env:%s'%msvs_version)
  308. if msvs_version is None:
  309. debug('sdk.py:mssdk_setup_env thinks msvs_version is None')
  310. return
  311. msvs_version = env.subst(msvs_version)
  312. from . import vs
  313. msvs = vs.get_vs_by_version(msvs_version)
  314. debug('sdk.py:mssdk_setup_env:msvs is :%s'%msvs)
  315. if not msvs:
  316. debug('sdk.py:mssdk_setup_env: no VS version detected, bailingout:%s'%msvs)
  317. return
  318. sdk_version = msvs.sdk_version
  319. debug('sdk.py:msvs.sdk_version is %s'%sdk_version)
  320. if not sdk_version:
  321. return
  322. mssdk = get_sdk_by_version(sdk_version)
  323. if not mssdk:
  324. mssdk = get_default_sdk()
  325. if not mssdk:
  326. return
  327. sdk_dir = mssdk.get_sdk_dir()
  328. debug('sdk.py:mssdk_setup_env: Using MSVS_VERSION:%s'%sdk_dir)
  329. else:
  330. mssdk = get_default_sdk()
  331. if not mssdk:
  332. return
  333. sdk_dir = mssdk.get_sdk_dir()
  334. debug('sdk.py:mssdk_setup_env: not using any env values. sdk_dir:%s'%sdk_dir)
  335. set_sdk_by_directory(env, sdk_dir)
  336. #print "No MSVS_VERSION: this is likely to be a bug"
  337. def mssdk_exists(version=None):
  338. sdks = get_installed_sdks()
  339. if version is None:
  340. return len(sdks) > 0
  341. return version in sdks
  342. # Local Variables:
  343. # tab-width:4
  344. # indent-tabs-mode:nil
  345. # End:
  346. # vim: set expandtab tabstop=4 shiftwidth=4: