6d0b0747e28f9494f0857f579a09e624a7ba690c
[senf.git] / scons / scons-1.2.0 / engine / SCons / Platform / posix.py
1 """SCons.Platform.posix
2
3 Platform-specific initialization for POSIX (Linux, UNIX, etc.) 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/posix.py 3842 2008/12/20 22:59:52 scons"
34
35 import errno
36 import os
37 import os.path
38 import string
39 import subprocess
40 import sys
41 import select
42
43 import SCons.Util
44 from SCons.Platform import TempFileMunge
45
46 exitvalmap = {
47     2 : 127,
48     13 : 126,
49 }
50
51 def escape(arg):
52     "escape shell special characters"
53     slash = '\\'
54     special = '"$()'
55
56     arg = string.replace(arg, slash, slash+slash)
57     for c in special:
58         arg = string.replace(arg, c, slash+c)
59
60     return '"' + arg + '"'
61
62 def exec_system(l, env):
63     stat = os.system(string.join(l))
64     if stat & 0xff:
65         return stat | 0x80
66     return stat >> 8
67
68 def exec_spawnvpe(l, env):
69     stat = os.spawnvpe(os.P_WAIT, l[0], l, env)
70     # os.spawnvpe() returns the actual exit code, not the encoding
71     # returned by os.waitpid() or os.system().
72     return stat
73
74 def exec_fork(l, env): 
75     pid = os.fork()
76     if not pid:
77         # Child process.
78         exitval = 127
79         try:
80             os.execvpe(l[0], l, env)
81         except OSError, e:
82             exitval = exitvalmap.get(e[0], e[0])
83             sys.stderr.write("scons: %s: %s\n" % (l[0], e[1]))
84         os._exit(exitval)
85     else:
86         # Parent process.
87         pid, stat = os.waitpid(pid, 0)
88         if stat & 0xff:
89             return stat | 0x80
90         return stat >> 8
91
92 def _get_env_command(sh, escape, cmd, args, env):
93     s = string.join(args)
94     if env:
95         l = ['env', '-'] + \
96             map(lambda t, e=escape: e(t[0])+'='+e(t[1]), env.items()) + \
97             [sh, '-c', escape(s)]
98         s = string.join(l)
99     return s
100
101 def env_spawn(sh, escape, cmd, args, env):
102     return exec_system([_get_env_command( sh, escape, cmd, args, env)], env)
103
104 def spawnvpe_spawn(sh, escape, cmd, args, env):
105     return exec_spawnvpe([sh, '-c', string.join(args)], env)
106
107 def fork_spawn(sh, escape, cmd, args, env):
108     return exec_fork([sh, '-c', string.join(args)], env)
109
110 def process_cmd_output(cmd_stdout, cmd_stderr, stdout, stderr):
111     stdout_eof = stderr_eof = 0
112     while not (stdout_eof and stderr_eof):
113         try:
114             (i,o,e) = select.select([cmd_stdout, cmd_stderr], [], [])
115             if cmd_stdout in i:
116                 str = cmd_stdout.read()
117                 if len(str) == 0:
118                     stdout_eof = 1
119                 elif stdout != None:
120                     stdout.write(str)
121             if cmd_stderr in i:
122                 str = cmd_stderr.read()
123                 if len(str) == 0:
124                     #sys.__stderr__.write( "stderr_eof=1\n" )
125                     stderr_eof = 1
126                 else:
127                     #sys.__stderr__.write( "str(stderr) = %s\n" % str )
128                     stderr.write(str)
129         except select.error, (_errno, _strerror):
130             if _errno != errno.EINTR:
131                 raise
132
133 def exec_popen3(l, env, stdout, stderr):
134     proc = subprocess.Popen(string.join(l),
135                             stdout=stdout,
136                             stderr=stderr,
137                             shell=True)
138     stat = proc.wait()
139     if stat & 0xff:
140         return stat | 0x80
141     return stat >> 8
142
143 def exec_piped_fork(l, env, stdout, stderr):
144     # spawn using fork / exec and providing a pipe for the command's
145     # stdout / stderr stream
146     if stdout != stderr:
147         (rFdOut, wFdOut) = os.pipe()
148         (rFdErr, wFdErr) = os.pipe()
149     else:
150         (rFdOut, wFdOut) = os.pipe()
151         rFdErr = rFdOut
152         wFdErr = wFdOut
153     # do the fork
154     pid = os.fork()
155     if not pid:
156         # Child process
157         os.close( rFdOut )
158         if rFdOut != rFdErr:
159             os.close( rFdErr )
160         os.dup2( wFdOut, 1 ) # is there some symbolic way to do that ?
161         os.dup2( wFdErr, 2 )
162         os.close( wFdOut )
163         if stdout != stderr:
164             os.close( wFdErr )
165         exitval = 127
166         try:
167             os.execvpe(l[0], l, env)
168         except OSError, e:
169             exitval = exitvalmap.get(e[0], e[0])
170             stderr.write("scons: %s: %s\n" % (l[0], e[1]))
171         os._exit(exitval)
172     else:
173         # Parent process
174         pid, stat = os.waitpid(pid, 0)
175         os.close( wFdOut )
176         if stdout != stderr:
177             os.close( wFdErr )
178         childOut = os.fdopen( rFdOut )
179         if stdout != stderr:
180             childErr = os.fdopen( rFdErr )
181         else:
182             childErr = childOut
183         process_cmd_output(childOut, childErr, stdout, stderr)
184         os.close( rFdOut )
185         if stdout != stderr:
186             os.close( rFdErr )
187         if stat & 0xff:
188             return stat | 0x80
189         return stat >> 8
190
191 def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr):
192     # spawn using Popen3 combined with the env command
193     # the command name and the command's stdout is written to stdout
194     # the command's stderr is written to stderr
195     return exec_popen3([_get_env_command(sh, escape, cmd, args, env)],
196                        env, stdout, stderr)
197
198 def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr):
199     # spawn using fork / exec and providing a pipe for the command's
200     # stdout / stderr stream
201     return exec_piped_fork([sh, '-c', string.join(args)],
202                            env, stdout, stderr)
203
204
205
206 def generate(env):
207     # If os.spawnvpe() exists, we use it to spawn commands.  Otherwise
208     # if the env utility exists, we use os.system() to spawn commands,
209     # finally we fall back on os.fork()/os.exec().  
210     #
211     # os.spawnvpe() is prefered because it is the most efficient.  But
212     # for Python versions without it, os.system() is prefered because it
213     # is claimed that it works better with threads (i.e. -j) and is more
214     # efficient than forking Python.
215     #
216     # NB: Other people on the scons-users mailing list have claimed that
217     # os.fork()/os.exec() works better than os.system().  There may just
218     # not be a default that works best for all users.
219
220     if os.__dict__.has_key('spawnvpe'):
221         spawn = spawnvpe_spawn
222     elif env.Detect('env'):
223         spawn = env_spawn
224     else:
225         spawn = fork_spawn
226
227     if env.Detect('env'):
228         pspawn = piped_env_spawn
229     else:
230         pspawn = piped_fork_spawn
231
232     if not env.has_key('ENV'):
233         env['ENV']        = {}
234     env['ENV']['PATH']    = '/usr/local/bin:/opt/bin:/bin:/usr/bin'
235     env['OBJPREFIX']      = ''
236     env['OBJSUFFIX']      = '.o'
237     env['SHOBJPREFIX']    = '$OBJPREFIX'
238     env['SHOBJSUFFIX']    = '$OBJSUFFIX'
239     env['PROGPREFIX']     = ''
240     env['PROGSUFFIX']     = ''
241     env['LIBPREFIX']      = 'lib'
242     env['LIBSUFFIX']      = '.a'
243     env['SHLIBPREFIX']    = '$LIBPREFIX'
244     env['SHLIBSUFFIX']    = '.so'
245     env['LIBPREFIXES']    = [ '$LIBPREFIX' ]
246     env['LIBSUFFIXES']    = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
247     env['PSPAWN']         = pspawn
248     env['SPAWN']          = spawn
249     env['SHELL']          = 'sh'
250     env['ESCAPE']         = escape
251     env['TEMPFILE']       = TempFileMunge
252     env['TEMPFILEPREFIX'] = '@'
253     #Based on LINUX: ARG_MAX=ARG_MAX=131072 - 3000 for environment expansion
254     #Note: specific platforms might rise or lower this value
255     env['MAXLINELENGTH']  = 128072
256
257     # This platform supports RPATH specifications.
258     env['__RPATH'] = '$_RPATH'