OLD | NEW |
(Empty) | |
| 1 # |
| 2 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining |
| 5 # a copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, |
| 8 # distribute, sublicense, and/or sell copies of the Software, and to |
| 9 # permit persons to whom the Software is furnished to do so, subject to |
| 10 # the following conditions: |
| 11 # |
| 12 # The above copyright notice and this permission notice shall be included |
| 13 # in all copies or substantial portions of the Software. |
| 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 22 # |
| 23 |
| 24 __revision__ = "src/engine/SCons/Script/SConsOptions.py 5134 2010/08/16 23:02:40
bdeegan" |
| 25 |
| 26 import optparse |
| 27 import re |
| 28 import sys |
| 29 import textwrap |
| 30 |
| 31 no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') |
| 32 |
| 33 try: |
| 34 from gettext import gettext |
| 35 except ImportError: |
| 36 def gettext(message): |
| 37 return message |
| 38 _ = gettext |
| 39 |
| 40 import SCons.Node.FS |
| 41 import SCons.Warnings |
| 42 |
| 43 OptionValueError = optparse.OptionValueError |
| 44 SUPPRESS_HELP = optparse.SUPPRESS_HELP |
| 45 |
| 46 diskcheck_all = SCons.Node.FS.diskcheck_types() |
| 47 |
| 48 def diskcheck_convert(value): |
| 49 if value is None: |
| 50 return [] |
| 51 if not SCons.Util.is_List(value): |
| 52 value = value.split(',') |
| 53 result = [] |
| 54 for v in value: |
| 55 v = v.lower() |
| 56 if v == 'all': |
| 57 result = diskcheck_all |
| 58 elif v == 'none': |
| 59 result = [] |
| 60 elif v in diskcheck_all: |
| 61 result.append(v) |
| 62 else: |
| 63 raise ValueError(v) |
| 64 return result |
| 65 |
| 66 class SConsValues(optparse.Values): |
| 67 """ |
| 68 Holder class for uniform access to SCons options, regardless |
| 69 of whether or not they can be set on the command line or in the |
| 70 SConscript files (using the SetOption() function). |
| 71 |
| 72 A SCons option value can originate three different ways: |
| 73 |
| 74 1) set on the command line; |
| 75 2) set in an SConscript file; |
| 76 3) the default setting (from the the op.add_option() |
| 77 calls in the Parser() function, below). |
| 78 |
| 79 The command line always overrides a value set in a SConscript file, |
| 80 which in turn always overrides default settings. Because we want |
| 81 to support user-specified options in the SConscript file itself, |
| 82 though, we may not know about all of the options when the command |
| 83 line is first parsed, so we can't make all the necessary precedence |
| 84 decisions at the time the option is configured. |
| 85 |
| 86 The solution implemented in this class is to keep these different sets |
| 87 of settings separate (command line, SConscript file, and default) |
| 88 and to override the __getattr__() method to check them in turn. |
| 89 This should allow the rest of the code to just fetch values as |
| 90 attributes of an instance of this class, without having to worry |
| 91 about where they came from. |
| 92 |
| 93 Note that not all command line options are settable from SConscript |
| 94 files, and the ones that are must be explicitly added to the |
| 95 "settable" list in this class, and optionally validated and coerced |
| 96 in the set_option() method. |
| 97 """ |
| 98 |
| 99 def __init__(self, defaults): |
| 100 self.__dict__['__defaults__'] = defaults |
| 101 self.__dict__['__SConscript_settings__'] = {} |
| 102 |
| 103 def __getattr__(self, attr): |
| 104 """ |
| 105 Fetches an options value, checking first for explicit settings |
| 106 from the command line (which are direct attributes), then the |
| 107 SConscript file settings, then the default values. |
| 108 """ |
| 109 try: |
| 110 return self.__dict__[attr] |
| 111 except KeyError: |
| 112 try: |
| 113 return self.__dict__['__SConscript_settings__'][attr] |
| 114 except KeyError: |
| 115 return getattr(self.__dict__['__defaults__'], attr) |
| 116 |
| 117 settable = [ |
| 118 'clean', |
| 119 'diskcheck', |
| 120 'duplicate', |
| 121 'help', |
| 122 'implicit_cache', |
| 123 'max_drift', |
| 124 'md5_chunksize', |
| 125 'no_exec', |
| 126 'num_jobs', |
| 127 'random', |
| 128 'stack_size', |
| 129 'warn', |
| 130 ] |
| 131 |
| 132 def set_option(self, name, value): |
| 133 """ |
| 134 Sets an option from an SConscript file. |
| 135 """ |
| 136 if not name in self.settable: |
| 137 raise SCons.Errors.UserError("This option is not settable from a SCo
nscript file: %s"%name) |
| 138 |
| 139 if name == 'num_jobs': |
| 140 try: |
| 141 value = int(value) |
| 142 if value < 1: |
| 143 raise ValueError |
| 144 except ValueError: |
| 145 raise SCons.Errors.UserError("A positive integer is required: %s
"%repr(value)) |
| 146 elif name == 'max_drift': |
| 147 try: |
| 148 value = int(value) |
| 149 except ValueError: |
| 150 raise SCons.Errors.UserError("An integer is required: %s"%repr(v
alue)) |
| 151 elif name == 'duplicate': |
| 152 try: |
| 153 value = str(value) |
| 154 except ValueError: |
| 155 raise SCons.Errors.UserError("A string is required: %s"%repr(val
ue)) |
| 156 if not value in SCons.Node.FS.Valid_Duplicates: |
| 157 raise SCons.Errors.UserError("Not a valid duplication style: %s"
% value) |
| 158 # Set the duplicate style right away so it can affect linking |
| 159 # of SConscript files. |
| 160 SCons.Node.FS.set_duplicate(value) |
| 161 elif name == 'diskcheck': |
| 162 try: |
| 163 value = diskcheck_convert(value) |
| 164 except ValueError, v: |
| 165 raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v
) |
| 166 if 'diskcheck' not in self.__dict__: |
| 167 # No --diskcheck= option was specified on the command line. |
| 168 # Set this right away so it can affect the rest of the |
| 169 # file/Node lookups while processing the SConscript files. |
| 170 SCons.Node.FS.set_diskcheck(value) |
| 171 elif name == 'stack_size': |
| 172 try: |
| 173 value = int(value) |
| 174 except ValueError: |
| 175 raise SCons.Errors.UserError("An integer is required: %s"%repr(v
alue)) |
| 176 elif name == 'md5_chunksize': |
| 177 try: |
| 178 value = int(value) |
| 179 except ValueError: |
| 180 raise SCons.Errors.UserError("An integer is required: %s"%repr(v
alue)) |
| 181 elif name == 'warn': |
| 182 if SCons.Util.is_String(value): |
| 183 value = [value] |
| 184 value = self.__SConscript_settings__.get(name, []) + value |
| 185 SCons.Warnings.process_warn_strings(value) |
| 186 |
| 187 self.__SConscript_settings__[name] = value |
| 188 |
| 189 class SConsOption(optparse.Option): |
| 190 def convert_value(self, opt, value): |
| 191 if value is not None: |
| 192 if self.nargs in (1, '?'): |
| 193 return self.check_value(opt, value) |
| 194 else: |
| 195 return tuple([self.check_value(opt, v) for v in value]) |
| 196 |
| 197 def process(self, opt, value, values, parser): |
| 198 |
| 199 # First, convert the value(s) to the right type. Howl if any |
| 200 # value(s) are bogus. |
| 201 value = self.convert_value(opt, value) |
| 202 |
| 203 # And then take whatever action is expected of us. |
| 204 # This is a separate method to make life easier for |
| 205 # subclasses to add new actions. |
| 206 return self.take_action( |
| 207 self.action, self.dest, opt, value, values, parser) |
| 208 |
| 209 def _check_nargs_optional(self): |
| 210 if self.nargs == '?' and self._short_opts: |
| 211 fmt = "option %s: nargs='?' is incompatible with short options" |
| 212 raise SCons.Errors.UserError(fmt % self._short_opts[0]) |
| 213 |
| 214 try: |
| 215 _orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS |
| 216 |
| 217 _orig_CHECK_METHODS = optparse.Option.CHECK_METHODS |
| 218 |
| 219 except AttributeError: |
| 220 # optparse.Option had no CONST_ACTIONS before Python 2.5. |
| 221 |
| 222 _orig_CONST_ACTIONS = ("store_const",) |
| 223 |
| 224 def _check_const(self): |
| 225 if self.action not in self.CONST_ACTIONS and self.const is not None: |
| 226 raise OptionError( |
| 227 "'const' must not be supplied for action %r" % self.action, |
| 228 self) |
| 229 |
| 230 # optparse.Option collects its list of unbound check functions |
| 231 # up front. This sucks because it means we can't just override |
| 232 # the _check_const() function like a normal method, we have to |
| 233 # actually replace it in the list. This seems to be the most |
| 234 # straightforward way to do that. |
| 235 |
| 236 _orig_CHECK_METHODS = [optparse.Option._check_action, |
| 237 optparse.Option._check_type, |
| 238 optparse.Option._check_choice, |
| 239 optparse.Option._check_dest, |
| 240 _check_const, |
| 241 optparse.Option._check_nargs, |
| 242 optparse.Option._check_callback] |
| 243 |
| 244 CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional] |
| 245 |
| 246 CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS |
| 247 |
| 248 class SConsOptionGroup(optparse.OptionGroup): |
| 249 """ |
| 250 A subclass for SCons-specific option groups. |
| 251 |
| 252 The only difference between this and the base class is that we print |
| 253 the group's help text flush left, underneath their own title but |
| 254 lined up with the normal "SCons Options". |
| 255 """ |
| 256 def format_help(self, formatter): |
| 257 """ |
| 258 Format an option group's help text, outdenting the title so it's |
| 259 flush with the "SCons Options" title we print at the top. |
| 260 """ |
| 261 formatter.dedent() |
| 262 result = formatter.format_heading(self.title) |
| 263 formatter.indent() |
| 264 result = result + optparse.OptionContainer.format_help(self, formatter) |
| 265 return result |
| 266 |
| 267 class SConsOptionParser(optparse.OptionParser): |
| 268 preserve_unknown_options = False |
| 269 |
| 270 def error(self, msg): |
| 271 self.print_usage(sys.stderr) |
| 272 sys.stderr.write("SCons error: %s\n" % msg) |
| 273 sys.exit(2) |
| 274 |
| 275 def _process_long_opt(self, rargs, values): |
| 276 """ |
| 277 SCons-specific processing of long options. |
| 278 |
| 279 This is copied directly from the normal |
| 280 optparse._process_long_opt() method, except that, if configured |
| 281 to do so, we catch the exception thrown when an unknown option |
| 282 is encountered and just stick it back on the "leftover" arguments |
| 283 for later (re-)processing. |
| 284 """ |
| 285 arg = rargs.pop(0) |
| 286 |
| 287 # Value explicitly attached to arg? Pretend it's the next |
| 288 # argument. |
| 289 if "=" in arg: |
| 290 (opt, next_arg) = arg.split("=", 1) |
| 291 rargs.insert(0, next_arg) |
| 292 had_explicit_value = True |
| 293 else: |
| 294 opt = arg |
| 295 had_explicit_value = False |
| 296 |
| 297 try: |
| 298 opt = self._match_long_opt(opt) |
| 299 except optparse.BadOptionError: |
| 300 if self.preserve_unknown_options: |
| 301 # SCons-specific: if requested, add unknown options to |
| 302 # the "leftover arguments" list for later processing. |
| 303 self.largs.append(arg) |
| 304 if had_explicit_value: |
| 305 # The unknown option will be re-processed later, |
| 306 # so undo the insertion of the explicit value. |
| 307 rargs.pop(0) |
| 308 return |
| 309 raise |
| 310 |
| 311 option = self._long_opt[opt] |
| 312 if option.takes_value(): |
| 313 nargs = option.nargs |
| 314 if nargs == '?': |
| 315 if had_explicit_value: |
| 316 value = rargs.pop(0) |
| 317 else: |
| 318 value = option.const |
| 319 elif len(rargs) < nargs: |
| 320 if nargs == 1: |
| 321 self.error(_("%s option requires an argument") % opt) |
| 322 else: |
| 323 self.error(_("%s option requires %d arguments") |
| 324 % (opt, nargs)) |
| 325 elif nargs == 1: |
| 326 value = rargs.pop(0) |
| 327 else: |
| 328 value = tuple(rargs[0:nargs]) |
| 329 del rargs[0:nargs] |
| 330 |
| 331 elif had_explicit_value: |
| 332 self.error(_("%s option does not take a value") % opt) |
| 333 |
| 334 else: |
| 335 value = None |
| 336 |
| 337 option.process(opt, value, values, self) |
| 338 |
| 339 def add_local_option(self, *args, **kw): |
| 340 """ |
| 341 Adds a local option to the parser. |
| 342 |
| 343 This is initiated by a SetOption() call to add a user-defined |
| 344 command-line option. We add the option to a separate option |
| 345 group for the local options, creating the group if necessary. |
| 346 """ |
| 347 try: |
| 348 group = self.local_option_group |
| 349 except AttributeError: |
| 350 group = SConsOptionGroup(self, 'Local Options') |
| 351 group = self.add_option_group(group) |
| 352 self.local_option_group = group |
| 353 |
| 354 result = group.add_option(*args, **kw) |
| 355 |
| 356 if result: |
| 357 # The option was added succesfully. We now have to add the |
| 358 # default value to our object that holds the default values |
| 359 # (so that an attempt to fetch the option's attribute will |
| 360 # yield the default value when not overridden) and then |
| 361 # we re-parse the leftover command-line options, so that |
| 362 # any value overridden on the command line is immediately |
| 363 # available if the user turns around and does a GetOption() |
| 364 # right away. |
| 365 setattr(self.values.__defaults__, result.dest, result.default) |
| 366 self.parse_args(self.largs, self.values) |
| 367 |
| 368 return result |
| 369 |
| 370 class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): |
| 371 def format_usage(self, usage): |
| 372 return "usage: %s\n" % usage |
| 373 |
| 374 def format_heading(self, heading): |
| 375 """ |
| 376 This translates any heading of "options" or "Options" into |
| 377 "SCons Options." Unfortunately, we have to do this here, |
| 378 because those titles are hard-coded in the optparse calls. |
| 379 """ |
| 380 if heading == 'options': |
| 381 # The versions of optparse.py shipped with Pythons 2.3 and |
| 382 # 2.4 pass this in uncapitalized; override that so we get |
| 383 # consistent output on all versions. |
| 384 heading = "Options" |
| 385 if heading == 'Options': |
| 386 heading = "SCons Options" |
| 387 return optparse.IndentedHelpFormatter.format_heading(self, heading) |
| 388 |
| 389 def format_option(self, option): |
| 390 """ |
| 391 A copy of the normal optparse.IndentedHelpFormatter.format_option() |
| 392 method. This has been snarfed so we can modify text wrapping to |
| 393 out liking: |
| 394 |
| 395 -- add our own regular expression that doesn't break on hyphens |
| 396 (so things like --no-print-directory don't get broken); |
| 397 |
| 398 -- wrap the list of options themselves when it's too long |
| 399 (the wrapper.fill(opts) call below); |
| 400 |
| 401 -- set the subsequent_indent when wrapping the help_text. |
| 402 """ |
| 403 # The help for each option consists of two parts: |
| 404 # * the opt strings and metavars |
| 405 # eg. ("-x", or "-fFILENAME, --file=FILENAME") |
| 406 # * the user-supplied help string |
| 407 # eg. ("turn on expert mode", "read data from FILENAME") |
| 408 # |
| 409 # If possible, we write both of these on the same line: |
| 410 # -x turn on expert mode |
| 411 # |
| 412 # But if the opt string list is too long, we put the help |
| 413 # string on a second line, indented to the same column it would |
| 414 # start in if it fit on the first line. |
| 415 # -fFILENAME, --file=FILENAME |
| 416 # read data from FILENAME |
| 417 result = [] |
| 418 |
| 419 try: |
| 420 opts = self.option_strings[option] |
| 421 except AttributeError: |
| 422 # The Python 2.3 version of optparse attaches this to |
| 423 # to the option argument, not to this object. |
| 424 opts = option.option_strings |
| 425 |
| 426 opt_width = self.help_position - self.current_indent - 2 |
| 427 if len(opts) > opt_width: |
| 428 wrapper = textwrap.TextWrapper(width=self.width, |
| 429 initial_indent = ' ', |
| 430 subsequent_indent = ' ') |
| 431 wrapper.wordsep_re = no_hyphen_re |
| 432 opts = wrapper.fill(opts) + '\n' |
| 433 indent_first = self.help_position |
| 434 else: # start help on same line as opts |
| 435 opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) |
| 436 indent_first = 0 |
| 437 result.append(opts) |
| 438 if option.help: |
| 439 |
| 440 try: |
| 441 expand_default = self.expand_default |
| 442 except AttributeError: |
| 443 # The HelpFormatter base class in the Python 2.3 version |
| 444 # of optparse has no expand_default() method. |
| 445 help_text = option.help |
| 446 else: |
| 447 help_text = expand_default(option) |
| 448 |
| 449 # SCons: indent every line of the help text but the first. |
| 450 wrapper = textwrap.TextWrapper(width=self.help_width, |
| 451 subsequent_indent = ' ') |
| 452 wrapper.wordsep_re = no_hyphen_re |
| 453 help_lines = wrapper.wrap(help_text) |
| 454 result.append("%*s%s\n" % (indent_first, "", help_lines[0])) |
| 455 for line in help_lines[1:]: |
| 456 result.append("%*s%s\n" % (self.help_position, "", line)) |
| 457 elif opts[-1] != "\n": |
| 458 result.append("\n") |
| 459 return "".join(result) |
| 460 |
| 461 # For consistent help output across Python versions, we provide a |
| 462 # subclass copy of format_option_strings() and these two variables. |
| 463 # This is necessary (?) for Python2.3, which otherwise concatenates |
| 464 # a short option with its metavar. |
| 465 _short_opt_fmt = "%s %s" |
| 466 _long_opt_fmt = "%s=%s" |
| 467 |
| 468 def format_option_strings(self, option): |
| 469 """Return a comma-separated list of option strings & metavariables.""" |
| 470 if option.takes_value(): |
| 471 metavar = option.metavar or option.dest.upper() |
| 472 short_opts = [] |
| 473 for sopt in option._short_opts: |
| 474 short_opts.append(self._short_opt_fmt % (sopt, metavar)) |
| 475 long_opts = [] |
| 476 for lopt in option._long_opts: |
| 477 long_opts.append(self._long_opt_fmt % (lopt, metavar)) |
| 478 else: |
| 479 short_opts = option._short_opts |
| 480 long_opts = option._long_opts |
| 481 |
| 482 if self.short_first: |
| 483 opts = short_opts + long_opts |
| 484 else: |
| 485 opts = long_opts + short_opts |
| 486 |
| 487 return ", ".join(opts) |
| 488 |
| 489 def Parser(version): |
| 490 """ |
| 491 Returns an options parser object initialized with the standard |
| 492 SCons options. |
| 493 """ |
| 494 |
| 495 formatter = SConsIndentedHelpFormatter(max_help_position=30) |
| 496 |
| 497 op = SConsOptionParser(option_class=SConsOption, |
| 498 add_help_option=False, |
| 499 formatter=formatter, |
| 500 usage="usage: scons [OPTION] [TARGET] ...",) |
| 501 |
| 502 op.preserve_unknown_options = True |
| 503 op.version = version |
| 504 |
| 505 # Add the options to the parser we just created. |
| 506 # |
| 507 # These are in the order we want them to show up in the -H help |
| 508 # text, basically alphabetical. Each op.add_option() call below |
| 509 # should have a consistent format: |
| 510 # |
| 511 # op.add_option("-L", "--long-option-name", |
| 512 # nargs=1, type="string", |
| 513 # dest="long_option_name", default='foo', |
| 514 # action="callback", callback=opt_long_option, |
| 515 # help="help text goes here", |
| 516 # metavar="VAR") |
| 517 # |
| 518 # Even though the optparse module constructs reasonable default |
| 519 # destination names from the long option names, we're going to be |
| 520 # explicit about each one for easier readability and so this code |
| 521 # will at least show up when grepping the source for option attribute |
| 522 # names, or otherwise browsing the source code. |
| 523 |
| 524 # options ignored for compatibility |
| 525 def opt_ignore(option, opt, value, parser): |
| 526 sys.stderr.write("Warning: ignoring %s option\n" % opt) |
| 527 op.add_option("-b", "-d", "-e", "-m", "-S", "-t", "-w", |
| 528 "--environment-overrides", |
| 529 "--no-keep-going", |
| 530 "--no-print-directory", |
| 531 "--print-directory", |
| 532 "--stop", |
| 533 "--touch", |
| 534 action="callback", callback=opt_ignore, |
| 535 help="Ignored for compatibility.") |
| 536 |
| 537 op.add_option('-c', '--clean', '--remove', |
| 538 dest="clean", default=False, |
| 539 action="store_true", |
| 540 help="Remove specified targets and dependencies.") |
| 541 |
| 542 op.add_option('-C', '--directory', |
| 543 nargs=1, type="string", |
| 544 dest="directory", default=[], |
| 545 action="append", |
| 546 help="Change to DIR before doing anything.", |
| 547 metavar="DIR") |
| 548 |
| 549 op.add_option('--cache-debug', |
| 550 nargs=1, |
| 551 dest="cache_debug", default=None, |
| 552 action="store", |
| 553 help="Print CacheDir debug info to FILE.", |
| 554 metavar="FILE") |
| 555 |
| 556 op.add_option('--cache-disable', '--no-cache', |
| 557 dest='cache_disable', default=False, |
| 558 action="store_true", |
| 559 help="Do not retrieve built targets from CacheDir.") |
| 560 |
| 561 op.add_option('--cache-force', '--cache-populate', |
| 562 dest='cache_force', default=False, |
| 563 action="store_true", |
| 564 help="Copy already-built targets into the CacheDir.") |
| 565 |
| 566 op.add_option('--cache-show', |
| 567 dest='cache_show', default=False, |
| 568 action="store_true", |
| 569 help="Print build actions for files from CacheDir.") |
| 570 |
| 571 config_options = ["auto", "force" ,"cache"] |
| 572 |
| 573 def opt_config(option, opt, value, parser, c_options=config_options): |
| 574 if not value in c_options: |
| 575 raise OptionValueError("Warning: %s is not a valid config type" % v
alue) |
| 576 setattr(parser.values, option.dest, value) |
| 577 opt_config_help = "Controls Configure subsystem: %s." \ |
| 578 % ", ".join(config_options) |
| 579 op.add_option('--config', |
| 580 nargs=1, type="string", |
| 581 dest="config", default="auto", |
| 582 action="callback", callback=opt_config, |
| 583 help = opt_config_help, |
| 584 metavar="MODE") |
| 585 |
| 586 op.add_option('-D', |
| 587 dest="climb_up", default=None, |
| 588 action="store_const", const=2, |
| 589 help="Search up directory tree for SConstruct, " |
| 590 "build all Default() targets.") |
| 591 |
| 592 deprecated_debug_options = { |
| 593 "dtree" : '; please use --tree=derived instead', |
| 594 "nomemoizer" : ' and has no effect', |
| 595 "stree" : '; please use --tree=all,status instead', |
| 596 "tree" : '; please use --tree=all instead', |
| 597 } |
| 598 |
| 599 debug_options = ["count", "explain", "findlibs", |
| 600 "includes", "memoizer", "memory", "objects", |
| 601 "pdb", "presub", "stacktrace", |
| 602 "time"] + list(deprecated_debug_options.keys()) |
| 603 |
| 604 def opt_debug(option, opt, value, parser, |
| 605 debug_options=debug_options, |
| 606 deprecated_debug_options=deprecated_debug_options): |
| 607 if value in debug_options: |
| 608 parser.values.debug.append(value) |
| 609 if value in deprecated_debug_options.keys(): |
| 610 try: |
| 611 parser.values.delayed_warnings |
| 612 except AttributeError: |
| 613 parser.values.delayed_warnings = [] |
| 614 msg = deprecated_debug_options[value] |
| 615 w = "The --debug=%s option is deprecated%s." % (value, msg) |
| 616 t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w) |
| 617 parser.values.delayed_warnings.append(t) |
| 618 else: |
| 619 raise OptionValueError("Warning: %s is not a valid debug type" % va
lue) |
| 620 opt_debug_help = "Print various types of debugging information: %s." \ |
| 621 % ", ".join(debug_options) |
| 622 op.add_option('--debug', |
| 623 nargs=1, type="string", |
| 624 dest="debug", default=[], |
| 625 action="callback", callback=opt_debug, |
| 626 help=opt_debug_help, |
| 627 metavar="TYPE") |
| 628 |
| 629 def opt_diskcheck(option, opt, value, parser): |
| 630 try: |
| 631 diskcheck_value = diskcheck_convert(value) |
| 632 except ValueError, e: |
| 633 raise OptionValueError("Warning: `%s' is not a valid diskcheck type"
% e) |
| 634 setattr(parser.values, option.dest, diskcheck_value) |
| 635 |
| 636 op.add_option('--diskcheck', |
| 637 nargs=1, type="string", |
| 638 dest='diskcheck', default=None, |
| 639 action="callback", callback=opt_diskcheck, |
| 640 help="Enable specific on-disk checks.", |
| 641 metavar="TYPE") |
| 642 |
| 643 def opt_duplicate(option, opt, value, parser): |
| 644 if not value in SCons.Node.FS.Valid_Duplicates: |
| 645 raise OptionValueError("`%s' is not a valid duplication style." % va
lue) |
| 646 setattr(parser.values, option.dest, value) |
| 647 # Set the duplicate style right away so it can affect linking |
| 648 # of SConscript files. |
| 649 SCons.Node.FS.set_duplicate(value) |
| 650 |
| 651 opt_duplicate_help = "Set the preferred duplication methods. Must be one of
" \ |
| 652 + ", ".join(SCons.Node.FS.Valid_Duplicates) |
| 653 |
| 654 op.add_option('--duplicate', |
| 655 nargs=1, type="string", |
| 656 dest="duplicate", default='hard-soft-copy', |
| 657 action="callback", callback=opt_duplicate, |
| 658 help=opt_duplicate_help) |
| 659 |
| 660 op.add_option('-f', '--file', '--makefile', '--sconstruct', |
| 661 nargs=1, type="string", |
| 662 dest="file", default=[], |
| 663 action="append", |
| 664 help="Read FILE as the top-level SConstruct file.") |
| 665 |
| 666 op.add_option('-h', '--help', |
| 667 dest="help", default=False, |
| 668 action="store_true", |
| 669 help="Print defined help message, or this one.") |
| 670 |
| 671 op.add_option("-H", "--help-options", |
| 672 action="help", |
| 673 help="Print this message and exit.") |
| 674 |
| 675 op.add_option('-i', '--ignore-errors', |
| 676 dest='ignore_errors', default=False, |
| 677 action="store_true", |
| 678 help="Ignore errors from build actions.") |
| 679 |
| 680 op.add_option('-I', '--include-dir', |
| 681 nargs=1, |
| 682 dest='include_dir', default=[], |
| 683 action="append", |
| 684 help="Search DIR for imported Python modules.", |
| 685 metavar="DIR") |
| 686 |
| 687 op.add_option('--implicit-cache', |
| 688 dest='implicit_cache', default=False, |
| 689 action="store_true", |
| 690 help="Cache implicit dependencies") |
| 691 |
| 692 def opt_implicit_deps(option, opt, value, parser): |
| 693 setattr(parser.values, 'implicit_cache', True) |
| 694 setattr(parser.values, option.dest, True) |
| 695 |
| 696 op.add_option('--implicit-deps-changed', |
| 697 dest="implicit_deps_changed", default=False, |
| 698 action="callback", callback=opt_implicit_deps, |
| 699 help="Ignore cached implicit dependencies.") |
| 700 |
| 701 op.add_option('--implicit-deps-unchanged', |
| 702 dest="implicit_deps_unchanged", default=False, |
| 703 action="callback", callback=opt_implicit_deps, |
| 704 help="Ignore changes in implicit dependencies.") |
| 705 |
| 706 op.add_option('--interact', '--interactive', |
| 707 dest='interactive', default=False, |
| 708 action="store_true", |
| 709 help="Run in interactive mode.") |
| 710 |
| 711 op.add_option('-j', '--jobs', |
| 712 nargs=1, type="int", |
| 713 dest="num_jobs", default=1, |
| 714 action="store", |
| 715 help="Allow N jobs at once.", |
| 716 metavar="N") |
| 717 |
| 718 op.add_option('-k', '--keep-going', |
| 719 dest='keep_going', default=False, |
| 720 action="store_true", |
| 721 help="Keep going when a target can't be made.") |
| 722 |
| 723 op.add_option('--max-drift', |
| 724 nargs=1, type="int", |
| 725 dest='max_drift', default=SCons.Node.FS.default_max_drift, |
| 726 action="store", |
| 727 help="Set maximum system clock drift to N seconds.", |
| 728 metavar="N") |
| 729 |
| 730 op.add_option('--md5-chunksize', |
| 731 nargs=1, type="int", |
| 732 dest='md5_chunksize', default=SCons.Node.FS.File.md5_chunksize
, |
| 733 action="store", |
| 734 help="Set chunk-size for MD5 signature computation to N kiloby
tes.", |
| 735 metavar="N") |
| 736 |
| 737 op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon', |
| 738 dest='no_exec', default=False, |
| 739 action="store_true", |
| 740 help="Don't build; just print commands.") |
| 741 |
| 742 op.add_option('--no-site-dir', |
| 743 dest='no_site_dir', default=False, |
| 744 action="store_true", |
| 745 help="Don't search or use the usual site_scons dir.") |
| 746 |
| 747 op.add_option('--profile', |
| 748 nargs=1, |
| 749 dest="profile_file", default=None, |
| 750 action="store", |
| 751 help="Profile SCons and put results in FILE.", |
| 752 metavar="FILE") |
| 753 |
| 754 op.add_option('-q', '--question', |
| 755 dest="question", default=False, |
| 756 action="store_true", |
| 757 help="Don't build; exit status says if up to date.") |
| 758 |
| 759 op.add_option('-Q', |
| 760 dest='no_progress', default=False, |
| 761 action="store_true", |
| 762 help="Suppress \"Reading/Building\" progress messages.") |
| 763 |
| 764 op.add_option('--random', |
| 765 dest="random", default=False, |
| 766 action="store_true", |
| 767 help="Build dependencies in random order.") |
| 768 |
| 769 op.add_option('-s', '--silent', '--quiet', |
| 770 dest="silent", default=False, |
| 771 action="store_true", |
| 772 help="Don't print commands.") |
| 773 |
| 774 op.add_option('--site-dir', |
| 775 nargs=1, |
| 776 dest='site_dir', default=None, |
| 777 action="store", |
| 778 help="Use DIR instead of the usual site_scons dir.", |
| 779 metavar="DIR") |
| 780 |
| 781 op.add_option('--stack-size', |
| 782 nargs=1, type="int", |
| 783 dest='stack_size', |
| 784 action="store", |
| 785 help="Set the stack size of the threads used to run jobs to N
kilobytes.", |
| 786 metavar="N") |
| 787 |
| 788 op.add_option('--taskmastertrace', |
| 789 nargs=1, |
| 790 dest="taskmastertrace_file", default=None, |
| 791 action="store", |
| 792 help="Trace Node evaluation to FILE.", |
| 793 metavar="FILE") |
| 794 |
| 795 tree_options = ["all", "derived", "prune", "status"] |
| 796 |
| 797 def opt_tree(option, opt, value, parser, tree_options=tree_options): |
| 798 import Main |
| 799 tp = Main.TreePrinter() |
| 800 for o in value.split(','): |
| 801 if o == 'all': |
| 802 tp.derived = False |
| 803 elif o == 'derived': |
| 804 tp.derived = True |
| 805 elif o == 'prune': |
| 806 tp.prune = True |
| 807 elif o == 'status': |
| 808 tp.status = True |
| 809 else: |
| 810 raise OptionValueError("Warning: %s is not a valid --tree optio
n" % o) |
| 811 parser.values.tree_printers.append(tp) |
| 812 |
| 813 opt_tree_help = "Print a dependency tree in various formats: %s." \ |
| 814 % ", ".join(tree_options) |
| 815 |
| 816 op.add_option('--tree', |
| 817 nargs=1, type="string", |
| 818 dest="tree_printers", default=[], |
| 819 action="callback", callback=opt_tree, |
| 820 help=opt_tree_help, |
| 821 metavar="OPTIONS") |
| 822 |
| 823 op.add_option('-u', '--up', '--search-up', |
| 824 dest="climb_up", default=0, |
| 825 action="store_const", const=1, |
| 826 help="Search up directory tree for SConstruct, " |
| 827 "build targets at or below current directory.") |
| 828 |
| 829 op.add_option('-U', |
| 830 dest="climb_up", default=0, |
| 831 action="store_const", const=3, |
| 832 help="Search up directory tree for SConstruct, " |
| 833 "build Default() targets from local SConscript.") |
| 834 |
| 835 def opt_version(option, opt, value, parser): |
| 836 sys.stdout.write(parser.version + '\n') |
| 837 sys.exit(0) |
| 838 op.add_option("-v", "--version", |
| 839 action="callback", callback=opt_version, |
| 840 help="Print the SCons version number and exit.") |
| 841 |
| 842 def opt_warn(option, opt, value, parser, tree_options=tree_options): |
| 843 if SCons.Util.is_String(value): |
| 844 value = value.split(',') |
| 845 parser.values.warn.extend(value) |
| 846 |
| 847 op.add_option('--warn', '--warning', |
| 848 nargs=1, type="string", |
| 849 dest="warn", default=[], |
| 850 action="callback", callback=opt_warn, |
| 851 help="Enable or disable warnings.", |
| 852 metavar="WARNING-SPEC") |
| 853 |
| 854 op.add_option('-Y', '--repository', '--srcdir', |
| 855 nargs=1, |
| 856 dest="repository", default=[], |
| 857 action="append", |
| 858 help="Search REPOSITORY for source and target files.") |
| 859 |
| 860 # Options from Make and Cons classic that we do not yet support, |
| 861 # but which we may support someday and whose (potential) meanings |
| 862 # we don't want to change. These all get a "the -X option is not |
| 863 # yet implemented" message and don't show up in the help output. |
| 864 |
| 865 def opt_not_yet(option, opt, value, parser): |
| 866 msg = "Warning: the %s option is not yet implemented\n" % opt |
| 867 sys.stderr.write(msg) |
| 868 |
| 869 op.add_option('-l', '--load-average', '--max-load', |
| 870 nargs=1, type="int", |
| 871 dest="load_average", default=0, |
| 872 action="callback", callback=opt_not_yet, |
| 873 # action="store", |
| 874 # help="Don't start multiple jobs unless load is below " |
| 875 # "LOAD-AVERAGE." |
| 876 help=SUPPRESS_HELP) |
| 877 op.add_option('--list-actions', |
| 878 dest="list_actions", |
| 879 action="callback", callback=opt_not_yet, |
| 880 # help="Don't build; list files and build actions." |
| 881 help=SUPPRESS_HELP) |
| 882 op.add_option('--list-derived', |
| 883 dest="list_derived", |
| 884 action="callback", callback=opt_not_yet, |
| 885 # help="Don't build; list files that would be built." |
| 886 help=SUPPRESS_HELP) |
| 887 op.add_option('--list-where', |
| 888 dest="list_where", |
| 889 action="callback", callback=opt_not_yet, |
| 890 # help="Don't build; list files and where defined." |
| 891 help=SUPPRESS_HELP) |
| 892 op.add_option('-o', '--old-file', '--assume-old', |
| 893 nargs=1, type="string", |
| 894 dest="old_file", default=[], |
| 895 action="callback", callback=opt_not_yet, |
| 896 # action="append", |
| 897 # help = "Consider FILE to be old; don't rebuild it." |
| 898 help=SUPPRESS_HELP) |
| 899 op.add_option('--override', |
| 900 nargs=1, type="string", |
| 901 action="callback", callback=opt_not_yet, |
| 902 dest="override", |
| 903 # help="Override variables as specified in FILE." |
| 904 help=SUPPRESS_HELP) |
| 905 op.add_option('-p', |
| 906 action="callback", callback=opt_not_yet, |
| 907 dest="p", |
| 908 # help="Print internal environments/objects." |
| 909 help=SUPPRESS_HELP) |
| 910 op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables', |
| 911 action="callback", callback=opt_not_yet, |
| 912 dest="no_builtin_rules", |
| 913 # help="Clear default environments and variables." |
| 914 help=SUPPRESS_HELP) |
| 915 op.add_option('--write-filenames', |
| 916 nargs=1, type="string", |
| 917 dest="write_filenames", |
| 918 action="callback", callback=opt_not_yet, |
| 919 # help="Write all filenames examined into FILE." |
| 920 help=SUPPRESS_HELP) |
| 921 op.add_option('-W', '--new-file', '--assume-new', '--what-if', |
| 922 nargs=1, type="string", |
| 923 dest="new_file", |
| 924 action="callback", callback=opt_not_yet, |
| 925 # help="Consider FILE to be changed." |
| 926 help=SUPPRESS_HELP) |
| 927 op.add_option('--warn-undefined-variables', |
| 928 dest="warn_undefined_variables", |
| 929 action="callback", callback=opt_not_yet, |
| 930 # help="Warn when an undefined variable is referenced." |
| 931 help=SUPPRESS_HELP) |
| 932 |
| 933 return op |
| 934 |
| 935 # Local Variables: |
| 936 # tab-width:4 |
| 937 # indent-tabs-mode:nil |
| 938 # End: |
| 939 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |