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