Add BUILD_TARGETS, COMMAND_LINE_TARGETS and DEFAULT_TARGETS variables.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 7 Nov 2003 04:46:59 +0000 (04:46 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 7 Nov 2003 04:46:59 +0000 (04:46 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@838 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
doc/scons.mod
doc/user/command-line.in
doc/user/command-line.sgml
src/CHANGES.txt
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Script/__init__.py
test/TARGETS.py [new file with mode: 0644]

index ff2864ce91b1882111fd5336aea42ec8a66031f0..453ff661cbb1569c840ea4a9265e1f8994088eca 100644 (file)
@@ -2374,6 +2374,13 @@ Later calls to
 will add to the (now empty) default-target list
 like normal.
 
+The current list of targets added using the
+.BR Default ()
+function or method is available in the
+.B DEFAULT_TARGETS
+list;
+see below.
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
 .RI DefaultEnvironment([ args ])
@@ -3567,6 +3574,147 @@ or the user's current PATHEXT
 (os.environ['PATHEXT'])
 by default.
 
+.SS SConscript Variables
+In addition to the global functions and methods,
+.B scons
+supports a number of Python variables
+that can be used in SConscript files
+to affect how you want the build to be performed.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+ARGUMENTS
+A dictionary of all the
+.IR keyword = value
+arguments specified on the command line.
+The dictionary is not in order,
+and if a given keyword has
+more than one value assigned to it
+on the command line,
+the last (right-most) value is
+the one in the
+.B ARGUMENTS
+dictionary.
+
+.ES
+if ARGUMENTS.get('debug', 0):
+    env = Environment(CCFLAGS = '-g')
+else:
+    env = Environment()
+.EE
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+BUILD_TARGETS
+A list of the targets which
+.B scons
+will actually try to build,
+regardless of whether they were specified on
+the command line or via the
+.BR Default ()
+function or method.
+The elements of this list may be strings
+.I or
+nodes, so you should run the list through the Python
+.B str
+function to make sure any Node path names
+are converted to strings.
+
+Because this list may be taken from the
+list of targets specified using the
+.BR Default ()
+function or method,
+the contents of the list may change
+on each successive call to
+.BR Default ().
+See the
+.B DEFAULT_TARGETS
+list, below,
+for additional information.
+
+.ES
+if 'foo' in BUILD_TARGETS:
+    print "Don't forget to test the `foo' program!"
+if 'special/program' in BUILD_TARGETS:
+    SConscript('special')
+.EE
+.IP
+Note that the
+.B BUILD_TARGETS
+list only contains targets expected listed
+on the command line or via calls to the
+.BR Default ()
+function or method.
+It does
+.I not
+contain all dependent targets that will be built as
+a result of making the sure the explicitly-specified
+targets are up to date.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+COMMAND_LINE_TARGETS
+A list of the targets explicitly specified on
+the command line.
+If there are no targets specified on the command line,
+the list is empty.
+This can be used, for example,
+to take specific actions only
+when a certain target or targets
+is explicitly being built:
+
+.ES
+if 'foo' in COMMAND_LINE_TARGETS:
+    print "Don't forget to test the `foo' program!"
+if 'special/program' in COMMAND_LINE_TARGETS:
+    SConscript('special')
+.EE
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+DEFAULT_TARGETS
+A list of the target
+.I nodes
+that have been specified using the
+.BR Default ()
+function or method.
+The elements of the list are nodes,
+so you need to run them through the Python
+.B str
+function to get at the path name for each Node.
+
+.ES
+print str(DEFAULT_TARGETS[0])
+if 'foo' in map(str, DEFAULT_TARGETS):
+    print "Don't forget to test the `foo' program!"
+.EE
+.IP
+The contents of the
+.B DEFAULT_TARGETS
+list change on on each successive call to the
+.BR Default ()
+function:
+
+.ES
+print map(str, DEFAULT_TARGETS)   # originally []
+Default('foo')
+print map(str, DEFAULT_TARGETS)   # now a node ['foo']
+Default('bar')
+print map(str, DEFAULT_TARGETS)   # now a node ['foo', 'bar']
+Default(None)
+print map(str, DEFAULT_TARGETS)   # back to []
+.EE
+.IP
+Consequently, be sure to use
+.B DEFAULT_TARGETS
+only after you've made all of your
+.BR Default ()
+calls,
+or else simply be careful of the order
+of these statements in your SConscript files
+so that you don't look for a specific
+default target before it's actually been added to the list.
+
 .SS Construction Variables
 .\" XXX From Gary Ruben, 23 April 2002:
 .\" I think it would be good to have an example with each construction
index d9b955f4d5b9d4436705fe37d8abd9bf071d341e..443be6726286c40c9da3f4d2ff0d26ca4353d16f 100644 (file)
 -->
 
 <!ENTITY ARGUMENTS "<varname>ARGUMENTS</varname>">
+<!ENTITY BUILD_TARGETS "<varname>BUILD_TARGETS</varname>">
+<!ENTITY COMMAND_LINE_TARGETS "<varname>COMMAND_LINE_TARGETS</varname>">
+<!ENTITY DEFAULT_TARGETS "<varname>DEFAULT_TARGETS</varname>">
 
 
 
index 09ee8cea82fa0ebfe292d30f9bb9d13e9f1eff11..9367c0912f2ef42b05cee17d6421bcbb7b93e2d5 100644 (file)
 
   </section>
 
+  <section>
+  <title>Getting at Command-Line Targets</title>
+
+    <para>
+
+    &SCons; supports a &COMMAND_LINE_TARGETS; variable
+    that lets you get at the list of targets that the
+    user specified on the command line.
+    You can use the targets to manipulate the
+    build in any way you wish.
+    As a simple example,
+    suppose that you want to print a reminder
+    to the user whenever a specific program is built.
+    You can do this by checking for the
+    target in the &COMMAND_LINE_TARGETS; list:
+
+    </para>
+
+    <scons_example name="COMMAND_LINE_TARGETS">
+      <file name="SConstruct" printme="1">
+      if 'bar' in COMMAND_LINE_TARGETS:
+          print "Don't forget to copy `bar' to the archive!"
+      Default(Program('foo.c'))
+      Program('bar.c')
+      </file>
+      <file name="foo.c">
+      foo.c
+      </file>
+      <file name="bar.c">
+      foo.c
+      </file>
+    </scons_example>
+
+    <para>
+
+    Then, running &SCons; with the default target
+    works as it always does,
+    but explicity specifying the &bar; target
+    on the command line generates the warning message:
+
+    </para>
+
+    <scons_output example="COMMAND_LINE_TARGETS">
+      <command>scons -Q</command>
+      <command>scons -Q bar</command>
+    </scons_output>
+
+    <para>
+
+    Another practical use for the &COMMAND_LINE_TARGETS; variable
+    might be to speed up a build
+    by only reading certain subsidiary &SConscript;
+    files if a specific target is requested.
+
+    </para>
+
+  </section>
+
   <section>
   <title>Controlling the Default Targets</title>
 
     <para>
 
     One of the most basic things you can control
-    is which targets &SCons; will build by default.
+    is which targets &SCons; will build by default--that is,
+    when there are no targets specified on the command line.
     As mentioned previously,
     &SCons; will normally build every target
     in or below the current directory
        <command>scons -Q .</command>
     </scons_output>
 
-  </section>
+    <section>
+    <title>Getting at the List of Default Targets</title>
+
+      <para>
+
+      &SCons; supports a &DEFAULT_TARGETS; variable
+      that lets you get at the current list of default targets.
+      The &DEFAULT_TARGETS variable has
+      two important differences from the &COMMAND_LINE_TARGETS; variable.
+      First, the &DEFAULT_TARGETS; variable is a list of
+      internal &SCons; nodes,
+      so you need to convert the list elements to strings
+      if you want to print them or look for a specific target name.
+      Fortunately, you can do this easily
+      by using the Python <function>map</function> function
+      to run the list through <function>str</function>:
 
-  <!--
+      </para>
+
+      <scons_example name="DEFAULT_TARGETS_1">
+         <file name="SConstruct" printme="1">
+         prog1 = Program('prog1.c')
+         Default(prog1)
+         print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
+         </file>
+         <file name="prog1.c">
+         prog1.c
+         </file>
+      </scons_example>
+
+      <para>
+
+      (Keep in mind that all of the manipulation of the
+      &DEFAULT_TARGETS; list takes place during the
+      first phase when &SCons; is reading up the &SConscript; files,
+      which is obvious if 
+      we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+
+      </para>
+
+      <scons_output example="DEFAULT_TARGETS_1">
+         <command>scons</command>
+      </scons_output>
+
+      <para>
+
+      Second,
+      the contents of the &DEFAULT_TARGETS; list change
+      in response to calls to the &Default: function,
+      as you can see from the following &SConstruct; file:
+
+      </para>
+
+      <scons_example name="DEFAULT_TARGETS_2">
+         <file name="SConstruct" printme="1">
+         prog1 = Program('prog1.c')
+         Default(prog1)
+         print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+         prog2 = Program('prog2.c')
+         Default(prog2)
+         print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+         </file>
+         <file name="prog1.c">
+         prog1.c
+         </file>
+         <file name="prog2.c">
+         prog2.c
+         </file>
+      </scons_example>
+
+      <para>
+
+      Which yields the output:
+
+      </para>
+
+      <scons_output example="DEFAULT_TARGETS_2">
+         <command>scons</command>
+      </scons_output>
+
+      <para>
+
+      In practice, this simply means that you
+      need to pay attention to the order in
+      which you call the &Default; function
+      and refer to the &DEFAULT_TARGETS; list,
+      to make sure that you don't examine the
+      list before you've added the default targets
+      you expect to find in it.
+
+      </para>
+
+    </section>
+
+  </section>
 
   <section>
-  <title>Getting at Command-Line Targets</title>
+  <title>Getting at the List of Build Targets, Regardless of Origin</title>
 
     <para>
 
-    XXX
+    We've already been introduced to the
+    &COMMAND_LINE_TARGETS; variable,
+    which contains a list of targets specified on the command line,
+    and the &DEFAULT_TARGETS; variable,
+    which contains a list of targets specified
+    via calls to the &Default; method or function.
+    Sometimes, however,
+    you want a list of whatever targets
+    &SCons; will try to build,
+    regardless of whether the targets came from the
+    command line or a &Default; call.
+    You could code this up by hand, as follows:
 
     </para>
 
-  </section>
+    <sconstruct>
+      if COMMAND_LINE_TARGETS:
+          targets = COMMAND_LINE_TARGETS
+      else:
+          targets = DEFAULT_TARGETS
+    </sconstruct>
 
-  -->
+    <para>
+
+    &SCons;, however, provides a convenient
+    &BUILD_TARGETS; variable
+    that eliminates the need for this by-hand manipulation.
+    Essentially, the &BUILD_TARGETS; variable
+    contains a list of the command-line targets,
+    if any were specified,
+    and if no command-line targets were specified,
+    it contains a list of the targets specified
+    via the &Default; method or function.
+
+    </para>
+
+    <para>
+
+    Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
+    you must convert the list elements to strings
+    if you want to print them or look for a specific target name,
+    just like the &DEFAULT_TARGETS; list:
+
+    </para>
+
+    <scons_example name="BUILD_TARGETS_1">
+      <file name="SConstruct" printme="1">
+      prog1 = Program('prog1.c')
+      Program('prog2.c')
+      Default(prog1)
+      print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
+      </file>
+      <file name="prog1.c">
+      prog1.c
+      </file>
+      <file name="prog2.c">
+      prog2.c
+      </file>
+    </scons_example>
+
+    <para>
+
+    Notice how the value of &BUILD_TARGETS;
+    changes depending on whether a target is
+    specified on the command line:
+
+    </para>
+
+    <scons_output example="BUILD_TARGETS_1">
+      <command>scons -Q</command>
+      <command>scons -Q prog2</command>
+      <command>scons -Q -c .</command>
+    </scons_output>
+
+  </section>
 
   <section>
   <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Options</title>
index 3377b6915369ca145dd69d8b12cc6b5b7f261bf8..f6f219ce0a5ee42ad0f0cf62e238a8e4f4daf3e6 100644 (file)
 
   </section>
 
+  <section>
+  <title>Getting at Command-Line Targets</title>
+
+    <para>
+
+    &SCons; supports a &COMMAND_LINE_TARGETS; variable
+    that lets you get at the list of targets that the
+    user specified on the command line.
+    You can use the targets to manipulate the
+    build in any way you wish.
+    As a simple example,
+    suppose that you want to print a reminder
+    to the user whenever a specific program is built.
+    You can do this by checking for the
+    target in the &COMMAND_LINE_TARGETS; list:
+
+    </para>
+
+    <programlisting>
+      if 'bar' in COMMAND_LINE_TARGETS:
+          print "Don't forget to copy `bar' to the archive!"
+      Default(Program('foo.c'))
+      Program('bar.c')
+    </programlisting>
+
+    <para>
+
+    Then, running &SCons; with the default target
+    works as it always does,
+    but explicity specifying the &bar; target
+    on the command line generates the warning message:
+
+    </para>
+
+    <literallayout>
+      % <userinput>scons -Q</userinput>
+      cc -c -o foo.o foo.c
+      cc -o foo foo.o
+      % <userinput>scons -Q bar</userinput>
+      Don't forget to copy `bar' to the archive!
+      cc -c -o bar.o bar.c
+      cc -o bar bar.o
+    </literallayout>
+
+    <para>
+
+    Another practical use for the &COMMAND_LINE_TARGETS; variable
+    might be to speed up a build
+    by only reading certain subsidiary &SConscript;
+    files if a specific target is requested.
+
+    </para>
+
+  </section>
+
   <section>
   <title>Controlling the Default Targets</title>
 
     <para>
 
     One of the most basic things you can control
-    is which targets &SCons; will build by default.
+    is which targets &SCons; will build by default--that is,
+    when there are no targets specified on the command line.
     As mentioned previously,
     &SCons; will normally build every target
     in or below the current directory
        cc -o prog2 prog2.o
     </literallayout>
 
-  </section>
+    <section>
+    <title>Getting at the List of Default Targets</title>
+
+      <para>
+
+      &SCons; supports a &DEFAULT_TARGETS; variable
+      that lets you get at the current list of default targets.
+      The &DEFAULT_TARGETS variable has
+      two important differences from the &COMMAND_LINE_TARGETS; variable.
+      First, the &DEFAULT_TARGETS; variable is a list of
+      internal &SCons; nodes,
+      so you need to convert the list elements to strings
+      if you want to print them or look for a specific target name.
+      Fortunately, you can do this easily
+      by using the Python <function>map</function> function
+      to run the list through <function>str</function>:
+
+      </para>
+
+      <programlisting>
+         prog1 = Program('prog1.c')
+         Default(prog1)
+         print "DEFAULT_TARGETS is", map(str, DEFAULT_TARGETS)
+      </programlisting>
 
-  <!--
+      <para>
+
+      (Keep in mind that all of the manipulation of the
+      &DEFAULT_TARGETS; list takes place during the
+      first phase when &SCons; is reading up the &SConscript; files,
+      which is obvious if 
+      we leave off the <literal>-Q</literal> flag when we run &SCons;:)
+
+      </para>
+
+      <literallayout>
+         % <userinput>scons</userinput>
+         scons: Reading SConscript files ...
+         DEFAULT_TARGETS is ['prog1']
+         scons: done reading SConscript files.
+         scons: Building targets ...
+         cc -c -o prog1.o prog1.c
+         cc -o prog1 prog1.o
+         scons: done building targets.
+      </literallayout>
+
+      <para>
+
+      Second,
+      the contents of the &DEFAULT_TARGETS; list change
+      in response to calls to the &Default;: function,
+      as you can see from the following &SConstruct; file:
+
+      </para>
+
+      <programlisting>
+         prog1 = Program('prog1.c')
+         Default(prog1)
+         print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+         prog2 = Program('prog2.c')
+         Default(prog2)
+         print "DEFAULT_TARGETS is now", map(str, DEFAULT_TARGETS)
+      </programlisting>
+
+      <para>
+
+      Which yields the output:
+
+      </para>
+
+      <literallayout>
+         % <userinput>scons</userinput>
+         scons: Reading SConscript files ...
+         DEFAULT_TARGETS is now ['prog1']
+         DEFAULT_TARGETS is now ['prog1', 'prog2']
+         scons: done reading SConscript files.
+         scons: Building targets ...
+         cc -c -o prog1.o prog1.c
+         cc -o prog1 prog1.o
+         cc -c -o prog2.o prog2.c
+         cc -o prog2 prog2.o
+         scons: done building targets.
+      </literallayout>
+
+      <para>
+
+      In practice, this simply means that you
+      need to pay attention to the order in
+      which you call the &Default; function
+      and refer to the &DEFAULT_TARGETS; list,
+      to make sure that you don't examine the
+      list before you've added the default targets
+      you expect to find in it.
+
+      </para>
+
+    </section>
+
+  </section>
 
   <section>
-  <title>Getting at Command-Line Targets</title>
+  <title>Getting at the List of Build Targets, Regardless of Origin</title>
 
     <para>
 
-    XXX
+    We've already been introduced to the
+    &COMMAND_LINE_TARGETS; variable,
+    which contains a list of targets specified on the command line,
+    and the &DEFAULT_TARGETS; variable,
+    which contains a list of targets specified
+    via calls to the &Default; method or function.
+    Sometimes, however,
+    you want a list of whatever targets
+    &SCons; will try to build,
+    regardless of whether the targets came from the
+    command line or a &Default; call.
+    You could code this up by hand, as follows:
 
     </para>
 
-  </section>
+    <programlisting>
+      if COMMAND_LINE_TARGETS:
+          targets = COMMAND_LINE_TARGETS
+      else:
+          targets = DEFAULT_TARGETS
+    </programlisting>
+
+    <para>
+
+    &SCons;, however, provides a convenient
+    &BUILD_TARGETS; variable
+    that eliminates the need for this by-hand manipulation.
+    Essentially, the &BUILD_TARGETS; variable
+    contains a list of the command-line targets,
+    if any were specified,
+    and if no command-line targets were specified,
+    it contains a list of the targets specified
+    via the &Default; method or function.
+
+    </para>
+
+    <para>
+
+    Because &BUILD_TARGETS; may contain a list of &SCons; nodes,
+    you must convert the list elements to strings
+    if you want to print them or look for a specific target name,
+    just like the &DEFAULT_TARGETS; list:
+
+    </para>
+
+    <programlisting>
+      prog1 = Program('prog1.c')
+      Program('prog2.c')
+      Default(prog1)
+      print "BUILD_TARGETS is", map(str, BUILD_TARGETS)
+    </programlisting>
+
+    <para>
+
+    Notice how the value of &BUILD_TARGETS;
+    changes depending on whether a target is
+    specified on the command line:
+
+    </para>
+
+    <literallayout>
+      % <userinput>scons -Q</userinput>
+      BUILD_TARGETS is ['prog1']
+      cc -c -o prog1.o prog1.c
+      cc -o prog1 prog1.o
+      % <userinput>scons -Q prog2</userinput>
+      BUILD_TARGETS is ['prog2']
+      cc -c -o prog2.o prog2.c
+      cc -o prog2 prog2.o
+      % <userinput>scons -Q -c .</userinput>
+      BUILD_TARGETS is ['.']
+      Removed prog1.o
+      Removed prog1
+      Removed prog2.o
+      Removed prog2
+    </literallayout>
 
-  -->
+  </section>
 
   <section>
   <title>Command-Line <varname>variable</varname>=<varname>value</varname> Build Options</title>
index 29053390769d1a97579097a82fb7385810d07c64..8629589fb8695d9ae9f45b04cedaba252fddb5bb 100644 (file)
@@ -25,6 +25,8 @@ RELEASE X.XX - XXX, XX XXX XXXX XX:XX:XX -XXXX
 
   - Fix subclassing the Environment and Scanner classes.
 
+  - Add BUILD_TARGETS, COMMAND_LINE_TARGETS and DEFAULT_TARGETS variables.
+
   From Steve Leblanc:
 
   - SGI fixes:  Fix C++ compilation, add a separate Tool/sgic++.py module.
index 6c6ad8a7963f8b7b61fcf574d19e40467a0a6a49..26be48335244618191a648374bbf934aa49833d8 100644 (file)
@@ -64,7 +64,6 @@ class _Null:
 
 _null = _Null
 
-DefaultTargets = None
 CleanTargets = {}
 CalculatorArgs = {}
 
@@ -811,18 +810,6 @@ class Base:
                                     source_factory=self.fs.Entry)
         return bld(self, target, source)
 
-    def Default(self, *targets):
-        global DefaultTargets
-        if DefaultTargets is None:
-            DefaultTargets = []
-        for t in targets:
-            if t is None:
-                DefaultTargets = []
-            elif isinstance(t, SCons.Node.Node):
-                DefaultTargets.append(t)
-            else:
-                DefaultTargets.extend(self.arg2nodes(t, self.fs.Entry))
-
     def Depends(self, target, dependency):
         """Explicity specify that 'target's depend on 'dependency'."""
         tlist = self.arg2nodes(target, self.fs.Entry)
index 2861f85afd5555d8c27a5367509c79bef2e7bf10..e6fd5c963db86384be95fef2adb4509d3a8df811 100644 (file)
@@ -1484,25 +1484,6 @@ class EnvironmentTestCase(unittest.TestCase):
         finally:
             os.chdir(save)
 
-    def test_Default(self):
-        """Test the Default() method"""
-        env = Environment(FOO = 'fff', BAR = 'bbb')
-
-        t = env.Default(None)
-        assert SCons.Environment.DefaultTargets == []
-
-        t = env.Default('xyz')
-        d = map(str, SCons.Environment.DefaultTargets)
-        assert d == ['xyz'], d
-
-        t = env.Default('$FOO')
-        d = map(str, SCons.Environment.DefaultTargets)
-        assert d == ['xyz', 'fff'], d
-
-        t = env.Default(None, '$BAR', 'another_file')
-        d = map(str, SCons.Environment.DefaultTargets)
-        assert d == ['bbb', 'another_file'], d
-
     def test_Depends(self):
         """Test the explicit Depends method."""
         env = Environment(FOO = 'xxx', BAR='yyy')
index fff18694a0768c91ac36e30efd885e564664b9c6..8894df7be44ab5ac26f85c333d9a4979a2b6d791 100644 (file)
@@ -53,13 +53,27 @@ import string
 import sys
 import traceback
 import types
+import UserList
+
+launch_dir = os.path.abspath(os.curdir)
 
 def do_nothing(text): pass
 HelpFunction = do_nothing
 
-arguments = {}
+Arguments = {}
+CommandLineTargets = []
+DefaultCalled = None
+DefaultTargets = []
 GlobalDict = {}
-launch_dir = os.path.abspath(os.curdir)
+
+class TargetList(UserList.UserList):
+    def _do_nothing(self, *args, **kw):
+        pass
+    def _add_Default(self, list):
+        self.extend(list)
+    def _clear(self):
+        del self[:]
+BuildTargets = TargetList()
 
 # global exports set by Export():
 global_exports = {}
@@ -71,10 +85,16 @@ sconscript_chdir = 1
 sconscript_reading = 0
 
 def _scons_add_args(alist):
-    global arguments
     for arg in alist:
         a, b = string.split(arg, '=', 2)
-        arguments[a] = b
+        Arguments[a] = b
+
+def _scons_add_targets(tlist):
+    if tlist:
+        CommandLineTargets.extend(tlist)
+        BuildTargets.extend(tlist)
+        BuildTargets._add_Default = BuildTargets._do_nothing
+        BuildTargets._clear = BuildTargets._do_nothing
 
 def get_calling_namespaces():
     """Return the locals and globals for the function that called
@@ -387,6 +407,26 @@ class SConsEnvironment(SCons.Environment.Base):
     # as global functions.
     #
 
+    def Default(self, *targets):
+        global DefaultCalled
+        global DefaultTargets
+        DefaultCalled = 1
+        for t in targets:
+            if t is None:
+                # Delete the elements from the list in-place, don't
+                # reassign an empty list to DefaultTargets, so that the
+                # DEFAULT_TARGETS variable will still point to the
+                # same object we point to.
+                del DefaultTargets[:]
+                BuildTargets._clear()
+            elif isinstance(t, SCons.Node.Node):
+                DefaultTargets.append(t)
+                BuildTargets._add_Default([t])
+            else:
+                nodes = self.arg2nodes(t, self.fs.Entry)
+                DefaultTargets.extend(nodes)
+                BuildTargets._add_Default(nodes)
+
     def EnsureSConsVersion(self, major, minor):
         """Exit abnormally if the SCons version is not late enough."""
         if not self._check_version(major,minor,SCons.__version__):
@@ -460,7 +500,7 @@ class SConsEnvironment(SCons.Environment.Base):
 #
 SCons.Environment.Environment = SConsEnvironment
 
-def Options(files=None, args=arguments):
+def Options(files=None, args=Arguments):
     return SCons.Options.Options(files, args)
 
 def SetBuildSignatureType(type):
@@ -545,6 +585,7 @@ class DefaultEnvironmentCall:
 # DefaultEnvironment().
 GlobalDefaultEnvironmentFunctions = [
     # Methods from the SConsEnvironment class, above.
+    'Default',
     'EnsurePythonVersion',
     'EnsureSConsVersion',
     'Exit',
@@ -566,7 +607,6 @@ GlobalDefaultEnvironmentFunctions = [
     'CacheDir',
     'Clean',
     'Command',
-    'Default',
     'Depends',
     'Dir',
     'File',
@@ -624,23 +664,31 @@ def BuildDefaultGlobals():
     SConstruct and SConscript files.
     """
 
-    globals = {}
-    globals['Action']            = SCons.Action.Action
-    globals['ARGUMENTS']         = arguments
-    globals['BoolOption']        = SCons.Options.BoolOption
-    globals['Builder']           = SCons.Builder.Builder
-    globals['Configure']         = SCons.SConf.SConf
-    globals['EnumOption']        = SCons.Options.EnumOption
-    globals['Environment']       = SCons.Environment.Environment
-    globals['ListOption']        = SCons.Options.ListOption
-    globals['Options']           = Options
-    globals['PackageOption']     = SCons.Options.PackageOption
-    globals['PathOption']        = SCons.Options.PathOption
-    globals['Platform']          = SCons.Platform.Platform
-    globals['Return']            = Return
-    globals['Scanner']           = SCons.Scanner.Base
-    globals['Tool']              = SCons.Tool.Tool
-    globals['WhereIs']           = SCons.Util.WhereIs
+    globals = {
+        # Global functions that don't get executed through the
+        # default Environment.
+        'Action'                : SCons.Action.Action,
+        'BoolOption'            : SCons.Options.BoolOption,
+        'Builder'               : SCons.Builder.Builder,
+        'Configure'             : SCons.SConf.SConf,
+        'EnumOption'            : SCons.Options.EnumOption,
+        'Environment'           : SCons.Environment.Environment,
+        'ListOption'            : SCons.Options.ListOption,
+        'Options'               : Options,
+        'PackageOption'         : SCons.Options.PackageOption,
+        'PathOption'            : SCons.Options.PathOption,
+        'Platform'              : SCons.Platform.Platform,
+        'Return'                : Return,
+        'Scanner'               : SCons.Scanner.Base,
+        'Tool'                  : SCons.Tool.Tool,
+        'WhereIs'               : SCons.Util.WhereIs,
+
+        # Other variables we provide.
+        'ARGUMENTS'             : Arguments,
+        'BUILD_TARGETS'         : BuildTargets,
+        'COMMAND_LINE_TARGETS'  : CommandLineTargets,
+        'DEFAULT_TARGETS'       : DefaultTargets,
+    }
 
     # Functions we might still convert to Environment methods.
     globals['CScan']             = SCons.Defaults.CScan
index a533c29d3a5fc1686cb6a1d31167ca0162748931..71ed2bec4d6712cd809cf7e73e5cf68d5b7bf4e8 100644 (file)
@@ -753,6 +753,7 @@ def _main(args, parser):
         else:
             targets.append(a)
     SCons.Script.SConscript._scons_add_args(xmit_args)
+    SCons.Script.SConscript._scons_add_targets(targets)
 
     target_top = None
     if options.climb_up:
@@ -865,6 +866,7 @@ def _main(args, parser):
         # There are no targets specified on the command line,
         # so if they used -u, -U or -D, we may have to restrict
         # what actually gets built.
+        d = None
         if target_top:
             if options.climb_up == 1:
                 # -u, local directory and below
@@ -886,18 +888,18 @@ def _main(args, parser):
                         # or not a file, so go ahead and keep it as a default
                         # target and let the engine sort it out:
                         return 1                
-                default_targets = SCons.Environment.DefaultTargets
-                if default_targets is None:
-                    default_targets = []
-                else:
-                    default_targets = filter(check_dir, default_targets)
-                SCons.Environment.DefaultTargets = default_targets
+                d = filter(check_dir, SCons.Script.SConscript.DefaultTargets)
+                SCons.Script.SConscript.DefaultTargets[:] = d
                 target_top = None
                 lookup_top = None
 
-        targets = SCons.Environment.DefaultTargets
-        if targets is None:
-            targets = [fs.Dir('.')]
+        if SCons.Script.SConscript.DefaultCalled:
+            targets = SCons.Script.SConscript.DefaultTargets
+        else:
+            if d is None:
+                d = [fs.Dir('.')]
+            targets = d
+
 
     if not targets:
         sys.stderr.write("scons: *** No targets specified and no Default() targets found.  Stop.\n")
diff --git a/test/TARGETS.py b/test/TARGETS.py
new file mode 100644 (file)
index 0000000..5c73d81
--- /dev/null
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test use of the COMMAND_LINE_TARGETS and DEFAULT_TARGETS variables.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+print COMMAND_LINE_TARGETS
+print map(str, BUILD_TARGETS)
+Default('.')
+print COMMAND_LINE_TARGETS
+print map(str, BUILD_TARGETS)
+""")
+
+test.write('aaa', 'aaa\n')
+test.write('bbb', 'bbb\n')
+
+expect = test.wrap_stdout(read_str = "[]\n[]\n[]\n['.']\n",
+                          build_str = "scons: `.' is up to date.\n")
+test.run(stdout = expect)
+
+expect = test.wrap_stdout(read_str = "['.']\n['.']\n['.']\n['.']\n",
+                          build_str = "scons: `.' is up to date.\n")
+test.run(arguments = '.', stdout = expect)
+
+expect = test.wrap_stdout(read_str = "['aaa']\n['aaa']\n['aaa']\n['aaa']\n",
+                          build_str = "scons: Nothing to be done for `aaa'.\n")
+test.run(arguments = 'aaa', stdout = expect)
+
+expect = test.wrap_stdout(read_str = "['bbb', 'aaa']\n['bbb', 'aaa']\n['bbb', 'aaa']\n['bbb', 'aaa']\n",
+                          build_str = """\
+scons: Nothing to be done for `bbb'.
+scons: Nothing to be done for `aaa'.
+""")
+test.run(arguments = 'bbb ccc=xyz -n aaa', stdout = expect)
+
+test.write('SConstruct', """
+env = Environment()
+print map(str, DEFAULT_TARGETS)
+print map(str, BUILD_TARGETS)
+Default('aaa')
+print map(str, DEFAULT_TARGETS)
+print map(str, BUILD_TARGETS)
+env.Default('bbb')
+print map(str, DEFAULT_TARGETS)
+print map(str, BUILD_TARGETS)
+env.Default(None)
+print map(str, DEFAULT_TARGETS)
+print map(str, BUILD_TARGETS)
+env.Default('ccc')
+""")
+
+test.write('ccc', "ccc\n")
+
+expect = test.wrap_stdout(build_str = "scons: Nothing to be done for `ccc'.\n",
+                          read_str = """\
+[]
+[]
+['aaa']
+['aaa']
+['aaa', 'bbb']
+['aaa', 'bbb']
+[]
+[]
+""")
+test.run(stdout = expect)
+
+expect = test.wrap_stdout(build_str = "scons: `.' is up to date.\n",
+                          read_str = """\
+[]
+['.']
+['aaa']
+['.']
+['aaa', 'bbb']
+['.']
+[]
+['.']
+""")
+test.run(arguments = '.', stdout = expect)
+
+test.pass_test()