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