summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2008-03-31 17:03:04 (GMT)
committerSteven Knight <knight@baldmt.com>2008-03-31 17:03:04 (GMT)
commit8a201fe36c6b3ee53892b43efd2a21e967a5fc19 (patch)
treec867300d84fadb6014b7017b2eca94deffcaab88 /src
parentbe25024e65a30e65a9e3799ffa5323e23f49003d (diff)
downloadSCons-8a201fe36c6b3ee53892b43efd2a21e967a5fc19.zip
SCons-8a201fe36c6b3ee53892b43efd2a21e967a5fc19.tar.gz
SCons-8a201fe36c6b3ee53892b43efd2a21e967a5fc19.tar.bz2
Merged revisions 2647-2719 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core ........ r2649 | stevenknight | 2008-02-08 06:43:30 -0800 (Fri, 08 Feb 2008) | 3 lines Make the "bootstrap" copy directory relative to the script location regardless of where the user is when executing. ........ r2650 | stevenknight | 2008-02-09 09:26:40 -0800 (Sat, 09 Feb 2008) | 3 lines Chdir back to the original directory before removing our temporary directory, to avoid "Permission denied" errors on Windows. ........ r2651 | stevenknight | 2008-02-09 10:02:09 -0800 (Sat, 09 Feb 2008) | 3 lines Fix floating-point numbers confusing our notion of the .class files that will be generated in certain configurations. ........ r2652 | stevenknight | 2008-02-09 10:26:48 -0800 (Sat, 09 Feb 2008) | 4 lines Issue 1868: change the RootDir "lookup path" from '/' to '' so that looking up '/foo' returns the same node as looking up 'foo' when the current directory is the root. ........ r2653 | stevenknight | 2008-02-09 11:16:17 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1902: Document all the values that can now be fetched with GetOption. Additional formatting cleanups. ........ r2654 | stevenknight | 2008-02-09 11:37:50 -0800 (Sat, 09 Feb 2008) | 3 lines Fix handling file names that contain substrings of multiple spaces when using ActionFactory instances like Copy() and Move(). ........ r2655 | stevenknight | 2008-02-09 13:36:14 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1898: Fix use of a variable expansion in a source file name (like foo$OBJSUFFIX) when trying to match source builder suffixes. ........ r2656 | stevenknight | 2008-02-09 20:58:32 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1903: don't allow Java generics syntax to interfere with identifying an anonymous inner class. ........ r2657 | stevenknight | 2008-02-09 21:02:37 -0800 (Sat, 09 Feb 2008) | 3 lines Left out the \w from the regular expression that matches generics, so we wouldn't match alphanumerics, only alphabetics. ........ r2658 | stevenknight | 2008-02-09 23:33:03 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1899: Enhance Chmod(), Delete(), Mkdir() and Touch() to take lists of Nodes or strings. ........ r2659 | stevenknight | 2008-02-10 00:15:24 -0800 (Sun, 10 Feb 2008) | 4 lines Issue 1878: Add comment lines to the generated config.h file describing the intent of the various #define/#undef lines. (David Cournapeau) ........ r2660 | stevenknight | 2008-02-11 18:15:27 -0800 (Mon, 11 Feb 2008) | 3 lines Issue 1682: Fix the ability to save and restore the ListOption value 'all' in newer Python versions that have an all() built-in function. ........ r2661 | stevenknight | 2008-02-27 07:25:18 -0800 (Wed, 27 Feb 2008) | 3 lines Issue 1919: Optimize the SCons.Util.is_*() and SCons.Util.flatten() functions. More efficient suffix selection in Selector.__call__() method. ........ r2662 | stevenknight | 2008-02-28 06:43:29 -0800 (Thu, 28 Feb 2008) | 3 lines Fix SCons.Util.is_List() method to use the passed-in ListTypes variable. (Daniel Svensson) ........ r2663 | stevenknight | 2008-02-28 06:57:44 -0800 (Thu, 28 Feb 2008) | 4 lines Issue 1884: avoid an infinite loop when trying to use saved copies of the ToolInitializer objects that we use to initialize the env.Install() and env.InstallAs() methods. ........ r2664 | garyo | 2008-02-28 07:25:25 -0800 (Thu, 28 Feb 2008) | 1 line Fix long-style command-line args in runtest.py (they were missing from getopt call). ........ r2665 | garyo | 2008-02-28 09:31:42 -0800 (Thu, 28 Feb 2008) | 1 line runtest.py: Use qmtest instead of qmtest.py; newer QMTest releases may only have qmtest in /usr/bin. ........ r2666 | stevenknight | 2008-02-28 12:10:02 -0800 (Thu, 28 Feb 2008) | 3 lines Remove dead code that was at one time apparently intended to grab the external environment's %INCLUDE% values. ........ r2667 | stevenknight | 2008-02-28 12:16:40 -0800 (Thu, 28 Feb 2008) | 3 lines Move the regular expression and function that check for whether a construction variable name is legal from Util.py to Environment.py. ........ r2668 | stevenknight | 2008-02-28 20:24:36 -0800 (Thu, 28 Feb 2008) | 2 lines Fix qmtest.py references (replace with qmtest) in tests and infrastructure. ........ r2669 | stevenknight | 2008-02-28 20:27:05 -0800 (Thu, 28 Feb 2008) | 7 lines Speed up the SubstitionEnvironment.__setitem__() method by: 1) avoiding checking for whether the variable name is legal if it already exists; 2) use the regular expression directly when checking the form for illegality; 3) more efficient check for whether a variable name is special. Add a timing script so we can document why we implemented it as we did and revisit it in the future if need be. ........ r2670 | stevenknight | 2008-02-28 20:51:44 -0800 (Thu, 28 Feb 2008) | 2 lines Add a shell script that generates context-diff output for review. ........ r2671 | GregNoel | 2008-03-01 00:40:16 -0800 (Sat, 01 Mar 2008) | 1 line add test to env.__setitem__ benchmark ........ r2672 | GregNoel | 2008-03-01 02:00:12 -0800 (Sat, 01 Mar 2008) | 1 line compatibility changes for env.__setitem__ benchmark ........ r2673 | stevenknight | 2008-03-01 09:56:57 -0800 (Sat, 01 Mar 2008) | 3 lines Capture a vanilla copy of the Python 2.[45] timeit.py module, as a basis for being able to use this to time Python 2.2 (and earlier). ........ r2674 | stevenknight | 2008-03-01 10:04:11 -0800 (Sat, 01 Mar 2008) | 3 lines Work around a race in the order in which we detect and report the build failures by letting the error messages show up in either order on stdout. ........ r2675 | stevenknight | 2008-03-01 10:05:24 -0800 (Sat, 01 Mar 2008) | 3 lines Back-port the captured timeit.py module, and the env.__setitem__.py script itself, to Python versions before 2.3. ........ r2676 | GregNoel | 2008-03-01 14:01:03 -0800 (Sat, 01 Mar 2008) | 1 line add banner information, remove inadvertent tabs ........ r2677 | stevenknight | 2008-03-02 05:04:52 -0800 (Sun, 02 Mar 2008) | 3 lines Don't look for a Copyright string in the source-packaged bench/timeit.py module that we captured. ........ r2678 | stevenknight | 2008-03-02 14:59:39 -0800 (Sun, 02 Mar 2008) | 6 lines Issue 1884: Allow env.{Install,InstallAs}() to be replaced by user- supplied wrappers that call the underlying builder. Fix how environment cloning so it only clones dynamically-added method attributes that the user hasn't also overwritten explicity. ........ r2679 | stevenknight | 2008-03-04 07:48:53 -0800 (Tue, 04 Mar 2008) | 3 lines Fix env.{Dir,Entry,File}() when the input is a list, broken last December when env.subst() was modified to return lists as-is. ........ r2680 | stevenknight | 2008-03-04 08:24:06 -0800 (Tue, 04 Mar 2008) | 2 lines Fix printing Python Value Nodes in --debug=explain output. (Jim Randall) ........ r2681 | garyo | 2008-03-04 12:37:39 -0800 (Tue, 04 Mar 2008) | 1 line Make File(), Dir() and Entry() return lists when passed a sequence. ........ r2682 | garyo | 2008-03-05 15:24:00 -0800 (Wed, 05 Mar 2008) | 1 line InstallBuilderWrapper and InstallBuilderWrapper should accept keyword args and pass them to the base builder, like other builders. ........ r2683 | stevenknight | 2008-03-06 06:32:13 -0800 (Thu, 06 Mar 2008) | 2 lines Python 1.5.2 compatibility: use apply() instead of **kw. ........ r2684 | garyo | 2008-03-14 13:07:09 -0700 (Fri, 14 Mar 2008) | 1 line Fix QMTest problem with $TERM variable in user's environment causing test failures. ........ r2685 | bdbaddog | 2008-03-14 13:16:20 -0700 (Fri, 14 Mar 2008) | 13 lines * Added java_where_includes - gets path list for java JDK's include dirs * Added java_where_java_home - gets JAVA_HOME path * Added path's to find java for sun's JDK rpm install to java_where_jar * moved paths() to be outside of java_ENV() routine and available for other routines to use as well as tests * set TERM to be dumb to fix broken readline causing massive failures on FC8 (only updated Gary's comments to include note about broken FC8 readline, as Gary committed the TERM just prior to my checkin) * Modified the following tests to use the above changes: * test/SWIG/SWIGOUTDIR.py * test/Java/swig-dependencies.py * test/Java/multi-step.py * test/Repository/Java.py * test/runtest/fallback.py [ This test also has been changed to remove more than one qmtest in your PATH, previously it would only remove one path which had qmtest, my system had a local and a system version ] ........ r2686 | stevenknight | 2008-03-15 20:50:07 -0700 (Sat, 15 Mar 2008) | 4 lines Add a warning about deprecating support for Python versions 1.5, 2.0 and 2.1. Fix the ability to SetOption('warn') so people can disable the warning by adding something to a SConscript file. ........ r2687 | stevenknight | 2008-03-15 21:48:26 -0700 (Sat, 15 Mar 2008) | 3 lines Issue 1942: Document the Dir(), File() and Entry() methods of Dir and File Nodes. (Greg Noel) ........ r2688 | GregNoel | 2008-03-16 00:05:04 -0700 (Sun, 16 Mar 2008) | 1 line Add parse_flags keyword option ........ r2689 | stevenknight | 2008-03-16 00:32:33 -0700 (Sun, 16 Mar 2008) | 3 lines Print a message if we're skipping the build of a package because the necessary underlying tool doesn't exist. ........ r2690 | stevenknight | 2008-03-16 00:40:28 -0700 (Sun, 16 Mar 2008) | 7 lines Add --warn=no-python-version to the $SCONSFLAGS variable when running tests under deprecated Python versions, so the warning doesn't interfere with running normal tests under those version. Have the test/python-version.py remove --warn=no-python-version from the $SCONSFLAGS variable, since it's explicitly testing that behavior. ........ r2691 | stevenknight | 2008-03-16 08:20:54 -0700 (Sun, 16 Mar 2008) | 4 lines Handle ripple effects from setting $SCONSFLAGS to suppress the deprecation under older Python versions by commonizing and moving much of the logic in QMTest/TestSCons.py. ........ r2692 | stevenknight | 2008-03-16 08:47:52 -0700 (Sun, 16 Mar 2008) | 5 lines Update the warning message for running under a deprecated Python version (text courtesy Greg Noel). Make that warning a subclass of the DeprecatedWarning class, so the message can also be disabled by setting --warn=no-deprecated. ........ r2693 | stevenknight | 2008-03-16 11:19:52 -0700 (Sun, 16 Mar 2008) | 4 lines Shorten the deprecated-python-version warning. Use sys.version_info to check, instead of hard-coded string comparisons. Edit the release note. ........ r2694 | stevenknight | 2008-03-16 11:29:10 -0700 (Sun, 16 Mar 2008) | 3 lines Have the warning mention both that 2.2 is the base un-deprecated version and the version they're running without getting too wordy. ........ r2695 | stevenknight | 2008-03-16 12:00:22 -0700 (Sun, 16 Mar 2008) | 2 lines Skip test/SWIG/SWIGOUTDIR.py if no installed jni.h files are found. ........ r2696 | stevenknight | 2008-03-18 18:01:46 -0700 (Tue, 18 Mar 2008) | 2 lines Remove old, commented-out deprecation test code. ........ r2697 | stevenknight | 2008-03-19 17:54:55 -0700 (Wed, 19 Mar 2008) | 2 lines Deprecate env.Copy() with a suppressable message. ........ r2699 | stevenknight | 2008-03-20 08:20:22 -0700 (Thu, 20 Mar 2008) | 2 lines Move the debug-nomemoizer.py test to the test/Deprecated subdirectory. ........ r2700 | stevenknight | 2008-03-20 08:37:51 -0700 (Thu, 20 Mar 2008) | 2 lines Issue 1954: Adds deprecation warnings for --debug={dtree,stree,tree}. ........ r2701 | stevenknight | 2008-03-23 00:33:25 -0700 (Sun, 23 Mar 2008) | 7 lines Add VariantDir() as a replacement for BuildDir(). Change "build directory" references in text (comments and documentation) to "variant directory." Move and rename tests that named BuildDir in their path. Add a release note about the forthcoming deprecation of BuildDir(). Add a test/Deprecated/BuildDir.py to track backwards compatibility. ........ r2702 | stevenknight | 2008-03-24 11:23:39 -0700 (Mon, 24 Mar 2008) | 4 lines Change the VariantDir() and SConscrip "build_dir" keyword to "variant_dir." Still support "build_dir" for (you guessed it) backwards compatibility. Add documentation update and release note. ........ r2703 | garyo | 2008-03-25 07:57:01 -0700 (Tue, 25 Mar 2008) | 1 line Improve Install error message when target and source list lengths don't match. ........ r2704 | garyo | 2008-03-25 08:10:24 -0700 (Tue, 25 Mar 2008) | 1 line Allow executing main scons.py script without running scons, using standard if __name__==__main__ idiom. ........ r2705 | stevenknight | 2008-03-26 08:51:58 -0700 (Wed, 26 Mar 2008) | 3 lines Update scripts that use {Source,Target}Signatures() to use Decider() or the default behavior. Update test condition checks as necessary. ........ r2706 | stevenknight | 2008-03-27 14:13:50 -0700 (Thu, 27 Mar 2008) | 2 lines Update some leftover uses of env.Copy() in some test scripts to env.Clone(). ........ r2707 | stevenknight | 2008-03-27 14:20:33 -0700 (Thu, 27 Mar 2008) | 6 lines Fix use of SetOption('warn') to disable warning messages. Refactor the Script.Main._setup_warn() function into Warnings.process_warn_strings(). Split test/option--warn.py into separate test/option/warn-*.py scripts for the individual subtests it contained. ........ r2708 | stevenknight | 2008-03-27 15:17:44 -0700 (Thu, 27 Mar 2008) | 5 lines Deprecate the {Target,Source}Signatures() functions and methods. Move the test scripts underneath the test/Deprecated directory. Update man page with the new --warn=* options (and some that were overlooked on previous checkins). Add a release note. ........ r2709 | stevenknight | 2008-03-27 23:22:38 -0700 (Thu, 27 Mar 2008) | 2 lines More conversion of env.Copy() calls to env.Clone(). ........ r2710 | stevenknight | 2008-03-28 00:09:40 -0700 (Fri, 28 Mar 2008) | 3 lines Test updates for old Python versions (1.5.2) now that we generate a warning message about the deprecation. ........ r2711 | stevenknight | 2008-03-28 22:11:03 -0700 (Fri, 28 Mar 2008) | 3 lines Chmod the built packages in build/dist to 0644 so they're publicy readable when they're copied over to the snapshot system. ........ r2712 | stevenknight | 2008-03-28 22:11:54 -0700 (Fri, 28 Mar 2008) | 3 lines Issue 1951: have Copy() preserve file times and mode when copying over individual files. (Leanid Nazdrynau) ........ r2713 | stevenknight | 2008-03-29 06:49:27 -0700 (Sat, 29 Mar 2008) | 3 lines Don't bother checking for equivalent file access times. Under system load it can vary because we do actually access the file. ........ r2714 | GregNoel | 2008-03-29 17:24:25 -0700 (Sat, 29 Mar 2008) | 1 line Fix regression test using Python 1.5.2 on OS X ........ r2715 | GregNoel | 2008-03-29 20:44:19 -0700 (Sat, 29 Mar 2008) | 1 line 'Copy' conflicts with 'copy' on case-insensitive file systems ........ r2716 | stevenknight | 2008-03-29 21:00:13 -0700 (Sat, 29 Mar 2008) | 3 lines Capture scripts for downloading and installing different versions of Python and SCons. ........ r2717 | stevenknight | 2008-03-30 08:48:28 -0700 (Sun, 30 Mar 2008) | 3 lines Fix a regression in how subst_path() handles lists (like a ListOption) in expansions of things like $CPPDEFINES and $CPPPATH. ........ r2718 | stevenknight | 2008-03-30 10:02:21 -0700 (Sun, 30 Mar 2008) | 6 lines User's Guide updates: -- Paragraph about deprecated BuildDir(). -- Updated output using the jar -C option. -- Updated default environment Dump(). -- Updated --debug=stacktrace output. ........ r2719 | stevenknight | 2008-03-31 00:50:08 -0700 (Mon, 31 Mar 2008) | 2 lines Update the branch for 0.98. ........
Diffstat (limited to 'src')
-rw-r--r--src/CHANGES.txt84
-rw-r--r--src/RELEASE.txt299
-rw-r--r--src/engine/SCons/Action.py19
-rw-r--r--src/engine/SCons/ActionTests.py19
-rw-r--r--src/engine/SCons/Builder.py9
-rw-r--r--src/engine/SCons/BuilderTests.py36
-rw-r--r--src/engine/SCons/Conftest.py39
-rw-r--r--src/engine/SCons/Defaults.py104
-rw-r--r--src/engine/SCons/Environment.py149
-rw-r--r--src/engine/SCons/EnvironmentTests.py149
-rw-r--r--src/engine/SCons/Node/FS.py69
-rw-r--r--src/engine/SCons/Node/FSTests.py108
-rw-r--r--src/engine/SCons/Node/__init__.py9
-rw-r--r--src/engine/SCons/Options/ListOption.py2
-rw-r--r--src/engine/SCons/Options/__init__.py27
-rw-r--r--src/engine/SCons/SConf.py2
-rw-r--r--src/engine/SCons/Scanner/CTests.py8
-rw-r--r--src/engine/SCons/Scanner/FortranTests.py6
-rw-r--r--src/engine/SCons/Scanner/IDLTests.py6
-rw-r--r--src/engine/SCons/Scanner/Prog.py4
-rw-r--r--src/engine/SCons/Script/Interactive.py4
-rw-r--r--src/engine/SCons/Script/Main.py91
-rw-r--r--src/engine/SCons/Script/SConsOptions.py51
-rw-r--r--src/engine/SCons/Script/SConscript.py14
-rw-r--r--src/engine/SCons/Script/__init__.py1
-rw-r--r--src/engine/SCons/Taskmaster.py4
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py14
-rw-r--r--src/engine/SCons/Tool/JavaCommonTests.py69
-rw-r--r--src/engine/SCons/Tool/__init__.py119
-rw-r--r--src/engine/SCons/Tool/applelink.py3
-rw-r--r--src/engine/SCons/Tool/dvips.py2
-rw-r--r--src/engine/SCons/Tool/install.py25
-rw-r--r--src/engine/SCons/Tool/msvc.py4
-rw-r--r--src/engine/SCons/Tool/msvs.py2
-rw-r--r--src/engine/SCons/Tool/qt.xml4
-rw-r--r--src/engine/SCons/Util.py149
-rw-r--r--src/engine/SCons/UtilTests.py61
-rw-r--r--src/engine/SCons/Warnings.py69
-rw-r--r--src/engine/SCons/compat/__init__.py10
-rw-r--r--src/engine/SCons/cppTests.py2
-rw-r--r--src/script/scons.py5
-rw-r--r--src/test_strings.py1
42 files changed, 1377 insertions, 475 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 81b54e6..dee5951 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -8,7 +8,7 @@
-RELEASE 0.XX - XXX
+RELEASE 0.98 - Sun, 30 Mar 2008 23:33:05 -0700
From Benoit Belley:
@@ -43,6 +43,12 @@ RELEASE 0.XX - XXX
- Add support for the Intel C compiler on Mac OS X.
+ - Speed up reading SConscript files by about 20% (for some
+ configurations) by: 1) optimizing the SCons.Util.is_*() and
+ SCons.Util.flatten() functions; 2) avoiding unnecessary os.stat()
+ calls by using a File's .suffix attribute directly instead of
+ stringifying it.
+
From Jérôme Berger:
- Have the D language scanner search for .di files as well as .d files.
@@ -56,7 +62,7 @@ RELEASE 0.XX - XXX
From Konstantin Bozhikov:
- Support expansion of construction variables that contain or refer
- to lists of other variables or Nodes within expansions like $PCPPATH.
+ to lists of other variables or Nodes within expansions like $CPPPATH.
- Change variable substitution (the env.subst() method) so that an
input sequence (list or tuple) is preserved as a list in the output.
@@ -74,6 +80,9 @@ RELEASE 0.XX - XXX
- Avoid use of -rpath with the Mac OS X linker.
+ - Add comment lines to the generated config.h file to describe what
+ the various #define/#undef lines are doing.
+
From Steven Knight:
- Support the ability to subclass the new-style "str" class as input
@@ -100,19 +109,74 @@ RELEASE 0.XX - XXX
- On Mac OS X, account for the fact that the header file generated
from a C++ file will be named (e.g.) file.cpp.h, not file.hpp.
+ - Fix floating-point numbers confusing the Java parser about
+ generated .class file names in some configurations.
+
+ - Document (nearly) all the values you can now fetch with GetOption().
+
+ - Fix use of file names containing strings of multiple spaces when
+ using ActionFactory instances like the Copy() or Move() function.
+
+ - Fix a 0.97 regression when using a variable expansion (like
+ $OBJSUFFIX) in a source file name to a builder with attached source
+ builders that match suffix (like Program()+Object()).
+
+ - Have the Java parser recognize generics (surrounded by angle brackets)
+ so they don't interfere with identifying anonymous inner classes.
+
+ - Avoid an infinite loop when trying to use saved copies of the
+ env.Install() or env.InstallAs() after replacing the method
+ attributes.
+
+ - Improve the performance of setting construction variables.
+
+ - When cloning a construction environment, avoid over-writing an
+ attribute for an added method if the user explicitly replaced it.
+
+ - Add a warning about deprecated support for Python 1.5, 2.0 and 2.1.
+
+ - Fix being able to SetOption('warn', ...) in SConscript files.
+
+ - Add a warning about env.Copy() being deprecated.
+
+ - Add warnings about the --debug={dtree,stree,tree} options
+ being deprecated.
+
+ - Add VariantDir() as the first step towards deprecating BuildDir().
+ Add the keyword argument "variant_dir" as the replacement for
+ "build_dir".
+
+ - Add warnings about the {Target,Source}Signatures() methods and
+ functions being deprecated.
+
From Rob Managan:
- Enhance TeX and LaTeX support to work with BuildDir(duplicate=0).
- Re-run LaTeX when it issues a package warning that it must be re-run.
+ From Leanid Nazdrynau:
+
+ - Have the Copy() action factory preserve file modes and times
+ when copying individual files.
+
From Jan Nijtmans:
- If $JARCHDIR isn't set explicitly, use the .java_classdir attribute
that was set when the Java() Builder built the .class files.
+ From Greg Noel:
+
+ - Document the Dir(), File() and Entry() methods of Dir and File Nodes.
+
+ - Add the parse_flags option when creating Environments
+
From Gary Oberbrunner:
+ - Make File(), Dir() and Entry() return a list of Nodes when passed
+ a list of names, instead of trying to make a string from the name
+ list and making a Node from that string.
+
- Fix the ability to build an Alias in --interactive mode.
- Fix the ability to hash the contents of actions for nested Python
@@ -126,6 +190,10 @@ RELEASE 0.XX - XXX
- Handle Intel C compiler network license files (port@system).
+ From Jim Randall:
+
+ - Fix how Python Value Nodes are printed in --debug=explain output.
+
From Adam Simpkins:
- Add a --interactive option that starts a session for building (or
@@ -136,6 +204,18 @@ RELEASE 0.XX - XXX
- Have the --interactive mode "build" command with no arguments
build the specified Default() targets.
+ - Fix the Chmod(), Delete(), Mkdir() and Touch() Action factories to
+ take a list (of Nodes or strings) as arguments.
+
+ From Vaclav Smilauer:
+
+ - Fix saving and restoring an Options value of 'all' on Python
+ versions where all() is a builtin function.
+
+ From Daniel Svensson:
+
+ - Code correction in SCons.Util.is_List().
+
From Ben Webb:
- Support the SWIG %module statement with following modifiers in
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 7327f21..0c4f905 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -20,25 +20,182 @@ more effectively, please sign up for the scons-users mailing list at:
-RELEASE 0.97.0d20071212 - Wed, 12 Dec 2007 09:29:32 -0600
+RELEASE 0.98 - Sun, 30 Mar 2008 23:33:05 -0700
- This is the eighth beta release of SCons. Please consult the
+ This is the ninth beta release of SCons. Please consult the
CHANGES.txt file for a list of specific changes since last release.
Please note the following important changes since release 0.97.0d20071212:
+ -- SUPPORT FOR PYTHON VERSIONS BEFORE 2.2 IS NOW DEPRECATED
+
+ SCons now prints the following warning when it is run by any
+ Python 1.5, 2.0 or 2.1 release or sub-release:
+
+ scons: warning: Support for pre-2.2 Python (VERSION) is deprecated.
+ If this will cause hardship, contact dev@scons.tigris.org.
+
+ You may disable all warnings about deprecated features by adding
+ the option "--warn=no-deprecated" to the command line or to the
+ $SCONSFLAGS environment variable:
+
+ $ scons --warn=no-deprecated
+
+ Using '--warn=no-deprecated' is compatible with earlier versions
+ of SCons.
+
+ You may also, as of this version of SCons, disable all warnings
+ about deprecated features by adding the following to any
+ SConscript file:
+
+ SetOption('warn', 'no-deprecated')
+
+ You may disable only the specific warning about running under
+ a deprecated Python version by adding the following to any
+ SConscript file:
+
+ SetOption('warn', 'no-python-version')
+
+ The warning may also be suppressed on the command line:
+
+ $ scons --warn=no-python-version
+
+ Or by specifying the --warn=no-python-version option in the
+ $SCONSFLAGS environment variable.
+
+ Using SetOption('warn', ...), and the 'no-python-version'
+ command-line option for suppressing this specific warning,
+ are *not* backwards-compatible to earlier versions of SCons.
+
+ -- THE env.Copy() METHOD IS NOW OFFICIALLY DEPRECATED
+
+ The env.Copy() method is now officially deprecated and will
+ be removed in a future release. Using the env.Copy() method
+ now generates the following message:
+
+ scons: warning: The env.Copy() method is deprecated; use the env.Clone() method instead.
+
+ You may disable all warnings about deprecated features by adding
+ the option "--warn=no-deprecated" to the command line or to the
+ $SCONSFLAGS environment variable:
+
+ $ scons --warn=no-deprecated
+
+ Using '--warn=no-deprecated' is compatible with earlier versions
+ of SCons.
+
+ You may also, as of this version of SCons, disable all warnings
+ about deprecated features by adding the following to any
+ SConscript file:
+
+ SetOption('warn', 'no-deprecated')
+
+ You may disable only the specific warning about the deprecated
+ env.Copy() method by adding the following to any SConscript
+ file:
+
+ SetOption('warn', 'no-deprecated-copy')
+
+ The warning may also be suppressed on the command line:
+
+ $ scons --warn=no-deprecated-copy
+
+ Or by specifying the --warn=no-deprecated-copy option in the
+ $SCONSFLAGS environment variable.
+
+ Using SetOption('warn', ...), and the 'no-deprecated-copy'
+ command-line option for suppressing this specific warning,
+ are *not* backwards-compatible to earlier versions of SCons.
+
+ -- THE --debug=dtree, --debug=stree AND --debug=tree OPTIONS ARE DEPRECATED
+
+ The --debug=dtree, --debug=stree and --debug=tree methods
+ are now officially deprecated and will be removed in a
+ future release. Using these options now generate a warning
+ message recommending use of the --tree=derived, --tree=all,status
+ and --tree=all options, respectively.
+
+ You may disable these warnings, and all warnings about
+ deprecated features, by adding the option "--warn=no-deprecated"
+ to the command line or to the $SCONSFLAGS environment
+ variable:
+
+ $ scons --warn=no-deprecated
+
+ Using '--warn=no-deprecated' is compatible with earlier versions
+ of SCons.
+
+ -- THE TargetSignatures() AND SourceSignatures() FUNCTIONS ARE DEPRECATED
+
+ The TargetSignatures() and SourceSignatures() functions,
+ and their corresponding env.TargetSignatures() and
+ env.SourceSignatures() methods, are now officially deprecated
+ and will be be removed in a future release. Using ahy of
+ these functions or methods now generates a message
+ similar to the following:
+
+ scons: warning: The env.TargetSignatures() method is deprecated;
+ convert your build to use the env.Decider() method instead.
+
+ You may disable all warnings about deprecated features by adding
+ the option "--warn=no-deprecated" to the command line or to the
+ $SCONSFLAGS environment variable:
+
+ $ scons --warn=no-deprecated
+
+ Using '--warn=no-deprecated' is compatible with earlier versions
+ of SCons.
+
+ You may also, as of this version of SCons, disable all warnings
+ about deprecated features by adding the following to any
+ SConscript file:
+
+ SetOption('warn', 'no-deprecated')
+
+ You may disable only the specific warning about the use of
+ TargetSignatures() or SourceSignatures() by adding the
+ following to any SConscript file:
+
+ SetOption('warn', 'no-deprecated-target-signatures')
+ SetOption('warn', 'no-deprecated-source-signatures')
+
+ The warnings may also be suppressed on the command line:
+
+ $ scons --warn=no-deprecated-target-signatures --warn=no-deprecated-source-signatures
+
+ Or by specifying these options in the $SCONSFLAGS environment
+ variable.
+
+ Using SetOption('warn', ...), or the command-line options
+ for suppressing these warnings, is *not* backwards-compatible
+ to earlier versions of SCons.
+
+ -- File(), Dir() and Entry() NOW RETURN A LIST WHEN THE INPUT IS A SEQUENCE
+
+ Previously, if these methods were passed a list, the list was
+ substituted and stringified, then passed as a single string to
+ create a File/Dir/Entry Node. This rarely if ever worked with
+ more than one element in the list. They now return a list of
+ Nodes when passed a list.
+
+ One case that works differently now is a passing in a
+ single-element sequence; that formerly was stringified
+ (returning its only element) and then a single Node would be
+ returned. Now a single-element list containing the Node will
+ be returned, for consistency.
+
-- THE env.subst() METHOD NOW RETURNS A LIST WHEN THE INPUT IS A SEQUENCE
The env.subst() method now returns a list with the elements
expanded when given a list as input. Previously, the env.subst()
method would always turn its result into a string.
- This behavior was changed because way it interfered with
- being able to include things like lists within the expansion
- of variables like $CPPPATH and have SCons understand that the
- elements of the "internal" lists still needed to be treated
- separately. This would show up as a list like ['subdir1',
- 'subdir'] showing up in a command line as "-Isubdir1 subdir".
+ This behavior was changed because it interfered with being able
+ to include things like lists within the expansion of variables
+ like $CPPPATH and then have SCons understand that the elements
+ of the "internal" lists still needed to be treated separately.
+ This would cause a $CPPPATH list like ['subdir1', 'subdir']
+ to show up in a command line as "-Isubdir1 subdir".
-- THE Jar() BUILDER NOW USES THE Java() BUILDER CLASSDIR BY DEFAULT
@@ -698,6 +855,105 @@ RELEASE 0.97.0d20071212 - Wed, 12 Dec 2007 09:29:32 -0600
Please note the following planned, future changes:
+ -- THE BuildDir() METHOD AND FUNCTION WILL BE DEPRECATED
+
+ The env.BuildDir() method and BuildDir() function are being
+ replaced by the new env.VariantDir() method and VariantDir()
+ function.
+
+ In some future release a deprecation warning will be added
+ to existing uses of the env.BuildDir() method and BuildDir()
+ function. At some point after the deprecation warning, the
+ env.Builder() method and BuildDir() function will either
+ be removed entirely or have their behavior changed.
+
+ You can prepare for this by changing all your uses of the
+ env.BuildDir() method to env.VariantDir() and uses of the
+ global BuildDir() function to VariantDir(). If you use a
+ named keyword argument of "build_dir" when calling
+ env.BuildDir() or BuildDir():
+
+ env.BuildDir(build_dir='opt', src_dir='src')
+
+ The keyword must be changed to "variant_dir":
+
+ env.VariantDir(variant_dir='opt', src_dir='src')
+
+ NOTE: CHANGING USES OF env.BuildDir() AND BuildDir() to
+ env.VariantDir() AND VariantDir() IS NOT BACKWARDS COMPATIBLE
+ TO VERSIONS OF SCons BEFORE 0.98. YOUR SConscript FILES
+ WILL NOT WORK ON EARLIER VERSIONS OF SCons AFTER MAKING
+ THIS CHANGE.
+
+ If you change SConscript files in software that you make
+ available for download or otherwise distribute, other users
+ may try to build your software with an earlier version of
+ SCons that does not have the env.VariantDir() method or
+ VariantDir() fnction. We recommend preparing for this in
+ one of two ways:
+
+ -- Make your SConscript files backwards-compatible by
+ including the following code near the beginning of your
+ top-level SConstruct file:
+
+ import SCons.Environment
+ try:
+ SCons.Environment.Environment.VariantDir
+ except AttributeError:
+ SCons.Environment.Environment.VariantDir = \
+ SCons.Environment.Environment.BuildDir
+
+ -- Use the EnsureSConsVersion() function to provide a
+ descriptive error message if your SConscript files
+ are executed by an earlier version of SCons:
+
+ EnsureSConsVersion(0, 98)
+
+ -- THE SConscript() "build_dir" KEYWORD ARGUMENT WILL BE DEPRECATED
+
+ The "build_dir" keyword argument of the SConscript function
+ and env.SConscript() method are being replaced by a new
+ "variant_dir" keyword argument.
+
+ In some future release a deprecation warning will be added
+ to existing uses of the SConscript()/env.SConscript()
+ "build_dir" keyword argument. At some point after the
+ deprecation warning, support for this keyword argument will
+ be removed entirely.
+
+ You can prepare for this by changing all your uses of the
+ SConscript()/env.SConscript() 'build_dir" keyword argument:
+
+ SConscript('src/SConscript', build_dir='opt')
+
+ To use the new "variant_dir" keyword argument:
+
+ SConscript('src/SConscript', variant_dir='opt')
+
+ NOTE: USING THE NEW "variant_dir" KEYWORD IS NOT BACKWARDS
+ COMPATIBLE TO VERSIONS OF SCons BEFORE 0.98. YOUR SConscript
+ FILES WILL NOT WORK ON EARLIER VERSIONS OF SCons AFTER
+ MAKING THIS CHANGE.
+
+ If you change SConscript files in software that you make
+ available for download or otherwise distribute, other users
+ may try to build your software with an earlier version of
+ SCons that does not support the "variant_dir" keyword.
+
+ If you can insist that users use a recent version of SCons
+ that supports "variant_dir", we recommend using the
+ EnsureSConsVersion() function to provide a descriptive error
+ message if your SConscript files are executed by an earlier
+ version of SCons:
+
+ EnsureSConsVersion(0, 98)
+
+ If you want to make sure that your SConscript files will
+ still work with earlier versions of SCons, then your best
+ bet is to continue to use the "build_dir" keyword until the
+ support is removed (which, in all likelihood, won't happen
+ for quite some time).
+
-- SCANNER NAMES HAVE BEEN DEPRECATED AND WILL BE REMOVED
Several internal variable names in SCons.Defaults for various
@@ -724,22 +980,23 @@ RELEASE 0.97.0d20071212 - Wed, 12 Dec 2007 09:29:32 -0600
The env.Copy() method (to make a copy of a construction
environment) is being replaced by the env.Clone() method.
- In some future release, a deprecation warning will be added
- to current uses of the env.Copy() method. At some point after
- the deprecation warning, the env.Copy() method will either be
- removed entirely or have its behavior changed.
+ As of SCons 0.98, a deprecation warning has been added to
+ current uses of the env.Copy() method. At some point in
+ the future, the env.Copy() method will either be removed
+ entirely or have its behavior changed.
You can prepare for this by changing all your uses of env.Copy()
to env.Clone(), which has the exact same calling arguments.
- NOTE: CHANGING USES OF env.Copy() TO env.Clone() WILL MAKE YOUR
- SConscript FILES NOT WORK ON EARLIER VERSIONS OF SCons.
+ NOTE: CHANGING USES OF env.Copy() TO env.Clone() WILL MAKE
+ YOUR SConscript FILES NOT WORK ON VERSIONS OF SCons BEFORE
+ 0.96.93.
- If you change SConscript files in software that you make available
- for download or otherwise distribute, other users may try to
- build your software with an earlier version of SCons that does
- not have the env.Clone() method. We recommend preparing for
- this in one of two ways:
+ If you change SConscript files in software that you make
+ available for download or otherwise distribute, other users
+ may try to build your software with an earlier version of
+ SCons that does not have the env.Clone() method. We recommend
+ preparing for this in one of two ways:
-- Make your SConscript files backwards-compatible by
including the following code near the beginning of your
@@ -835,10 +1092,6 @@ RELEASE 0.97.0d20071212 - Wed, 12 Dec 2007 09:29:32 -0600
created as part of the build, and also does not clean up
SideEffect files (for example, Visual Studio .pdb files).
- - Switching content signatures from "MD5" to "timestamp" and back
- again can cause unusual errors. These errors can be cleared up by
- removing all .sconsign files.
-
- When using multiple Repositories, changing the name of an include
file can cause an old version of the file to be used.
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index cd4bf6a..367174c 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -566,7 +566,7 @@ class CommandAction(_ActionAction):
"""
from SCons.Subst import escape_list
import SCons.Util
- flatten = SCons.Util.flatten
+ flatten_sequence = SCons.Util.flatten_sequence
is_String = SCons.Util.is_String
is_List = SCons.Util.is_List
@@ -601,7 +601,7 @@ class CommandAction(_ActionAction):
# If the value is a list, then we assume it is a
# path list, because that's a pretty common list-like
# value to stick in an environment variable:
- value = flatten(value)
+ value = flatten_sequence(value)
ENV[key] = string.join(map(str, value), os.pathsep)
else:
# If it isn't a string or a list, then we just coerce
@@ -891,9 +891,8 @@ class ListAction(ActionBase):
return string.join(map(str, self.list), '\n')
def presub_lines(self, env):
- return SCons.Util.flatten(map(lambda a, env=env:
- a.presub_lines(env),
- self.list))
+ return SCons.Util.flatten_sequence(
+ map(lambda a, env=env: a.presub_lines(env), self.list))
def get_contents(self, target, source, env):
"""Return the signature contents of this action list.
@@ -949,13 +948,21 @@ class ActionCaller:
contents = remove_set_lineno_codes(contents)
return contents
def subst(self, s, target, source, env):
+ # If s is a list, recursively apply subst()
+ # to every element in the list
+ if SCons.Util.is_List(s):
+ result = []
+ for elem in s:
+ result.append(self.subst(elem, target, source, env))
+ return self.parent.convert(result)
+
# Special-case hack: Let a custom function wrapped in an
# ActionCaller get at the environment through which the action
# was called by using this hard-coded value as a special return.
if s == '$__env__':
return env
elif SCons.Util.is_String(s):
- return env.subst(s, 0, target, source)
+ return env.subst(s, 1, target, source)
return self.parent.convert(s)
def subst_args(self, target, source, env):
return map(lambda x, self=self, t=target, s=source, e=env:
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 2ad4bef..74664b0 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -1772,20 +1772,21 @@ class ActionCallerTestCase(unittest.TestCase):
def test_strfunction(self):
"""Test calling the ActionCaller strfunction() method"""
strfunc_args = []
- def actfunc(a1, a2, a3):
+ def actfunc(a1, a2, a3, a4):
pass
- def strfunc(a1, a2, a3, args=strfunc_args):
- args.extend([a1, a2, a3])
+ def strfunc(a1, a2, a3, a4, args=strfunc_args):
+ args.extend([a1, a2, a3, a4])
af = SCons.Action.ActionFactory(actfunc, strfunc)
- ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3], {})
- ac.strfunction([], [], Environment(FOO = 2))
- assert strfunc_args == [1, '2', 3], strfunc_args
+ ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
+ ac.strfunction([], [], Environment(FOO = 2, WS='white space'))
+ assert strfunc_args == [1, '2', 3, 'white space'], strfunc_args
del strfunc_args[:]
- ac = SCons.Action.ActionCaller(af, [], {'a3' : 6, 'a2' : '$BAR', 'a1' : 4})
- ac.strfunction([], [], Environment(BAR = 5))
- assert strfunc_args == [4, '5', 6], strfunc_args
+ d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
+ ac = SCons.Action.ActionCaller(af, [], d)
+ ac.strfunction([], [], Environment(BAR = 5, WS='w s'))
+ assert strfunc_args == [4, '5', 6, 'w s'], strfunc_args
class ActionFactoryTestCase(unittest.TestCase):
def test___init__(self):
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 4021f2b..2e10a8d 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -712,14 +712,9 @@ class BuilderBase:
return None
result = []
-
- if SCons.Util.is_List(source):
- source = SCons.Util.flatten(source)
- else:
- source = [source]
- for s in source:
+ for s in SCons.Util.flatten(source):
if SCons.Util.is_String(s):
- match_suffix = match_src_suffix(s)
+ match_suffix = match_src_suffix(env.subst(s))
if not match_suffix and not '.' in s:
src_suf = self.get_src_suffix(env)
s = self._adjustixes(s, None, src_suf)[0]
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index cf13025..1b7bc38 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -31,6 +31,7 @@ def Func():
pass
import os.path
+import re
import sys
import types
import StringIO
@@ -84,14 +85,9 @@ class Environment:
def subst(self, s):
if not SCons.Util.is_String(s):
return s
- try:
- if s[0] == '$':
- return self.d.get(s[1:], '')
- if s[1] == '$':
- return s[0] + self.d.get(s[2:], '')
- except IndexError:
- pass
- return self.d.get(s, s)
+ def substitute(m, d=self.d):
+ return d.get(m.group(1), '')
+ return re.sub(r'\$(\w+)', substitute, s)
def subst_target_source(self, string, raw=0, target=None,
source=None, dict=None, conv=None):
return SCons.Subst.scons_subst(string, self, raw, target,
@@ -107,7 +103,7 @@ class Environment:
list = []
for a in args:
if SCons.Util.is_String(a):
- a = factory(a)
+ a = factory(self.subst(a))
list.append(a)
return list
def get_factory(self, factory):
@@ -163,6 +159,7 @@ class MyNode_without_target_from_source:
self.builder = None
self.is_explicit = None
self.side_effect = 0
+ self.suffix = os.path.splitext(name)[1]
def disambiguate(self):
return self
def __str__(self):
@@ -628,6 +625,21 @@ class BuilderTestCase(unittest.TestCase):
tgt = b9(env, target=None, source='foo_altsrc.b')
assert str(tgt[0]) == 'foo.c', str(tgt[0])
+ def test_src_suffix_expansion(self):
+ """Test handling source suffixes when an expansion is involved"""
+ env = Environment(OBJSUFFIX = '.obj')
+
+ b1 = SCons.Builder.Builder(action = '',
+ src_suffix='.c',
+ suffix='.obj')
+ b2 = SCons.Builder.Builder(action = '',
+ src_builder=b1,
+ src_suffix='.obj',
+ suffix='.exe')
+ tgt = b2(env, target=None, source=['foo$OBJSUFFIX'])
+ s = map(str, tgt[0].sources)
+ assert s == ['foo.obj'], s
+
def test_suffix(self):
"""Test Builder creation with a specified target suffix
@@ -1099,9 +1111,9 @@ class BuilderTestCase(unittest.TestCase):
assert r == 'A_', r
r = builder.get_suffix(env)
assert r == '.B', r
- r = builder.get_prefix(env, ['X.C'])
+ r = builder.get_prefix(env, [MyNode('X.C')])
assert r == 'E_', r
- r = builder.get_suffix(env, ['X.C'])
+ r = builder.get_suffix(env, [MyNode('X.C')])
assert r == '.D', r
builder = SCons.Builder.Builder(prefix='A_', suffix={}, action={})
@@ -1132,7 +1144,7 @@ class BuilderTestCase(unittest.TestCase):
assert r == 'A_', r
r = builder.get_suffix(env)
assert r == None, r
- r = builder.get_suffix(env, ['X.src_sfx1'])
+ r = builder.get_suffix(env, [MyNode('X.src_sfx1')])
assert r == None, r
r = builder.get_src_suffix(env)
assert r == '.src_sfx1', r
diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py
index 33899f6..d311168 100644
--- a/src/engine/SCons/Conftest.py
+++ b/src/engine/SCons/Conftest.py
@@ -206,7 +206,9 @@ int main() {
context.Display("Checking for %s function %s()... " % (lang, function_name))
ret = context.BuildProg(text, suffix)
- _YesNoResult(context, ret, "HAVE_" + function_name, text)
+ _YesNoResult(context, ret, "HAVE_" + function_name, text,
+ "Define to 1 if the system has the function `%s'." %\
+ function_name)
return ret
@@ -253,7 +255,8 @@ def CheckHeader(context, header_name, header = None, language = None,
context.Display("Checking for %s header file %s... " % (lang, header_name))
ret = context.CompileProg(text, suffix)
- _YesNoResult(context, ret, "HAVE_" + header_name, text)
+ _YesNoResult(context, ret, "HAVE_" + header_name, text,
+ "Define to 1 if you have the <%s> header file." % header_name)
return ret
@@ -310,7 +313,8 @@ int main() {
context.Display("Checking for %s type %s... " % (lang, type_name))
ret = context.BuildProg(text, suffix)
- _YesNoResult(context, ret, "HAVE_" + type_name, text)
+ _YesNoResult(context, ret, "HAVE_" + type_name, text,
+ "Define to 1 if the system has the type `%s'." % type_name)
if ret and fallback and context.headerfilename:
f = open(context.headerfilename, "a")
f.write("typedef %s %s;\n" % (fallback, type_name))
@@ -374,7 +378,8 @@ int main()
st = context.CompileProg(src % (type_name, expect), suffix)
if not st:
context.Display("yes\n")
- _Have(context, "SIZEOF_%s" % type_name, expect)
+ _Have(context, "SIZEOF_%s" % type_name, expect,
+ "The size of `%s', as computed by sizeof." % type_name)
return expect
else:
context.Display("no\n")
@@ -410,7 +415,8 @@ int main() {
if not st:
context.Display("yes\n")
- _Have(context, "SIZEOF_%s" % type_name, size)
+ _Have(context, "SIZEOF_%s" % type_name, size,
+ "The size of `%s', as computed by sizeof." % type_name)
return size
else:
context.Display("no\n")
@@ -466,7 +472,8 @@ int main()
""" % (symbol, symbol)
st = context.CompileProg(src, suffix)
- _YesNoResult(context, st, "HAVE_DECL_" + symbol, src)
+ _YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
+ "Set to 1 if %s is defined." % symbol)
return st
def CheckLib(context, libs, func_name = None, header = None,
@@ -563,7 +570,8 @@ return 0;
ret = context.BuildProg(text, suffix)
- _YesNoResult(context, ret, sym, text)
+ _YesNoResult(context, ret, sym, text,
+ "Define to 1 if you have the `%s' library." % lib_name)
if oldLIBS != -1 and (ret or not autoadd):
context.SetLIBS(oldLIBS)
@@ -576,15 +584,17 @@ return 0;
# END OF PUBLIC FUNCTIONS
#
-def _YesNoResult(context, ret, key, text):
+def _YesNoResult(context, ret, key, text, comment = None):
"""
Handle the result of a test with a "yes" or "no" result.
"ret" is the return value: empty if OK, error message when not.
"key" is the name of the symbol to be defined (HAVE_foo).
"text" is the source code of the program used for testing.
+ "comment" is the C comment to add above the line defining the symbol (the
+ comment is automatically put inside a /* */). If None, no comment is added.
"""
if key:
- _Have(context, key, not ret)
+ _Have(context, key, not ret, comment)
if ret:
context.Display("no\n")
_LogFailed(context, text, ret)
@@ -592,7 +602,7 @@ def _YesNoResult(context, ret, key, text):
context.Display("yes\n")
-def _Have(context, key, have):
+def _Have(context, key, have, comment = None):
"""
Store result of a test in context.havedict and context.headerfilename.
"key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-
@@ -620,12 +630,17 @@ def _Have(context, key, have):
else:
line = "#define %s %s\n" % (key_up, str(have))
+ if comment is not None:
+ lines = "\n/* %s */\n" % comment + line
+ else:
+ lines = "\n" + line
+
if context.headerfilename:
f = open(context.headerfilename, "a")
- f.write(line)
+ f.write(lines)
f.close()
elif hasattr(context,'config_h'):
- context.config_h = context.config_h + line
+ context.config_h = context.config_h + lines
def _LogFailed(context, text, msg):
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index 3cd47ef..aebef39 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -40,6 +40,7 @@ import os
import os.path
import shutil
import stat
+import string
import time
import types
import sys
@@ -157,19 +158,34 @@ LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
# ways by creating ActionFactory instances.
ActionFactory = SCons.Action.ActionFactory
-def chmod_func(path, mode):
- return os.chmod(str(path), mode)
+def get_paths_str(dest):
+ # If dest is a list, we need to manually call str() on each element
+ if SCons.Util.is_List(dest):
+ elem_strs = []
+ for element in dest:
+ elem_strs.append('"' + str(element) + '"')
+ return '[' + string.join(elem_strs, ', ') + ']'
+ else:
+ return '"' + str(dest) + '"'
+
+def chmod_func(dest, mode):
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for element in dest:
+ os.chmod(str(element), mode)
+
+def chmod_strfunc(dest, mode):
+ return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
-Chmod = ActionFactory(chmod_func,
- lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
+Chmod = ActionFactory(chmod_func, chmod_strfunc)
def copy_func(dest, src):
if SCons.Util.is_List(src) and os.path.isdir(dest):
for file in src:
- shutil.copy(file, dest)
+ shutil.copy2(file, dest)
return 0
elif os.path.isfile(src):
- return shutil.copy(src, dest)
+ return shutil.copy2(src, dest)
else:
return shutil.copytree(src, dest, 1)
@@ -177,40 +193,53 @@ Copy = ActionFactory(copy_func,
lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
convert=str)
-def delete_func(entry, must_exist=0):
- entry = str(entry)
- if not must_exist and not os.path.exists(entry):
- return None
- if not os.path.exists(entry) or os.path.isfile(entry):
- return os.unlink(entry)
- else:
- return shutil.rmtree(entry, 1)
+def delete_func(dest, must_exist=0):
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for entry in dest:
+ entry = str(entry)
+ if not must_exist and not os.path.exists(entry):
+ continue
+ if not os.path.exists(entry) or os.path.isfile(entry):
+ os.unlink(entry)
+ continue
+ else:
+ shutil.rmtree(entry, 1)
+ continue
-def delete_strfunc(entry, must_exist=0):
- return 'Delete("%s")' % entry
+def delete_strfunc(dest, must_exist=0):
+ return 'Delete(%s)' % get_paths_str(dest)
Delete = ActionFactory(delete_func, delete_strfunc)
-Mkdir = ActionFactory(os.makedirs,
- lambda dir: 'Mkdir("%s")' % dir,
- convert=str)
+def mkdir_func(dest):
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for entry in dest:
+ os.makedirs(str(entry))
+
+Mkdir = ActionFactory(mkdir_func,
+ lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
Move = ActionFactory(lambda dest, src: os.rename(src, dest),
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
convert=str)
-def touch_func(file):
- file = str(file)
- mtime = int(time.time())
- if os.path.exists(file):
- atime = os.path.getatime(file)
- else:
- open(file, 'w')
- atime = mtime
- return os.utime(file, (atime, mtime))
+def touch_func(dest):
+ if not SCons.Util.is_List(dest):
+ dest = [dest]
+ for file in dest:
+ file = str(file)
+ mtime = int(time.time())
+ if os.path.exists(file):
+ atime = os.path.getatime(file)
+ else:
+ open(file, 'w')
+ atime = mtime
+ os.utime(file, (atime, mtime))
Touch = ActionFactory(touch_func,
- lambda file: 'Touch("%s")' % file)
+ lambda file: 'Touch(%s)' % get_paths_str(file))
# Internal utility functions
@@ -224,9 +253,6 @@ def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
if not list:
return list
- if SCons.Util.is_List(list):
- list = SCons.Util.flatten(list)
-
l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
if not l is None:
list = l
@@ -292,18 +318,8 @@ def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
else:
c = _concat_ixes
- if SCons.Util.is_List(list):
- list = SCons.Util.flatten(list)
-
- if SCons.Util.is_List(stripprefixes):
- stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
- else:
- stripprefixes = [env.subst(stripprefixes)]
-
- if SCons.Util.is_List(stripsuffixes):
- stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
- else:
- stripsuffixes = [stripsuffixes]
+ stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
+ stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
stripped = []
for l in SCons.PathList.PathList(list).subst_path(env, None, None):
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 02ad332..ce98034 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -38,6 +38,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import copy
import os
import os.path
+import re
import shlex
import string
from UserDict import UserDict
@@ -64,6 +65,10 @@ class _Null:
_null = _Null
+_warn_copy_deprecated = True
+_warn_source_signatures_deprecated = True
+_warn_target_signatures_deprecated = True
+
CleanTargets = {}
CalculatorArgs = {}
@@ -279,6 +284,18 @@ class BuilderDict(UserDict):
for i, v in dict.items():
self.__setitem__(i, v)
+
+
+_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
+
+def is_valid_construction_var(varstr):
+ """Return if the specified string is a legitimate construction
+ variable.
+ """
+ return _is_valid_var.match(varstr)
+
+
+
class SubstitutionEnvironment:
"""Base class for different flavors of construction environments.
@@ -332,6 +349,11 @@ class SubstitutionEnvironment:
self._special_set['BUILDERS'] = _set_BUILDERS
self._special_set['SCANNERS'] = _set_SCANNERS
+ # Freeze the keys of self._special_set in a list for use by
+ # methods that need to check. (Empirically, list scanning has
+ # gotten better than dict.has_key() in Python 2.5.)
+ self._special_set_keys = self._special_set.keys()
+
def __cmp__(self, other):
return cmp(self._dict, other._dict)
@@ -346,12 +368,28 @@ class SubstitutionEnvironment:
return self._dict[key]
def __setitem__(self, key, value):
- special = self._special_set.get(key)
- if special:
- special(self, key, value)
+ # This is heavily used. This implementation is the best we have
+ # according to the timings in bench/env.__setitem__.py.
+ #
+ # The "key in self._special_set_keys" test here seems to perform
+ # pretty well for the number of keys we have. A hard-coded
+ # list works a little better in Python 2.5, but that has the
+ # disadvantage of maybe getting out of sync if we ever add more
+ # variable names. Using self._special_set.has_key() works a
+ # little better in Python 2.4, but is worse then this test.
+ # So right now it seems like a good trade-off, but feel free to
+ # revisit this with bench/env.__setitem__.py as needed (and
+ # as newer versions of Python come out).
+ if key in self._special_set_keys:
+ self._special_set[key](self, key, value)
else:
- if not SCons.Util.is_valid_construction_var(key):
- raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+ # If we already have the entry, then it's obviously a valid
+ # key and we don't need to check. If we do check, using a
+ # global, pre-compiled regular expression directly is more
+ # efficient than calling another function or a method.
+ if not self._dict.has_key(key) \
+ and not _is_valid_var.match(key):
+ raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
self._dict[key] = value
def get(self, key, default=None):
@@ -373,10 +411,7 @@ class SubstitutionEnvironment:
if not args:
return []
- if SCons.Util.is_List(args):
- args = SCons.Util.flatten(args)
- else:
- args = [args]
+ args = SCons.Util.flatten(args)
nodes = []
for v in args:
@@ -465,7 +500,7 @@ class SubstitutionEnvironment:
try:
get = obj.get
except AttributeError:
- pass
+ obj = SCons.Util.to_String_for_subst(obj)
else:
obj = get()
return obj
@@ -543,16 +578,19 @@ class SubstitutionEnvironment:
environment, and doesn't even create a wrapper object if there
are no overrides.
"""
- if overrides:
- o = copy_non_reserved_keywords(overrides)
- overrides = {}
- for key, value in o.items():
+ if not overrides: return self
+ o = copy_non_reserved_keywords(overrides)
+ if not o: return self
+ overrides = {}
+ merges = None
+ for key, value in o.items():
+ if key == 'parse_flags':
+ merges = value
+ else:
overrides[key] = SCons.Subst.scons_subst_once(value, self, key)
- if overrides:
- env = OverrideEnvironment(self, overrides)
- return env
- else:
- return self
+ env = OverrideEnvironment(self, overrides)
+ if merges: env.MergeFlags(merges)
+ return env
def ParseFlags(self, *flags):
"""
@@ -820,6 +858,7 @@ class Base(SubstitutionEnvironment):
tools=None,
toolpath=None,
options=None,
+ parse_flags = None,
**kw):
"""
Initialization of a basic SCons construction environment,
@@ -894,6 +933,9 @@ class Base(SubstitutionEnvironment):
for key, val in save.items():
self._dict[key] = val
+ # Finally, apply any flags to be merged in
+ if parse_flags: self.MergeFlags(parse_flags)
+
#######################################################################
# Utility methods that are primarily for internal use by SCons.
# These begin with lower-case letters.
@@ -1139,7 +1181,7 @@ class Base(SubstitutionEnvironment):
self._dict[key] = self._dict[key] + val
self.scanner_map_delete(kw)
- def Clone(self, tools=[], toolpath=None, **kw):
+ def Clone(self, tools=[], toolpath=None, parse_flags = None, **kw):
"""Return a copy of a construction Environment. The
copy is like a Python "deep copy"--that is, independent
copies are made recursively of each objects--except that
@@ -1157,9 +1199,14 @@ class Base(SubstitutionEnvironment):
else:
clone._dict['BUILDERS'] = BuilderDict(cbd, clone)
+ # Check the methods added via AddMethod() and re-bind them to
+ # the cloned environment. Only do this if the attribute hasn't
+ # been overwritten by the user explicitly and still points to
+ # the added method.
clone.added_methods = []
for mw in self.added_methods:
- clone.added_methods.append(mw.clone(clone))
+ if mw == getattr(self, mw.name):
+ clone.added_methods.append(mw.clone(clone))
clone._memo = {}
@@ -1176,10 +1223,18 @@ class Base(SubstitutionEnvironment):
# apply them again in case the tools overwrote them
apply(clone.Replace, (), new)
+ # Finally, apply any flags to be merged in
+ if parse_flags: clone.MergeFlags(parse_flags)
+
if __debug__: logInstanceCreation(self, 'Environment.EnvironmentClone')
return clone
def Copy(self, *args, **kw):
+ global _warn_copy_deprecated
+ if _warn_copy_deprecated:
+ msg = "The env.Copy() method is deprecated; use the env.Clone() method instead."
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedCopyWarning, msg)
+ _warn_copy_deprecated = False
return apply(self.Clone, args, kw)
def _changed_build(self, dependency, target, prev_ni):
@@ -1641,10 +1696,11 @@ class Base(SubstitutionEnvironment):
t.set_always_build()
return tlist
- def BuildDir(self, build_dir, src_dir, duplicate=1):
- build_dir = self.arg2nodes(build_dir, self.fs.Dir)[0]
- src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
- self.fs.BuildDir(build_dir, src_dir, duplicate)
+ def BuildDir(self, *args, **kw):
+ if kw.has_key('build_dir'):
+ kw['variant_dir'] = kw['build_dir']
+ del kw['build_dir']
+ return apply(self.VariantDir, args, kw)
def Builder(self, **kw):
nkw = self.subst_kw(kw)
@@ -1705,7 +1761,13 @@ class Base(SubstitutionEnvironment):
def Dir(self, name, *args, **kw):
"""
"""
- return apply(self.fs.Dir, (self.subst(name),) + args, kw)
+ s = self.subst(name)
+ if SCons.Util.is_Sequence(s):
+ result=[]
+ for e in s:
+ result.append(apply(self.fs.Dir, (e,) + args, kw))
+ return result
+ return apply(self.fs.Dir, (s,) + args, kw)
def NoClean(self, *targets):
"""Tags a target so that it will not be cleaned by -c"""
@@ -1728,7 +1790,13 @@ class Base(SubstitutionEnvironment):
def Entry(self, name, *args, **kw):
"""
"""
- return apply(self.fs.Entry, (self.subst(name),) + args, kw)
+ s = self.subst(name)
+ if SCons.Util.is_Sequence(s):
+ result=[]
+ for e in s:
+ result.append(apply(self.fs.Entry, (e,) + args, kw))
+ return result
+ return apply(self.fs.Entry, (s,) + args, kw)
def Environment(self, **kw):
return apply(SCons.Environment.Environment, [], self.subst_kw(kw))
@@ -1746,7 +1814,13 @@ class Base(SubstitutionEnvironment):
def File(self, name, *args, **kw):
"""
"""
- return apply(self.fs.File, (self.subst(name),) + args, kw)
+ s = self.subst(name)
+ if SCons.Util.is_Sequence(s):
+ result=[]
+ for e in s:
+ result.append(apply(self.fs.File, (e,) + args, kw))
+ return result
+ return apply(self.fs.File, (s,) + args, kw)
def FindFile(self, file, dirs):
file = self.subst(file)
@@ -1851,6 +1925,12 @@ class Base(SubstitutionEnvironment):
return entries
def SourceSignatures(self, type):
+ global _warn_source_signatures_deprecated
+ if _warn_source_signatures_deprecated:
+ msg = "The env.SourceSignatures() method is deprecated;\n" + \
+ "\tconvert your build to use the env.Decider() method instead."
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedSourceSignaturesWarning, msg)
+ _warn_source_signatures_deprecated = False
type = self.subst(type)
self.src_sig_type = type
if type == 'MD5':
@@ -1881,6 +1961,12 @@ class Base(SubstitutionEnvironment):
return [self.subst(arg)]
def TargetSignatures(self, type):
+ global _warn_target_signatures_deprecated
+ if _warn_target_signatures_deprecated:
+ msg = "The env.TargetSignatures() method is deprecated;\n" + \
+ "\tconvert your build to use the env.Decider() method instead."
+ SCons.Warnings.warn(SCons.Warnings.DeprecatedTargetSignaturesWarning, msg)
+ _warn_target_signatures_deprecated = False
type = self.subst(type)
self.tgt_sig_type = type
if type in ('MD5', 'content'):
@@ -1901,6 +1987,11 @@ class Base(SubstitutionEnvironment):
"""
return SCons.Node.Python.Value(value, built_value)
+ def VariantDir(self, variant_dir, src_dir, duplicate=1):
+ variant_dir = self.arg2nodes(variant_dir, self.fs.Dir)[0]
+ src_dir = self.arg2nodes(src_dir, self.fs.Dir)[0]
+ self.fs.VariantDir(variant_dir, src_dir, duplicate)
+
def FindSourceFiles(self, node='.'):
""" returns a list of all source files.
"""
@@ -1984,7 +2075,7 @@ class OverrideEnvironment(Base):
except KeyError:
return self.__dict__['__subject'].__getitem__(key)
def __setitem__(self, key, value):
- if not SCons.Util.is_valid_construction_var(key):
+ if not is_valid_construction_var(key):
raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
self.__dict__['overrides'][key] = value
def __delitem__(self, key):
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 4ffff7a..6c10ee0 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -542,9 +542,13 @@ class SubstitutionTestCase(unittest.TestCase):
return self.val
class MyObj:
- pass
+ def get(self):
+ return self
- env = SubstitutionEnvironment(FOO='foo', BAR='bar', PROXY=MyProxy('my1'))
+ env = SubstitutionEnvironment(FOO='foo',
+ BAR='bar',
+ LIST=['one', 'two'],
+ PROXY=MyProxy('my1'))
r = env.subst_path('$FOO')
assert r == ['foo'], r
@@ -552,6 +556,9 @@ class SubstitutionTestCase(unittest.TestCase):
r = env.subst_path(['$FOO', 'xxx', '$BAR'])
assert r == ['foo', 'xxx', 'bar'], r
+ r = env.subst_path(['$FOO', '$LIST', '$BAR'])
+ assert map(str, r) == ['foo', 'one two', 'bar'], r
+
r = env.subst_path(['$FOO', '$TARGET', '$SOURCE', '$BAR'])
assert r == ['foo', '', '', 'bar'], r
@@ -689,6 +696,16 @@ sys.exit(1)
r = env4.func2()
assert r == 'func2-4', r
+ # Test that clones don't re-bind an attribute that the user
+ env1 = Environment(FOO = '1')
+ env1.AddMethod(func2)
+ def replace_func2():
+ return 'replace_func2'
+ env1.func2 = replace_func2
+ env2 = env1.Clone(FOO = '2')
+ r = env2.func2()
+ assert r == 'replace_func2', r
+
def test_Override(self):
"Test overriding construction variables"
env = SubstitutionEnvironment(ONE=1, TWO=2, THREE=3, FOUR=4)
@@ -2511,26 +2528,26 @@ def generate(env):
assert t[6].path == 'file'
assert t[6].always_build
- def test_BuildDir(self):
- """Test the BuildDir() method"""
+ def test_VariantDir(self):
+ """Test the VariantDir() method"""
class MyFS:
def Dir(self, name):
return name
- def BuildDir(self, build_dir, src_dir, duplicate):
- self.build_dir = build_dir
+ def VariantDir(self, variant_dir, src_dir, duplicate):
+ self.variant_dir = variant_dir
self.src_dir = src_dir
self.duplicate = duplicate
env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
env.fs = MyFS()
- env.BuildDir('build', 'src')
- assert env.fs.build_dir == 'build', env.fs.build_dir
+ env.VariantDir('build', 'src')
+ assert env.fs.variant_dir == 'build', env.fs.variant_dir
assert env.fs.src_dir == 'src', env.fs.src_dir
assert env.fs.duplicate == 1, env.fs.duplicate
- env.BuildDir('build${FOO}', '${BAR}src', 0)
- assert env.fs.build_dir == 'buildfff', env.fs.build_dir
+ env.VariantDir('build${FOO}', '${BAR}src', 0)
+ assert env.fs.variant_dir == 'buildfff', env.fs.variant_dir
assert env.fs.src_dir == 'bbbsrc', env.fs.src_dir
assert env.fs.duplicate == 0, env.fs.duplicate
@@ -2717,6 +2734,12 @@ def generate(env):
d = env.Dir('${BAR}_$BAR')
assert d == 'Dir(bardir_bardir)', d
+ d = env.Dir(['dir1'])
+ assert d == ['Dir(dir1)'], d
+
+ d = env.Dir(['dir1', 'dir2'])
+ assert d == ['Dir(dir1)', 'Dir(dir2)'], d
+
def test_NoClean(self):
"""Test the NoClean() method"""
env = self.TestEnvironment(FOO='ggg', BAR='hhh')
@@ -2788,6 +2811,12 @@ def generate(env):
e = env.Entry('${BAR}_$BAR')
assert e == 'Entry(barentry_barentry)', e
+ e = env.Entry(['entry1'])
+ assert e == ['Entry(entry1)'], e
+
+ e = env.Entry(['entry1', 'entry2'])
+ assert e == ['Entry(entry1)', 'Entry(entry2)'], e
+
def test_File(self):
"""Test the File() method"""
class MyFS:
@@ -2806,6 +2835,12 @@ def generate(env):
f = env.File('${BAR}_$BAR')
assert f == 'File(barfile_barfile)', f
+ f = env.File(['file1'])
+ assert f == ['File(file1)'], f
+
+ f = env.File(['file1', 'file2'])
+ assert f == ['File(file1)', 'File(file2)'], f
+
def test_FindFile(self):
"""Test the FindFile() method"""
env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
@@ -3279,6 +3314,42 @@ def generate(env):
for x in added + ['OVERRIDE']:
assert over.has_key(x), bad_msg % x
+ def test_parse_flags(self):
+ '''Test the Base class parse_flags argument'''
+ # all we have to show is that it gets to MergeFlags internally
+ env = Environment(parse_flags = '-X')
+ assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
+
+ env = Environment(CCFLAGS=None, parse_flags = '-Y')
+ assert env['CCFLAGS'] == ['-Y'], env['CCFLAGS']
+
+ env = Environment(CPPDEFINES = 'FOO', parse_flags = '-std=c99 -X -DBAR')
+ assert env['CFLAGS'] == ['-std=c99'], env['CFLAGS']
+ assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
+ assert env['CPPDEFINES'] == ['FOO', 'BAR'], env['CPPDEFINES']
+
+ def test_clone_parse_flags(self):
+ '''Test the env.Clone() parse_flags argument'''
+ # all we have to show is that it gets to MergeFlags internally
+ env = Environment(tools = [])
+ env2 = env.Clone(parse_flags = '-X')
+ assert not env.has_key('CCFLAGS')
+ assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
+
+ env = Environment(tools = [], CCFLAGS=None)
+ env2 = env.Clone(parse_flags = '-Y')
+ assert env['CCFLAGS'] is None, env['CCFLAGS']
+ assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
+
+ env = Environment(tools = [], CPPDEFINES = 'FOO')
+ env2 = env.Clone(parse_flags = '-std=c99 -X -DBAR')
+ assert not env.has_key('CFLAGS')
+ assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS']
+ assert not env.has_key('CCFLAGS')
+ assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
+ assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
+ assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES']
+
class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
@@ -3507,6 +3578,28 @@ class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
x = env3.Split('$AAA')
assert x == ['x3', 'y3', 'z3'], x
+ def test_parse_flags(self):
+ '''Test the OverrideEnvironment parse_flags argument'''
+ # all we have to show is that it gets to MergeFlags internally
+ env = SubstitutionEnvironment()
+ env2 = env.Override({'parse_flags' : '-X'})
+ assert not env.has_key('CCFLAGS')
+ assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
+
+ env = SubstitutionEnvironment(CCFLAGS=None)
+ env2 = env.Override({'parse_flags' : '-Y'})
+ assert env['CCFLAGS'] is None, env['CCFLAGS']
+ assert env2['CCFLAGS'] == ['-Y'], env2['CCFLAGS']
+
+ env = SubstitutionEnvironment(CPPDEFINES = 'FOO')
+ env2 = env.Override({'parse_flags' : '-std=c99 -X -DBAR'})
+ assert not env.has_key('CFLAGS')
+ assert env2['CFLAGS'] == ['-std=c99'], env2['CFLAGS']
+ assert not env.has_key('CCFLAGS')
+ assert env2['CCFLAGS'] == ['-X'], env2['CCFLAGS']
+ assert env['CPPDEFINES'] == 'FOO', env['CPPDEFINES']
+ assert env2['CPPDEFINES'] == ['FOO','BAR'], env2['CPPDEFINES']
+
class NoSubstitutionProxyTestCase(unittest.TestCase,TestEnvironmentFixture):
@@ -3609,6 +3702,39 @@ class NoSubstitutionProxyTestCase(unittest.TestCase,TestEnvironmentFixture):
x = apply(proxy.subst_target_source, args, kw)
assert x == ' ttt sss ', x
+class EnvironmentVariableTestCase(unittest.TestCase):
+
+ def test_is_valid_construction_var(self):
+ """Testing is_valid_construction_var()"""
+ r = is_valid_construction_var("_a")
+ assert not r is None, r
+ r = is_valid_construction_var("z_")
+ assert not r is None, r
+ r = is_valid_construction_var("X_")
+ assert not r is None, r
+ r = is_valid_construction_var("2a")
+ assert r is None, r
+ r = is_valid_construction_var("a2_")
+ assert not r is None, r
+ r = is_valid_construction_var("/")
+ assert r is None, r
+ r = is_valid_construction_var("_/")
+ assert r is None, r
+ r = is_valid_construction_var("a/")
+ assert r is None, r
+ r = is_valid_construction_var(".b")
+ assert r is None, r
+ r = is_valid_construction_var("_.b")
+ assert r is None, r
+ r = is_valid_construction_var("b1._")
+ assert r is None, r
+ r = is_valid_construction_var("-b")
+ assert r is None, r
+ r = is_valid_construction_var("_-b")
+ assert r is None, r
+ r = is_valid_construction_var("b1-_")
+ assert r is None, r
+
if __name__ == "__main__":
@@ -3616,7 +3742,8 @@ if __name__ == "__main__":
tclasses = [ SubstitutionTestCase,
BaseTestCase,
OverrideEnvironmentTestCase,
- NoSubstitutionProxyTestCase ]
+ NoSubstitutionProxyTestCase,
+ EnvironmentVariableTestCase ]
for tclass in tclasses:
names = unittest.getTestCaseNames(tclass, 'test_')
suite.addTests(map(tclass, names))
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 1a3c010..f73161f 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -73,10 +73,10 @@ default_max_drift = 2*24*60*60
#
# A number of the above factors, however, can be set after we've already
# been asked to return a string for a Node, because a Repository() or
-# BuildDir() call or the like may not occur until later in SConscript
+# VariantDir() call or the like may not occur until later in SConscript
# files. So this variable controls whether we bother trying to save
# string values for Nodes. The wrapper interface can set this whenever
-# they're done mucking with Repository and BuildDir and the other stuff,
+# they're done mucking with Repository and VariantDir and the other stuff,
# to let this module know it can start returning saved string values
# for Nodes.
#
@@ -445,7 +445,7 @@ class EntryProxy(SCons.Util.Proxy):
def __get_srcdir(self):
"""Returns the directory containing the source node linked to this
- node via BuildDir(), or the directory of this node if not linked."""
+ node via VariantDir(), or the directory of this node if not linked."""
return EntryProxy(self.get().srcnode().dir)
def __get_rsrcnode(self):
@@ -453,7 +453,7 @@ class EntryProxy(SCons.Util.Proxy):
def __get_rsrcdir(self):
"""Returns the directory containing the source node linked to this
- node via BuildDir(), or the directory of this node if not linked."""
+ node via VariantDir(), or the directory of this node if not linked."""
return EntryProxy(self.get().srcnode().rfile().dir)
def __get_dir(self):
@@ -1197,21 +1197,21 @@ class FS(LocalFS):
"""
return self._lookup(name, directory, Dir, create)
- def BuildDir(self, build_dir, src_dir, duplicate=1):
- """Link the supplied build directory to the source directory
+ def VariantDir(self, variant_dir, src_dir, duplicate=1):
+ """Link the supplied variant directory to the source directory
for purposes of building files."""
if not isinstance(src_dir, SCons.Node.Node):
src_dir = self.Dir(src_dir)
- if not isinstance(build_dir, SCons.Node.Node):
- build_dir = self.Dir(build_dir)
- if src_dir.is_under(build_dir):
- raise SCons.Errors.UserError, "Source directory cannot be under build directory."
- if build_dir.srcdir:
- if build_dir.srcdir == src_dir:
+ if not isinstance(variant_dir, SCons.Node.Node):
+ variant_dir = self.Dir(variant_dir)
+ if src_dir.is_under(variant_dir):
+ raise SCons.Errors.UserError, "Source directory cannot be under variant directory."
+ if variant_dir.srcdir:
+ if variant_dir.srcdir == src_dir:
return # We already did this.
- raise SCons.Errors.UserError, "'%s' already has a source directory: '%s'."%(build_dir, build_dir.srcdir)
- build_dir.link(src_dir, duplicate)
+ raise SCons.Errors.UserError, "'%s' already has a source directory: '%s'."%(variant_dir, variant_dir.srcdir)
+ variant_dir.link(src_dir, duplicate)
def Repository(self, *dirs):
"""Specify Repository directories to search."""
@@ -1220,11 +1220,11 @@ class FS(LocalFS):
d = self.Dir(d)
self.Top.addRepository(d)
- def build_dir_target_climb(self, orig, dir, tail):
- """Create targets in corresponding build directories
+ def variant_dir_target_climb(self, orig, dir, tail):
+ """Create targets in corresponding variant directories
Climb the directory tree, and look up path names
- relative to any linked build directories we find.
+ relative to any linked variant directories we find.
Even though this loops and walks up the tree, we don't memoize
the return value because this is really only used to process
@@ -1232,10 +1232,10 @@ class FS(LocalFS):
"""
targets = []
message = None
- fmt = "building associated BuildDir targets: %s"
+ fmt = "building associated VariantDir targets: %s"
start_dir = dir
while dir:
- for bd in dir.build_dirs:
+ for bd in dir.variant_dirs:
if start_dir.is_under(bd):
# If already in the build-dir location, don't reflect
return [orig], fmt % str(orig)
@@ -1314,7 +1314,7 @@ class Dir(Base):
self.cwd = self
self.searched = 0
self._sconsign = None
- self.build_dirs = []
+ self.variant_dirs = []
self.root = self.dir.root
# Don't just reset the executor, replace its action list,
@@ -1385,16 +1385,16 @@ class Dir(Base):
a path containing '..'), an absolute path name, a top-relative
('#foo') path name, or any kind of object.
"""
- name = self.labspath + '/' + name
+ name = self.entry_labspath(name)
return self.root._lookup_abs(name, klass, create)
def link(self, srcdir, duplicate):
- """Set this directory as the build directory for the
+ """Set this directory as the variant directory for the
supplied source directory."""
self.srcdir = srcdir
self.duplicate = duplicate
self.__clearRepositoryCache(duplicate)
- srcdir.build_dirs.append(self)
+ srcdir.variant_dirs.append(self)
def getRepositories(self):
"""Returns a list of repositories for this directory.
@@ -1580,9 +1580,9 @@ class Dir(Base):
return not self.builder is MkdirBuilder and self.has_builder()
def alter_targets(self):
- """Return any corresponding targets in a build directory.
+ """Return any corresponding targets in a variant directory.
"""
- return self.fs.build_dir_target_climb(self, self, [])
+ return self.fs.variant_dir_target_climb(self, self, [])
def scanner_key(self):
"""A directory does not get scanned."""
@@ -1696,7 +1696,7 @@ class Dir(Base):
for dir in self.srcdir_list():
if self.is_under(dir):
# We shouldn't source from something in the build path;
- # build_dir is probably under src_dir, in which case
+ # variant_dir is probably under src_dir, in which case
# we are reflecting.
break
if dir.entry_exists_on_disk(name):
@@ -1823,8 +1823,8 @@ class Dir(Base):
The "source" argument, when true, specifies that corresponding
source Nodes must be returned if you're globbing in a build
- directory (initialized with BuildDir()). The default behavior
- is to return Nodes local to the BuildDir().
+ directory (initialized with VariantDir()). The default behavior
+ is to return Nodes local to the VariantDir().
The "strings" argument, when true, returns the matches as strings,
not Nodes. The strings are path names relative to this directory.
@@ -1940,7 +1940,7 @@ class RootDir(Dir):
# except for the "lookup abspath," which does not have the
# drive letter.
self.abspath = name + os.sep
- self.labspath = '/'
+ self.labspath = ''
self.path = name + os.sep
self.tpath = name + os.sep
self._morph()
@@ -1951,6 +1951,7 @@ class RootDir(Dir):
# os.path.normpath() seems to preserve double slashes at the
# beginning of a path (presumably for UNC path names), but
# collapses triple slashes to a single slash.
+ self._lookupDict[''] = self
self._lookupDict['/'] = self
self._lookupDict['//'] = self
self._lookupDict[os.sep] = self
@@ -2008,7 +2009,7 @@ class RootDir(Dir):
return self.abspath + name
def entry_labspath(self, name):
- return self.labspath + name
+ return '/' + name
def entry_path(self, name):
return self.path + name
@@ -2525,11 +2526,11 @@ class File(Base):
return not scb is None
def alter_targets(self):
- """Return any corresponding targets in a build directory.
+ """Return any corresponding targets in a variant directory.
"""
if self.is_derived():
return [], None
- return self.fs.build_dir_target_climb(self, self.dir, [self.name])
+ return self.fs.variant_dir_target_climb(self, self.dir, [self.name])
def _rmv_existing(self):
self.clear_memoized_values()
@@ -2596,7 +2597,7 @@ class File(Base):
if self.duplicate and not self.is_derived() and not self.linked:
src = self.srcnode()
if not src is self:
- # At this point, src is meant to be copied in a build directory.
+ # At this point, src is meant to be copied in a variant directory.
src = src.rfile()
if src.abspath != self.abspath:
if src.exists():
@@ -2605,7 +2606,7 @@ class File(Base):
# not actually occur if the -n option is being used.
else:
# The source file does not exist. Make sure no old
- # copy remains in the build directory.
+ # copy remains in the variant directory.
if Base.exists(self) or self.islink():
self.fs.unlink(self.path)
# Return None explicitly because the Base.exists() call
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index b698e87..cfdc978 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -123,14 +123,14 @@ class _tempdirTestCase(unittest.TestCase):
def tearDown(self):
os.chdir(self.save_cwd)
-class BuildDirTestCase(unittest.TestCase):
+class VariantDirTestCase(unittest.TestCase):
def runTest(self):
- """Test build dir functionality"""
+ """Test variant dir functionality"""
test=TestCmd(workdir='')
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
- fs.BuildDir('build', 'src')
+ fs.VariantDir('build', 'src')
f2 = fs.File('build/test2')
d1 = fs.Dir('build')
assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
@@ -139,7 +139,7 @@ class BuildDirTestCase(unittest.TestCase):
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
- fs.BuildDir('build', '.')
+ fs.VariantDir('build', '.')
f2 = fs.File('build/test2')
d1 = fs.Dir('build')
assert f1.srcnode().path == 'test1', f1.srcnode().path
@@ -147,16 +147,16 @@ class BuildDirTestCase(unittest.TestCase):
assert d1.srcnode().path == '.', d1.srcnode().path
fs = SCons.Node.FS.FS()
- fs.BuildDir('build/var1', 'src')
- fs.BuildDir('build/var2', 'src')
+ fs.VariantDir('build/var1', 'src')
+ fs.VariantDir('build/var2', 'src')
f1 = fs.File('build/var1/test1')
f2 = fs.File('build/var2/test1')
assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
fs = SCons.Node.FS.FS()
- fs.BuildDir('../var1', 'src')
- fs.BuildDir('../var2', 'src')
+ fs.VariantDir('../var1', 'src')
+ fs.VariantDir('../var2', 'src')
f1 = fs.File('../var1/test1')
f2 = fs.File('../var2/test1')
assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
@@ -180,11 +180,11 @@ class BuildDirTestCase(unittest.TestCase):
# A source file in the repository
test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
- # Some source files in the build directory
+ # Some source files in the variant directory
test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
- # An old derived file in the build directories
+ # An old derived file in the variant directories
test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
@@ -199,8 +199,8 @@ class BuildDirTestCase(unittest.TestCase):
os.chdir(test.workpath('work'))
fs = SCons.Node.FS.FS(test.workpath('work'))
- fs.BuildDir('build/var1', 'src', duplicate=0)
- fs.BuildDir('build/var2', 'src')
+ fs.VariantDir('build/var1', 'src', duplicate=0)
+ fs.VariantDir('build/var2', 'src')
f1 = fs.File('build/var1/test.in')
f1out = fs.File('build/var1/test.out')
f1out.builder = 1
@@ -356,7 +356,7 @@ class BuildDirTestCase(unittest.TestCase):
assert bdt == [var1_new_dir, var2_new_dir], bdt
# Test that an IOError trying to Link a src file
- # into a BuildDir ends up throwing a StopError.
+ # into a VariantDir ends up throwing a StopError.
fIO = fs.File("build/var2/IOError")
save_Link = SCons.Node.FS.Link
@@ -392,13 +392,13 @@ class BuildDirTestCase(unittest.TestCase):
# This used to generate a UserError when we forbid the source
# directory from being outside the top-level SConstruct dir.
fs = SCons.Node.FS.FS()
- fs.BuildDir('build', '/test/foo')
+ fs.VariantDir('build', '/test/foo')
exc_caught = 0
try:
try:
fs = SCons.Node.FS.FS()
- fs.BuildDir('build', 'build/src')
+ fs.VariantDir('build', 'build/src')
except SCons.Errors.UserError:
exc_caught = 1
assert exc_caught, "Should have caught a UserError."
@@ -407,25 +407,25 @@ class BuildDirTestCase(unittest.TestCase):
test.unlink( "build/foo" )
fs = SCons.Node.FS.FS()
- fs.BuildDir('build', 'src1')
+ fs.VariantDir('build', 'src1')
- # Calling the same BuildDir twice should work fine.
- fs.BuildDir('build', 'src1')
+ # Calling the same VariantDir twice should work fine.
+ fs.VariantDir('build', 'src1')
- # Trying to move a build dir to a second source dir
+ # Trying to move a variant dir to a second source dir
# should blow up
try:
- fs.BuildDir('build', 'src2')
+ fs.VariantDir('build', 'src2')
except SCons.Errors.UserError:
pass
else:
assert 0, "Should have caught a UserError."
# Test against a former bug. Make sure we can get a repository
- # path for the build directory itself!
+ # path for the variant directory itself!
fs=SCons.Node.FS.FS(test.workpath('work'))
test.subdir('work')
- fs.BuildDir('build/var3', 'src', duplicate=0)
+ fs.VariantDir('build/var3', 'src', duplicate=0)
d1 = fs.Dir('build/var3')
r = d1.rdir()
assert r == d1, "%s != %s" % (r, d1)
@@ -524,10 +524,10 @@ class BuildDirTestCase(unittest.TestCase):
delattr(os, 'symlink')
shutil.copy2 = real_copy
- # Test BuildDir "reflection," where a same-named subdirectory
- # exists underneath a build_dir.
+ # Test VariantDir "reflection," where a same-named subdirectory
+ # exists underneath a variant_dir.
fs = SCons.Node.FS.FS()
- fs.BuildDir('work/src/b1/b2', 'work/src')
+ fs.VariantDir('work/src/b1/b2', 'work/src')
dir_list = [
'work/src',
@@ -1737,8 +1737,8 @@ class DirTestCase(_tempdirTestCase):
sub1 = bld.Dir('sub')
sub2 = sub1.Dir('sub')
sub3 = sub2.Dir('sub')
- self.fs.BuildDir(bld, src, duplicate=0)
- self.fs.BuildDir(sub2, src, duplicate=0)
+ self.fs.VariantDir(bld, src, duplicate=0)
+ self.fs.VariantDir(sub2, src, duplicate=0)
def check(result, expect):
result = map(str, result)
@@ -1760,7 +1760,7 @@ class DirTestCase(_tempdirTestCase):
s = sub3.srcdir_list()
check(s, ['src/sub', 'src/sub/sub/sub'])
- self.fs.BuildDir('src/b1/b2', 'src')
+ self.fs.VariantDir('src/b1/b2', 'src')
b1 = src.Dir('b1')
b1_b2 = b1.Dir('b2')
b1_b2_b1 = b1_b2.Dir('b1')
@@ -1792,7 +1792,7 @@ class DirTestCase(_tempdirTestCase):
bld0 = self.fs.Dir('bld0')
src0 = self.fs.Dir('src0')
- self.fs.BuildDir(bld0, src0, duplicate=0)
+ self.fs.VariantDir(bld0, src0, duplicate=0)
n = bld0.srcdir_duplicate('does_not_exist')
assert n is None, n
@@ -1807,7 +1807,7 @@ class DirTestCase(_tempdirTestCase):
bld1 = self.fs.Dir('bld1')
src1 = self.fs.Dir('src1')
- self.fs.BuildDir(bld1, src1, duplicate=1)
+ self.fs.VariantDir(bld1, src1, duplicate=1)
n = bld1.srcdir_duplicate('does_not_exist')
assert n is None, n
@@ -1832,7 +1832,7 @@ class DirTestCase(_tempdirTestCase):
bld0 = self.fs.Dir('bld0')
src0 = self.fs.Dir('src0')
- self.fs.BuildDir(bld0, src0, duplicate=0)
+ self.fs.VariantDir(bld0, src0, duplicate=0)
derived_f = src0.File('derived-f')
derived_f.is_derived = return_true
@@ -1867,7 +1867,7 @@ class DirTestCase(_tempdirTestCase):
n = src0.srcdir_find_file('on-disk-e1')
check(n, ['src0/on-disk-e1', 'src0'])
- # Now check from the build directory.
+ # Now check from the variant directory.
n = bld0.srcdir_find_file('does_not_exist')
assert n == (None, None), n
@@ -1893,7 +1893,7 @@ class DirTestCase(_tempdirTestCase):
bld1 = self.fs.Dir('bld1')
src1 = self.fs.Dir('src1')
- self.fs.BuildDir(bld1, src1, duplicate=1)
+ self.fs.VariantDir(bld1, src1, duplicate=1)
derived_f = src1.File('derived-f')
derived_f.is_derived = return_true
@@ -1923,7 +1923,7 @@ class DirTestCase(_tempdirTestCase):
n = src1.srcdir_find_file('on-disk-e1')
check(n, ['src1/on-disk-e1', 'src1'])
- # Now check from the build directory.
+ # Now check from the variant directory.
n = bld1.srcdir_find_file('does_not_exist')
assert n == (None, None), n
@@ -2069,7 +2069,7 @@ class FileTestCase(_tempdirTestCase):
assert src_f1.exists(), "%s apparently does not exist?" % src_f1
test.subdir('build')
- fs.BuildDir('build', 'src')
+ fs.VariantDir('build', 'src')
build_f1 = fs.File('build/f1')
assert build_f1.exists(), "%s did not realize that %s exists" % (build_f1, src_f1)
@@ -2638,7 +2638,7 @@ class RepositoryTestCase(_tempdirTestCase):
test.write([self.rep2, "i_exist"], "\n")
test.write(["work", "i_exist_too"], "\n")
- fs.BuildDir('build', '.')
+ fs.VariantDir('build', '.')
f = fs.File(test.workpath("work", "i_do_not_exist"))
assert not f.rexists()
@@ -3023,7 +3023,7 @@ class disambiguateTestCase(unittest.TestCase):
test.subdir(['src', 'edir'])
test.write(['src', 'efile'], "src/efile\n")
- fs.BuildDir(test.workpath('build'), test.workpath('src'))
+ fs.VariantDir(test.workpath('build'), test.workpath('src'))
build_bdir = fs.Entry(test.workpath('build/bdir'))
d = build_bdir.disambiguate()
@@ -3141,8 +3141,8 @@ class SpecialAttrTestCase(unittest.TestCase):
s = str(f.srcpath.win32)
assert s == 'foo\\bar\\baz.blat', s
- # Test what happens with BuildDir()
- fs.BuildDir('foo', 'baz')
+ # Test what happens with VariantDir()
+ fs.VariantDir('foo', 'baz')
s = str(f.srcpath)
assert s == os.path.normpath('baz/bar/baz.blat'), s
@@ -3156,7 +3156,7 @@ class SpecialAttrTestCase(unittest.TestCase):
g = f.srcdir.get()
assert isinstance(g, SCons.Node.FS.Dir), g.__class__
- # And now what happens with BuildDir() + Repository()
+ # And now what happens with VariantDir() + Repository()
fs.Repository(test.workpath('repository'))
f = fs.Entry('foo/sub/file.suffix').get_subst_proxy()
@@ -3250,8 +3250,8 @@ class SaveStringsTestCase(unittest.TestCase):
fs1 = SCons.Node.FS.FS(test.workpath('fs1'))
nodes = setup(fs1)
- fs1.BuildDir('d0', 'src', duplicate=0)
- fs1.BuildDir('d1', 'src', duplicate=1)
+ fs1.VariantDir('d0', 'src', duplicate=0)
+ fs1.VariantDir('d1', 'src', duplicate=1)
s = map(str, nodes)
expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
@@ -3266,8 +3266,8 @@ class SaveStringsTestCase(unittest.TestCase):
SCons.Node.FS.save_strings(1)
fs2 = SCons.Node.FS.FS(test.workpath('fs2'))
nodes = setup(fs2)
- fs2.BuildDir('d0', 'src', duplicate=0)
- fs2.BuildDir('d1', 'src', duplicate=1)
+ fs2.VariantDir('d0', 'src', duplicate=0)
+ fs2.VariantDir('d1', 'src', duplicate=1)
s = map(str, nodes)
expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
@@ -3280,10 +3280,27 @@ class SaveStringsTestCase(unittest.TestCase):
assert s == expect, 'node str() not cached: %s'%s
+class AbsolutePathTestCase(unittest.TestCase):
+ def test_root_lookup_equivalence(self):
+ """Test looking up /fff vs. fff in the / directory"""
+ test=TestCmd(workdir='')
+
+ fs = SCons.Node.FS.FS('/')
+
+ save_cwd = os.getcwd()
+ try:
+ os.chdir('/')
+ fff1 = fs.File('fff')
+ fff2 = fs.File('/fff')
+ assert fff1 is fff2, "fff and /fff returned different Nodes!"
+ finally:
+ os.chdir(save_cwd)
+
+
if __name__ == "__main__":
suite = unittest.TestSuite()
- suite.addTest(BuildDirTestCase())
+ suite.addTest(VariantDirTestCase())
suite.addTest(find_fileTestCase())
suite.addTest(StringDirTestCase())
suite.addTest(stored_infoTestCase())
@@ -3296,6 +3313,7 @@ if __name__ == "__main__":
suite.addTest(SpecialAttrTestCase())
suite.addTest(SaveStringsTestCase())
tclasses = [
+ AbsolutePathTestCase,
BaseTestCase,
CacheDirTestCase,
DirTestCase,
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 4ca34e0..2e136f0 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -225,7 +225,7 @@ class Node:
self.attributes = self.Attrs() # Generic place to stick information about the Node.
self.side_effect = 0 # true iff this node is a side effect
self.side_effects = [] # the side effects of building this target
- self.linked = 0 # is this node linked to the build directory?
+ self.linked = 0 # is this node linked to the variant directory?
self.clear_memoized_values()
@@ -505,7 +505,7 @@ class Node:
Returns true iff this node is derived (i.e. built).
This should return true only for nodes whose path should be in
- the build directory when duplicate=0 and should contribute their build
+ the variant directory when duplicate=0 and should contribute their build
signatures when they are used as source files to other derived files. For
example: source with source builders are not derived in this sense,
and hence should not return true.
@@ -1161,7 +1161,10 @@ class Node:
# so we only print them after running them through this lambda
# to turn them into the right relative Node and then return
# its string.
- stringify = lambda s, E=self.dir.Entry: str(E(s))
+ def stringify( s, E=self.dir.Entry ) :
+ if hasattr( s, 'dir' ) :
+ return str(E(s))
+ return str(s)
lines = []
diff --git a/src/engine/SCons/Options/ListOption.py b/src/engine/SCons/Options/ListOption.py
index 5aa508a..6954905 100644
--- a/src/engine/SCons/Options/ListOption.py
+++ b/src/engine/SCons/Options/ListOption.py
@@ -86,7 +86,7 @@ class _ListOption(UserList.UserList):
return 'all'
else:
return string.join(self, ',')
- def __repr__(self):
+ def prepare_to_store(self):
return self.__str__()
def _converter(val, allowedElems, mapdict):
diff --git a/src/engine/SCons/Options/__init__.py b/src/engine/SCons/Options/__init__.py
index 3dc7772..9389c7b 100644
--- a/src/engine/SCons/Options/__init__.py
+++ b/src/engine/SCons/Options/__init__.py
@@ -35,6 +35,7 @@ import os.path
import string
import sys
+import SCons.Environment
import SCons.Errors
import SCons.Util
import SCons.Warnings
@@ -121,7 +122,7 @@ class Options:
return
if not SCons.Util.is_String(key) or \
- not SCons.Util.is_valid_construction_var(key):
+ not SCons.Environment.is_valid_construction_var(key):
raise SCons.Errors.UserError, "Illegal Options.Add() key `%s'" % str(key)
self._do_add(key, help, default, validator, converter)
@@ -234,19 +235,25 @@ class Options:
fh = open(filename, 'w')
try:
- # Make an assignment in the file for each option within the environment
- # that was assigned a value other than the default.
+ # Make an assignment in the file for each option
+ # within the environment that was assigned a value
+ # other than the default.
for option in self.options:
try:
value = env[option.key]
try:
- eval(repr(value))
- except KeyboardInterrupt:
- raise
- except:
- # Convert stuff that has a repr() that
- # cannot be evaluated into a string
- value = SCons.Util.to_String(value)
+ prepare = value.prepare_to_store
+ except AttributeError:
+ try:
+ eval(repr(value))
+ except KeyboardInterrupt:
+ raise
+ except:
+ # Convert stuff that has a repr() that
+ # cannot be evaluated into a string
+ value = SCons.Util.to_String(value)
+ else:
+ value = prepare()
defaultVal = env.subst(SCons.Util.to_String(option.default))
if option.converter:
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index c5de498..130e0d3 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -381,7 +381,7 @@ class SConfBase:
e.g. custom_tests={'CheckPrivate':MyPrivateTest}, where MyPrivateTest
defines a custom test.
Note also the conf_dir and log_file arguments (you may want to
- build tests in the BuildDir, not in the SourceDir)
+ build tests in the VariantDir, not in the SourceDir)
"""
global SConfFS
if not SConfFS:
diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py
index 5d6765d..cadc491 100644
--- a/src/engine/SCons/Scanner/CTests.py
+++ b/src/engine/SCons/Scanner/CTests.py
@@ -276,7 +276,7 @@ class CScannerTestCase5(unittest.TestCase):
deps = s(n, env, path)
# Make sure rexists() got called on the file node being
- # scanned, essential for cooperation with BuildDir functionality.
+ # scanned, essential for cooperation with VariantDir functionality.
assert n.rexists_called
headers = ['f1.h', 'f2.h', 'f3-test.h',
@@ -377,11 +377,11 @@ class CScannerTestCase11(unittest.TestCase):
class CScannerTestCase12(unittest.TestCase):
def runTest(self):
- """Find files in BuildDir() directories"""
+ """Find files in VariantDir() directories"""
os.chdir(test.workpath('work'))
fs = SCons.Node.FS.FS(test.workpath('work'))
- fs.BuildDir('build1', 'src', 1)
- fs.BuildDir('build2', 'src', 0)
+ fs.VariantDir('build1', 'src', 1)
+ fs.VariantDir('build2', 'src', 0)
fs.Repository(test.workpath('repository'))
env = DummyEnvironment(CPPPATH=[])
env.fs = fs
diff --git a/src/engine/SCons/Scanner/FortranTests.py b/src/engine/SCons/Scanner/FortranTests.py
index 82db694..ff63bda 100644
--- a/src/engine/SCons/Scanner/FortranTests.py
+++ b/src/engine/SCons/Scanner/FortranTests.py
@@ -364,7 +364,7 @@ class FortranScannerTestCase9(unittest.TestCase):
deps = s(n, env, path)
# Make sure rexists() got called on the file node being
- # scanned, essential for cooperation with BuildDir functionality.
+ # scanned, essential for cooperation with VariantDir functionality.
assert n.rexists_called
headers = ['d1/f3.f', 'f3.f']
@@ -441,8 +441,8 @@ class FortranScannerTestCase14(unittest.TestCase):
def runTest(self):
os.chdir(test.workpath('work'))
fs = SCons.Node.FS.FS(test.workpath('work'))
- fs.BuildDir('build1', 'src', 1)
- fs.BuildDir('build2', 'src', 0)
+ fs.VariantDir('build1', 'src', 1)
+ fs.VariantDir('build2', 'src', 0)
fs.Repository(test.workpath('repository'))
env = DummyEnvironment([])
env.fs = fs
diff --git a/src/engine/SCons/Scanner/IDLTests.py b/src/engine/SCons/Scanner/IDLTests.py
index 2332a57..bca2ac8 100644
--- a/src/engine/SCons/Scanner/IDLTests.py
+++ b/src/engine/SCons/Scanner/IDLTests.py
@@ -296,7 +296,7 @@ class IDLScannerTestCase5(unittest.TestCase):
deps = s(n, env, path)
# Make sure rexists() got called on the file node being
- # scanned, essential for cooperation with BuildDir functionality.
+ # scanned, essential for cooperation with VariantDir functionality.
assert n.rexists_called
headers = ['d1/f1.idl', 'd1/f2.idl',
@@ -391,8 +391,8 @@ class IDLScannerTestCase11(unittest.TestCase):
def runTest(self):
os.chdir(test.workpath('work'))
fs = SCons.Node.FS.FS(test.workpath('work'))
- fs.BuildDir('build1', 'src', 1)
- fs.BuildDir('build2', 'src', 0)
+ fs.VariantDir('build1', 'src', 1)
+ fs.VariantDir('build2', 'src', 0)
fs.Repository(test.workpath('repository'))
env = DummyEnvironment([])
env.fs = fs
diff --git a/src/engine/SCons/Scanner/Prog.py b/src/engine/SCons/Scanner/Prog.py
index e8d1669..102205f 100644
--- a/src/engine/SCons/Scanner/Prog.py
+++ b/src/engine/SCons/Scanner/Prog.py
@@ -54,10 +54,8 @@ def scan(node, env, libpath = ()):
return []
if SCons.Util.is_String(libs):
libs = string.split(libs)
- elif SCons.Util.is_List(libs):
- libs = SCons.Util.flatten(libs)
else:
- libs = [libs]
+ libs = SCons.Util.flatten(libs)
try:
prefix = env['LIBPREFIXES']
diff --git a/src/engine/SCons/Script/Interactive.py b/src/engine/SCons/Script/Interactive.py
index e38c400..d18eec1 100644
--- a/src/engine/SCons/Script/Interactive.py
+++ b/src/engine/SCons/Script/Interactive.py
@@ -217,12 +217,12 @@ class SConsInteractiveCmd(cmd.Cmd):
def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes):
seen_nodes[node] = 1
- # If this file is in a BuildDir and has a
+ # If this file is in a VariantDir and has a
# corresponding source file in the source tree, remember the
# node in the source tree, too. This is needed in
# particular to clear cached implicit dependencies on the
# source file, since the scanner will scan it if the
- # BuildDir was created with duplicate=0.
+ # VariantDir was created with duplicate=0.
try:
rfile_method = node.rfile
except AttributeError:
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index bcbd0a1..80b9032 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -404,6 +404,16 @@ class TreePrinter:
SCons.Util.print_tree(t, func, prune=self.prune, showtags=s)
+def python_version_string():
+ return string.split(sys.version)[0]
+
+def python_version_unsupported(version=sys.version_info):
+ return version < (1, 5, 2)
+
+def python_version_deprecated(version=sys.version_info):
+ return version < (2, 2, 0)
+
+
# Global variables
print_objects = 0
@@ -578,51 +588,6 @@ def _scons_internal_error():
traceback.print_exc()
sys.exit(2)
-def _setup_warn(arg):
- """The --warn option. An argument to this option
- should be of the form <warning-class> or no-<warning-class>.
- The warning class is munged in order to get an actual class
- name from the SCons.Warnings module to enable or disable.
- The supplied <warning-class> is split on hyphens, each element
- is captialized, then smushed back together. Then the string
- "SCons.Warnings." is added to the front and "Warning" is added
- to the back to get the fully qualified class name.
-
- For example, --warn=deprecated will enable the
- SCons.Warnings.DeprecatedWarning class.
-
- --warn=no-dependency will disable the
- SCons.Warnings.DependencyWarning class.
-
- As a special case, --warn=all and --warn=no-all
- will enable or disable (respectively) the base
- class of all warnings, which is SCons.Warning.Warning."""
-
- elems = string.split(string.lower(arg), '-')
- enable = 1
- if elems[0] == 'no':
- enable = 0
- del elems[0]
-
- if len(elems) == 1 and elems[0] == 'all':
- class_name = "Warning"
- else:
- def _capitalize(s):
- if s[:5] == "scons":
- return "SCons" + s[5:]
- else:
- return string.capitalize(s)
- class_name = string.join(map(_capitalize, elems), '') + "Warning"
- try:
- clazz = getattr(SCons.Warnings, class_name)
- except AttributeError:
- sys.stderr.write("No warning type: '%s'\n" % arg)
- else:
- if enable:
- SCons.Warnings.enableWarningClass(clazz)
- else:
- SCons.Warnings.suppressWarningClass(clazz)
-
def _SConstruct_exists(dirname='', repositories=[]):
"""This function checks that an SConstruct file exists in a directory.
If so, it returns the path of the file. By default, it checks the
@@ -766,8 +731,7 @@ def _main(parser):
for warning in default_warnings:
SCons.Warnings.enableWarningClass(warning)
SCons.Warnings._warningOut = _scons_internal_warning
- if options.warn:
- _setup_warn(options.warn)
+ SCons.Warnings.process_warn_strings(options.warn)
# Now that we have the warnings configuration set up, we can actually
# issue (or suppress) any warnings about warning-worthy things that
@@ -912,7 +876,7 @@ def _main(parser):
SCons.Script._SConscript._SConscript(fs, script)
except SCons.Errors.StopError, e:
# We had problems reading an SConscript file, such as it
- # couldn't be copied in to the BuildDir. Since we're just
+ # couldn't be copied in to the VariantDir. Since we're just
# reading SConscript files and haven't started building
# things yet, stop regardless of whether they used -i or -k
# or anything else.
@@ -927,6 +891,26 @@ def _main(parser):
memory_stats.append('after reading SConscript files:')
count_stats.append(('post-', 'read'))
+ # Re-{enable,disable} warnings in case they disabled some in
+ # the SConscript file.
+ #
+ # We delay enabling the PythonVersionWarning class until here so that,
+ # if they explicity disabled it in either in the command line or in
+ # $SCONSFLAGS, or in the SConscript file, then the search through
+ # the list of deprecated warning classes will find that disabling
+ # first and not issue the warning.
+ SCons.Warnings.enableWarningClass(SCons.Warnings.PythonVersionWarning)
+ SCons.Warnings.process_warn_strings(options.warn)
+
+ # Now that we've read the SConscript files, we can check for the
+ # warning about deprecated Python versions--delayed until here
+ # in case they disabled the warning in the SConscript files.
+ if python_version_deprecated():
+ msg = "Support for pre-2.2 Python (%s) is deprecated.\n" + \
+ " If this will cause hardship, contact dev@scons.tigris.org."
+ SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning,
+ msg % python_version_string())
+
if not options.help:
SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
@@ -953,7 +937,7 @@ def _main(parser):
# Change directory to the top-level SConstruct directory, then tell
# the Node.FS subsystem that we're all done reading the SConscript
- # files and calling Repository() and BuildDir() and changing
+ # files and calling Repository() and VariantDir() and changing
# directories and the like, so it can go ahead and start memoizing
# the string values of file system nodes.
@@ -1215,6 +1199,15 @@ def main():
global exit_status
global first_command_start
+ # Check up front for a Python version we do not support. We
+ # delay the check for deprecated Python versions until later,
+ # after the SConscript files have been read, in case they
+ # disable that warning.
+ if python_version_unsupported():
+ msg = "scons: *** SCons version %s does not run under Python version %s.\n"
+ sys.stderr.write(msg % (SCons.__version__, python_version_string()))
+ sys.exit(1)
+
parts = ["SCons by Steven Knight et al.:\n"]
try:
parts.append(version_string("script", __main__))
diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py
index 8f7116d..ee34a85 100644
--- a/src/engine/SCons/Script/SConsOptions.py
+++ b/src/engine/SCons/Script/SConsOptions.py
@@ -38,6 +38,7 @@ except ImportError:
_ = gettext
import SCons.Node.FS
+import SCons.Warnings
OptionValueError = optparse.OptionValueError
SUPPRESS_HELP = optparse.SUPPRESS_HELP
@@ -123,6 +124,7 @@ class SConsValues(optparse.Values):
'num_jobs',
'random',
'stack_size',
+ 'warn',
]
def set_option(self, name, value):
@@ -169,6 +171,11 @@ class SConsValues(optparse.Values):
value = int(value)
except ValueError:
raise SCons.Errors.UserError, "An integer is required: %s"%repr(value)
+ elif name == 'warn':
+ if SCons.Util.is_String(value):
+ value = [value]
+ value = self.__SConscript_settings__.get(name, []) + value
+ SCons.Warnings.process_warn_strings(value)
self.__SConscript_settings__[name] = value
@@ -563,29 +570,32 @@ def Parser(version):
help="Search up directory tree for SConstruct, "
"build all Default() targets.")
- debug_options = ["count", "dtree", "explain", "findlibs",
- "includes", "memoizer", "memory", "objects",
- "pdb", "presub", "stacktrace", "stree",
- "time", "tree"]
-
deprecated_debug_options = {
- "nomemoizer" : ' and has no effect',
+ "dtree" : '; please use --tree=derived instead',
+ "nomemoizer" : ' and has no effect',
+ "stree" : '; please use --tree=all,status instead',
+ "tree" : '; please use --tree=all instead',
}
+ debug_options = ["count", "explain", "findlibs",
+ "includes", "memoizer", "memory", "objects",
+ "pdb", "presub", "stacktrace",
+ "time"] + deprecated_debug_options.keys()
+
def opt_debug(option, opt, value, parser,
debug_options=debug_options,
deprecated_debug_options=deprecated_debug_options):
if value in debug_options:
parser.values.debug.append(value)
- elif value in deprecated_debug_options.keys():
- try:
- parser.values.delayed_warnings
- except AttributeError:
- parser.values.delayed_warnings = []
- msg = deprecated_debug_options[value]
- w = "The --debug=%s option is deprecated%s." % (value, msg)
- t = (SCons.Warnings.DeprecatedWarning, w)
- parser.values.delayed_warnings.append(t)
+ if value in deprecated_debug_options.keys():
+ try:
+ parser.values.delayed_warnings
+ except AttributeError:
+ parser.values.delayed_warnings = []
+ msg = deprecated_debug_options[value]
+ w = "The --debug=%s option is deprecated%s." % (value, msg)
+ t = (SCons.Warnings.DeprecatedWarning, w)
+ parser.values.delayed_warnings.append(t)
else:
raise OptionValueError("Warning: %s is not a valid debug type" % value)
opt_debug_help = "Print various types of debugging information: %s." \
@@ -803,10 +813,15 @@ def Parser(version):
action="callback", callback=opt_version,
help="Print the SCons version number and exit.")
+ def opt_warn(option, opt, value, parser, tree_options=tree_options):
+ if SCons.Util.is_String(value):
+ value = string.split(value, ',')
+ parser.values.warn.extend(value)
+
op.add_option('--warn', '--warning',
- nargs=1,
- dest="warn", default=None,
- action="store",
+ nargs=1, type="string",
+ dest="warn", default=[],
+ action="callback", callback=opt_warn,
help="Enable or disable warnings.",
metavar="WARNING-SPEC")
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 5278d40..36a147d 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -403,16 +403,16 @@ class SConsEnvironment(SCons.Environment.Base):
if kw.get('exports'):
exports.extend(self.Split(kw['exports']))
- build_dir = kw.get('build_dir')
- if build_dir:
+ variant_dir = kw.get('variant_dir') or kw.get('build_dir')
+ if variant_dir:
if len(files) != 1:
raise SCons.Errors.UserError, \
- "Invalid SConscript() usage - can only specify one SConscript with a build_dir"
+ "Invalid SConscript() usage - can only specify one SConscript with a variant_dir"
duplicate = kw.get('duplicate', 1)
src_dir = kw.get('src_dir')
if not src_dir:
src_dir, fname = os.path.split(str(files[0]))
- files = [os.path.join(str(build_dir), fname)]
+ files = [os.path.join(str(variant_dir), fname)]
else:
if not isinstance(src_dir, SCons.Node.Node):
src_dir = self.fs.Dir(src_dir)
@@ -422,11 +422,11 @@ class SConsEnvironment(SCons.Environment.Base):
if fn.is_under(src_dir):
# Get path relative to the source directory.
fname = fn.get_path(src_dir)
- files = [os.path.join(str(build_dir), fname)]
+ files = [os.path.join(str(variant_dir), fname)]
else:
files = [fn.abspath]
- kw['src_dir'] = build_dir
- self.fs.BuildDir(build_dir, src_dir, duplicate)
+ kw['src_dir'] = variant_dir
+ self.fs.VariantDir(variant_dir, src_dir, duplicate)
return (files, exports)
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 44f01b8..ddeaf9e 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -321,6 +321,7 @@ GlobalDefaultEnvironmentFunctions = [
'Tag',
'TargetSignatures',
'Value',
+ 'VariantDir',
]
GlobalDefaultBuilders = [
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 9db8138..66202dc 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -548,7 +548,7 @@ class Taskmaster:
except:
# We had a problem just trying to figure out the
# children (like a child couldn't be linked in to a
- # BuildDir, or a Scanner threw something). Arrange to
+ # VariantDir, or a Scanner threw something). Arrange to
# raise the exception when the Task is "executed."
self.ready_exc = sys.exc_info()
if S: S.problem = S.problem + 1
@@ -675,7 +675,7 @@ class Taskmaster:
raise
except:
# We had a problem just trying to get this task ready (like
- # a child couldn't be linked in to a BuildDir when deciding
+ # a child couldn't be linked in to a VariantDir when deciding
# whether this node is current). Arrange to raise the
# exception when the Task is "executed."
self.ready_exc = sys.exc_info()
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 0991c37..d028a39 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -49,14 +49,16 @@ if java_parsing:
# double-backslashes;
# a single-line comment "//";
# single or double quotes preceeded by a backslash;
- # single quotes, double quotes, open or close braces, semi-colons;
+ # single quotes, double quotes, open or close braces, semi-colons,
+ # periods, open or close parentheses;
+ # floating-point numbers;
# any alphanumeric token (keyword, class name, specifier);
+ # any alphanumeric token surrounded by angle brackets (generics);
# the multi-line comment begin and end tokens /* and */;
- # array declarations "[]";
- # semi-colons;
- # periods.
+ # array declarations "[]".
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"\{\}\;\.\(\)]|' +
- r'[A-Za-z_][\w\$\.]*|/\*|\*/|\[\])')
+ r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' +
+ r'/\*|\*/|\[\])')
class OuterState:
"""The initial state for parsing a Java file for classes,
@@ -199,6 +201,8 @@ if java_parsing:
return IgnoreState('*/', self)
elif token == '\n':
return self
+ elif token[0] == '<' and token[-1] == '>':
+ return self
elif token == '(':
self.brace_level = self.brace_level + 1
return self
diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py
index 1675190..bffe09e 100644
--- a/src/engine/SCons/Tool/JavaCommonTests.py
+++ b/src/engine/SCons/Tool/JavaCommonTests.py
@@ -466,6 +466,75 @@ class test
pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5')
assert expect == classes, (expect, classes)
+ def test_floating_point_numbers(self):
+ """Test floating-point numbers in the input stream"""
+ input = """
+// Broken.java
+class Broken
+{
+ /**
+ * Detected.
+ */
+ Object anonymousInnerOK = new Runnable() { public void run () {} };
+
+ /**
+ * Detected.
+ */
+ class InnerOK { InnerOK () { } }
+
+ {
+ System.out.println("a number: " + 1000.0 + "");
+ }
+
+ /**
+ * Not detected.
+ */
+ Object anonymousInnerBAD = new Runnable() { public void run () {} };
+
+ /**
+ * Not detected.
+ */
+ class InnerBAD { InnerBAD () { } }
+}
+"""
+
+ expect = ['Broken$1', 'Broken$InnerOK', 'Broken$2', 'Broken$InnerBAD', 'Broken']
+
+ pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4')
+ assert expect == classes, (expect, classes)
+
+ pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5')
+ assert expect == classes, (expect, classes)
+
+
+ def test_genercis(self):
+ """Test that generics don't interfere with detecting anonymous classes"""
+
+ input = """\
+import java.util.Date;
+import java.util.Comparator;
+
+public class Foo
+{
+ public void foo()
+ {
+ Comparator<Date> comp = new Comparator<Date>()
+ {
+ static final long serialVersionUID = 1L;
+ public int compare(Date lhs, Date rhs)
+ {
+ return 0;
+ }
+ };
+ }
+}
+"""
+
+ expect = [ 'Foo$1', 'Foo' ]
+
+ pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.6')
+ assert expect == classes, (expect, classes)
+
if __name__ == "__main__":
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index d4e3815..1e69f1e 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -422,32 +422,33 @@ def CreateJavaFileBuilder(env):
env['JAVASUFFIX'] = '.java'
return java_file
-class ToolInitializer:
+class ToolInitializerMethod:
"""
- A class for delayed initialization of Tools modules.
-
- This is intended to be added to a construction environment in
- place of the method(s) normally called for a Builder (env.Object,
- env.StaticObject, etc.). When called, it searches the specified
- list of tools, applies the first one that exists to the construction
- environment, and calls whatever builder was (presumably) added the
- construction environment in our place.
+ This is added to a construction environment in place of a
+ method(s) normally called for a Builder (env.Object, env.StaticObject,
+ etc.). When called, it has its associated ToolInitializer
+ object search the specified list of tools and apply the first
+ one that exists to the construction environment. It then calls
+ whatever builder was (presumably) added to the construction
+ environment in place of this particular instance.
"""
- def __init__(self, name, tools):
+ def __init__(self, name, initializer):
"""
Note: we store the tool name as __name__ so it can be used by
the class that attaches this to a construction environment.
"""
self.__name__ = name
- if not SCons.Util.is_List(tools):
- tools = [tools]
- self.tools = tools
- def __call__(self, env, *args, **kw):
- for t in self.tools:
- tool = SCons.Tool.Tool(t)
- if tool.exists(env):
- env.Tool(tool)
- break
+ self.initializer = initializer
+
+ def get_builder(self, env):
+ """
+ Returns the appropriate real Builder for this method name
+ after having the associated ToolInitializer object apply
+ the appropriate Tool module.
+ """
+ builder = getattr(env, self.__name__)
+
+ self.initializer.apply_tools(env)
builder = getattr(env, self.__name__)
if builder is self:
@@ -455,21 +456,79 @@ class ToolInitializer:
# for this name was found (or possibly there's a mismatch
# between the name we were called by and the Builder name
# added by the Tool module).
- #
- # (Eventually this is where we'll put a more informative
- # error message about the inability to find that tool
- # as cut over more Builders+Tools to using this.
- return [], []
+ return None
+
+ self.initializer.remove_methods(env)
+
+ return builder
- # Let the construction environment remove the added method
- # so we no longer copy and re-bind this method when the
- # construction environment gets cloned.
- env.RemoveMethod(self)
+ def __call__(self, env, *args, **kw):
+ """
+ """
+ builder = self.get_builder(env)
+ if builder is None:
+ return [], []
return apply(builder, args, kw)
+class ToolInitializer:
+ """
+ A class for delayed initialization of Tools modules.
+
+ Instances of this class associate a list of Tool modules with
+ a list of Builder method names that will be added by those Tool
+ modules. As part of instantiating this object for a particular
+ construction environment, we also add the appropriate
+ ToolInitializerMethod objects for the various Builder methods
+ that we want to use to delay Tool searches until necessary.
+ """
+ def __init__(self, env, tools, names):
+ if not SCons.Util.is_List(tools):
+ tools = [tools]
+ if not SCons.Util.is_List(names):
+ names = [names]
+ self.env = env
+ self.tools = tools
+ self.names = names
+ self.methods = {}
+ for name in names:
+ method = ToolInitializerMethod(name, self)
+ self.methods[name] = method
+ env.AddMethod(method)
+
+ def remove_methods(self, env):
+ """
+ Removes the methods that were added by the tool initialization
+ so we no longer copy and re-bind them when the construction
+ environment gets cloned.
+ """
+ for method in self.methods.values():
+ env.RemoveMethod(method)
+
+ def apply_tools(self, env):
+ """
+ Searches the list of associated Tool modules for one that
+ exists, and applies that to the construction environment.
+ """
+ for t in self.tools:
+ tool = SCons.Tool.Tool(t)
+ if tool.exists(env):
+ env.Tool(tool)
+ return
+
+ # If we fall through here, there was no tool module found.
+ # This is where we can put an informative error message
+ # about the inability to find the tool. We'll start doing
+ # this as we cut over more pre-defined Builder+Tools to use
+ # the ToolInitializer class.
+
def Initializers(env):
- env.AddMethod(ToolInitializer('Install', 'install'))
- env.AddMethod(ToolInitializer('InstallAs', 'install'))
+ ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs'])
+ def Install(self, *args, **kw):
+ return apply(self._InternalInstall, args, kw)
+ def InstallAs(self, *args, **kw):
+ return apply(self._InternalInstallAs, args, kw)
+ env.AddMethod(Install)
+ env.AddMethod(InstallAs)
def FindTool(tools, env):
for tool in tools:
diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py
index 532301f..7500133 100644
--- a/src/engine/SCons/Tool/applelink.py
+++ b/src/engine/SCons/Tool/applelink.py
@@ -62,5 +62,4 @@ def generate(env):
def exists(env):
- import sys
- return sys.platform == 'darwin'
+ return env['PLATFORM'] == 'darwin'
diff --git a/src/engine/SCons/Tool/dvips.py b/src/engine/SCons/Tool/dvips.py
index 9996fc2..ec95f16 100644
--- a/src/engine/SCons/Tool/dvips.py
+++ b/src/engine/SCons/Tool/dvips.py
@@ -58,7 +58,7 @@ def generate(env):
env['DVIPS'] = 'dvips'
env['DVIPSFLAGS'] = SCons.Util.CLVar('')
- # I'm not quite sure I got the directories and filenames right for build_dir
+ # I'm not quite sure I got the directories and filenames right for variant_dir
# We need to be in the correct directory for the sake of latex \includegraphics eps included files.
env['PSCOM'] = 'cd ${TARGET.dir} && $DVIPS $DVIPSFLAGS -o ${TARGET.file} ${SOURCE.file}'
env['PSPREFIX'] = ''
diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py
index c7eee61..983fb12 100644
--- a/src/engine/SCons/Tool/install.py
+++ b/src/engine/SCons/Tool/install.py
@@ -75,7 +75,8 @@ def installFunc(target, source, env):
except KeyError:
raise SCons.Errors.UserError('Missing INSTALL construction variable.')
- assert( len(target)==len(source) )
+ assert len(target)==len(source), \
+ "Installing source %s into target %s: target and source lists must have same length."%(map(str, source), map(str, target))
for t,s in zip(target,source):
if install(t.get_path(),s.get_path(),env):
return 1
@@ -131,8 +132,9 @@ installas_action = SCons.Action.Action(installFunc, stringFunc)
BaseInstallBuilder = None
-def InstallBuilderWrapper(env, target, source, dir=None):
+def InstallBuilderWrapper(env, target=None, source=None, dir=None, **kw):
if target and dir:
+ import SCons.Errors
raise SCons.Errors.UserError, "Both target and dir defined for Install(), only one may be defined."
if not dir:
dir=target
@@ -156,13 +158,15 @@ def InstallBuilderWrapper(env, target, source, dir=None):
# '#' on the file name portion as meaning the Node should
# be relative to the top-level SConstruct directory.
target = env.fs.Entry('.'+os.sep+src.name, dnode)
- tgt.extend(BaseInstallBuilder(env, target, src))
+ #tgt.extend(BaseInstallBuilder(env, target, src, **kw))
+ tgt.extend(apply(BaseInstallBuilder, (env, target, src), kw))
return tgt
-def InstallAsBuilderWrapper(env, target, source):
+def InstallAsBuilderWrapper(env, target=None, source=None, **kw):
result = []
for src, tgt in map(lambda x, y: (x, y), source, target):
- result.extend(BaseInstallBuilder(env, tgt, src))
+ #result.extend(BaseInstallBuilder(env, tgt, src, **kw))
+ result.extend(apply(BaseInstallBuilder, (env, tgt, src), kw))
return result
added = None
@@ -195,15 +199,8 @@ def generate(env):
emitter = [ add_targets_to_INSTALLED_FILES, ],
name = 'InstallBuilder')
- try:
- env['BUILDERS']['Install']
- except KeyError, e:
- env['BUILDERS']['Install'] = InstallBuilderWrapper
-
- try:
- env['BUILDERS']['InstallAs']
- except KeyError, e:
- env['BUILDERS']['InstallAs'] = InstallAsBuilderWrapper
+ env['BUILDERS']['_InternalInstall'] = InstallBuilderWrapper
+ env['BUILDERS']['_InternalInstallAs'] = InstallAsBuilderWrapper
# We'd like to initialize this doing something like the following,
# but there isn't yet support for a ${SOURCE.type} expansion that
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py
index c6fe461..a1067c0 100644
--- a/src/engine/SCons/Tool/msvc.py
+++ b/src/engine/SCons/Tool/msvc.py
@@ -513,10 +513,6 @@ def _get_msvc8_default_paths(env, version, suite, use_mfc_dirs):
include_paths.append( os.path.join( atlmfc_path, 'include' ) )
lib_paths.append( os.path.join( atlmfc_path, 'lib' ) )
- env_include_path = SCons.Util.get_environment_var('INCLUDE')
- if env_include_path:
- include_paths.append( env_include_path )
-
if SCons.Util.can_read_reg and paths.has_key('FRAMEWORKSDKDIR'):
fwdir = paths['FRAMEWORKSDKDIR']
include_paths.append( os.path.join( fwdir, 'include' ) )
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index d4efa74..ca1b5f6 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -1504,7 +1504,7 @@ def GenerateProject(target, source, env):
builddspfile = target[0]
dspfile = builddspfile.srcnode()
- # this detects whether or not we're using a BuildDir
+ # this detects whether or not we're using a VariantDir
if not dspfile is builddspfile:
try:
bdsp = open(str(builddspfile), "w+")
diff --git a/src/engine/SCons/Tool/qt.xml b/src/engine/SCons/Tool/qt.xml
index 66fe554..ea73698 100644
--- a/src/engine/SCons/Tool/qt.xml
+++ b/src/engine/SCons/Tool/qt.xml
@@ -112,7 +112,7 @@ As stated in the qt documentation, include the moc file at the end of
the cxx file. Note that you have to include the file, which is generated
by the transformation ${QT_MOCCXXPREFIX}&lt;basename&gt;${QT_MOCCXXSUFFIX}, by default
&lt;basename&gt;.moc. A warning is generated after building the moc file, if you
-do not include the correct file. If you are using BuildDir, you may
+do not include the correct file. If you are using VariantDir, you may
need to specify duplicate=1. You can turn off automatic moc file generation
by setting QT_AUTOSCAN to 0. See also the corresponding
&b-Moc;
@@ -123,7 +123,7 @@ The implementation files generated from .ui files are handled much the same
as yacc or lex files. Each .ui file given as a source of Program, Library or
SharedLibrary will generate three files, the declaration file, the
implementation file and a moc file. Because there are also generated headers,
-you may need to specify duplicate=1 in calls to BuildDir.
+you may need to specify duplicate=1 in calls to VariantDir.
See also the corresponding
&b-Uic;
builder method.
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 08ce1f2..311c6a8 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -190,15 +190,8 @@ class NodeList(UserList):
return CallableComposite(attrList)
return self.__class__(attrList)
-_valid_var = re.compile(r'[_a-zA-Z]\w*$')
_get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
-def is_valid_construction_var(varstr):
- """Return if the specified string is a legitimate construction
- variable.
- """
- return _valid_var.match(varstr)
-
def get_environment_var(varstr):
"""Given a string, first determine if it looks like a reference
to a single environment variable, like "$FOO" or "${FOO}".
@@ -407,40 +400,130 @@ except TypeError:
t = type(obj)
return t is StringType \
or (t is InstanceType and isinstance(obj, UserString))
-else:
- # A modern Python version with new-style classes, so we can just use
- # isinstance().
- def is_Dict(obj):
- return isinstance(obj, (dict, UserDict))
- def is_List(obj):
- return isinstance(obj, (list, UserList))
+ def is_Scalar(obj):
+ return is_String(obj) or not is_Sequence(obj)
- def is_Sequence(obj):
- return isinstance(obj, (list, UserList, tuple))
+ def flatten(obj, result=None):
+ """Flatten a sequence to a non-nested list.
- def is_Tuple(obj):
- return isinstance(obj, (tuple))
-
- def is_String(obj):
- # Empirically, Python versions with new-style classes all have unicode.
- return isinstance(obj, (str, unicode, UserString))
+ Flatten() converts either a single scalar or a nested sequence
+ to a non-nested list. Note that flatten() considers strings
+ to be scalars instead of sequences like Python would.
+ """
+ if is_Scalar(obj):
+ return [obj]
+ if result is None:
+ result = []
+ for item in obj:
+ if is_Scalar(item):
+ result.append(item)
+ else:
+ flatten_sequence(item, result)
+ return result
+ def flatten_sequence(sequence, result=None):
+ """Flatten a sequence to a non-nested list.
+ Same as flatten(), but it does not handle the single scalar
+ case. This is slightly more efficient when one knows that
+ the sequence to flatten can not be a scalar.
+ """
+ if result is None:
+ result = []
+ for item in sequence:
+ if is_Scalar(item):
+ result.append(item)
+ else:
+ flatten_sequence(item, result)
+ return result
+else:
+ # A modern Python version with new-style classes, so we can just use
+ # isinstance().
+ #
+ # We are using the following trick to speed-up these
+ # functions. Default arguments are used to take a snapshot of the
+ # the global functions and constants used by these functions. This
+ # transforms accesses to global variable into local variables
+ # accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL).
+
+ DictTypes = (dict, UserDict)
+ ListTypes = (list, UserList)
+ SequenceTypes = (list, tuple, UserList)
+
+ # Empirically, Python versions with new-style classes all have
+ # unicode.
+ #
+ # Note that profiling data shows a speed-up when comparing
+ # explicitely with str and unicode instead of simply comparing
+ # with basestring. (at least on Python 2.5.1)
+ StringTypes = (str, unicode, UserString)
+
+ def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes):
+ return isinstance(obj, DictTypes)
+
+ def is_List(obj, isinstance=isinstance, ListTypes=ListTypes):
+ return isinstance(obj, ListTypes)
+
+ def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes):
+ return isinstance(obj, SequenceTypes)
+
+ def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
+ return isinstance(obj, tuple)
+
+ def is_String(obj, isinstance=isinstance, StringTypes=StringTypes):
+ return isinstance(obj, StringTypes)
+
+ def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes):
+ # Profiling shows that there is an impressive speed-up of 2x
+ # when explicitely checking for strings instead of just not
+ # sequence when the argument (i.e. obj) is already a string.
+ # But, if obj is a not string than it is twice as fast to
+ # check only for 'not sequence'. The following code therefore
+ # assumes that the obj argument is a string must of the time.
+ return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes)
+
+ def do_flatten(sequence, result, isinstance=isinstance,
+ StringTypes=StringTypes, SequenceTypes=SequenceTypes):
+ for item in sequence:
+ if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
+ result.append(item)
+ else:
+ do_flatten(item, result)
-def is_Scalar(e):
- return is_String(e) or (not is_List(e) and not is_Tuple(e))
+ def flatten(obj, isinstance=isinstance, StringTypes=StringTypes,
+ SequenceTypes=SequenceTypes, do_flatten=do_flatten):
+ """Flatten a sequence to a non-nested list.
-def flatten(sequence, scalarp=is_Scalar, result=None):
- if result is None:
+ Flatten() converts either a single scalar or a nested sequence
+ to a non-nested list. Note that flatten() considers strings
+ to be scalars instead of sequences like Python would.
+ """
+ if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
+ return [obj]
result = []
- for item in sequence:
- if scalarp(item):
- result.append(item)
- else:
- flatten(item, scalarp, result)
- return result
+ for item in obj:
+ if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
+ result.append(item)
+ else:
+ do_flatten(item, result)
+ return result
+
+ def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes,
+ SequenceTypes=SequenceTypes, do_flatten=do_flatten):
+ """Flatten a sequence to a non-nested list.
+ Same as flatten(), but it does not handle the single scalar
+ case. This is slightly more efficient when one knows that
+ the sequence to flatten can not be a scalar.
+ """
+ result = []
+ for item in sequence:
+ if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
+ result.append(item)
+ else:
+ do_flatten(item, result)
+ return result
# The SCons "semi-deep" copy.
@@ -886,7 +969,7 @@ class Selector(OrderedDict):
so that get_suffix() calls always return the first suffix added."""
def __call__(self, env, source):
try:
- ext = splitext(str(source[0]))[1]
+ ext = source[0].suffix
except IndexError:
ext = ""
try:
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 44d6fa8..8a24ef1 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -384,38 +384,6 @@ class UtilTestCase(unittest.TestCase):
finally:
os.environ['PATH'] = env_path
-
-
- def test_is_valid_construction_var(self):
- """Testing is_valid_construction_var()"""
- r = is_valid_construction_var("_a")
- assert not r is None, r
- r = is_valid_construction_var("z_")
- assert not r is None, r
- r = is_valid_construction_var("X_")
- assert not r is None, r
- r = is_valid_construction_var("2a")
- assert r is None, r
- r = is_valid_construction_var("a2_")
- assert not r is None, r
- r = is_valid_construction_var("/")
- assert r is None, r
- r = is_valid_construction_var("_/")
- assert r is None, r
- r = is_valid_construction_var("a/")
- assert r is None, r
- r = is_valid_construction_var(".b")
- assert r is None, r
- r = is_valid_construction_var("_.b")
- assert r is None, r
- r = is_valid_construction_var("b1._")
- assert r is None, r
- r = is_valid_construction_var("-b")
- assert r is None, r
- r = is_valid_construction_var("_-b")
- assert r is None, r
- r = is_valid_construction_var("b1-_")
- assert r is None, r
def test_get_env_var(self):
"""Testing get_environment_var()."""
@@ -635,6 +603,14 @@ class UtilTestCase(unittest.TestCase):
def test_Selector(self):
"""Test the Selector class"""
+ class MyNode:
+ def __init__(self, name):
+ self.name = name
+ self.suffix = os.path.splitext(name)[1]
+
+ def __str__(self):
+ return self.name
+
s = Selector({'a' : 'AAA', 'b' : 'BBB'})
assert s['a'] == 'AAA', s['a']
assert s['b'] == 'BBB', s['b']
@@ -658,22 +634,22 @@ class UtilTestCase(unittest.TestCase):
s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
ret = s(env, [])
assert ret == None, ret
- ret = s(env, ['foo.d'])
+ ret = s(env, [MyNode('foo.d')])
assert ret == 'DDD', ret
- ret = s(env, ['bar.e'])
+ ret = s(env, [MyNode('bar.e')])
assert ret == 'EEE', ret
- ret = s(env, ['bar.x'])
+ ret = s(env, [MyNode('bar.x')])
assert ret == None, ret
s[None] = 'XXX'
- ret = s(env, ['bar.x'])
+ ret = s(env, [MyNode('bar.x')])
assert ret == 'XXX', ret
env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
- ret = s(env, ['foo.f'])
+ ret = s(env, [MyNode('foo.f')])
assert ret == 'FFF', ret
- ret = s(env, ['bar.g'])
+ ret = s(env, [MyNode('bar.g')])
assert ret == 'GGG', ret
def test_adjustixes(self):
@@ -746,9 +722,18 @@ class MD5TestCase(unittest.TestCase):
s = MD5signature('222')
assert 'bcbe3365e6ac95ea2c0343a2395834dd' == s, s
+
+class flattenTestCase(unittest.TestCase):
+
+ def test_scalar(self):
+ """Test flattening a scalar"""
+ result = flatten('xyz')
+ assert result == ['xyz'], result
+
if __name__ == "__main__":
suite = unittest.TestSuite()
tclasses = [ dictifyTestCase,
+ flattenTestCase,
MD5TestCase,
UtilTestCase,
]
diff --git a/src/engine/SCons/Warnings.py b/src/engine/SCons/Warnings.py
index 5354959..c9b8a26 100644
--- a/src/engine/SCons/Warnings.py
+++ b/src/engine/SCons/Warnings.py
@@ -29,6 +29,9 @@ This file implements the warnings framework for SCons.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import string
+import sys
+
import SCons.Errors
class Warning(SCons.Errors.UserError):
@@ -49,6 +52,15 @@ class DependencyWarning(Warning):
class DeprecatedWarning(Warning):
pass
+class DeprecatedCopyWarning(DeprecatedWarning):
+ pass
+
+class DeprecatedSourceSignaturesWarning(DeprecatedWarning):
+ pass
+
+class DeprecatedTargetSignaturesWarning(DeprecatedWarning):
+ pass
+
class DuplicateEnvironmentWarning(Warning):
pass
@@ -70,6 +82,9 @@ class NoObjectCountWarning(Warning):
class NoParallelSupportWarning(Warning):
pass
+class PythonVersionWarning(DeprecatedWarning):
+ pass
+
class ReservedVariableWarning(Warning):
pass
@@ -88,7 +103,7 @@ def suppressWarningClass(clazz):
"""Suppresses all warnings that are of type clazz or
derived from clazz."""
_enabled.insert(0, (clazz, 0))
-
+
def enableWarningClass(clazz):
"""Suppresses all warnings that are of type clazz or
derived from clazz."""
@@ -110,7 +125,57 @@ def warn(clazz, *args):
if flag:
if _warningAsException:
raise warning
-
+
if _warningOut:
_warningOut(warning)
break
+
+def process_warn_strings(arguments):
+ """Process string specifications of enabling/disabling warnings,
+ as passed to the --warn option or the SetOption('warn') function.
+
+
+ An argument to this option should be of the form <warning-class>
+ or no-<warning-class>. The warning class is munged in order
+ to get an actual class name from the classes above, which we
+ need to pass to the {enable,disable}WarningClass() functions.
+ The supplied <warning-class> is split on hyphens, each element
+ is capitalized, then smushed back together. Then the string
+ "Warning" is appended to get the class name.
+
+ For example, 'deprecated' will enable the DeprecatedWarning
+ class. 'no-dependency' will disable the .DependencyWarning
+ class.
+
+ As a special case, --warn=all and --warn=no-all will enable or
+ disable (respectively) the base Warning class of all warnings.
+
+ """
+
+ def _capitalize(s):
+ if s[:5] == "scons":
+ return "SCons" + s[5:]
+ else:
+ return string.capitalize(s)
+
+ for arg in arguments:
+
+ elems = string.split(string.lower(arg), '-')
+ enable = 1
+ if elems[0] == 'no':
+ enable = 0
+ del elems[0]
+
+ if len(elems) == 1 and elems[0] == 'all':
+ class_name = "Warning"
+ else:
+ class_name = string.join(map(_capitalize, elems), '') + "Warning"
+ try:
+ clazz = globals()[class_name]
+ except KeyError:
+ sys.stderr.write("No warning type: '%s'\n" % arg)
+ else:
+ if enable:
+ enableWarningClass(clazz)
+ else:
+ suppressWarningClass(clazz)
diff --git a/src/engine/SCons/compat/__init__.py b/src/engine/SCons/compat/__init__.py
index 91e3776..1d36dbc 100644
--- a/src/engine/SCons/compat/__init__.py
+++ b/src/engine/SCons/compat/__init__.py
@@ -173,6 +173,16 @@ except ImportError:
# Pre-2.4 Python has no subprocess module.
import_as('_scons_subprocess', 'subprocess')
+import sys
+try:
+ sys.version_info
+except AttributeError:
+ # Pre-1.6 Python has no sys.version_info
+ import string
+ version_string = string.split(sys.version)[0]
+ version_ints = map(int, string.split(version_string, '.'))
+ sys.version_info = tuple(version_ints + ['final', 0])
+
try:
import UserString
except ImportError:
diff --git a/src/engine/SCons/cppTests.py b/src/engine/SCons/cppTests.py
index 33fd01d..ed1479b 100644
--- a/src/engine/SCons/cppTests.py
+++ b/src/engine/SCons/cppTests.py
@@ -625,9 +625,9 @@ class fileTestCase(unittest.TestCase):
os.chdir(path)
def tearDown(self):
+ os.chdir(self.orig_cwd)
shutil.rmtree(self.tempdir)
_Cleanup.remove(self.tempdir)
- os.chdir(self.orig_cwd)
def strip_initial_spaces(self, s):
#lines = s.split('\n')
diff --git a/src/script/scons.py b/src/script/scons.py
index fbffe68..db01549 100644
--- a/src/script/scons.py
+++ b/src/script/scons.py
@@ -157,5 +157,6 @@ sys.path = libs + sys.path
# END STANDARD SCons SCRIPT HEADER
##############################################################################
-import SCons.Script
-SCons.Script.main()
+if __name__ == "__main__":
+ import SCons.Script
+ SCons.Script.main()
diff --git a/src/test_strings.py b/src/test_strings.py
index c446cad..0b6344f 100644
--- a/src/test_strings.py
+++ b/src/test_strings.py
@@ -185,6 +185,7 @@ check_list = [
CheckExpandedCopyright(
build_src,
remove_list = [
+ 'bench/timeit.py',
'bin',
'config',
'debian',