~ubuntu-branches/ubuntu/utopic/scons/utopic-proposed

« back to all changes in this revision

Viewing changes to engine/SCons/Platform/win32.py

  • Committer: Bazaar Package Importer
  • Author(s): Mark Brown
  • Date: 2004-08-24 08:57:22 UTC
  • mfrom: (0.2.1 upstream) (1.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040824085722-hfk4f0pjbyu0ebxv
Tags: 0.96.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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__ = "/home/scons/scons/branch.0/baseline/src/engine/SCons/Platform/win32.py 0.96.1.D001 2004/08/23 09:55:29 knight"
 
34
 
 
35
import os
 
36
import os.path
 
37
import string
 
38
import sys
 
39
import tempfile
 
40
from SCons.Platform.posix import exitvalmap
 
41
 
 
42
# XXX See note below about why importing SCons.Action should be
 
43
# eventually refactored.
 
44
import SCons.Action
 
45
import SCons.Util
 
46
 
 
47
class TempFileMunge:
 
48
    """A callable class.  You can set an Environment variable to this,
 
49
    then call it with a string argument, then it will perform temporary
 
50
    file substitution on it.  This is used to circumvent the win32 long command
 
51
    line limitation.
 
52
 
 
53
    Example usage:
 
54
    env["TEMPFILE"] = TempFileMunge
 
55
    env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES')}"
 
56
    """
 
57
    def __init__(self, cmd):
 
58
        self.cmd = cmd
 
59
 
 
60
    def __call__(self, target, source, env, for_signature):
 
61
        if for_signature:
 
62
            return self.cmd
 
63
        cmd = env.subst_list(self.cmd, 0, target, source)[0]
 
64
        try:
 
65
            maxline = int(env.subst('$MAXLINELENGTH'))
 
66
        except ValueError:
 
67
            maxline = 2048
 
68
        if (reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)) <= maxline:
 
69
            return self.cmd
 
70
        else:
 
71
            # We do a normpath because mktemp() has what appears to be
 
72
            # a bug in Win32 that will use a forward slash as a path
 
73
            # delimiter.  Win32's link mistakes that for a command line
 
74
            # switch and barfs.
 
75
            #
 
76
            # We use the .lnk suffix for the benefit of the Phar Lap
 
77
            # linkloc linker, which likes to append an .lnk suffix if
 
78
            # none is given.
 
79
            tmp = os.path.normpath(tempfile.mktemp('.lnk'))
 
80
            native_tmp = SCons.Util.get_native_path(tmp)
 
81
 
 
82
            if env['SHELL'] and env['SHELL'] == 'sh':
 
83
                # The sh shell will try to escape the backslashes in the
 
84
                # path, so unescape them.
 
85
                native_tmp = string.replace(native_tmp, '\\', r'\\\\')
 
86
                # In Cygwin, we want to use rm to delete the temporary
 
87
                # file, because del does not exist in the sh shell.
 
88
                rm = env.Detect('rm') or 'del'
 
89
            else:
 
90
                # Don't use 'rm' if the shell is not sh, because rm won't
 
91
                # work with the win32 shells (cmd.exe or command.com) or
 
92
                # win32 path names.
 
93
                rm = 'del'
 
94
 
 
95
            args = map(SCons.Util.quote_spaces, cmd[1:])
 
96
            open(tmp, 'w').write(string.join(args, " ") + "\n")
 
97
            # XXX Using the SCons.Action.print_actions value directly
 
98
            # like this is bogus, but expedient.  This class should
 
99
            # really be rewritten as an Action that defines the
 
100
            # __call__() and strfunction() methods and lets the
 
101
            # normal action-execution logic handle whether or not to
 
102
            # print/execute the action.  The problem, though, is all
 
103
            # of that is decided before we execute this method as
 
104
            # part of expanding the $TEMPFILE construction variable.
 
105
            # Consequently, refactoring this will have to wait until
 
106
            # we get more flexible with allowing Actions to exist
 
107
            # independently and get strung together arbitrarily like
 
108
            # Ant tasks.  In the meantime, it's going to be more
 
109
            # user-friendly to not let obsession with architectural
 
110
            # purity get in the way of just being helpful, so we'll
 
111
            # reach into SCons.Action directly.
 
112
            if SCons.Action.print_actions:
 
113
                print("Using tempfile "+native_tmp+" for command line:\n"+
 
114
                      str(cmd[0]) + " " + string.join(args," "))
 
115
            return [ cmd[0], '@' + native_tmp + '\n' + rm, native_tmp ]
 
116
 
 
117
# The upshot of all this is that, if you are using Python 1.5.2,
 
