3ec0a526d349c1a0aa0dca99e981c33e3025479a
[senf.git] / scons / scons-1.2.0 / engine / SCons / Platform / win32.py
1 """SCons.Platform.win32
2
3 Platform-specific initialization for Win32 systems.
4
5 There normally shouldn't be any need to import this module directly.  It
6 will usually be imported through the generic SCons.Platform.Platform()
7 selection method.
8 """
9
10 #
11 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
12 #
13 # Permission is hereby granted, free of charge, to any person obtaining
14 # a copy of this software and associated documentation files (the
15 # "Software"), to deal in the Software without restriction, including
16 # without limitation the rights to use, copy, modify, merge, publish,
17 # distribute, sublicense, and/or sell copies of the Software, and to
18 # permit persons to whom the Software is furnished to do so, subject to
19 # the following conditions:
20 #
21 # The above copyright notice and this permission notice shall be included
22 # in all copies or substantial portions of the Software.
23 #
24 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
25 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
26 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #
32
33 __revision__ = "src/engine/SCons/Platform/win32.py 3842 2008/12/20 22:59:52 scons"
34
35 import os
36 import os.path
37 import string
38 import sys
39 import tempfile
40
41 from SCons.Platform.posix import exitvalmap
42 from SCons.Platform import TempFileMunge
43 import SCons.Util
44
45
46
47 try:
48     import msvcrt
49     import win32api
50     import win32con
51
52     msvcrt.get_osfhandle
53     win32api.SetHandleInformation
54     win32con.HANDLE_FLAG_INHERIT
55 except ImportError:
56     parallel_msg = \
57         "you do not seem to have the pywin32 extensions installed;\n" + \
58         "\tparallel (-j) builds may not work reliably with open Python files."
59 except AttributeError:
60     parallel_msg = \
61         "your pywin32 extensions do not support file handle operations;\n" + \
62         "\tparallel (-j) builds may not work reliably with open Python files."
63 else:
64     parallel_msg = None
65
66     import __builtin__
67
68     _builtin_file = __builtin__.file
69     _builtin_open = __builtin__.open
70
71     def _scons_file(*args, **kw):
72         fp = apply(_builtin_file, args, kw)
73         win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
74                                       win32con.HANDLE_FLAG_INHERIT,
75                                       0)
76         return fp
77
78     def _scons_open(*args, **kw):
79         fp = apply(_builtin_open, args, kw)
80         win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
81                                       win32con.HANDLE_FLAG_INHERIT,
82                                       0)
83         return fp
84
85     __builtin__.file = _scons_file
86     __builtin__.open = _scons_open
87
88
89
90 # The upshot of all this is that, if you are using Python 1.5.2,
91 # you had better have cmd or command.com in your PATH when you run
92 # scons.
93
94 def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
95     # There is no direct way to do that in python. What we do
96     # here should work for most cases:
97     #   In case stdout (stderr) is not redirected to a file,
98     #   we redirect it into a temporary file tmpFileStdout
99     #   (tmpFileStderr) and copy the contents of this file
100     #   to stdout (stderr) given in the argument
101     if not sh:
102         sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
103         return 127
104     else:
105         # one temporary file for stdout and stderr
106         tmpFileStdout = os.path.normpath(tempfile.mktemp())
107         tmpFileStderr = os.path.normpath(tempfile.mktemp())
108
109         # check if output is redirected
110         stdoutRedirected = 0
111         stderrRedirected = 0
112         for arg in args:
113             # are there more possibilities to redirect stdout ?
114             if (string.find( arg, ">", 0, 1 ) != -1 or
115                 string.find( arg, "1>", 0, 2 ) != -1):
116                 stdoutRedirected = 1
117             # are there more possibilities to redirect stderr ?
118             if string.find( arg, "2>", 0, 2 ) != -1:
119                 stderrRedirected = 1
120
121         # redirect output of non-redirected streams to our tempfiles
122         if stdoutRedirected == 0:
123             args.append(">" + str(tmpFileStdout))
124         if stderrRedirected == 0:
125             args.append("2>" + str(tmpFileStderr))
126
127         # actually do the spawn
128         try:
129             args = [sh, '/C', escape(string.join(args)) ]
130             ret = os.spawnve(os.P_WAIT, sh, args, env)
131         except OSError, e:
132             # catch any error
133             try:
134                 ret = exitvalmap[e[0]]
135             except KeyError:
136                 sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1]))
137             if stderr != None:
138                 stderr.write("scons: %s: %s\n" % (cmd, e[1]))
139         # copy child output from tempfiles to our streams
140         # and do clean up stuff
141         if stdout != None and stdoutRedirected == 0:
142             try:
143                 stdout.write(open( tmpFileStdout, "r" ).read())
144                 os.remove( tmpFileStdout )
145             except (IOError, OSError):
146                 pass
147
148         if stderr != None and stderrRedirected == 0:
149             try:
150                 stderr.write(open( tmpFileStderr, "r" ).read())
151                 os.remove( tmpFileStderr )
152             except (IOError, OSError):
153                 pass
154         return ret
155
156 def exec_spawn(l, env):
157     try:
158         result = os.spawnve(os.P_WAIT, l[0], l, env)
159     except OSError, e:
160         try:
161             result = exitvalmap[e[0]]
162             sys.stderr.write("scons: %s: %s\n" % (l[0], e[1]))
163         except KeyError:
164             result = 127
165             if len(l) > 2:
166                 if len(l[2]) < 1000:
167                     command = string.join(l[0:3])
168                 else:
169                     command = l[0]
170             else:
171                 command = l[0]
172             sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e[0], command, e[1]))
173     return result
174
175 def spawn(sh, escape, cmd, args, env):
176     if not sh:
177         sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
178         return 127
179     return exec_spawn([sh, '/C', escape(string.join(args))], env)
180
181 # Windows does not allow special characters in file names anyway, so no
182 # need for a complex escape function, we will just quote the arg, except
183 # that "cmd /c" requires that if an argument ends with a backslash it
184 # needs to be escaped so as not to interfere with closing double quote
185 # that we add.
186 def escape(x):
187     if x[-1] == '\\':
188         x = x + '\\'
189     return '"' + x + '"'
190
191 # Get the windows system directory name
192 def get_system_root():
193     # A resonable default if we can't read the registry
194     try:
195         val = os.environ['SYSTEMROOT']
196     except KeyError:
197         val = "C:/WINDOWS"
198         pass
199
200     # First see if we can look in the registry...
201     if SCons.Util.can_read_reg:
202         try:
203             # Look for Windows NT system root
204             k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
205                                       'Software\\Microsoft\\Windows NT\\CurrentVersion')
206             val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
207         except SCons.Util.RegError:
208             try:
209                 # Okay, try the Windows 9x system root
210                 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
211                                           'Software\\Microsoft\\Windows\\CurrentVersion')
212                 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
213             except KeyboardInterrupt:
214                 raise
215             except:
216                 pass
217     return val
218
219 # Get the location of the program files directory
220 def get_program_files_dir():
221     # Now see if we can look in the registry...
222     val = ''
223     if SCons.Util.can_read_reg:
224         try:
225             # Look for Windows Program Files directory
226             k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
227                                       'Software\\Microsoft\\Windows\\CurrentVersion')
228             val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
229         except SCons.Util.RegError:
230             val = ''
231             pass
232
233     if val == '':
234         # A reasonable default if we can't read the registry
235         # (Actually, it's pretty reasonable even if we can :-)
236         val = os.path.join(os.path.dirname(get_system_root()),"Program Files")
237         
238     return val
239
240 def generate(env):
241     # Attempt to find cmd.exe (for WinNT/2k/XP) or
242     # command.com for Win9x
243     cmd_interp = ''
244     # First see if we can look in the registry...
245     if SCons.Util.can_read_reg:
246         try:
247             # Look for Windows NT system root
248             k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
249                                           'Software\\Microsoft\\Windows NT\\CurrentVersion')
250             val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
251             cmd_interp = os.path.join(val, 'System32\\cmd.exe')
252         except SCons.Util.RegError:
253             try:
254                 # Okay, try the Windows 9x system root
255                 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
256                                               'Software\\Microsoft\\Windows\\CurrentVersion')
257                 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
258                 cmd_interp = os.path.join(val, 'command.com')
259             except KeyboardInterrupt:
260                 raise
261             except:
262                 pass
263
264     # For the special case of not having access to the registry, we
265     # use a temporary path and pathext to attempt to find the command
266     # interpreter.  If we fail, we try to find the interpreter through
267     # the env's PATH.  The problem with that is that it might not
268     # contain an ENV and a PATH.
269     if not cmd_interp:
270         systemroot = r'C:\Windows'
271         if os.environ.has_key('SYSTEMROOT'):
272             systemroot = os.environ['SYSTEMROOT']
273         tmp_path = systemroot + os.pathsep + \
274                    os.path.join(systemroot,'System32')
275         tmp_pathext = '.com;.exe;.bat;.cmd'
276         if os.environ.has_key('PATHEXT'):
277             tmp_pathext = os.environ['PATHEXT'] 
278         cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
279         if not cmd_interp:
280             cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
281
282     if not cmd_interp:
283         cmd_interp = env.Detect('cmd')
284         if not cmd_interp:
285             cmd_interp = env.Detect('command')
286
287     
288     if not env.has_key('ENV'):
289         env['ENV']        = {}
290
291     # Import things from the external environment to the construction
292     # environment's ENV.  This is a potential slippery slope, because we
293     # *don't* want to make builds dependent on the user's environment by
294     # default.  We're doing this for SYSTEMROOT, though, because it's
295     # needed for anything that uses sockets, and seldom changes, and
296     # for SYSTEMDRIVE because it's related.
297     #
298     # Weigh the impact carefully before adding other variables to this list.
299     import_env = [ 'SYSTEMDRIVE', 'SYSTEMROOT', 'TEMP', 'TMP' ]
300     for var in import_env:
301         v = os.environ.get(var)
302         if v:
303             env['ENV'][var] = v
304
305     env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
306     env['OBJPREFIX']      = ''
307     env['OBJSUFFIX']      = '.obj'
308     env['SHOBJPREFIX']    = '$OBJPREFIX'
309     env['SHOBJSUFFIX']    = '$OBJSUFFIX'
310     env['PROGPREFIX']     = ''
311     env['PROGSUFFIX']     = '.exe'
312     env['LIBPREFIX']      = ''
313     env['LIBSUFFIX']      = '.lib'
314     env['SHLIBPREFIX']    = ''
315     env['SHLIBSUFFIX']    = '.dll'
316     env['LIBPREFIXES']    = [ '$LIBPREFIX' ]
317     env['LIBSUFFIXES']    = [ '$LIBSUFFIX' ]
318     env['PSPAWN']         = piped_spawn
319     env['SPAWN']          = spawn
320     env['SHELL']          = cmd_interp
321     env['TEMPFILE']       = TempFileMunge
322     env['TEMPFILEPREFIX'] = '@'
323     env['MAXLINELENGTH']  = 2048
324     env['ESCAPE']         = escape