Package SCons :: Package Script :: Module Main
[hide private]
[frames] | no frames]

Source Code for Module SCons.Script.Main

   1  """SCons.Script 
   2   
   3  This file implements the main() function used by the scons script. 
   4   
   5  Architecturally, this *is* the scons script, and will likely only be 
   6  called from the external "scons" wrapper.  Consequently, anything here 
   7  should not be, or be considered, part of the build engine.  If it's 
   8  something that we expect other software to want to use, it should go in 
   9  some other module.  If it's specific to the "scons" script invocation, 
  10  it goes here. 
  11   
  12  """ 
  13   
  14  # 
  15  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  16  # 
  17  # Permission is hereby granted, free of charge, to any person obtaining 
  18  # a copy of this software and associated documentation files (the 
  19  # "Software"), to deal in the Software without restriction, including 
  20  # without limitation the rights to use, copy, modify, merge, publish, 
  21  # distribute, sublicense, and/or sell copies of the Software, and to 
  22  # permit persons to whom the Software is furnished to do so, subject to 
  23  # the following conditions: 
  24  # 
  25  # The above copyright notice and this permission notice shall be included 
  26  # in all copies or substantial portions of the Software. 
  27  # 
  28  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  29  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  30  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  31  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  32  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  33  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  34  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  35  # 
  36   
  37  __revision__ = "src/engine/SCons/Script/Main.py 3795 2008/11/25 22:04:43 scons" 
  38   
  39  import os 
  40  import os.path 
  41  import string 
  42  import sys 
  43  import time 
  44  import traceback 
  45   
  46  # Strip the script directory from sys.path() so on case-insensitive 
  47  # (Windows) systems Python doesn't think that the "scons" script is the 
  48  # "SCons" package.  Replace it with our own version directory so, if 
  49  # if they're there, we pick up the right version of the build engine 
  50  # modules. 
  51  #sys.path = [os.path.join(sys.prefix, 
  52  #                         'lib', 
  53  #                         'scons-%d' % SCons.__version__)] + sys.path[1:] 
  54   
  55  import SCons.CacheDir 
  56  import SCons.Debug 
  57  import SCons.Defaults 
  58  import SCons.Environment 
  59  import SCons.Errors 
  60  import SCons.Job 
  61  import SCons.Node 
  62  import SCons.Node.FS 
  63  import SCons.SConf 
  64  import SCons.Script 
  65  import SCons.Taskmaster 
  66  import SCons.Util 
  67  import SCons.Warnings 
  68   
  69  import SCons.Script.Interactive 
  70   
