OLD | NEW |
1 """SCons.Action | 1 """SCons.Action |
2 | 2 |
3 This encapsulates information about executing any sort of action that | 3 This encapsulates information about executing any sort of action that |
4 can build one or more target Nodes (typically files) from one or more | 4 can build one or more target Nodes (typically files) from one or more |
5 source Nodes (also typically files) given a specific Environment. | 5 source Nodes (also typically files) given a specific Environment. |
6 | 6 |
7 The base class here is ActionBase. The base class supplies just a few | 7 The base class here is ActionBase. The base class supplies just a few |
8 OO utility methods and some generic methods for displaying information | 8 OO utility methods and some generic methods for displaying information |
9 about an Action in response to the various commands that control printing. | 9 about an Action in response to the various commands that control printing. |
10 | 10 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 There is a related independent ActionCaller class that looks like a | 69 There is a related independent ActionCaller class that looks like a |
70 regular Action, and which serves as a wrapper for arbitrary functions | 70 regular Action, and which serves as a wrapper for arbitrary functions |
71 that we want to let the user specify the arguments to now, but actually | 71 that we want to let the user specify the arguments to now, but actually |
72 execute later (when an out-of-date check determines that it's needed to | 72 execute later (when an out-of-date check determines that it's needed to |
73 be executed, for example). Objects of this class are returned by an | 73 be executed, for example). Objects of this class are returned by an |
74 ActionFactory class that provides a __call__() method as a convenient | 74 ActionFactory class that provides a __call__() method as a convenient |
75 way for wrapping up the functions. | 75 way for wrapping up the functions. |
76 | 76 |
77 """ | 77 """ |
78 | 78 |
79 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion | 79 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons F
oundation |
80 # | 80 # |
81 # Permission is hereby granted, free of charge, to any person obtaining | 81 # Permission is hereby granted, free of charge, to any person obtaining |
82 # a copy of this software and associated documentation files (the | 82 # a copy of this software and associated documentation files (the |
83 # "Software"), to deal in the Software without restriction, including | 83 # "Software"), to deal in the Software without restriction, including |
84 # without limitation the rights to use, copy, modify, merge, publish, | 84 # without limitation the rights to use, copy, modify, merge, publish, |
85 # distribute, sublicense, and/or sell copies of the Software, and to | 85 # distribute, sublicense, and/or sell copies of the Software, and to |
86 # permit persons to whom the Software is furnished to do so, subject to | 86 # permit persons to whom the Software is furnished to do so, subject to |
87 # the following conditions: | 87 # the following conditions: |
88 # | 88 # |
89 # The above copyright notice and this permission notice shall be included | 89 # The above copyright notice and this permission notice shall be included |
90 # in all copies or substantial portions of the Software. | 90 # in all copies or substantial portions of the Software. |
91 # | 91 # |
92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | 92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | 95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | 96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
99 | 99 |
100 __revision__ = "src/engine/SCons/Action.py 3842 2008/12/20 22:59:52 scons" | 100 __revision__ = "src/engine/SCons/Action.py 3897 2009/01/13 06:45:54 scons" |
101 | 101 |
102 import cPickle | 102 import cPickle |
103 import dis | 103 import dis |
104 import os | 104 import os |
105 import string | 105 import string |
106 import sys | 106 import sys |
107 import subprocess | 107 import subprocess |
108 | 108 |
109 from SCons.Debug import logInstanceCreation | 109 from SCons.Debug import logInstanceCreation |
110 import SCons.Errors | 110 import SCons.Errors |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 return None | 385 return None |
386 | 386 |
387 def _do_create_list_action(act, kw): | 387 def _do_create_list_action(act, kw): |
388 """A factory for list actions. Convert the input list into Actions | 388 """A factory for list actions. Convert the input list into Actions |
389 and then wrap them in a ListAction.""" | 389 and then wrap them in a ListAction.""" |
390 acts = [] | 390 acts = [] |
391 for a in act: | 391 for a in act: |
392 aa = _do_create_action(a, kw) | 392 aa = _do_create_action(a, kw) |
393 if aa is not None: acts.append(aa) | 393 if aa is not None: acts.append(aa) |
394 if not acts: | 394 if not acts: |
395 return None | 395 return ListAction([]) |
396 elif len(acts) == 1: | 396 elif len(acts) == 1: |
397 return acts[0] | 397 return acts[0] |
398 else: | 398 else: |
399 return ListAction(acts) | 399 return ListAction(acts) |
400 | 400 |
401 def Action(act, *args, **kw): | 401 def Action(act, *args, **kw): |
402 """A factory for action objects.""" | 402 """A factory for action objects.""" |
403 # Really simple: the _do_create_* routines do the heavy lifting. | 403 # Really simple: the _do_create_* routines do the heavy lifting. |
404 _do_create_keywords(args, kw) | 404 _do_create_keywords(args, kw) |
405 if is_List(act): | 405 if is_List(act): |
406 return _do_create_list_action(act, kw) | 406 return _do_create_list_action(act, kw) |
407 return _do_create_action(act, kw) | 407 return _do_create_action(act, kw) |
408 | 408 |
409 class ActionBase: | 409 class ActionBase: |
410 """Base class for all types of action objects that can be held by | 410 """Base class for all types of action objects that can be held by |
411 other objects (Builders, Executors, etc.) This provides the | 411 other objects (Builders, Executors, etc.) This provides the |
412 common methods for manipulating and combining those actions.""" | 412 common methods for manipulating and combining those actions.""" |
413 | 413 |
414 def __cmp__(self, other): | 414 def __cmp__(self, other): |
415 return cmp(self.__dict__, other) | 415 return cmp(self.__dict__, other) |
416 | 416 |
| 417 def no_batch_key(self, env, target, source): |
| 418 return None |
| 419 |
| 420 batch_key = no_batch_key |
| 421 |
417 def genstring(self, target, source, env): | 422 def genstring(self, target, source, env): |
418 return str(self) | 423 return str(self) |
419 | 424 |
420 def get_contents(self, target, source, env): | 425 def get_contents(self, target, source, env): |
421 result = [ self.get_presig(target, source, env) ] | 426 result = [ self.get_presig(target, source, env) ] |
422 # This should never happen, as the Action() factory should wrap | 427 # This should never happen, as the Action() factory should wrap |
423 # the varlist, but just in case an action is created directly, | 428 # the varlist, but just in case an action is created directly, |
424 # we duplicate this check here. | 429 # we duplicate this check here. |
425 vl = self.varlist | 430 vl = self.varlist |
426 if is_String(vl): vl = (vl,) | 431 if is_String(vl): vl = (vl,) |
(...skipping 12 matching lines...) Expand all Loading... |
439 # in order to return the proper string here, since | 444 # in order to return the proper string here, since |
440 # it may call LazyAction, which looks up a key | 445 # it may call LazyAction, which looks up a key |
441 # in that env. So we temporarily remember the env here, | 446 # in that env. So we temporarily remember the env here, |
442 # and CommandGeneratorAction will use this env | 447 # and CommandGeneratorAction will use this env |
443 # when it calls its _generate method. | 448 # when it calls its _generate method. |
444 self.presub_env = env | 449 self.presub_env = env |
445 lines = string.split(str(self), '\n') | 450 lines = string.split(str(self), '\n') |
446 self.presub_env = None # don't need this any more | 451 self.presub_env = None # don't need this any more |
447 return lines | 452 return lines |
448 | 453 |
449 def get_executor(self, env, overrides, tlist, slist, executor_kw): | 454 def get_targets(self, env, executor): |
450 """Return the Executor for this Action.""" | 455 """ |
451 return SCons.Executor.Executor(self, env, overrides, | 456 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used |
452 tlist, slist, executor_kw) | 457 by this action. |
| 458 """ |
| 459 return self.targets |
453 | 460 |
454 class _ActionAction(ActionBase): | 461 class _ActionAction(ActionBase): |
455 """Base class for actions that create output objects.""" | 462 """Base class for actions that create output objects.""" |
456 def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), | 463 def __init__(self, cmdstr=_null, strfunction=_null, varlist=(), |
457 presub=_null, chdir=None, exitstatfunc=None, | 464 presub=_null, chdir=None, exitstatfunc=None, |
| 465 batch_key=None, targets='$TARGETS', |
458 **kw): | 466 **kw): |
459 self.cmdstr = cmdstr | 467 self.cmdstr = cmdstr |
460 if strfunction is not _null: | 468 if strfunction is not _null: |
461 if strfunction is None: | 469 if strfunction is None: |
462 self.cmdstr = None | 470 self.cmdstr = None |
463 else: | 471 else: |
464 self.strfunction = strfunction | 472 self.strfunction = strfunction |
465 self.varlist = varlist | 473 self.varlist = varlist |
466 self.presub = presub | 474 self.presub = presub |
467 self.chdir = chdir | 475 self.chdir = chdir |
468 if not exitstatfunc: | 476 if not exitstatfunc: |
469 exitstatfunc = default_exitstatfunc | 477 exitstatfunc = default_exitstatfunc |
470 self.exitstatfunc = exitstatfunc | 478 self.exitstatfunc = exitstatfunc |
471 | 479 |
| 480 self.targets = targets |
| 481 |
| 482 if batch_key: |
| 483 if not callable(batch_key): |
| 484 # They have set batch_key, but not to their own |
| 485 # callable. The default behavior here will batch |
| 486 # *all* targets+sources using this action, separated |
| 487 # for each construction environment. |
| 488 def default_batch_key(self, env, target, source): |
| 489 return (id(self), id(env)) |
| 490 batch_key = default_batch_key |
| 491 SCons.Util.AddMethod(self, batch_key, 'batch_key') |
| 492 |
472 def print_cmd_line(self, s, target, source, env): | 493 def print_cmd_line(self, s, target, source, env): |
473 sys.stdout.write(s + "\n") | 494 sys.stdout.write(s + "\n") |
474 | 495 |
475 def __call__(self, target, source, env, | 496 def __call__(self, target, source, env, |
476 exitstatfunc=_null, | 497 exitstatfunc=_null, |
477 presub=_null, | 498 presub=_null, |
478 show=_null, | 499 show=_null, |
479 execute=_null, | 500 execute=_null, |
480 chdir=_null): | 501 chdir=_null, |
| 502 executor=None): |
481 if not is_List(target): | 503 if not is_List(target): |
482 target = [target] | 504 target = [target] |
483 if not is_List(source): | 505 if not is_List(source): |
484 source = [source] | 506 source = [source] |
485 | 507 |
486 if presub is _null: | 508 if presub is _null: |
487 presub = self.presub | 509 presub = self.presub |
488 if presub is _null: | 510 if presub is _null: |
489 presub = print_actions_presub | 511 presub = print_actions_presub |
490 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc | 512 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc |
491 if show is _null: show = print_actions | 513 if show is _null: show = print_actions |
492 if execute is _null: execute = execute_actions | 514 if execute is _null: execute = execute_actions |
493 if chdir is _null: chdir = self.chdir | 515 if chdir is _null: chdir = self.chdir |
494 save_cwd = None | 516 save_cwd = None |
495 if chdir: | 517 if chdir: |
496 save_cwd = os.getcwd() | 518 save_cwd = os.getcwd() |
497 try: | 519 try: |
498 chdir = str(chdir.abspath) | 520 chdir = str(chdir.abspath) |
499 except AttributeError: | 521 except AttributeError: |
500 if not is_String(chdir): | 522 if not is_String(chdir): |
501 chdir = str(target[0].dir) | 523 if executor: |
| 524 chdir = str(executor.batches[0].targets[0].dir) |
| 525 else: |
| 526 chdir = str(target[0].dir) |
502 if presub: | 527 if presub: |
| 528 if executor: |
| 529 target = executor.get_all_targets() |
| 530 source = executor.get_all_sources() |
503 t = string.join(map(str, target), ' and ') | 531 t = string.join(map(str, target), ' and ') |
504 l = string.join(self.presub_lines(env), '\n ') | 532 l = string.join(self.presub_lines(env), '\n ') |
505 out = "Building %s with action:\n %s\n" % (t, l) | 533 out = "Building %s with action:\n %s\n" % (t, l) |
506 sys.stdout.write(out) | 534 sys.stdout.write(out) |
507 cmd = None | 535 cmd = None |
508 if show and self.strfunction: | 536 if show and self.strfunction: |
509 cmd = self.strfunction(target, source, env) | 537 if executor: |
| 538 target = executor.get_all_targets() |
| 539 source = executor.get_all_sources() |
| 540 try: |
| 541 cmd = self.strfunction(target, source, env, executor) |
| 542 except TypeError: |
| 543 cmd = self.strfunction(target, source, env) |
510 if cmd: | 544 if cmd: |
511 if chdir: | 545 if chdir: |
512 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd | 546 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd |
513 try: | 547 try: |
514 get = env.get | 548 get = env.get |
515 except AttributeError: | 549 except AttributeError: |
516 print_func = self.print_cmd_line | 550 print_func = self.print_cmd_line |
517 else: | 551 else: |
518 print_func = get('PRINT_CMD_LINE_FUNC') | 552 print_func = get('PRINT_CMD_LINE_FUNC') |
519 if not print_func: | 553 if not print_func: |
520 print_func = self.print_cmd_line | 554 print_func = self.print_cmd_line |
521 print_func(cmd, target, source, env) | 555 print_func(cmd, target, source, env) |
522 stat = 0 | 556 stat = 0 |
523 if execute: | 557 if execute: |
524 if chdir: | 558 if chdir: |
525 os.chdir(chdir) | 559 os.chdir(chdir) |
526 try: | 560 try: |
527 stat = self.execute(target, source, env) | 561 stat = self.execute(target, source, env, executor=executor) |
528 if isinstance(stat, SCons.Errors.BuildError): | 562 if isinstance(stat, SCons.Errors.BuildError): |
529 s = exitstatfunc(stat.status) | 563 s = exitstatfunc(stat.status) |
530 if s: | 564 if s: |
531 stat.status = s | 565 stat.status = s |
532 else: | 566 else: |
533 stat = s | 567 stat = s |
534 else: | 568 else: |
535 stat = exitstatfunc(stat) | 569 stat = exitstatfunc(stat) |
536 finally: | 570 finally: |
537 if save_cwd: | 571 if save_cwd: |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 if filter(is_List, cmd): | 684 if filter(is_List, cmd): |
651 raise TypeError, "CommandAction should be given only " \ | 685 raise TypeError, "CommandAction should be given only " \ |
652 "a single command" | 686 "a single command" |
653 self.cmd_list = cmd | 687 self.cmd_list = cmd |
654 | 688 |
655 def __str__(self): | 689 def __str__(self): |
656 if is_List(self.cmd_list): | 690 if is_List(self.cmd_list): |
657 return string.join(map(str, self.cmd_list), ' ') | 691 return string.join(map(str, self.cmd_list), ' ') |
658 return str(self.cmd_list) | 692 return str(self.cmd_list) |
659 | 693 |
660 def process(self, target, source, env): | 694 def process(self, target, source, env, executor=None): |
661 result = env.subst_list(self.cmd_list, 0, target, source) | 695 if executor: |
| 696 result = env.subst_list(self.cmd_list, 0, executor=executor) |
| 697 else: |
| 698 result = env.subst_list(self.cmd_list, 0, target, source) |
662 silent = None | 699 silent = None |
663 ignore = None | 700 ignore = None |
664 while 1: | 701 while 1: |
665 try: c = result[0][0][0] | 702 try: c = result[0][0][0] |
666 except IndexError: c = None | 703 except IndexError: c = None |
667 if c == '@': silent = 1 | 704 if c == '@': silent = 1 |
668 elif c == '-': ignore = 1 | 705 elif c == '-': ignore = 1 |
669 else: break | 706 else: break |
670 result[0][0] = result[0][0][1:] | 707 result[0][0] = result[0][0][1:] |
671 try: | 708 try: |
672 if not result[0][0]: | 709 if not result[0][0]: |
673 result[0] = result[0][1:] | 710 result[0] = result[0][1:] |
674 except IndexError: | 711 except IndexError: |
675 pass | 712 pass |
676 return result, ignore, silent | 713 return result, ignore, silent |
677 | 714 |
678 def strfunction(self, target, source, env): | 715 def strfunction(self, target, source, env, executor=None): |
679 if self.cmdstr is None: | 716 if self.cmdstr is None: |
680 return None | 717 return None |
681 if self.cmdstr is not _null: | 718 if self.cmdstr is not _null: |
682 from SCons.Subst import SUBST_RAW | 719 from SCons.Subst import SUBST_RAW |
683 c = env.subst(self.cmdstr, SUBST_RAW, target, source) | 720 if executor: |
| 721 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) |
| 722 else: |
| 723 c = env.subst(self.cmdstr, SUBST_RAW, target, source) |
684 if c: | 724 if c: |
685 return c | 725 return c |
686 cmd_list, ignore, silent = self.process(target, source, env) | 726 cmd_list, ignore, silent = self.process(target, source, env, executor) |
687 if silent: | 727 if silent: |
688 return '' | 728 return '' |
689 return _string_from_cmd_list(cmd_list[0]) | 729 return _string_from_cmd_list(cmd_list[0]) |
690 | 730 |
691 def execute(self, target, source, env): | 731 def execute(self, target, source, env, executor=None): |
692 """Execute a command action. | 732 """Execute a command action. |
693 | 733 |
694 This will handle lists of commands as well as individual commands, | 734 This will handle lists of commands as well as individual commands, |
695 because construction variable substitution may turn a single | 735 because construction variable substitution may turn a single |
696 "command" into a list. This means that this class can actually | 736 "command" into a list. This means that this class can actually |
697 handle lists of commands, even though that's not how we use it | 737 handle lists of commands, even though that's not how we use it |
698 externally. | 738 externally. |
699 """ | 739 """ |
700 escape_list = SCons.Subst.escape_list | 740 escape_list = SCons.Subst.escape_list |
701 flatten_sequence = SCons.Util.flatten_sequence | 741 flatten_sequence = SCons.Util.flatten_sequence |
(...skipping 24 matching lines...) Expand all Loading... |
726 # value to stick in an environment variable: | 766 # value to stick in an environment variable: |
727 value = flatten_sequence(value) | 767 value = flatten_sequence(value) |
728 ENV[key] = string.join(map(str, value), os.pathsep) | 768 ENV[key] = string.join(map(str, value), os.pathsep) |
729 else: | 769 else: |
730 # If it isn't a string or a list, then we just coerce | 770 # If it isn't a string or a list, then we just coerce |
731 # it to a string, which is the proper way to handle | 771 # it to a string, which is the proper way to handle |
732 # Dir and File instances and will produce something | 772 # Dir and File instances and will produce something |
733 # reasonable for just about everything else: | 773 # reasonable for just about everything else: |
734 ENV[key] = str(value) | 774 ENV[key] = str(value) |
735 | 775 |
736 cmd_list, ignore, silent = self.process(target, map(rfile, source), env) | 776 if executor: |
| 777 target = executor.get_all_targets() |
| 778 source = executor.get_all_sources() |
| 779 cmd_list, ignore, silent = self.process(target, map(rfile, source), env,
executor) |
737 | 780 |
738 # Use len() to filter out any "command" that's zero-length. | 781 # Use len() to filter out any "command" that's zero-length. |
739 for cmd_line in filter(len, cmd_list): | 782 for cmd_line in filter(len, cmd_list): |
740 # Escape the command line for the interpreter we are using. | 783 # Escape the command line for the interpreter we are using. |
741 cmd_line = escape_list(cmd_line, escape) | 784 cmd_line = escape_list(cmd_line, escape) |
742 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) | 785 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV) |
743 if not ignore and result: | 786 if not ignore and result: |
744 msg = "Error %s" % result | 787 msg = "Error %s" % result |
745 return SCons.Errors.BuildError(errstr=msg, | 788 return SCons.Errors.BuildError(errstr=msg, |
746 status=result, | 789 status=result, |
747 action=self, | 790 action=self, |
748 command=cmd_line) | 791 command=cmd_line) |
749 return 0 | 792 return 0 |
750 | 793 |
751 def get_presig(self, target, source, env): | 794 def get_presig(self, target, source, env, executor=None): |
752 """Return the signature contents of this action's command line. | 795 """Return the signature contents of this action's command line. |
753 | 796 |
754 This strips $(-$) and everything in between the string, | 797 This strips $(-$) and everything in between the string, |
755 since those parts don't affect signatures. | 798 since those parts don't affect signatures. |
756 """ | 799 """ |
757 from SCons.Subst import SUBST_SIG | 800 from SCons.Subst import SUBST_SIG |
758 cmd = self.cmd_list | 801 cmd = self.cmd_list |
759 if is_List(cmd): | 802 if is_List(cmd): |
760 cmd = string.join(map(str, cmd)) | 803 cmd = string.join(map(str, cmd)) |
761 else: | 804 else: |
762 cmd = str(cmd) | 805 cmd = str(cmd) |
763 return env.subst_target_source(cmd, SUBST_SIG, target, source) | 806 if executor: |
| 807 return env.subst_target_source(cmd, SUBST_SIG, executor=executor) |
| 808 else: |
| 809 return env.subst_target_source(cmd, SUBST_SIG, target, source) |
764 | 810 |
765 def get_implicit_deps(self, target, source, env): | 811 def get_implicit_deps(self, target, source, env, executor=None): |
766 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) | 812 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True) |
767 if is_String(icd) and icd[:1] == '$': | 813 if is_String(icd) and icd[:1] == '$': |
768 icd = env.subst(icd) | 814 icd = env.subst(icd) |
769 if not icd or icd in ('0', 'None'): | 815 if not icd or icd in ('0', 'None'): |
770 return [] | 816 return [] |
771 from SCons.Subst import SUBST_SIG | 817 from SCons.Subst import SUBST_SIG |
772 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) | 818 if executor: |
| 819 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executo
r) |
| 820 else: |
| 821 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source) |
773 res = [] | 822 res = [] |
774 for cmd_line in cmd_list: | 823 for cmd_line in cmd_list: |
775 if cmd_line: | 824 if cmd_line: |
776 d = env.WhereIs(str(cmd_line[0])) | 825 d = env.WhereIs(str(cmd_line[0])) |
777 if d: | 826 if d: |
778 res.append(env.fs.File(d)) | 827 res.append(env.fs.File(d)) |
779 return res | 828 return res |
780 | 829 |
781 class CommandGeneratorAction(ActionBase): | 830 class CommandGeneratorAction(ActionBase): |
782 """Class for command-generator actions.""" | 831 """Class for command-generator actions.""" |
783 def __init__(self, generator, kw): | 832 def __init__(self, generator, kw): |
784 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction') | 833 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction') |
785 self.generator = generator | 834 self.generator = generator |
786 self.gen_kw = kw | 835 self.gen_kw = kw |
787 self.varlist = kw.get('varlist', ()) | 836 self.varlist = kw.get('varlist', ()) |
| 837 self.targets = kw.get('targets', '$TARGETS') |
788 | 838 |
789 def _generate(self, target, source, env, for_signature): | 839 def _generate(self, target, source, env, for_signature, executor=None): |
790 # ensure that target is a list, to make it easier to write | 840 # ensure that target is a list, to make it easier to write |
791 # generator functions: | 841 # generator functions: |
792 if not is_List(target): | 842 if not is_List(target): |
793 target = [target] | 843 target = [target] |
794 | 844 |
795 ret = self.generator(target=target, source=source, env=env, for_signatur
e=for_signature) | 845 if executor: |
| 846 target = executor.get_all_targets() |
| 847 source = executor.get_all_sources() |
| 848 ret = self.generator(target=target, |
| 849 source=source, |
| 850 env=env, |
| 851 for_signature=for_signature) |
796 #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw) | 852 #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw) |
797 gen_cmd = apply(Action, (ret,), self.gen_kw) | 853 gen_cmd = apply(Action, (ret,), self.gen_kw) |
798 if not gen_cmd: | 854 if not gen_cmd: |
799 raise SCons.Errors.UserError("Object returned from command generator
: %s cannot be used to create an Action." % repr(ret)) | 855 raise SCons.Errors.UserError("Object returned from command generator
: %s cannot be used to create an Action." % repr(ret)) |
800 return gen_cmd | 856 return gen_cmd |
801 | 857 |
802 def __str__(self): | 858 def __str__(self): |
803 try: | 859 try: |
804 env = self.presub_env | 860 env = self.presub_env |
805 except AttributeError: | 861 except AttributeError: |
806 env = None | 862 env = None |
807 if env is None: | 863 if env is None: |
808 env = SCons.Defaults.DefaultEnvironment() | 864 env = SCons.Defaults.DefaultEnvironment() |
809 act = self._generate([], [], env, 1) | 865 act = self._generate([], [], env, 1) |
810 return str(act) | 866 return str(act) |
811 | 867 |
812 def genstring(self, target, source, env): | 868 def batch_key(self, env, target, source): |
813 return self._generate(target, source, env, 1).genstring(target, source,
env) | 869 return self._generate(target, source, env, 1).batch_key(env, target, sou
rce) |
| 870 |
| 871 def genstring(self, target, source, env, executor=None): |
| 872 return self._generate(target, source, env, 1, executor).genstring(target
, source, env) |
814 | 873 |
815 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, | 874 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, |
816 show=_null, execute=_null, chdir=_null): | 875 show=_null, execute=_null, chdir=_null, executor=None): |
817 act = self._generate(target, source, env, 0) | 876 act = self._generate(target, source, env, 0, executor) |
| 877 if act is None: |
| 878 raise UserError("While building `%s': Cannot deduce file extension f
rom source files: %s" % (repr(map(str, target)), repr(map(str, source)))) |
818 return act(target, source, env, exitstatfunc, presub, | 879 return act(target, source, env, exitstatfunc, presub, |
819 show, execute, chdir) | 880 show, execute, chdir, executor) |
820 | 881 |
821 def get_presig(self, target, source, env): | 882 def get_presig(self, target, source, env, executor=None): |
822 """Return the signature contents of this action's command line. | 883 """Return the signature contents of this action's command line. |
823 | 884 |
824 This strips $(-$) and everything in between the string, | 885 This strips $(-$) and everything in between the string, |
825 since those parts don't affect signatures. | 886 since those parts don't affect signatures. |
826 """ | 887 """ |
827 return self._generate(target, source, env, 1).get_presig(target, source,
env) | 888 return self._generate(target, source, env, 1, executor).get_presig(targe
t, source, env) |
828 | 889 |
829 def get_implicit_deps(self, target, source, env): | 890 def get_implicit_deps(self, target, source, env, executor=None): |
830 return self._generate(target, source, env, 1).get_implicit_deps(target,
source, env) | 891 return self._generate(target, source, env, 1, executor).get_implicit_dep
s(target, source, env) |
| 892 |
| 893 def get_targets(self, env, executor): |
| 894 return self._generate(None, None, env, 1, executor).get_targets(env, exe
cutor) |
831 | 895 |
832 | 896 |
833 | 897 |
834 # A LazyAction is a kind of hybrid generator and command action for | 898 # A LazyAction is a kind of hybrid generator and command action for |
835 # strings of the form "$VAR". These strings normally expand to other | 899 # strings of the form "$VAR". These strings normally expand to other |
836 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also | 900 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also |
837 # want to be able to replace them with functions in the construction | 901 # want to be able to replace them with functions in the construction |
838 # environment. Consequently, we want lazy evaluation and creation of | 902 # environment. Consequently, we want lazy evaluation and creation of |
839 # an Action in the case of the function, but that's overkill in the more | 903 # an Action in the case of the function, but that's overkill in the more |
840 # normal case of expansion to other strings. | 904 # normal case of expansion to other strings. |
(...skipping 16 matching lines...) Expand all Loading... |
857 self.var = SCons.Util.to_String(var) | 921 self.var = SCons.Util.to_String(var) |
858 self.gen_kw = kw | 922 self.gen_kw = kw |
859 | 923 |
860 def get_parent_class(self, env): | 924 def get_parent_class(self, env): |
861 c = env.get(self.var) | 925 c = env.get(self.var) |
862 if is_String(c) and not '\n' in c: | 926 if is_String(c) and not '\n' in c: |
863 return CommandAction | 927 return CommandAction |
864 return CommandGeneratorAction | 928 return CommandGeneratorAction |
865 | 929 |
866 def _generate_cache(self, env): | 930 def _generate_cache(self, env): |
867 c = env.get(self.var, '') | 931 if env: |
| 932 c = env.get(self.var, '') |
| 933 else: |
| 934 c = '' |
868 #TODO(1.5) gen_cmd = Action(c, **self.gen_kw) | 935 #TODO(1.5) gen_cmd = Action(c, **self.gen_kw) |
869 gen_cmd = apply(Action, (c,), self.gen_kw) | 936 gen_cmd = apply(Action, (c,), self.gen_kw) |
870 if not gen_cmd: | 937 if not gen_cmd: |
871 raise SCons.Errors.UserError("$%s value %s cannot be used to create
an Action." % (self.var, repr(c))) | 938 raise SCons.Errors.UserError("$%s value %s cannot be used to create
an Action." % (self.var, repr(c))) |
872 return gen_cmd | 939 return gen_cmd |
873 | 940 |
874 def _generate(self, target, source, env, for_signature): | 941 def _generate(self, target, source, env, for_signature, executor=None): |
875 return self._generate_cache(env) | 942 return self._generate_cache(env) |
876 | 943 |
877 def __call__(self, target, source, env, *args, **kw): | 944 def __call__(self, target, source, env, *args, **kw): |
878 args = (self, target, source, env) + args | 945 args = (self, target, source, env) + args |
879 c = self.get_parent_class(env) | 946 c = self.get_parent_class(env) |
880 #TODO(1.5) return c.__call__(*args, **kw) | 947 #TODO(1.5) return c.__call__(*args, **kw) |
881 return apply(c.__call__, args, kw) | 948 return apply(c.__call__, args, kw) |
882 | 949 |
883 def get_presig(self, target, source, env): | 950 def get_presig(self, target, source, env): |
884 c = self.get_parent_class(env) | 951 c = self.get_parent_class(env) |
(...skipping 23 matching lines...) Expand all Loading... |
908 | 975 |
909 def function_name(self): | 976 def function_name(self): |
910 try: | 977 try: |
911 return self.execfunction.__name__ | 978 return self.execfunction.__name__ |
912 except AttributeError: | 979 except AttributeError: |
913 try: | 980 try: |
914 return self.execfunction.__class__.__name__ | 981 return self.execfunction.__class__.__name__ |
915 except AttributeError: | 982 except AttributeError: |
916 return "unknown_python_function" | 983 return "unknown_python_function" |
917 | 984 |
918 def strfunction(self, target, source, env): | 985 def strfunction(self, target, source, env, executor=None): |
919 if self.cmdstr is None: | 986 if self.cmdstr is None: |
920 return None | 987 return None |
921 if self.cmdstr is not _null: | 988 if self.cmdstr is not _null: |
922 from SCons.Subst import SUBST_RAW | 989 from SCons.Subst import SUBST_RAW |
923 c = env.subst(self.cmdstr, SUBST_RAW, target, source) | 990 if executor: |
| 991 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor) |
| 992 else: |
| 993 c = env.subst(self.cmdstr, SUBST_RAW, target, source) |
924 if c: | 994 if c: |
925 return c | 995 return c |
926 def array(a): | 996 def array(a): |
927 def quote(s): | 997 def quote(s): |
928 try: | 998 try: |
929 str_for_display = s.str_for_display | 999 str_for_display = s.str_for_display |
930 except AttributeError: | 1000 except AttributeError: |
931 s = repr(s) | 1001 s = repr(s) |
932 else: | 1002 else: |
933 s = str_for_display() | 1003 s = str_for_display() |
(...skipping 12 matching lines...) Expand all Loading... |
946 tstr = array(target) | 1016 tstr = array(target) |
947 sstr = array(source) | 1017 sstr = array(source) |
948 return "%s(%s, %s)" % (name, tstr, sstr) | 1018 return "%s(%s, %s)" % (name, tstr, sstr) |
949 | 1019 |
950 def __str__(self): | 1020 def __str__(self): |
951 name = self.function_name() | 1021 name = self.function_name() |
952 if name == 'ActionCaller': | 1022 if name == 'ActionCaller': |
953 return str(self.execfunction) | 1023 return str(self.execfunction) |
954 return "%s(target, source, env)" % name | 1024 return "%s(target, source, env)" % name |
955 | 1025 |
956 def execute(self, target, source, env): | 1026 def execute(self, target, source, env, executor=None): |
957 exc_info = (None,None,None) | 1027 exc_info = (None,None,None) |
958 try: | 1028 try: |
| 1029 if executor: |
| 1030 target = executor.get_all_targets() |
| 1031 source = executor.get_all_sources() |
959 rsources = map(rfile, source) | 1032 rsources = map(rfile, source) |
960 try: | 1033 try: |
961 result = self.execfunction(target=target, source=rsources, env=e
nv) | 1034 result = self.execfunction(target=target, source=rsources, env=e
nv) |
962 except KeyboardInterrupt, e: | 1035 except KeyboardInterrupt, e: |
963 raise | 1036 raise |
964 except SystemExit, e: | 1037 except SystemExit, e: |
965 raise | 1038 raise |
966 except Exception, e: | 1039 except Exception, e: |
967 result = e | 1040 result = e |
968 exc_info = sys.exc_info() | 1041 exc_info = sys.exc_info() |
969 | 1042 |
970 if result: | 1043 if result: |
971 result = SCons.Errors.convert_to_BuildError(result, exc_info) | 1044 result = SCons.Errors.convert_to_BuildError(result, exc_info) |
972 result.node=target | 1045 result.node=target |
973 result.action=self | 1046 result.action=self |
974 result.command=self.strfunction(target, source, env) | 1047 try: |
| 1048 result.command=self.strfunction(target, source, env, executo
r) |
| 1049 except TypeError: |
| 1050 result.command=self.strfunction(target, source, env) |
975 | 1051 |
976 # FIXME: This maintains backward compatibility with respect to | 1052 # FIXME: This maintains backward compatibility with respect to |
977 # which type of exceptions were returned by raising an | 1053 # which type of exceptions were returned by raising an |
978 # exception and which ones were returned by value. It would | 1054 # exception and which ones were returned by value. It would |
979 # probably be best to always return them by value here, but | 1055 # probably be best to always return them by value here, but |
980 # some codes do not check the return value of Actions and I do | 1056 # some codes do not check the return value of Actions and I do |
981 # not have the time to modify them at this point. | 1057 # not have the time to modify them at this point. |
982 if (exc_info[1] and | 1058 if (exc_info[1] and |
983 not isinstance(exc_info[1],EnvironmentError)): | 1059 not isinstance(exc_info[1],EnvironmentError)): |
984 raise result | 1060 raise result |
(...skipping 21 matching lines...) Expand all Loading... |
1006 def __init__(self, list): | 1082 def __init__(self, list): |
1007 if __debug__: logInstanceCreation(self, 'Action.ListAction') | 1083 if __debug__: logInstanceCreation(self, 'Action.ListAction') |
1008 def list_of_actions(x): | 1084 def list_of_actions(x): |
1009 if isinstance(x, ActionBase): | 1085 if isinstance(x, ActionBase): |
1010 return x | 1086 return x |
1011 return Action(x) | 1087 return Action(x) |
1012 self.list = map(list_of_actions, list) | 1088 self.list = map(list_of_actions, list) |
1013 # our children will have had any varlist | 1089 # our children will have had any varlist |
1014 # applied; we don't need to do it again | 1090 # applied; we don't need to do it again |
1015 self.varlist = () | 1091 self.varlist = () |
| 1092 self.targets = '$TARGETS' |
1016 | 1093 |
1017 def genstring(self, target, source, env): | 1094 def genstring(self, target, source, env): |
1018 return string.join(map(lambda a, t=target, s=source, e=env: | 1095 return string.join(map(lambda a, t=target, s=source, e=env: |
1019 a.genstring(t, s, e), | 1096 a.genstring(t, s, e), |
1020 self.list), | 1097 self.list), |
1021 '\n') | 1098 '\n') |
1022 | 1099 |
1023 def __str__(self): | 1100 def __str__(self): |
1024 return string.join(map(str, self.list), '\n') | 1101 return string.join(map(str, self.list), '\n') |
1025 | 1102 |
1026 def presub_lines(self, env): | 1103 def presub_lines(self, env): |
1027 return SCons.Util.flatten_sequence( | 1104 return SCons.Util.flatten_sequence( |
1028 map(lambda a, env=env: a.presub_lines(env), self.list)) | 1105 map(lambda a, env=env: a.presub_lines(env), self.list)) |
1029 | 1106 |
1030 def get_presig(self, target, source, env): | 1107 def get_presig(self, target, source, env): |
1031 """Return the signature contents of this action list. | 1108 """Return the signature contents of this action list. |
1032 | 1109 |
1033 Simple concatenation of the signatures of the elements. | 1110 Simple concatenation of the signatures of the elements. |
1034 """ | 1111 """ |
1035 return string.join(map(lambda x, t=target, s=source, e=env: | 1112 return string.join(map(lambda x, t=target, s=source, e=env: |
1036 x.get_contents(t, s, e), | 1113 x.get_contents(t, s, e), |
1037 self.list), | 1114 self.list), |
1038 "") | 1115 "") |
1039 | 1116 |
1040 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, | 1117 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null, |
1041 show=_null, execute=_null, chdir=_null): | 1118 show=_null, execute=_null, chdir=_null, executor=None): |
| 1119 if executor: |
| 1120 target = executor.get_all_targets() |
| 1121 source = executor.get_all_sources() |
1042 for act in self.list: | 1122 for act in self.list: |
1043 stat = act(target, source, env, exitstatfunc, presub, | 1123 stat = act(target, source, env, exitstatfunc, presub, |
1044 show, execute, chdir) | 1124 show, execute, chdir, executor) |
1045 if stat: | 1125 if stat: |
1046 return stat | 1126 return stat |
1047 return 0 | 1127 return 0 |
1048 | 1128 |
1049 def get_implicit_deps(self, target, source, env): | 1129 def get_implicit_deps(self, target, source, env): |
1050 result = [] | 1130 result = [] |
1051 for act in self.list: | 1131 for act in self.list: |
1052 result.extend(act.get_implicit_deps(target, source, env)) | 1132 result.extend(act.get_implicit_deps(target, source, env)) |
1053 return result | 1133 return result |
1054 | 1134 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 return map(lambda x, self=self, t=target, s=source, e=env: | 1184 return map(lambda x, self=self, t=target, s=source, e=env: |
1105 self.subst(x, t, s, e), | 1185 self.subst(x, t, s, e), |
1106 self.args) | 1186 self.args) |
1107 | 1187 |
1108 def subst_kw(self, target, source, env): | 1188 def subst_kw(self, target, source, env): |
1109 kw = {} | 1189 kw = {} |
1110 for key in self.kw.keys(): | 1190 for key in self.kw.keys(): |
1111 kw[key] = self.subst(self.kw[key], target, source, env) | 1191 kw[key] = self.subst(self.kw[key], target, source, env) |
1112 return kw | 1192 return kw |
1113 | 1193 |
1114 def __call__(self, target, source, env): | 1194 def __call__(self, target, source, env, executor=None): |
1115 args = self.subst_args(target, source, env) | 1195 args = self.subst_args(target, source, env) |
1116 kw = self.subst_kw(target, source, env) | 1196 kw = self.subst_kw(target, source, env) |
1117 #TODO(1.5) return self.parent.actfunc(*args, **kw) | 1197 #TODO(1.5) return self.parent.actfunc(*args, **kw) |
1118 return apply(self.parent.actfunc, args, kw) | 1198 return apply(self.parent.actfunc, args, kw) |
1119 | 1199 |
1120 def strfunction(self, target, source, env): | 1200 def strfunction(self, target, source, env): |
1121 args = self.subst_args(target, source, env) | 1201 args = self.subst_args(target, source, env) |
1122 kw = self.subst_kw(target, source, env) | 1202 kw = self.subst_kw(target, source, env) |
1123 #TODO(1.5) return self.parent.strfunc(*args, **kw) | 1203 #TODO(1.5) return self.parent.strfunc(*args, **kw) |
1124 return apply(self.parent.strfunc, args, kw) | 1204 return apply(self.parent.strfunc, args, kw) |
(...skipping 13 matching lines...) Expand all Loading... |
1138 """ | 1218 """ |
1139 def __init__(self, actfunc, strfunc, convert=lambda x: x): | 1219 def __init__(self, actfunc, strfunc, convert=lambda x: x): |
1140 self.actfunc = actfunc | 1220 self.actfunc = actfunc |
1141 self.strfunc = strfunc | 1221 self.strfunc = strfunc |
1142 self.convert = convert | 1222 self.convert = convert |
1143 | 1223 |
1144 def __call__(self, *args, **kw): | 1224 def __call__(self, *args, **kw): |
1145 ac = ActionCaller(self, args, kw) | 1225 ac = ActionCaller(self, args, kw) |
1146 action = Action(ac, strfunction=ac.strfunction) | 1226 action = Action(ac, strfunction=ac.strfunction) |
1147 return action | 1227 return action |
OLD | NEW |