118
# you had better have cmd or command.com in your PATH when you run
 
119
# scons.
 
120
 
 
121
def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
 
122
    # There is no direct way to do that in python. What we do
 
123
    # here should work for most cases:
 
124
    #   In case stdout (stderr) is not redirected to a file,
 
125
    #   we redirect it into a temporary file tmpFileStdout
 
126
    #   (tmpFileStderr) and copy the contents of this file
 
127
    #   to stdout (stderr) given in the argument
 
128
    if not sh:
 
129
        sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
 
130
        return 127
 
131
    else:
 
132
        # one temporary file for stdout and stderr
 
133
        tmpFileStdout = os.path.normpath(tempfile.mktemp())
 
134
        tmpFileStderr = os.path.normpath(tempfile.mktemp())
 
135
 
 
136
        # check if output is redirected
 
137
        stdoutRedirected = 0
 
138
        stderrRedirected = 0
 
139
        for arg in args:
 
140
            # are there more possibilities to redirect stdout ?
 
141
            if (string.find( arg, ">", 0, 1 ) != -1 or
 
142
                string.find( arg, "1>", 0, 2 ) != -1):
 
143
                stdoutRedirected = 1
 
144
            # are there more possibilities to redirect stderr ?
 
145
            if string.find( arg, "2>", 0, 2 ) != -1:
 
146
                stderrRedirected = 1
 
147
 
 
148
        # redirect output of non-redirected streams to our tempfiles
 
149
        if stdoutRedirected == 0:
 
150
            args.append(">" + str(tmpFileStdout))
 
151
        if stderrRedirected == 0:
 
152
            args.append("2>" + str(tmpFileStderr))
 
153
 
 
154
        # actually do the spawn
 
155
        try:
 
156
            args = [sh, '/C', escape(string.join(args)) ]
 
157
            ret = os.spawnve(os.P_WAIT, sh, args, env)
 
158
        except OSError, e:
 
159
            # catch any error
 
160
            ret = exitvalmap[e[0]]
 
161
            if stderr != None:
 
162
                stderr.write("scons: %s: %s\n" % (cmd, e[1]))
 
163
        # copy child output from tempfiles to our streams
 
164
        # and do clean up stuff
 
165
        if stdout != None and stdoutRedirected == 0:
 
166
            try:
 
167
                stdout.write(open( tmpFileStdout, "r" ).read())
 
168
                os.remove( tmpFileStdout )
 
169
            except (IOError, OSError):
 
170
                pass
 
171
 
 
172
        if stderr != None and stderrRedirected == 0:
 
173
            try:
 
174
                stderr.write(open( tmpFileStderr, "r" ).read())
 
175
                os.remove( tmpFileStderr )
 
176
            except (IOError, OSError):
 
177
                pass
 
178
        return ret
 
179
 
 
180
def spawn(sh, escape, cmd, args, env):
 
181
    if not sh:
 
182
        sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
 
183
        return 127
 
184
    else:
 
185
        try:
 
186
            args = [sh, '/C', escape(string.join(args)) ]
 
187
            ret = os.spawnve(os.P_WAIT, sh, args, env)
 
188
        except OSError, e:
 
189
            ret = exitvalmap[e[0]]
 
190
            sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
 
191
        return ret
 
192
 
 
193
# Windows does not allow special characters in file names anyway, so
 
194
# no need for a complex escape function, we will just quote the arg.
 
195
escape = lambda x: '"' + x + '"'
 
196
 
 
197
# Get the windows system directory name
 
198
def get_system_root():
 
199
    # A resonable default if we can't read the registry
 
200
    try:
 
201
        val = os.environ['SYSTEMROOT']
 
202
    except KeyError:
 
203
        val = "C:/WINDOWS"
 
204
        pass
 
205
 
 
206
    # First see if we can look in the registry...
 
207
    if SCons.Util.can_read_reg:
 
208
        try:
 
209
            # Look for Windows NT system root
 
210
            k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 
211
                                      'Software\\Microsoft\\Windows NT\\CurrentVersion')
 
212
            val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
 
213
        except SCons.Util.RegError:
 
214
            try:
 
215
                # Okay, try the Windows 9x system root
 
216
                k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 
217
                                          'Software\\Microsoft\\Windows\\CurrentVersion')
 
218
                val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
 
219
            except KeyboardInterrupt:
 
220
                raise
 
221
            except:
 
222
                pass
 
223
    return val
 
224
 
 
225
# Get the location of the program files directory
 
226
def get_program_files_dir():
 
227
    # Now see if we can look in the registry...
 
228
    val = ''
 
229
    if SCons.Util.can_read_reg:
 