71 -def fetch_win32_parallel_msg():
72 # A subsidiary function that exists solely to isolate this import 73 # so we don't have to pull it in on all platforms, and so that an 74 # in-line "import" statement in the _main() function below doesn't 75 # cause warnings about local names shadowing use of the 'SCons' 76 # globl in nest scopes and UnboundLocalErrors and the like in some 77 # versions (2.1) of Python. 78 import SCons.Platform.win32 79 return SCons.Platform.win32.parallel_msg
80 81 # 82
83 -class SConsPrintHelpException(Exception):
84 pass
85 86 display = SCons.Util.display 87 progress_display = SCons.Util.DisplayEngine() 88 89 first_command_start = None 90 last_command_end = None 91
92 -class Progressor:
93 prev = '' 94 count = 0 95 target_string = '$TARGET' 96
97 - def __init__(self, obj, interval=1, file=None, overwrite=False):
98 if file is None: 99 file = sys.stdout 100 101 self.obj = obj 102 self.file = file 103 self.interval = interval 104 self.overwrite = overwrite 105 106 if callable(obj): 107 self.func = obj 108 elif SCons.Util.is_List(obj): 109 self.func = self.spinner 110 elif string.find(obj, self.target_string) != -1: 111 self.func = self.replace_string 112 else: 113 self.func = self.string
114
115 - def write(self, s):
116 self.file.write(s) 117 self.file.flush() 118 self.prev = s
119
120 - def erase_previous(self):
121 if self.prev: 122 length = len(self.prev) 123 if self.prev[-1] in ('\n', '\r'): 124 length = length - 1 125 self.write(' ' * length + '\r') 126 self.prev = ''
127
128 - def spinner(self, node):
129 self.write(self.obj[self.count % len(self.obj)])
130
131 - def string(self, node):
132 self.write(self.obj)
133
134 - def replace_string(self, node):
135 self.write(string.replace(self.obj, self.target_string, str(node)))
136
137 - def __call__(self, node):
138 self.count = self.count + 1 139 if (self.count % self.interval) == 0: 140 if self.overwrite: 141 self.erase_previous() 142 self.func(node)
143 144 ProgressObject = SCons.Util.Null() 145
146 -def Progress(*args, **kw):
147 global ProgressObject 148 ProgressObject = apply(Progressor, args, kw)
149 150 # Task control. 151 # 152 153 _BuildFailures = [] 154
155 -def GetBuildFailures():
156 return _BuildFailures
157
158 -class BuildTask(SCons.Taskmaster.Task):
159 """An SCons build task.""" 160 progress = ProgressObject 161
162 - def display(self, message):
163 display('scons: ' + message)
164
165 - def prepare(self):
166 self.progress(self.targets[0]) 167 return SCons.Taskmaster.Task.prepare(self)
168
169 - def needs_execute(self):
170 target = self.targets[0] 171 if target.get_state() == SCons.Node.executing: 172 return True 173 else: 174 if self.top and target.has_builder(): 175 display("scons: `%s' is up to date." % str(self.node)) 176 return False
177
178 - def execute(self):
179 if print_time: 180 start_time = time.time() 181 global first_command_start 182 if first_command_start is None: 183 first_command_start = start_time 184 SCons.Taskmaster.Task.execute(self) 185 if print_time: 186 global cumulative_command_time 187 global last_command_end 188 finish_time = time.time() 189 last_command_end = finish_time 190 cumulative_command_time = cumulative_command_time+finish_time-start_time 191 sys.stdout.write("Command execution time: %f seconds\n"%(finish_time-start_time))
192
193 - def do_failed(self, status=2):
194 _BuildFailures.append(self.exception[1]) 195 global exit_status 196 global this_build_status 197 if self.options.ignore_errors: 198 SCons.Taskmaster.Task.executed(self) 199 elif self.options.keep_going: 200 SCons.Taskmaster.Task.fail_continue(self) 201 exit_status = status 202 this_build_status = status 203 else: 204 SCons.Taskmaster.Task.fail_stop(self) 205 exit_status = status 206 this_build_status = status
207
208 - def executed(self):
209 t = self.targets[0] 210 if self.top and not t.has_builder() and not t.side_effect: 211 if not t.exists(): 212 errstr="Do not know how to make target `%s'." % t 213 sys.stderr.write("scons: *** " + errstr) 214 if not self.options.keep_going: 215 sys.stderr.write(" Stop.") 216 sys.stderr.write("\n") 217 try: 218 raise SCons.Errors.BuildError(t, errstr) 219 except KeyboardInterrupt: 220 raise 221 except: 222 self.exception_set() 223 self.do_failed() 224 else: 225 print "scons: Nothing to be done for `%s'." % t 226 SCons.Taskmaster.Task.executed(self) 227 else: 228 SCons.Taskmaster.Task.executed(self)
229
230 - def failed(self):
231 # Handle the failure of a build task. The primary purpose here 232 # is to display the various types of Errors and Exceptions 233 # appropriately. 234 exc_info = self.exc_info() 235 try: 236 t, e, tb = exc_info 237 except ValueError: 238 t, e = exc_info 239 tb = None 240 241 if t is None: 242 # The Taskmaster didn't record an exception for this Task; 243 # see if the sys module has one. 244 try: 245 t, e, tb = sys.exc_info()[:] 246 except ValueError: 247 t, e = exc_info 248 tb = None 249 250 # Deprecated string exceptions will have their string stored 251 # in the first entry of the tuple. 252 if e is None: 253 e = t 254 255 buildError = SCons.Errors.convert_to_BuildError(e) 256 if not buildError.node: 257 buildError.node = self.node 258 259 node = buildError.node 260 if not SCons.Util.is_List(node): 261 node = [ node ] 262 nodename = string.join(map(str, node), ', ') 263 264 errfmt = "scons: *** [%s] %s\n" 265 sys.stderr.write(errfmt % (nodename, buildError)) 266 267 if (buildError.exc_info[2] and buildError.exc_info[1] and 268 # TODO(1.5) 269 #not isinstance( 270 # buildError.exc_info[1], 271 # (EnvironmentError, SCons.Errors.StopError, SCons.Errors.UserError))): 272 not isinstance(buildError.exc_info[1], EnvironmentError) and 273 not isinstance(buildError.exc_info[1], SCons.Errors.StopError) and 274 not isinstance(buildError.exc_info[1], SCons.Errors.UserError)): 275 type, value, trace = buildError.exc_info 276 traceback.print_exception(type, value, trace) 277 elif tb and print_stacktrace: 278 sys.stderr.write("scons: internal stack trace:\n") 279 traceback.print_tb(tb, file=sys.stderr) 280 281 self.exception = (e, buildError, tb) # type, value, traceback 282 self.do_failed(buildError.exitstatus) 283 284 self.exc_clear()
285
286 - def postprocess(self):
287 if self.top: 288 t = self.targets[0] 289 for tp in self.options.tree_printers: 290 tp.display(t) 291 if self.options.debug_includes: 292 tree = t.render_include_tree() 293 if tree: 294 print 295 print tree 296 SCons.Taskmaster.Task.postprocess(self)
297
298 - def make_ready(self):
299 """Make a task ready for execution""" 300 SCons.Taskmaster.Task.make_ready(self) 301 if self.out_of_date and self.options.debug_explain: 302 explanation = self.out_of_date[0].explain() 303 if explanation: 304 sys.stdout.write("scons: " + explanation)
305
306 -class CleanTask(SCons.Taskmaster.Task):
307 """An SCons clean task."""
308 - def fs_delete(self, path, pathstr, remove=1):
309 try: 310 if