diff options
author | Steven Knight <knight@baldmt.com> | 2006-02-13 03:52:41 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2006-02-13 03:52:41 (GMT) |
commit | 804ff6d25ac70aabcd913fe44d441799867a7dd7 (patch) | |
tree | 004e8fcfa1e69736fcbbf7590da8036b9a8ae4eb | |
parent | f325a0ceb04f04d045862eee8373a586011e4ebf (diff) | |
download | SCons-804ff6d25ac70aabcd913fe44d441799867a7dd7.zip SCons-804ff6d25ac70aabcd913fe44d441799867a7dd7.tar.gz SCons-804ff6d25ac70aabcd913fe44d441799867a7dd7.tar.bz2 |
Add a NoClean() function. (Steven Johnson)
-rw-r--r-- | doc/design/engine.sgml | 36 | ||||
-rw-r--r-- | doc/design/scons.mod | 1 | ||||
-rw-r--r-- | doc/man/scons.1 | 76 | ||||
-rw-r--r-- | doc/scons.mod | 1 | ||||
-rw-r--r-- | doc/user/MANIFEST | 2 | ||||
-rw-r--r-- | doc/user/file-removal.in | 148 | ||||
-rw-r--r-- | doc/user/file-removal.sgml | 141 | ||||
-rw-r--r-- | doc/user/main.in | 8 | ||||
-rw-r--r-- | doc/user/main.sgml | 8 | ||||
-rw-r--r-- | doc/user/precious.in | 90 | ||||
-rw-r--r-- | doc/user/precious.sgml | 84 | ||||
-rw-r--r-- | src/CHANGES.txt | 5 | ||||
-rw-r--r-- | src/engine/SCons/Environment.py | 9 | ||||
-rw-r--r-- | src/engine/SCons/EnvironmentTests.py | 23 | ||||
-rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 9 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 5 | ||||
-rw-r--r-- | src/engine/SCons/Script/Main.py | 4 | ||||
-rw-r--r-- | src/engine/SCons/Script/__init__.py | 1 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 18 | ||||
-rw-r--r-- | src/engine/SCons/UtilTests.py | 6 | ||||
-rw-r--r-- | test/option-c.py | 14 |
21 files changed, 491 insertions, 198 deletions
diff --git a/doc/design/engine.sgml b/doc/design/engine.sgml index 9452420..df78e3b 100644 --- a/doc/design/engine.sgml +++ b/doc/design/engine.sgml @@ -1385,7 +1385,43 @@ Comments? </para> </section> + + <section> + <title>Suppressing cleanup removal of build-targets</title> + <para> + + By default, &SCons; explicitly removes all build-targets + when invoked to perform "cleanup". Files that should not be + removed during "cleanup" can be specified via the + &NoClean; method: + + </para> + + <programlisting> + env.Library(target = 'libfoo.a', source = ['aaa.c', 'bbb.c', 'ccc.c']) + env.NoClean('libfoo.a') + </programlisting> + + <para> + + The NoClean operation has precedence over the Clean operation. + A target that is specified as both Clean and NoClean, will not + be removed during a clean. + + In the following example, target 'foo' will not be removed + during "cleanup": + + <programlisting> + env.Clean(target = 'foo') + env.NoClean('foo') + </programlisting> + + + </para> + + </section> + <section> <title>Suppressing build-target removal</title> diff --git a/doc/design/scons.mod b/doc/design/scons.mod index 58a6576..5b246a4 100644 --- a/doc/design/scons.mod +++ b/doc/design/scons.mod @@ -155,6 +155,7 @@ <!ENTITY ListOption "<function>ListOption</function>"> <!ENTITY Local "<function>Local</function>"> <!ENTITY Module "<function>Module</function>"> +<!ENTITY NoClean "<function>NoClean</function>"> <!ENTITY Objects "<function>Objects</function>"> <!ENTITY Options "<function>Options</function>"> <!ENTITY PackageOption "<function>PackageOption</function>"> diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 3c014c6..45d7a5b 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -262,7 +262,14 @@ scons -c build export to remove target files under build and export. Additional files or directories to remove can be specified using the -Clean() function. +.BR Clean() +function. +Conversely, targets that would normally be removed by the +.B -c +invocation +can be prevented from being removed by using the +.BR NoClean () +function. A subset of a hierarchical tree may be built by remaining at the top-level directory (where the @@ -406,7 +413,12 @@ Ignored for compatibility with non-GNU versions of Clean up by removing all target files for which a construction command is specified. Also remove any files or directories associated to the construction command -using the Clean() function. +using the +.BR Clean () +function. +Will not remove any targets specified by the +.BR NoClean () +function. .TP --cache-disable, --no-cache @@ -2088,6 +2100,19 @@ will also accept the return value of any of the construction environment Builder methods. Examples: +The related +.BR NoClean () +function overrides calling +.BR Clean () +for the same target, +and any targets passed to both functions will +.I not +be removed by the +.B -c +option. + +Examples: + .ES Clean('foo', ['bar', 'baz']) Clean('dist', env.Program('hello', 'hello.c')) @@ -2757,6 +2782,53 @@ Returns a list of the target Node or Nodes. '\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" .TP +.RI NoClean( target ", ...)" +.TP +.RI env.NoClean( target ", ...)" +Specifies a list of files or directories which should +.I not +be removed whenever the targets (or their dependencies) +are specified with the +.B -c +command line option. +The specified targets may be a list +or an individual target. +Multiple calls to +.BR NoClean () +are legal, +and prevent each specified target +from being removed by calls to the +.B -c +option. + +Multiple files or directories should be specified +either as separate arguments to the +.BR NoClean () +method, or as a list. +.BR NoClean () +will also accept the return value of any of the construction environment +Builder methods. + +Calling +.BR NoClean () +for a target overrides calling +.BR Clean () +for the same target, +and any targets passed to both functions will +.I not +be removed by the +.B -c +option. + +Examples: + +.ES +NoClean('foo.elf') +NoClean(env.Program('hello', 'hello.c')) +.EE + +'\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.TP .RI env.ParseConfig( command ", [" function ", " unique ]) Calls the specified .I function diff --git a/doc/scons.mod b/doc/scons.mod index b8b64aa..975f445 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -162,6 +162,7 @@ <!ENTITY Mkdir "<function>Mkdir</function>"> <!ENTITY Module "<function>Module</function>"> <!ENTITY Move "<function>Move</function>"> +<!ENTITY NoClean "<function>NoClean</function>"> <!ENTITY Objects "<function>Objects</function>"> <!ENTITY Options "<function>Options</function>"> <!ENTITY PackageOption "<function>PackageOption</function>"> diff --git a/doc/user/MANIFEST b/doc/user/MANIFEST index 3af2c9c..04c293b 100644 --- a/doc/user/MANIFEST +++ b/doc/user/MANIFEST @@ -17,6 +17,7 @@ environments.sgml errors.sgml example.sgml factories.sgml +file-removal.sgml help.sgml hierarchy.sgml install.sgml @@ -27,7 +28,6 @@ main.sgml make.sgml nodes.sgml parseconfig.sgml -precious.sgml preface.sgml python.sgml repositories.sgml diff --git a/doc/user/file-removal.in b/doc/user/file-removal.in new file mode 100644 index 0000000..1d259bf --- /dev/null +++ b/doc/user/file-removal.in @@ -0,0 +1,148 @@ +<!-- + + __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. + +--> + + <para> + + There are two occasions when &SCons; will, + by default, remove target files. + The first is when &SCons; determines that + an target file needs to be rebuilt + and removes the existing version of the target + before executing + The second is when &SCons; is invoked with the + <literal>-c</literal> option to "clean" + a tree of its built targets. + + These behaviours can be suppressed with the + &Precious; and &NoClean; functions, respectively. + + </para> + + <section> + <title>Preventing target removal during build: the &Precious; Function</title> + + <para> + + By default, &SCons; removes targets before building them. + Sometimes, however, this is not what you want. + For example, you may want to update a library incrementally, + not by having it deleted and then rebuilt from all + of the constituent object files. + In such cases, you can use the + &Precious; method to prevent + &SCons; from removing the target before it is built: + + </para> + + <scons_example name="precious-ex1"> + <file name="SConstruct" printme="1"> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Precious(lib) + </file> + <file name="f1.c"> + int f1() { } + </file> + <file name="f2.c"> + int f2() { } + </file> + <file name="f3.c"> + int f3() { } + </file> + </scons_example> + + <para> + + Although the output doesn't look any different, + &SCons; does not, in fact, + delete the target library before rebuilding it: + + </para> + + <scons_output example="precious-ex1"> + <scons_output_command>scons -Q</scons_output_command> + </scons_output> + + <para> + + &SCons; will, however, still delete files marked as &Precious; + when the <literal>-c</literal> option is used. + + </para> + + </section> + + + <section> + <title>Preventing target removal during clean: the &NoClean; Function</title> + + <para> + + By default, &SCons; removes all built targets when invoked + with the <literal>-c</literal> option to clean a source tree + of built tragets. + Sometimes, however, this is not what you want. + For example, you may want to remove only intermediate generated files + (such as object files), + but leave the final targets + (the libraries) + untouched. + + In such cases, you can use the &NoClean; method to prevent &SCons; + from removing a target during a clean: + + </para> + + <scons_example name="noclean-ex1"> + <file name="SConstruct" printme="1"> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.NoClean(lib) + </file> + <file name="f1.c"> + int f1() { } + </file> + <file name="f2.c"> + int f2() { } + </file> + <file name="f3.c"> + int f3() { } + </file> + </scons_example> + + <para> + + Notice that the <filename>libfoo.a</filename> + is not listed as a removed file: + + </para> + + <scons_output example="noclean-ex1"> + <scons_output_command>scons -Q</scons_output_command> + <scons_output_command>scons -c</scons_output_command> + </scons_output> + + </section> + diff --git a/doc/user/file-removal.sgml b/doc/user/file-removal.sgml new file mode 100644 index 0000000..76a2e01 --- /dev/null +++ b/doc/user/file-removal.sgml @@ -0,0 +1,141 @@ +<!-- + + __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. + +--> + + <para> + + There are two occasions when &SCons; will, + by default, remove target files. + The first is when &SCons; determines that + an target file needs to be rebuilt + and removes the existing version of the target + before executing + The second is when &SCons; is invoked with the + <literal>-c</literal> option to "clean" + a tree of its built targets. + + These behaviours can be suppressed with the + &Precious; and &NoClean; functions, respectively. + + </para> + + <section> + <title>Preventing target removal during build: the &Precious; Function</title> + + <para> + + By default, &SCons; removes targets before building them. + Sometimes, however, this is not what you want. + For example, you may want to update a library incrementally, + not by having it deleted and then rebuilt from all + of the constituent object files. + In such cases, you can use the + &Precious; method to prevent + &SCons; from removing the target before it is built: + + </para> + + <programlisting> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.Precious(lib) + </programlisting> + + <para> + + Although the output doesn't look any different, + &SCons; does not, in fact, + delete the target library before rebuilding it: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + </screen> + + <para> + + &SCons; will, however, still delete files marked as &Precious; + when the <literal>-c</literal> option is used. + + </para> + + </section> + + + <section> + <title>Preventing target removal during clean: the &NoClean; Function</title> + + <para> + + By default, &SCons; removes all built targets when invoked + with the <literal>-c</literal> option to clean a source tree + of built tragets. + Sometimes, however, this is not what you want. + For example, you may want to remove only intermediate generated files + (such as object files), + but leave the final targets + (the libraries) + untouched. + + In such cases, you can use the &NoClean; method to prevent &SCons; + from removing a target during a clean: + + </para> + + <programlisting> + env = Environment(RANLIBCOM='') + lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) + env.NoClean(lib) + </programlisting> + + <para> + + Notice that the <filename>libfoo.a</filename> + is not listed as a removed file: + + </para> + + <screen> + % <userinput>scons -Q</userinput> + cc -o f1.o -c f1.c + cc -o f2.o -c f2.c + cc -o f3.o -c f3.c + ar rc libfoo.a f1.o f2.o f3.o + % <userinput>scons -c</userinput> + scons: Reading SConscript files ... + scons: done reading SConscript files. + scons: Cleaning targets ... + Removed f1.o + Removed f2.o + Removed f3.o + scons: done cleaning targets. + </screen> + + </section> + diff --git a/doc/user/main.in b/doc/user/main.in index a720915..af3b0ee 100644 --- a/doc/user/main.in +++ b/doc/user/main.in @@ -59,6 +59,7 @@ <!ENTITY errors SYSTEM "errors.sgml"> <!ENTITY example SYSTEM "example.sgml"> <!ENTITY factories SYSTEM "factories.sgml"> + <!ENTITY file-removal SYSTEM "file-removal.sgml"> <!ENTITY help SYSTEM "help.sgml"> <!ENTITY hierarchy SYSTEM "hierarchy.sgml"> <!ENTITY java SYSTEM "java.sgml"> @@ -68,7 +69,6 @@ <!ENTITY make SYSTEM "make.sgml"> <!ENTITY nodes SYSTEM "nodes.sgml"> <!ENTITY parseconfig SYSTEM "parseconfig.sgml"> - <!ENTITY precious SYSTEM "precious.sgml"> <!ENTITY preface SYSTEM "preface.sgml"> <!ENTITY python SYSTEM "python.sgml"> <!ENTITY repositories SYSTEM "repositories.sgml"> @@ -190,9 +190,9 @@ &factories; </chapter> - <chapter id="chap-precious"> - <title>Preventing Removal of Targets: the &Precious; Function</title> - &precious; + <chapter id="chap-file-removal"> + <title>Preventing Removal of Targets</title> + &file-removal; </chapter> <chapter id="chap-hierarchical"> diff --git a/doc/user/main.sgml b/doc/user/main.sgml index a720915..af3b0ee 100644 --- a/doc/user/main.sgml +++ b/doc/user/main.sgml @@ -59,6 +59,7 @@ <!ENTITY errors SYSTEM "errors.sgml"> <!ENTITY example SYSTEM "example.sgml"> <!ENTITY factories SYSTEM "factories.sgml"> + <!ENTITY file-removal SYSTEM "file-removal.sgml"> <!ENTITY help SYSTEM "help.sgml"> <!ENTITY hierarchy SYSTEM "hierarchy.sgml"> <!ENTITY java SYSTEM "java.sgml"> @@ -68,7 +69,6 @@ <!ENTITY make SYSTEM "make.sgml"> <!ENTITY nodes SYSTEM "nodes.sgml"> <!ENTITY parseconfig SYSTEM "parseconfig.sgml"> - <!ENTITY precious SYSTEM "precious.sgml"> <!ENTITY preface SYSTEM "preface.sgml"> <!ENTITY python SYSTEM "python.sgml"> <!ENTITY repositories SYSTEM "repositories.sgml"> @@ -190,9 +190,9 @@ &factories; </chapter> - <chapter id="chap-precious"> - <title>Preventing Removal of Targets: the &Precious; Function</title> - &precious; + <chapter id="chap-file-removal"> + <title>Preventing Removal of Targets</title> + &file-removal; </chapter> <chapter id="chap-hierarchical"> diff --git a/doc/user/precious.in b/doc/user/precious.in deleted file mode 100644 index f5e000b..0000000 --- a/doc/user/precious.in +++ /dev/null @@ -1,90 +0,0 @@ -<!-- - - __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. - ---> - -<!-- - -=head2 The C<AfterBuild> method - -The C<AfterBuild> method evaluates the specified perl string after -building the given file or files (or finding that they are up to date). -The eval will happen once per specified file. C<AfterBuild> is called -as follows: - - AfterBuild $env 'foo.o', qq(print "foo.o is up to date!\n"); - -The perl string is evaluated in the C<script> package, and has access -to all variables and subroutines defined in the F<Conscript> file in -which the C<AfterBuild> method is called. - ---> - - <para> - - By default, &SCons; removes targets before building them. - Sometimes, however, this is not what you want. - For example, you may want to update a library incrementally, - not by having it deleted and then rebuilt from all - of the constituent object files. - In such cases, you can use the - &Precious; method to prevent - &SCons; from removing the target before it is built: - - </para> - - <scons_example name="ex1"> - <file name="SConstruct" printme="1"> - env = Environment() - lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) - env.Precious(lib) - </file> - <file name="f1.c"> - int f1() { } - </file> - <file name="f2.c"> - int f2() { } - </file> - <file name="f3.c"> - int f3() { } - </file> - </scons_example> - - <para> - - Although the output doesn't look any different, - &SCons; does not, in fact, - delete the target library before rebuilding it: - - </para> - - <scons_output example="ex1"> - <scons_output_command>scons -Q</scons_output_command> - </scons_output> - - <para> - - &SCons; will, however, still delete files marked as &Precious; - when the <literal>-c</literal> option is used. - - </para> diff --git a/doc/user/precious.sgml b/doc/user/precious.sgml deleted file mode 100644 index 6e80c85..0000000 --- a/doc/user/precious.sgml +++ /dev/null @@ -1,84 +0,0 @@ -<!-- - - __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. - ---> - -<!-- - -=head2 The C<AfterBuild> method - -The C<AfterBuild> method evaluates the specified perl string after -building the given file or files (or finding that they are up to date). -The eval will happen once per specified file. C<AfterBuild> is called -as follows: - - AfterBuild $env 'foo.o', qq(print "foo.o is up to date!\n"); - -The perl string is evaluated in the C<script> package, and has access -to all variables and subroutines defined in the F<Conscript> file in -which the C<AfterBuild> method is called. - ---> - - <para> - - By default, &SCons; removes targets before building them. - Sometimes, however, this is not what you want. - For example, you may want to update a library incrementally, - not by having it deleted and then rebuilt from all - of the constituent object files. - In such cases, you can use the - &Precious; method to prevent - &SCons; from removing the target before it is built: - - </para> - - <programlisting> - env = Environment() - lib = env.Library('foo', ['f1.c', 'f2.c', 'f3.c']) - env.Precious(lib) - </programlisting> - - <para> - - Although the output doesn't look any different, - &SCons; does not, in fact, - delete the target library before rebuilding it: - - </para> - - <screen> - % <userinput>scons -Q</userinput> - cc -c -o f1.o f1.c - cc -c -o f2.o f2.c - cc -c -o f3.o f3.c - ar r libfoo.a f1.o f2.o f3.o - ranlib libfoo.a - </screen> - - <para> - - &SCons; will, however, still delete files marked as &Precious; - when the <literal>-c</literal> option is used. - - </para> diff --git a/src/CHANGES.txt b/src/CHANGES.txt index e2d5d7c..9e6cb16 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -62,6 +62,11 @@ RELEASE 0.97 - XXX - Support $MAKEINDEX, $MAKEINDEXCOM, $MAKEINDEXCOMSTR and $MAKEINDEXFLAGS for generating indices from .idx files. + From Steven Johnson: + + - Add a NoClean() Environment method and function to override removal + of targets during a -c clean, including documentation and tests. + From Steven Knight: - Check for whether files exist on disk by listing the directory diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 92b1e3d..691098d 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -1285,6 +1285,15 @@ class Base(SubstitutionEnvironment): """ return apply(self.fs.Dir, (self.subst(name),) + args, kw) + def NoClean(self, *targets): + """Tags a target so that it will not be cleaned by -c""" + tlist = [] + for t in targets: + tlist.extend(self.arg2nodes(t, self.fs.Entry)) + for t in tlist: + t.set_noclean() + return tlist + def Entry(self, name, *args, **kw): """ """ diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 58c8ae8..48b258e 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -2285,6 +2285,29 @@ def generate(env): d = env.Dir('${BAR}_$BAR') assert d == 'Dir(bardir_bardir)', d + def test_NoClean(self): + """Test the NoClean() method""" + env = Environment(FOO='ggg', BAR='hhh') + env.Dir('p_hhhb') + env.File('p_d') + t = env.NoClean('p_a', 'p_${BAR}b', ['p_c', 'p_d'], 'p_$FOO') + + assert t[0].__class__.__name__ == 'Entry', t[0].__class__.__name__ + assert t[0].path == 'p_a' + assert t[0].noclean + assert t[1].__class__.__name__ == 'Dir', t[1].__class__.__name__ + assert t[1].path == 'p_hhhb' + assert t[1].noclean + assert t[2].__class__.__name__ == 'Entry', t[2].__class__.__name__ + assert t[2].path == 'p_c' + assert t[2].noclean + assert t[3].__class__.__name__ == 'File', t[3].__class__.__name__ + assert t[3].path == 'p_d' + assert t[3].noclean + assert t[4].__class__.__name__ == 'Entry', t[4].__class__.__name__ + assert t[4].path == 'p_ggg' + assert t[4].noclean + def test_Dump(self): """Test the Dump() method""" diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 4f7b65a..cd546cd 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -704,6 +704,15 @@ class NodeTestCase(unittest.TestCase): node.set_always_build(3) assert node.always_build == 3 + def test_set_noclean(self): + """Test setting a Node's noclean value + """ + node = SCons.Node.Node() + node.set_noclean() + assert node.noclean + node.set_noclean(7) + assert node.noclean == 7 + def test_set_precious(self): """Test setting a Node's precious value """ diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 483e88b..67a72ae 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -197,6 +197,7 @@ class Node: self.env = None self.state = no_state self.precious = None + self.noclean = None self.always_build = None self.found_includes = {} self.includes = None @@ -740,6 +741,10 @@ class Node: """Set the Node's precious value.""" self.precious = precious + def set_noclean(self, noclean = 1): + """Set the Node's noclean value.""" + self.noclean = noclean + def set_always_build(self, always_build = 1): """Set the Node's always_build value.""" self.always_build = always_build diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 8b3058a..5b35e14 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -224,7 +224,7 @@ class CleanTask(SCons.Taskmaster.Task): def show(self): target = self.targets[0] - if target.has_builder() or target.side_effect: + if (target.has_builder() or target.side_effect) and not target.noclean: for t in self.targets: if not t.isdir(): display("Removed " + str(t)) @@ -235,7 +235,7 @@ class CleanTask(SCons.Taskmaster.Task): def remove(self): target = self.targets[0] - if target.has_builder() or target.side_effect: + if (target.has_builder() or target.side_effect) and not target.noclean: for t in self.targets: try: removed = t.remove() diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 97ffdce..ce96867 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -281,6 +281,7 @@ GlobalDefaultEnvironmentFunctions = [ #The Command() method is handled separately, below. 'Depends', 'Dir', + 'NoClean', 'Entry', 'Execute', 'File', diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 37f3c06..d96f56c 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -343,14 +343,15 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): if showtags: if showtags == 2: - print ' E = exists' - print ' R = exists in repository only' - print ' b = implicit builder' - print ' B = explicit builder' - print ' S = side effect' - print ' P = precious' - print ' A = always build' - print ' C = current' + print ' E = exists' + print ' R = exists in repository only' + print ' b = implicit builder' + print ' B = explicit builder' + print ' S = side effect' + print ' P = precious' + print ' A = always build' + print ' C = current' + print ' N = no clean' print '' tags = ['['] @@ -362,6 +363,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): tags.append(' P'[IDX(root.precious)]) tags.append(' A'[IDX(root.always_build)]) tags.append(' C'[IDX(root.current())]) + tags.append(' N'[IDX(root.noclean())]) tags.append(']') else: diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index 724c51d..aa93db1 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -74,6 +74,8 @@ class UtilTestCase(unittest.TestCase): return 1 def current(self): return 1 + def noclean(self): + return 1 def tree_case_1(self): """Fixture for the render_tree() and print_tree() tests.""" @@ -98,7 +100,7 @@ class UtilTestCase(unittest.TestCase): """ lines = string.split(expect, '\n')[:-1] - lines = map(lambda l: '[E BSPAC]'+l, lines) + lines = map(lambda l: '[E BSPACN]'+l, lines) withtags = string.join(lines, '\n') + '\n' return foo, expect, withtags @@ -121,7 +123,7 @@ class UtilTestCase(unittest.TestCase): """ lines = string.split(expect, '\n')[:-1] - lines = map(lambda l: '[E BSPAC]'+l, lines) + lines = map(lambda l: '[E BSPACN]'+l, lines) withtags = string.join(lines, '\n') + '\n' return blat_o, expect, withtags diff --git a/test/option-c.py b/test/option-c.py index fbad75c..8814827 100644 --- a/test/option-c.py +++ b/test/option-c.py @@ -51,6 +51,8 @@ env.B(target = 'foo1.out', source = 'foo1.in') env.B(target = 'foo2.out', source = 'foo2.xxx') env.B(target = 'foo2.xxx', source = 'foo2.in') env.B(target = 'foo3.out', source = 'foo3.in') +env.B(target = 'foo4.out', source = 'foo4.in') +env.NoClean('foo4.out') import os if hasattr(os, 'symlink'): def symlink1(env, target, source): @@ -73,12 +75,15 @@ test.write('foo2.in', "foo2.in\n") test.write('foo3.in', "foo3.in\n") -test.run(arguments = 'foo1.out foo2.out foo3.out') +test.write('foo4.in', "foo4.in\n") + +test.run(arguments = 'foo1.out foo2.out foo3.out foo4.out') test.must_match(test.workpath('foo1.out'), "foo1.in\n") test.must_match(test.workpath('foo2.xxx'), "foo2.in\n") test.must_match(test.workpath('foo2.out'), "foo2.in\n") test.must_match(test.workpath('foo3.out'), "foo3.in\n") +test.must_match(test.workpath('foo4.out'), "foo4.in\n") test.run(arguments = '-c foo1.out', stdout = test.wrap_stdout("Removed foo1.out\n", cleaning=1)) @@ -87,6 +92,7 @@ test.must_not_exist(test.workpath('foo1.out')) test.must_exist(test.workpath('foo2.xxx')) test.must_exist(test.workpath('foo2.out')) test.must_exist(test.workpath('foo3.out')) +test.must_exist(test.workpath('foo4.out')) test.run(arguments = '--clean foo2.out foo2.xxx', stdout = test.wrap_stdout("Removed foo2.xxx\nRemoved foo2.out\n", @@ -96,6 +102,7 @@ test.must_not_exist(test.workpath('foo1.out')) test.must_not_exist(test.workpath('foo2.xxx')) test.must_not_exist(test.workpath('foo2.out')) test.must_exist(test.workpath('foo3.out')) +test.must_exist(test.workpath('foo4.out')) test.run(arguments = '--remove foo3.out', stdout = test.wrap_stdout("Removed foo3.out\n", cleaning=1)) @@ -104,6 +111,7 @@ test.must_not_exist(test.workpath('foo1.out')) test.must_not_exist(test.workpath('foo2.xxx')) test.must_not_exist(test.workpath('foo2.out')) test.must_not_exist(test.workpath('foo3.out')) +test.must_exist(test.workpath('foo4.out')) test.run(arguments = '.') @@ -112,6 +120,7 @@ test.must_match(test.workpath('foo2.xxx'), "foo2.in\n") test.must_match(test.workpath('foo2.out'), "foo2.in\n") test.must_match(test.workpath('foo3.out'), "foo3.in\n") test.must_match(test.workpath('foo3.out'), "foo3.in\n") +test.must_match(test.workpath('foo4.out'), "foo4.in\n") test.must_exist(test.workpath('touch1.out')) test.must_exist(test.workpath('touch2.out')) @@ -126,6 +135,7 @@ test.must_match(test.workpath('foo1.out'), "foo1.in\n") test.must_not_exist(test.workpath('foo2.xxx')) test.must_match(test.workpath('foo2.out'), "foo2.in\n") test.must_match(test.workpath('foo3.out'), "foo3.in\n") +test.must_match(test.workpath('foo4.out'), "foo4.in\n") test.must_exist(test.workpath('touch1.out')) test.must_exist(test.workpath('touch2.out')) @@ -134,6 +144,7 @@ test.run(arguments = '-c .') test.must_not_exist(test.workpath('foo1.out')) test.must_not_exist(test.workpath('foo2.out')) test.must_not_exist(test.workpath('foo3.out')) +test.must_exist(test.workpath('foo4.out')) test.must_not_exist(test.workpath('touch1.out')) test.must_not_exist(test.workpath('touch2.out')) @@ -162,6 +173,7 @@ test.must_match(test.workpath('foo1.out'), "foo1.in\n") test.must_match(test.workpath('foo2.xxx'), "foo2.in\n") test.must_match(test.workpath('foo2.out'), "foo2.in\n") test.must_match(test.workpath('foo3.out'), "foo3.in\n") +test.must_match(test.workpath('foo4.out'), "foo4.in\n") test.must_exist(test.workpath('touch1.out')) test.must_exist(test.workpath('touch2.out')) |