230
        try:
 
231
            # Look for Windows Program Files directory
 
232
            k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 
233
                                      'Software\\Microsoft\\Windows\\CurrentVersion')
 
234
            val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
 
235
        except SCons.Util.RegError:
 
236
            val = ''
 
237
            pass
 
238
 
 
239
    if val == '':
 
240
        # A reasonable default if we can't read the registry
 
241
        # (Actually, it's pretty reasonable even if we can :-)
 
242
        val = os.path.join(os.path.dirname(get_system_root()),"Program Files")
 
243
        
 
244
    return val
 
245
 
 
246
def generate(env):
 
247
    # Attempt to find cmd.exe (for WinNT/2k/XP) or
 
248
    # command.com for Win9x
 
249
    cmd_interp = ''
 
250
    # First see if we can look in the registry...
 
251
    if SCons.Util.can_read_reg:
 
252
        try:
 
253
            # Look for Windows NT system root
 
254
            k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 
255
                                          'Software\\Microsoft\\Windows NT\\CurrentVersion')
 
256
            val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
 
257
            cmd_interp = os.path.join(val, 'System32\\cmd.exe')
 
258
        except SCons.Util.RegError:
 
259
            try:
 
260
                # Okay, try the Windows 9x system root
 
261
                k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 
262
                                              'Software\\Microsoft\\Windows\\CurrentVersion')
 
263
                val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
 
264
                cmd_interp = os.path.join(val, 'command.com')
 
265
            except KeyboardInterrupt:
 
266
                raise
 
267
            except:
 
268
                pass
 
269
 
 
270
    # For the special case of not having access to the registry, we
 
271
    # use a temporary path and pathext to attempt to find the command
 
272
    # interpreter.  If we fail, we try to find the interpreter through
 
273
    # the env's PATH.  The problem with that is that it might not
 
274
    # contain an ENV and a PATH.
 
275
    if not cmd_interp:
 
276
        systemroot = r'C:\Windows'
 
277
        if os.environ.has_key('SYSTEMROOT'):
 
278
            systemroot = os.environ['SYSTEMROOT']
 
279
        tmp_path = systemroot + os.pathsep + \
 
280
                   os.path.join(systemroot,'System32')
 
281
        tmp_pathext = '.com;.exe;.bat;.cmd'
 
282
        if os.environ.has_key('PATHEXT'):
 
283
            tmp_pathext = os.environ['PATHEXT'] 
 
284
        cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
 
285
        if not cmd_interp:
 
286
            cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
 
287
 
 
288
    if not cmd_interp:
 
289
        cmd_interp = env.Detect('cmd')
 
290
        if not cmd_interp:
 
291
            cmd_interp = env.Detect('command')
 
292
 
 
293
    
 
294
    if not env.has_key('ENV'):
 
295
        env['ENV']        = {}
 
296
 
 
297
    # Import things from the external environment to the construction
 
298
    # environment's ENV.  This is a potential slippery slope, because we
 
299
    # *don't* want to make builds dependent on the user's environment by
 
300
    # default.  We're doing this for SYSTEMROOT, though, because it's
 
301
    # needed for anything that uses sockets, and seldom changes.  Weigh
 
302
    # the impact carefully before adding other variables to this list.
 
303
    import_env = [ 'SYSTEMROOT' ]
 
304
    for var in import_env:
 
305
        v = os.environ.get(var)
 
306
        if v:
 
307
            env['ENV'][var] = v
 
308
 
 
309
    env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
 
310
    env['OBJPREFIX']      = ''
 
311
    env['OBJSUFFIX']      = '.obj'
 
312
    env['SHOBJPREFIX']    = '$OBJPREFIX'
 
313
    env['SHOBJSUFFIX']    = '$OBJSUFFIX'
 
314
    env['PROGPREFIX']     = ''
 
315
    env['PROGSUFFIX']     = '.exe'
 
316
    env['LIBPREFIX']      = ''
 
317
    env['LIBSUFFIX']      = '.lib'
 
318
    env['SHLIBPREFIX']    = ''
 
319
    env['SHLIBSUFFIX']    = '.dll'
 
320
    env['LIBPREFIXES']    = [ '$LIBPREFIX' ]
 
321
    env['LIBSUFFIXES']    = [ '$LIBSUFFIX' ]
 
322
    env['PSPAWN']         = piped_spawn
 
323
    env['SPAWN']          = spawn
 
324
    env['SHELL']          = cmd_interp
 
325
    env['TEMPFILE']       = TempFileMunge
 
326
    env['MAXLINELENGTH']  = 2048
 
327
    env['ESCAPE']         = escape