Merged revisions 2647-2719 via svnmerge from
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 31 Mar 2008 17:03:04 +0000 (17:03 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Mon, 31 Mar 2008 17:03:04 +0000 (17:03 +0000)
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.
........

git-svn-id: http://scons.tigris.org/svn/scons/trunk@2721 fdb21ef1-2011-0410-befe-b5e4ea1792b1

187 files changed:
QMTest/TestRuntest.py
QMTest/TestSCons.py
README
SConstruct
bench/env.__setitem__.py [new file with mode: 0644]
bench/timeit.py [new file with mode: 0644]
bin/install-python.sh [new file with mode: 0644]
bin/install-scons.sh [new file with mode: 0644]
bin/scons-review.sh [new file with mode: 0755]
bootstrap.py
doc/SConscript
doc/man/scons.1
doc/scons.mod
doc/user/java.xml
doc/user/separate.in
doc/user/separate.xml
doc/user/troubleshoot.xml
doc/user/variants.in
doc/user/variants.xml
runtest.py
src/CHANGES.txt
src/RELEASE.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/Builder.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Conftest.py
src/engine/SCons/Defaults.py
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Options/ListOption.py
src/engine/SCons/Options/__init__.py
src/engine/SCons/SConf.py
src/engine/SCons/Scanner/CTests.py
src/engine/SCons/Scanner/FortranTests.py
src/engine/SCons/Scanner/IDLTests.py
src/engine/SCons/Scanner/Prog.py
src/engine/SCons/Script/Interactive.py
src/engine/SCons/Script/Main.py
src/engine/SCons/Script/SConsOptions.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Script/__init__.py
src/engine/SCons/Taskmaster.py
src/engine/SCons/Tool/JavaCommon.py
src/engine/SCons/Tool/JavaCommonTests.py
src/engine/SCons/Tool/__init__.py
src/engine/SCons/Tool/applelink.py
src/engine/SCons/Tool/dvips.py
src/engine/SCons/Tool/install.py
src/engine/SCons/Tool/msvc.py
src/engine/SCons/Tool/msvs.py
src/engine/SCons/Tool/qt.xml
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
src/engine/SCons/Warnings.py
src/engine/SCons/compat/__init__.py
src/engine/SCons/cppTests.py
src/script/scons.py
src/test_strings.py
test/Alias/Alias.py
test/Alias/errors.py
test/Alias/srcdir.py
test/CPPPATH/CPPPATH.py
test/CPPPATH/match-dir.py
test/CacheDir/VariantDir.py [moved from test/CacheDir/BuildDir.py with 97% similarity]
test/Chmod.py
test/Configure/VariantDir-SConscript.py [moved from test/Configure/BuildDir-SConscript.py with 99% similarity]
test/Configure/VariantDir.py [moved from test/Configure/BuildDir.py with 97% similarity]
test/Configure/cache-not-ok.py
test/Configure/cache-ok.py
test/Configure/config-h.py
test/Copy-Action.py [moved from test/Copy.py with 73% similarity]
test/Delete.py
test/Deprecated/BuildDir.py [new file with mode: 0644]
test/Deprecated/CacheDir/timestamp-content.py [moved from test/CacheDir/timestamp-content.py with 98% similarity]
test/Deprecated/CacheDir/timestamp-timestamp.py [moved from test/CacheDir/timestamp-timestamp.py with 98% similarity]
test/Deprecated/Copy.py [new file with mode: 0644]
test/Deprecated/SConscript-build_dir.py [moved from test/BuildDir/Sconscript-build_dir.py with 95% similarity]
test/Deprecated/SourceSignatures/basic.py [moved from test/SourceSignatures/basic.py with 79% similarity]
test/Deprecated/SourceSignatures/env.py [moved from test/SourceSignatures/env.py with 82% similarity]
test/Deprecated/SourceSignatures/implicit-cache.py [moved from test/SourceSignatures/implicit-cache.py with 71% similarity]
test/Deprecated/SourceSignatures/no-csigs.py [moved from test/SourceSignatures/no-csigs.py with 93% similarity]
test/Deprecated/SourceSignatures/overrides.py [moved from test/SourceSignatures/overrides.py with 85% similarity]
test/Deprecated/SourceSignatures/switch-rebuild.py [moved from test/SourceSignatures/switch-rebuild.py with 74% similarity]
test/Deprecated/TargetSignatures/build-content.py [moved from test/TargetSignatures/build-content.py with 85% similarity]
test/Deprecated/TargetSignatures/content.py [moved from test/TargetSignatures/content.py with 88% similarity]
test/Deprecated/TargetSignatures/overrides.py [moved from test/TargetSignatures/overrides.py with 90% similarity]
test/Deprecated/debug-dtree.py [moved from test/option/debug-dtree.py with 87% similarity]
test/Deprecated/debug-nomemoizer.py [moved from test/option/debug-nomemoizer.py with 100% similarity]
test/Deprecated/debug-stree.py [moved from test/option/debug-stree.py with 88% similarity]
test/Deprecated/debug-tree.py [moved from test/option/debug-tree.py with 90% similarity]
test/Dir/source.py
test/Fortran/F77PATH.py
test/Fortran/F90PATH.py
test/Fortran/FORTRANPATH.py
test/GetBuildFailures/parallel.py
test/Glob/VariantDir.py [moved from test/Glob/BuildDir.py with 94% similarity]
test/Glob/source.py
test/Glob/strings.py
test/IDL/midl.py
test/Install/Install.py
test/Install/InstallAs.py
test/Install/wrap-by-attribute.py [new file with mode: 0644]
test/Interactive/implicit-VariantDir.py [moved from test/Interactive/implicit-BuildDir.py with 94% similarity]
test/Java/multi-step.py
test/Java/swig-dependencies.py
test/MSVC/msvc.py
test/MSVC/pdb-VariantDir-path.py [moved from test/MSVC/pdb-BuildDir-path.py with 90% similarity]
test/MSVS/vs-6.0-files.py
test/MSVS/vs-7.0-files.py
test/MSVS/vs-7.1-files.py
test/MSVS/vs-8.0-files.py
test/Mkdir.py
test/NodeOps.py
test/Options/ListOption.py
test/QT/QTFLAGS.py
test/QT/installed.py
test/QT/moc-from-cpp.py
test/QT/moc-from-header.py
test/QT/source-from-ui.py
test/Repository/Java.py
test/Repository/Local.py
test/Repository/M4.py
test/Repository/VariantDir.py [moved from test/Repository/BuildDir.py with 98% similarity]
test/Repository/variants.py
test/SCONSFLAGS.py
test/SConscript/src_dir.py
test/SWIG/SWIGOUTDIR.py
test/SWIG/build-dir.py
test/Scanner/generated.py
test/SideEffect/variant_dir.py [moved from test/SideEffect/build_dir.py with 96% similarity]
test/TARGET-dir.py
test/TEX/auxiliaries.py
test/TEX/variant_dir.py [moved from test/TEX/build_dir.py with 97% similarity]
test/TEX/variant_dir_dup0.py [moved from test/TEX/build_dir_dup0.py with 97% similarity]
test/Touch.py
test/Value.py
test/VariantDir/CPPPATH-subdir.py [moved from test/BuildDir/CPPPATH-subdir.py with 97% similarity]
test/VariantDir/Clean.py [moved from test/BuildDir/Clean.py with 90% similarity]
test/VariantDir/File-create.py [moved from test/BuildDir/File-create.py with 91% similarity]
test/VariantDir/SConscript-variant_dir.py [new file with mode: 0644]
test/VariantDir/VariantDir.py [moved from test/BuildDir/BuildDir.py with 96% similarity]
test/VariantDir/errors.py [moved from test/BuildDir/errors.py with 92% similarity]
test/VariantDir/guess-subdir.py [moved from test/BuildDir/guess-subdir.py with 91% similarity]
test/VariantDir/nested-sconscripts.py [moved from test/BuildDir/nested-sconscripts.py with 94% similarity]
test/VariantDir/reflect.py [moved from test/BuildDir/reflect.py with 91% similarity]
test/VariantDir/removed-files.py [moved from test/BuildDir/removed-files.py with 97% similarity]
test/VariantDir/under.py [moved from test/BuildDir/under.py with 88% similarity]
test/emitter.py
test/explain/basic.py
test/implicit-cache/basic.py
test/no-global-dependencies.py
test/option--U.py
test/option--duplicate.py
test/option--warn.py [deleted file]
test/option-n.py
test/option-u.py
test/option/debug-memoizer.py
test/option/warn-dependency.py [new file with mode: 0644]
test/option/warn-duplicate-environment.py [new file with mode: 0644]
test/option/warn-misleading-keywords.py [new file with mode: 0644]
test/option/warn-missing-sconscript.py [new file with mode: 0644]
test/packaging/use-builddir.py
test/python-version.py [new file with mode: 0644]
test/runtest/baseline/combined.py
test/runtest/baseline/fail.py
test/runtest/baseline/no_result.py
test/runtest/baseline/pass.py
test/runtest/fallback.py
test/runtest/print_time.py
test/runtest/python.py
test/runtest/simple/combined.py
test/runtest/simple/fail.py
test/runtest/simple/no_result.py
test/runtest/simple/pass.py
test/runtest/src.py
test/runtest/testlistfile.py
test/sconsign/ghost-entries.py
test/sconsign/script/Signatures.py
test/sconsign/script/dblite.py
test/srcchange.py
test/subdivide.py
test/symlink/VariantDir.py [moved from test/symlink/BuildDir.py with 98% similarity]
test/toolpath/VariantDir.py [moved from test/toolpath/BuildDir.py with 93% similarity]

index ee33b250916f4bc9575551e40cb6f7799f84cf46..e44cd27bc7f2855a03d45277d6ca0036747bfc3b 100644 (file)
@@ -121,9 +121,9 @@ class TestRuntest(TestCommon):
         apply(TestCommon.__init__, [self], kw)
   
         if not noqmtest:
-            qmtest_py = self.where_is('qmtest.py')
-            if not qmtest_py:
-                self.skip_test("Could not find 'qmtest.py'; skipping test(s).\n")
+            qmtest = self.where_is('qmtest')
+            if not qmtest:
+                self.skip_test("Could not find 'qmtest'; skipping test(s).\n")
 
         things_to_copy = [
             'runtest.py',
index 6b6f5ed71fd34903347950d0a17e0cac65519a96..d5aa057f4a7350c1ac67e6b7058101d3be32c3eb 100644 (file)
@@ -42,9 +42,9 @@ from TestCommon import __all__
 # here provides some independent verification that what we packaged
 # conforms to what we expect.
 
-default_version = '0.97.0'
+default_version = '0.98.0'
 
-SConsVersion = '__VERSION__'
+SConsVersion = '0.98.0'
 if SConsVersion == '__' + 'VERSION' + '__':
     SConsVersion = default_version
 
@@ -139,6 +139,40 @@ def re_escape(str):
     return str
 
 
+
+try:
+    sys.version_info
+except AttributeError:
+    # Pre-1.6 Python has no sys.version_info
+    version_string = string.split(sys.version)[0]
+    version_ints = map(int, string.split(version_string, '.'))
+    sys.version_info = tuple(version_ints + ['final', 0])
+
+def python_version_string():
+    return string.split(sys.version)[0]
+
+def python_minor_version_string():
+    return sys.version[:3]
+
+def unsupported_python_version(version=sys.version_info):
+    return version < (1, 5, 2)
+
+def deprecated_python_version(version=sys.version_info):
+    return version < (2, 2, 0)
+
+if deprecated_python_version():
+    msg = r"""
+scons: warning: Support for pre-2.2 Python (%s) is deprecated.
+    If this will cause hardship, contact dev@scons.tigris.org.
+"""
+
+    deprecated_python_expr = re_escape(msg % python_version_string()) + file_expr
+    del msg
+else:
+    deprecated_python_expr = ""
+
+
+
 class TestSCons(TestCommon):
     """Class for testing SCons.
 
@@ -187,6 +221,21 @@ class TestSCons(TestCommon):
             kw['match'] = match_exact
         if not kw.has_key('workdir'):
             kw['workdir'] = ''
+
+       # Term causing test failures due to bogus readline init
+       # control character output on FC8
+        # TERM can cause test failures due to control chars in prompts etc.
+        os.environ['TERM'] = 'dumb'
+
+        if deprecated_python_version():
+            sconsflags = os.environ.get('SCONSFLAGS')
+            if sconsflags:
+                sconsflags = [sconsflags]
+            else:
+                sconsflags = []
+            sconsflags = sconsflags + ['--warn=no-python-version']
+            os.environ['SCONSFLAGS'] = string.join(sconsflags)
+
         apply(TestCommon.__init__, [self], kw)
 
         import SCons.Node.FS
@@ -381,6 +430,16 @@ class TestSCons(TestCommon):
 
         return s
 
+    def paths(self,patterns):
+        import glob
+        result = []
+        for p in patterns:
+            paths = glob.glob(p)
+            paths.sort()
+            result.extend(paths)
+        return result
+
+
     def java_ENV(self, version=None):
         """
         Initialize with a default external environment that uses a local
@@ -397,31 +456,55 @@ class TestSCons(TestCommon):
         env = SCons.Environment.Environment()
         self._java_env[version] = env
 
-        def paths(patterns):
-            import glob
-            result = []
-            for p in patterns:
-                paths = glob.glob(p)
-                paths.sort()
-                result.extend(paths)
-            return result
 
         if version:
             patterns = [
+                '/usr/java/jdk%s*/bin'    % version,
                 '/usr/lib/jvm/*-%s*/bin' % version,
                 '/usr/local/j2sdk%s*/bin' % version,
             ]
-            java_path = paths(patterns) + [env['ENV']['PATH']]
+            java_path = self.paths(patterns) + [env['ENV']['PATH']]
         else:
             patterns = [
+                '/usr/java/latest/bin',
                 '/usr/lib/jvm/*/bin',
                 '/usr/local/j2sdk*/bin',
             ]
-            java_path = paths(patterns) + [env['ENV']['PATH']]
+            java_path = self.paths(patterns) + [env['ENV']['PATH']]
 
         env['ENV']['PATH'] = string.join(java_path, os.pathsep)
         return env['ENV']
 
+    def java_where_includes(self,version=None):
+        """
+        Return java include paths compiling java jni code
+        """
+        import glob
+        import sys
+        if not version:
+            version=''
+        jni_dirs = ['/usr/lib/jvm/java-*-sun-%s*/include/jni.h'%version,
+                    '/usr/java/jdk%s*/include/jni.h'%version,
+                    ]
+        dirs = self.paths(jni_dirs)
+        if not dirs:
+            return None
+        d=os.path.dirname(self.paths(jni_dirs)[0])
+        result=[d]
+
+        if sys.platform == 'win32':
+            result.append(os.path.join(d,'win32'))
+        elif sys.platform == 'linux2':
+            result.append(os.path.join(d,'linux'))
+        return result
+
+
+    def java_where_java_home(self,version=None):
+        import os.path
+        jar=self.java_where_jar(version)
+        home=os.path.normpath('%s/..'%jar)
+        return home
+
     def java_where_jar(self, version=None):
         ENV = self.java_ENV(version)
         if self.detect_tool('jar', ENV=ENV):
@@ -601,7 +684,7 @@ env = Environment(QTDIR = QTDIR,
                   QT_UIC = r'%s',
                   tools=['default','qt'])
 dup = 1
-if ARGUMENTS.get('build_dir', 0):
+if ARGUMENTS.get('variant_dir', 0):
     if ARGUMENTS.get('chdir', 0):
         SConscriptChdir(1)
     else:
@@ -612,7 +695,7 @@ if ARGUMENTS.get('build_dir', 0):
         env['QT_DEBUG'] = 1
     else:
         builddir = 'build'
-    BuildDir(builddir, '.', duplicate=dup)
+    VariantDir(builddir, '.', duplicate=dup)
     print builddir, dup
     sconscript = Dir(builddir).File('SConscript')
 else:
@@ -849,7 +932,7 @@ print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
         hand-code slicing the right number of characters).
         """
         # see also sys.prefix documentation
-        return sys.version[:3]
+        return python_minor_version_string()
 
     def get_platform_python(self):
         """
diff --git a/README b/README
index 36dbe2305e493dca1ff49b16c0fce5ac2422cb29..5cb92013c78703f5b91c5b3bf6b8b2b3af440a83 100644 (file)
--- a/README
+++ b/README
@@ -83,11 +83,11 @@ In this case, your options are:
     --  (Optional.)  Install from a pre-packaged SCons package that
         does not require distutils:
 
-            Red Hat Linux       scons-0.97.noarch.rpm
+            Red Hat Linux       scons-0.98.noarch.rpm
 
             Debian GNU/Linux    use apt-get to get the official package
 
-            Windows             scons-0.97.win32.exe
+            Windows             scons-0.98.win32.exe
 
     --  (Recommended.)  Download the latest distutils package from the
         following URL:
@@ -159,7 +159,7 @@ And on Windows:
 
 By default, the above commands will do the following:
 
-    --  Install the version-numbered "scons-0.97" and "sconsign-0.97"
+    --  Install the version-numbered "scons-0.98" and "sconsign-0.98"
         scripts in the default system script directory (/usr/bin or
         C:\Python*\Scripts, for example).  This can be disabled by
         specifying the "--no-version-script" option on the command
@@ -173,24 +173,24 @@ By default, the above commands will do the following:
         making it the default on your system.
 
         On UNIX or Linux systems, you can have the "scons" and "sconsign"
-        scripts be hard links or symbolic links to the "scons-0.97" and
-        "sconsign-0.97" scripts by specifying the "--hardlink-scons" or
+        scripts be hard links or symbolic links to the "scons-0.98" and
+        "sconsign-0.98" scripts by specifying the "--hardlink-scons" or
         "--symlink-scons" options on the command line.
 
-    --  Install "scons-0.97.bat" and "scons.bat" wrapper scripts in the
+    --  Install "scons-0.98.bat" and "scons.bat" wrapper scripts in the
         Python prefix directory on Windows (C:\Python*, for example).
         This can be disabled by specifying the "--no-install-bat" option
         on the command line.
 
         On UNIX or Linux systems, the "--install-bat" option may be
-        specified to have "scons-0.97.bat" and "scons.bat" files installed
+        specified to have "scons-0.98.bat" and "scons.bat" files installed
         in the default system script directory, which is useful if you
         want to install SCons in a shared file system directory that can
         be used to execute SCons from both UNIX/Linux and Windows systems.
 
     --  Install the SCons build engine (a Python module) in an
         appropriate version-numbered SCons library directory
-        (/usr/lib/scons-0.97 or C:\Python*\scons-0.97, for example).
+        (/usr/lib/scons-0.98 or C:\Python*\scons-0.98, for example).
         See below for more options related to installing the build
         engine library.
 
@@ -527,18 +527,18 @@ On Windows:
 Depending on the utilities installed on your system, any or all of the
 following packages will be built:
 
-        build/dist/scons-0.97-1.noarch.rpm
-        build/dist/scons-0.97-1.src.rpm
-        build/dist/scons-0.97.linux-i686.tar.gz
-        build/dist/scons-0.97.tar.gz
-        build/dist/scons-0.97.win32.exe
-        build/dist/scons-0.97.zip
-        build/dist/scons-doc-0.97.tar.gz
-        build/dist/scons-local-0.97.tar.gz
-        build/dist/scons-local-0.97.zip
-        build/dist/scons-src-0.97.tar.gz
-        build/dist/scons-src-0.97.zip
-        build/dist/scons_0.97-1_all.deb
+        build/dist/scons-0.98-1.noarch.rpm
+        build/dist/scons-0.98-1.src.rpm
+        build/dist/scons-0.98.linux-i686.tar.gz
+        build/dist/scons-0.98.tar.gz
+        build/dist/scons-0.98.win32.exe
+        build/dist/scons-0.98.zip
+        build/dist/scons-doc-0.98.tar.gz
+        build/dist/scons-local-0.98.tar.gz
+        build/dist/scons-local-0.98.zip
+        build/dist/scons-src-0.98.tar.gz
+        build/dist/scons-src-0.98.zip
+        build/dist/scons_0.98-1_all.deb
 
 The SConstruct file is supposed to be smart enough to avoid trying to
 build packages for which you don't have the proper utilities installed.
index 72e3e064fdb037a67e67a87db8614b1ea55fb840..226513b9586fd0eeec3ba3d3ded540aa04869c61 100644 (file)
@@ -45,7 +45,7 @@ import sys
 import tempfile
 
 project = 'scons'
-default_version = '0.97.0'
+default_version = '0.98.0'
 copyright = "Copyright (c) %s The SCons Foundation" % copyright_years
 
 SConsignFile()
@@ -806,9 +806,13 @@ for p in [ scons ]:
 
     distutils_targets = [ win32_exe ]
 
-    Local(env.Install('$DISTDIR', distutils_targets))
+    dist_distutils_targets = env.Install('$DISTDIR', distutils_targets)
+    Local(dist_distutils_targets)
+    AddPostAction(dist_distutils_targets, Chmod(dist_distutils_targets, 0644))
 
-    if gzip:
+    if not gzip:
+        print "gzip not found; skipping .tar.gz package for %s." % pkg
+    else:
 
         distutils_formats.append('gztar')
 
@@ -819,6 +823,8 @@ for p in [ scons ]:
         dist_tar_gz             = env.Install('$DISTDIR', tar_gz)
         dist_platform_tar_gz    = env.Install('$DISTDIR', platform_tar_gz)
         Local(dist_tar_gz, dist_platform_tar_gz)
+        AddPostAction(dist_tar_gz, Chmod(dist_tar_gz, 0644))
+        AddPostAction(dist_platform_tar_gz, Chmod(dist_platform_tar_gz, 0644))
 
         #
         # Unpack the tar.gz archive created by the distutils into
@@ -892,7 +898,9 @@ for p in [ scons ]:
                                                                 bytes))
         env.Command(digest, tar_gz, Digestify)
 
-    if zipit:
+    if not zipit:
+        print "zip not found; skipping .zip package for %s." % pkg
+    else:
 
         distutils_formats.append('zip')
 
@@ -903,6 +911,8 @@ for p in [ scons ]:
         dist_zip            = env.Install('$DISTDIR', zip)
         dist_platform_zip   = env.Install('$DISTDIR', platform_zip)
         Local(dist_zip, dist_platform_zip)
+        AddPostAction(dist_zip, Chmod(dist_zip, 0644))
+        AddPostAction(dist_platform_zip, Chmod(dist_platform_zip, 0644))
 
         #
         # Unpack the zip archive created by the distutils into
@@ -990,6 +1000,8 @@ for p in [ scons ]:
         dist_noarch_rpm = env.Install('$DISTDIR', noarch_rpm)
         dist_src_rpm    = env.Install('$DISTDIR', src_rpm)
         Local(dist_noarch_rpm, dist_src_rpm)
+        AddPostAction(dist_noarch_rpm, Chmod(dist_noarch_rpm, 0644))
+        AddPostAction(dist_src_rpm, Chmod(dist_src_rpm, 0644))
 
         dfiles = map(lambda x, d=test_rpm_dir: os.path.join(d, 'usr', x),
                      dst_files)
@@ -1058,6 +1070,8 @@ for p in [ scons ]:
 
     dist_local_tar_gz = os.path.join("$DISTDIR/%s.tar.gz" % s_l_v)
     dist_local_zip = os.path.join("$DISTDIR/%s.zip" % s_l_v)
+    AddPostAction(dist_local_tar_gz, Chmod(dist_local_tar_gz, 0644))
+    AddPostAction(dist_local_zip, Chmod(dist_local_zip, 0644))
 
     commands = [
         Delete(build_dir_local),
@@ -1159,7 +1173,9 @@ SConscript('doc/SConscript')
 # source archive from the project files and files in the change.
 #
 
-if svn_status:
+if not svn_status:
+   "Not building in a Subversion tree; skipping building src package."
+else:
     slines = filter(lambda l: l[0] in ' MA', svn_status_lines)
     sentries = map(lambda l: l.split()[-1], slines)
     sfiles = filter(os.path.isfile, sentries)
diff --git a/bench/env.__setitem__.py b/bench/env.__setitem__.py
new file mode 100644 (file)
index 0000000..3826176
--- /dev/null
@@ -0,0 +1,362 @@
+# __COPYRIGHT__
+#
+# Benchmarks for testing various possible implementations of the
+# env.__setitem__() method(s) in the src/engine/SCons/Environment.py
+# module.
+
+import os.path
+import re
+import string
+import sys
+import timeit
+
+# Utility Timing class and function from:
+# ASPN: Python Cookbook : Timing various python statements
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/544297
+#
+# These wrap the basic timeit function to make it a little more
+# convenient to do side-by-side tests of code.
+
+class Timing:
+    def __init__(self, name, num, init, statement):
+        self.__timer = timeit.Timer(statement, init)
+        self.__num   = num
+        self.name    = name
+        self.statement = statement
+        self.__result  = None
+        
+    def timeit(self):
+        self.__result = self.__timer.timeit(self.__num)
+        
+    def getResult(self):
+        return self.__result
+
+def times(num=1000000, init='', title='Results:', **statements):
+    # time each statement
+    timings = []
+    for n, s in statements.items():
+        t = Timing(n, num, init, s)
+        t.timeit()
+        timings.append(t)
+    
+    print
+    print title
+    l = []
+    for i in timings: l.append((i.getResult(),i.name))
+    l.sort()
+    for i in l: print "  %9.3f s   %s" % i
+
+# Import the necessary local SCons.* modules used by some of our
+# alternative implementations below, first manipulating sys.path so
+# we pull in the right local modules without forcing the user to set
+# PYTHONPATH.
+
+import __main__
+try:
+    filename = __main__.__file__
+except AttributeError:
+    filename = sys.argv[0]
+script_dir = os.path.split(filename)[0]
+if script_dir:
+    script_dir = script_dir + '/'
+sys.path = [os.path.abspath(script_dir + '../src/engine')] + sys.path
+
+import SCons.Errors
+import SCons.Environment
+
+is_valid_construction_var = SCons.Environment.is_valid_construction_var
+global_valid_var = re.compile(r'[_a-zA-Z]\w*$')
+
+# The classes with different __setitem__() implementations that we're
+# going to horse-race.
+#
+# The base class (Environment) should contain *all* class initialization
+# of anything that will be used by any of the competing sub-class
+# implementations.  Each timing run will create an instance of the class,
+# and all competing sub-classes should share the same initialization
+# overhead so our timing focuses on just the __setitem__() performance.
+#
+# All subclasses should be prefixed with env_, in which case they'll be
+# picked up automatically by the code below for testing.
+#
+# The env_Original subclass contains the original implementation (which
+# actually had the is_valid_construction_var() function in SCons.Util
+# originally).
+#
+# The other subclasses (except for env_Best) each contain *one*
+# significant change from the env_Original implementation.  The doc string
+# describes the change, and is what gets displayed in the final timing.
+# The doc strings of these other subclasses are "grouped" informally
+# by a prefix that kind of indicates what specific aspect of __setitem__()
+# is being varied and tested.
+#
+# The env_Best subclass contains the "best practices" from each of
+# the different "groups" of techniques tested in the other subclasses,
+# and is where to experiment with different combinations of techniques.
+# After we're done should be the one that shows up at the top of the
+# list as we run our timings.
+
+class Environment:
+    _special_set = {
+        'BUILDERS' : None,
+        'SCANNERS' : None,
+        'TARGET'   : None,
+        'TARGETS'  : None,
+        'SOURCE'   : None,
+        'SOURCES'  : None,
+    }
+    _special_set_keys = _special_set.keys()
+    _valid_var = re.compile(r'[_a-zA-Z]\w*$')
+    def __init__(self, **kw):
+        self._dict = kw
+
+class env_Original(Environment):
+    """Original __setitem__()"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not SCons.Environment.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_Global_is_valid(Environment):
+    """is_valid_construction_var():  use a global function"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_Method_is_valid(Environment):
+    """is_valid_construction_var():  use a method"""
+    def is_valid_construction_var(self, varstr):
+        """Return if the specified string is a legitimate construction
+        variable.
+        """
+        return self._valid_var.match(varstr)
+
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not self.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_regex_attribute_is_valid(Environment):
+    """is_valid_construction_var():  use a regex attribute"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not self._valid_var.match(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_global_regex_is_valid(Environment):
+    """is_valid_construction_var():  use a global regex"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not global_valid_var.match(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_special_set_has_key(Environment):
+    """_special_set.get():  use _special_set.has_key() instead"""
+    def __setitem__(self, key, value):
+        if self._special_set.has_key(key):
+            self._special_set[key](self, key, value)
+        else:
+            if not SCons.Environment.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_key_in_tuple(Environment):
+    """_special_set.get():  use "key in tuple" instead"""
+    def __setitem__(self, key, value):
+        if key in ('BUILDERS', 'SCANNERS', 'TARGET', 'TARGETS', 'SOURCE', 'SOURCES'):
+            self._special_set[key](self, key, value)
+        else:
+            if not SCons.Environment.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_key_in_list(Environment):
+    """_special_set.get():  use "key in list" instead"""
+    def __setitem__(self, key, value):
+        if key in ['BUILDERS', 'SCANNERS', 'TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
+            self._special_set[key](self, key, value)
+        else:
+            if not SCons.Environment.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_key_in_attribute(Environment):
+    """_special_set.get():  use "key in attribute" instead"""
+    def __setitem__(self, key, value):
+        if key in self._special_set_keys:
+            self._special_set[key](self, key, value)
+        else:
+            if not SCons.Environment.is_valid_construction_var(key):
+                raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_try_except(Environment):
+    """avoid is_valid_construction_var():  use try:-except:"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            try:
+                self._dict[key]
+            except KeyError:
+                if not SCons.Environment.is_valid_construction_var(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_not_has_key(Environment):
+    """avoid is_valid_construction_var():  use not .has_key()"""
+    def __setitem__(self, key, value):
+        special = self._special_set.get(key)
+        if special:
+            special(self, key, value)
+        else:
+            if not self._dict.has_key(key) \
+                and not SCons.Environment.is_valid_construction_var(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_Best_attribute(Environment):
+    """Best __setitem__(), with an attribute"""
+    def __setitem__(self, key, value):
+        if key in self._special_set_keys:
+            self._special_set[key](self, key, value)
+        else:
+            if not self._dict.has_key(key) \
+               and not global_valid_var.match(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_Best_has_key(Environment):
+    """Best __setitem__(), with has_key"""
+    def __setitem__(self, key, value):
+        if self._special_set.has_key(key):
+            self._special_set[key](self, key, value)
+        else:
+            if not self._dict.has_key(key) \
+               and not global_valid_var.match(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+class env_Best_list(Environment):
+    """Best __setitem__(), with a list"""
+    def __setitem__(self, key, value):
+        if key in ['BUILDERS', 'SCANNERS', 'TARGET', 'TARGETS', 'SOURCE', 'SOURCES']:
+            self._special_set[key](self, key, value)
+        else:
+            if not self._dict.has_key(key) \
+               and not global_valid_var.match(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+            self._dict[key] = value
+
+try:
+    ''.isalnum
+except AttributeError:
+    pass
+else:
+    class env_isalnum(Environment):
+        """Greg's Folly: isalnum instead of probe"""
+        def __setitem__(self, key, value):
+            if self._special_set.has_key(key):
+                self._special_set[key](self, key, value)
+            else:
+                if not key.isalnum() and not global_valid_var.match(key):
+                    raise SCons.Errors.UserError, "Illegal construction variable `%s'" % key
+                self._dict[key] = value
+
+# We'll use the names of all the env_* classes we find later to build
+# the dictionary of statements to be timed, and the import statement
+# that the timer will use to get at these classes.
+
+class_names = []
+for n in locals().keys():
+    #if n.startswith('env_'):
+    if n[:4] == 'env_':
+        class_names.append(n)
+
+# This is *the* function that gets timed.  It will get called for the
+# specified number of iterations for the cross product of the number of
+# classes we're testing and the number of data sets (defined below).
+
+iterations = 10000
+
+def do_it(names, env_class):
+    e = env_class()
+    for key in names:
+        e[key] = 1
+
+# Build the list of "statements" that will be tested.  For each class
+# we're testing, the doc string describing the class is the key, and
+# the statement we test is a simple "doit(names, {class})" call.
+
+statements = {}
+
+for class_name in class_names:
+    ec = eval(class_name)
+    statements[ec.__doc__] = 'do_it(names, %s)' % class_name
+
+# The common_imports string is used in the initialization of each
+# test run.  The timeit module insulates the test snippets from the
+# global namespace, so we have to import these explicitly from __main__.
+
+common_import_variables = ['do_it'] + class_names
+
+common_imports = """
+from __main__ import %s
+""" % string.join(common_import_variables, ', ')
+
+# The test data (lists of variable names) that we'll use for the runs.
+
+same_variable_names = ['XXX'] * 100
+uniq_variable_names = []
+for i in range(100): uniq_variable_names.append('X%05d' % i)
+mixed_variable_names = uniq_variable_names[:50] + same_variable_names[:50]
+
+# Lastly, put it all together...
+
+def run_it(title, init):
+      s = statements.copy()
+      s['num'] = iterations
+      s['title'] = title
+      s['init'] = init
+      apply(times,(),s)
+
+print 'Environment __setitem__ benchmark using',
+print 'Python', string.split(sys.version)[0],
+print 'on', sys.platform, os.name
+
+run_it('Results for re-adding an existing variable name 100 times:',
+      common_imports + """
+import __main__ ; names = __main__.same_variable_names
+""")
+
+run_it('Results for adding 100 variable names, 50 existing and 50 new:',
+      common_imports + """
+import __main__ ; names = __main__.mixed_variable_names
+""")
+
+run_it('Results for adding 100 new, unique variable names:',
+      common_imports + """
+import __main__ ; names = __main__.uniq_variable_names
+""")
diff --git a/bench/timeit.py b/bench/timeit.py
new file mode 100644 (file)
index 0000000..d5e33bb
--- /dev/null
@@ -0,0 +1,297 @@
+#! /usr/bin/env python
+
+"""Tool for measuring execution time of small code snippets.
+
+This module avoids a number of common traps for measuring execution
+times.  See also Tim Peters' introduction to the Algorithms chapter in
+the Python Cookbook, published by O'Reilly.
+
+Library usage: see the Timer class.
+
+Command line usage:
+    python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement]
+
+Options:
+  -n/--number N: how many times to execute 'statement' (default: see below)
+  -r/--repeat N: how many times to repeat the timer (default 3)
+  -s/--setup S: statement to be executed once initially (default 'pass')
+  -t/--time: use time.time() (default on Unix)
+  -c/--clock: use time.clock() (default on Windows)
+  -v/--verbose: print raw timing results; repeat for more digits precision
+  -h/--help: print this usage message and exit
+  statement: statement to be timed (default 'pass')
+
+A multi-line statement may be given by specifying each line as a
+separate argument; indented lines are possible by enclosing an
+argument in quotes and using leading spaces.  Multiple -s options are
+treated similarly.
+
+If -n is not given, a suitable number of loops is calculated by trying
+successive powers of 10 until the total time is at least 0.2 seconds.
+
+The difference in default timer function is because on Windows,
+clock() has microsecond granularity but time()'s granularity is 1/60th
+of a second; on Unix, clock() has 1/100th of a second granularity and
+time() is much more precise.  On either platform, the default timer
+functions measure wall clock time, not the CPU time.  This means that
+other processes running on the same computer may interfere with the
+timing.  The best thing to do when accurate timing is necessary is to
+repeat the timing a few times and use the best time.  The -r option is
+good for this; the default of 3 repetitions is probably enough in most
+cases.  On Unix, you can use clock() to measure CPU time.
+
+Note: there is a certain baseline overhead associated with executing a
+pass statement.  The code here doesn't try to hide it, but you should
+be aware of it.  The baseline overhead can be measured by invoking the
+program without arguments.
+
+The baseline overhead differs between Python versions!  Also, to
+fairly compare older Python versions to Python 2.3, you may want to
+use python -O for the older versions to avoid timing SET_LINENO
+instructions.
+"""
+
+try:
+    import gc
+except ImportError:
+    class _fake_gc:
+        def isenabled(self):
+            return None
+        def enable(self):
+            pass
+        def disable(self):
+            pass
+    gc = _fake_gc()
+import sys
+import time
+try:
+    import itertools
+except ImportError:
+    # Must be an older Python version (see timeit() below)
+    itertools = None
+
+import string
+
+__all__ = ["Timer"]
+
+dummy_src_name = "<timeit-src>"
+default_number = 1000000
+default_repeat = 3
+
+if sys.platform == "win32":
+    # On Windows, the best timer is time.clock()
+    default_timer = time.clock
+else:
+    # On most other platforms the best timer is time.time()
+    default_timer = time.time
+
+# Don't change the indentation of the template; the reindent() calls
+# in Timer.__init__() depend on setup being indented 4 spaces and stmt
+# being indented 8 spaces.
+template = """
+def inner(_it, _timer):
+    %(setup)s
+    _t0 = _timer()
+    for _i in _it:
+        %(stmt)s
+    _t1 = _timer()
+    return _t1 - _t0
+"""
+
+def reindent(src, indent):
+    """Helper to reindent a multi-line statement."""
+    return string.replace(src, "\n", "\n" + " "*indent)
+
+class Timer:
+    """Class for timing execution speed of small code snippets.
+
+    The constructor takes a statement to be timed, an additional
+    statement used for setup, and a timer function.  Both statements
+    default to 'pass'; the timer function is platform-dependent (see
+    module doc string).
+
+    To measure the execution time of the first statement, use the
+    timeit() method.  The repeat() method is a convenience to call
+    timeit() multiple times and return a list of results.
+
+    The statements may contain newlines, as long as they don't contain
+    multi-line string literals.
+    """
+
+    def __init__(self, stmt="pass", setup="pass", timer=default_timer):
+        """Constructor.  See class doc string."""
+        self.timer = timer
+        stmt = reindent(stmt, 8)
+        setup = reindent(setup, 4)
+        src = template % {'stmt': stmt, 'setup': setup}
+        self.src = src # Save for traceback display
+        code = compile(src, dummy_src_name, "exec")
+        ns = {}
+        exec code in globals(), ns
+        self.inner = ns["inner"]
+
+    def print_exc(self, file=None):
+        """Helper to print a traceback from the timed code.
+
+        Typical use:
+
+            t = Timer(...)       # outside the try/except
+            try:
+                t.timeit(...)    # or t.repeat(...)
+            except:
+                t.print_exc()
+
+        The advantage over the standard traceback is that source lines
+        in the compiled template will be displayed.
+
+        The optional file argument directs where the traceback is
+        sent; it defaults to sys.stderr.
+        """
+        import linecache, traceback
+        linecache.cache[dummy_src_name] = (len(self.src),
+                                           None,
+                                           self.src.split("\n"),
+                                           dummy_src_name)
+        traceback.print_exc(file=file)
+
+    def timeit(self, number=default_number):
+        """Time 'number' executions of the main statement.
+
+        To be precise, this executes the setup statement once, and
+        then returns the time it takes to execute the main statement
+        a number of times, as a float measured in seconds.  The
+        argument is the number of times through the loop, defaulting
+        to one million.  The main statement, the setup statement and
+        the timer function to be used are passed to the constructor.
+        """
+        if itertools:
+            it = itertools.repeat(None, number)
+        else:
+            it = [None] * number
+        gcold = gc.isenabled()
+        gc.disable()
+        timing = self.inner(it, self.timer)
+        if gcold:
+            gc.enable()
+        return timing
+
+    def repeat(self, repeat=default_repeat, number=default_number):
+        """Call timeit() a few times.
+
+        This is a convenience function that calls the timeit()
+        repeatedly, returning a list of results.  The first argument
+        specifies how many times to call timeit(), defaulting to 3;
+        the second argument specifies the timer argument, defaulting
+        to one million.
+
+        Note: it's tempting to calculate mean and standard deviation
+        from the result vector and report these.  However, this is not
+        very useful.  In a typical case, the lowest value gives a
+        lower bound for how fast your machine can run the given code
+        snippet; higher values in the result vector are typically not
+        caused by variability in Python's speed, but by other
+        processes interfering with your timing accuracy.  So the min()
+        of the result is probably the only number you should be
+        interested in.  After that, you should look at the entire
+        vector and apply common sense rather than statistics.
+        """
+        r = []
+        for i in range(repeat):
+            t = self.timeit(number)
+            r.append(t)
+        return r
+
+def main(args=None):
+    """Main program, used when run as a script.
+
+    The optional argument specifies the command line to be parsed,
+    defaulting to sys.argv[1:].
+
+    The return value is an exit code to be passed to sys.exit(); it
+    may be None to indicate success.
+
+    When an exception happens during timing, a traceback is printed to
+    stderr and the return value is 1.  Exceptions at other times
+    (including the template compilation) are not caught.
+    """
+    if args is None:
+        args = sys.argv[1:]
+    import getopt
+    try:
+        opts, args = getopt.getopt(args, "n:s:r:tcvh",
+                                   ["number=", "setup=", "repeat=",
+                                    "time", "clock", "verbose", "help"])
+    except getopt.error, err:
+        print err
+        print "use -h/--help for command line help"
+        return 2
+    timer = default_timer
+    stmt = string.join(args, "\n") or "pass"
+    number = 0 # auto-determine
+    setup = []
+    repeat = default_repeat
+    verbose = 0
+    precision = 3
+    for o, a in opts:
+        if o in ("-n", "--number"):
+            number = int(a)
+        if o in ("-s", "--setup"):
+            setup.append(a)
+        if o in ("-r", "--repeat"):
+            repeat = int(a)
+            if repeat <= 0:
+                repeat = 1
+        if o in ("-t", "--time"):
+            timer = time.time
+        if o in ("-c", "--clock"):
+            timer = time.clock
+        if o in ("-v", "--verbose"):
+            if verbose:
+                precision = precision + 1
+            verbose = precision + 1
+        if o in ("-h", "--help"):
+            print __doc__,
+            return 0
+    setup = string.join(setup, "\n") or "pass"
+    # Include the current directory, so that local imports work (sys.path
+    # contains the directory of this script, rather than the current
+    # directory)
+    import os
+    sys.path.insert(0, os.curdir)
+    t = Timer(stmt, setup, timer)
+    if number == 0:
+        # determine number so that 0.2 <= total time < 2.0
+        for i in range(1, 10):
+            number = 10**i
+            try:
+                x = t.timeit(number)
+            except:
+                t.print_exc()
+                return 1
+            if verbose:
+                print "%d loops -> %.*g secs" % (number, precision, x)
+            if x >= 0.2:
+                break
+    try:
+        r = t.repeat(repeat, number)
+    except:
+        t.print_exc()
+        return 1
+    best = min(r)
+    if verbose:
+        print "raw times:", string.join(map(lambda x, p=precision: "%.*g" % (p, x), r))
+    print "%d loops," % number,
+    usec = best * 1e6 / number
+    if usec < 1000:
+        print "best of %d: %.*g usec per loop" % (repeat, precision, usec)
+    else:
+        msec = usec / 1000
+        if msec < 1000:
+            print "best of %d: %.*g msec per loop" % (repeat, precision, msec)
+        else:
+            sec = msec / 1000
+            print "best of %d: %.*g sec per loop" % (repeat, precision, sec)
+    return None
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/bin/install-python.sh b/bin/install-python.sh
new file mode 100644 (file)
index 0000000..699a280
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/sh
+#
+# A script for unpacking and installing different historic versions of
+# Python in a consistent manner for side-by-side development testing.
+#
+# This was written for a Linux system (specifically Ubuntu) but should
+# be reasonably generic to any POSIX-style system with a /usr/local
+# hierarchy.
+
+USAGE="\
+Usage: $0 [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...]
+"
+
+PRINT="echo"
+EXECUTE="eval"
+
+DOWNLOADS=Downloads
+DOWNLOADS_URL=http://www.python.org/ftp/python
+SUDO=sudo
+PREFIX=/usr/local
+
+while getopts "ad:hnq" FLAG; do
+    case ${FLAG} in
+    a )
+        ALL="1"
+        ;;
+    d )
+        DOWNLOADS="${OPTARG}"
+        ;;
+    h )
+        echo "${USAGE}"
+        exit 0
+        ;;
+    n )
+        EXECUTE=":"
+        ;;
+    p )
+        PREFIX="${OPTARG}"
+        ;;
+    q )
+        PRINT=":"
+        ;;
+    * )
+        echo "$0: unknown option ${FLAG}; use -h for help." >&2
+        exit 1
+        ;;
+    esac
+done
+
+shift `expr ${OPTIND} - 1`
+
+VERSIONS="$*"
+
+if test "X${ALL}" != "X"; then
+    if test "${VERSIONS}"; then
+        msg="$0:  -a and version arguments both specified on the command line"
+        echo "${msg}" >&2
+        exit 1
+    fi
+    VERSIONS="
+    1.5.2
+    2.0.1
+    2.1.3
+    2.2
+    2.3.6
+    2.4.4
+    "
+    # 2.5.1
+fi
+
+Command()
+{
+    ${PRINT} "$*"
+    ARGS=`echo "$*" | sed 's/\\$/\\\\$/'`
+    ${EXECUTE} "$*"
+}
+
+for VERSION in $VERSIONS; do
+    PYTHON=Python-${VERSION}
+
+    TAR_GZ=${PYTHON}.tgz
+    if test ! -f ${DOWNLOADS}/${TAR_GZ}; then
+        if test ! -d ${DOWNLOADS}; then
+            Command mkdir ${DOWNLOADS}
+        fi
+        Command "( cd ${DOWNLOADS} && wget ${DOWNLOADS_URL}/${VERSION}/${TAR_GZ} )"
+    fi
+
+    Command tar zxf ${DOWNLOADS}/${TAR_GZ}
+
+    (
+        Command cd ${PYTHON}
+
+        case ${VERSION} in
+        1.5* )
+            CONFIGUREFLAGS="--with-threads"
+            ;;
+        1.6* | 2.0* )
+            # Add the zlib module so we get zipfile compression.
+            Command ed Modules/Setup.in <<EOF
+/^#zlib/s/#//
+w
+q
+EOF
+            CONFIGUREFLAGS="--with-threads"
+            ;;
+        esac
+
+        Command ./configure --prefix=${PREFIX} ${CONFIGUREFLAGS} 2>&1 | tee configure.out
+        Command make 2>&1 | tee make.out
+        Command ${SUDO} make install
+
+        Command ${SUDO} rm -f ${PREFIX}/bin/{idle,pydoc,python,python-config,smtpd.py}
+
+        ${PRINT} cd ..
+    )
+
+    Command rm -rf ${Python}
+done
diff --git a/bin/install-scons.sh b/bin/install-scons.sh
new file mode 100644 (file)
index 0000000..50c1cce
--- /dev/null
@@ -0,0 +1,176 @@
+#!/bin/sh
+#
+# A script for unpacking and installing different historic versions of
+# SCons in a consistent manner for side-by-side development testing.
+#
+# This abstracts the changes we've made to the SCons setup.py scripts in
+# different versions so that, no matter what version is specified, it ends
+# up install the necessary script(s) and library into version-specific
+# names that won't interfere with other things.
+#
+# We expect to extract the .tar.gz files from a Downloads subdirectory
+# in the current directory.
+#
+# Note that this script cleans up after itself, removing the extracted
+# directory in which we do the build.
+#
+# This was written for a Linux system (specifically Ubuntu) but should
+# be reasonably generic to any POSIX-style system with a /usr/local
+# hierarchy.
+
+USAGE="\
+Usage: $0 [-ahnq] [-d DIR] [-p PREFIX] [VERSION ...]
+"
+
+PRINT="echo"
+EXECUTE="eval"
+
+DOWNLOADS=Downloads
+DOWNLOADS_URL=http://downloads.sourceforge.net/scons
+SUDO=sudo
+PREFIX=/usr/local
+
+while getopts "ad:hnq" FLAG; do
+    case ${FLAG} in
+    a )
+        ALL="1"
+        ;;
+    d )
+        DOWNLOADS="${OPTARG}"
+        ;;
+    h )
+        echo "${USAGE}"
+        exit 0
+        ;;
+    n )
+        EXECUTE=":"
+        ;;
+    p )
+        PREFIX="${OPTARG}"
+        ;;
+    q )
+        PRINT=":"
+        ;;
+    * )
+        echo "$0: unknown option ${FLAG}; use -h for help." >&2
+        exit 1
+        ;;
+    esac
+done
+
+shift `expr ${OPTIND} - 1`
+
+VERSIONS="$*"
+
+if test "X${ALL}" != "X"; then
+    if test "${VERSIONS}"; then
+        msg="$0:  -a and version arguments both specified on the command line"
+        echo "${msg}" >&2
+        exit 1
+    fi
+    VERSIONS="
+    0.01
+    0.02
+    0.03
+    0.04
+    0.05
+    0.06
+    0.07
+    0.08
+    0.09
+    0.10
+    0.11
+    0.12
+    0.13
+    0.14
+    0.90
+    0.91
+    0.92
+    0.93
+    0.94
+    0.94.1
+    0.95
+    0.95.1
+    0.96
+    0.96.1
+    0.96.90
+    0.96.91
+    0.96.92
+    0.96.93
+    0.96.94
+    0.96.95
+    0.96.96
+    0.97
+    0.97.0d20070809
+    0.97.0d20070918
+    0.97.0d20071212
+    "
+fi
+
+Command()
+{
+    ${PRINT} "$*"
+    ARGS=`echo "$*" | sed 's/\\$/\\\\$/'`
+    ${EXECUTE} "$*"
+}
+
+for VERSION in $VERSIONS; do
+    SCONS=scons-${VERSION}
+
+    TAR_GZ=${SCONS}.tar.gz
+    if test ! -f ${DOWNLOADS}/${TAR_GZ}; then
+        if test ! -d ${DOWNLOADS}; then
+            Command mkdir ${DOWNLOADS}
+        fi
+        Command "( cd ${DOWNLOADS} && wget ${DOWNLOADS_URL}/${TAR_GZ} )"
+    fi
+
+    Command tar zxf ${DOWNLOADS}/${TAR_GZ}
+
+    (
+        Command cd ${SCONS}
+
+        case ${VERSION} in
+        0.0[123456789] | 0.10 )
+            # 0.01 through 0.10 install /usr/local/bin/scons and
+            # /usr/local/lib/scons.  The "scons" script knows how to
+            # look up the library in a version-specific directory, but
+            # we have to move both it and the library directory into
+            # the right version-specific name by hand.
+            Command python setup.py build
+            Command ${SUDO} python setup.py install --prefix=${PREFIX}
+            Command ${SUDO} mv ${PREFIX}/bin/scons ${PREFIX}/bin/scons-${VERSION}
+            Command ${SUDO} mv ${PREFIX}/lib/scons ${PREFIX}/lib/scons-${VERSION}
+            ;;
+        0.1[1234] | 0.90 )
+            # 0.11 through 0.90 install /usr/local/bin/scons and
+            # /usr/local/lib/scons-${VERSION}.  We just need to move
+            # the script to a version-specific name.
+            Command python setup.py build
+            Command ${SUDO} python setup.py install --prefix=${PREFIX}
+            Command ${SUDO} mv ${PREFIX}/bin/scons ${PREFIX}/bin/scons-${VERSION}
+            ;;
+        0.9[123456] | 0.9[456].1 | 0.96.90 )
+            # 0.91 through 0.96.90 install /usr/local/bin/scons,
+            # /usr/local/bin/sconsign and /usr/local/lib/scons-${VERSION}.
+            # We need to move both scripts to version-specific names.
+            Command python setup.py build
+            Command ${SUDO} python setup.py install --prefix=${PREFIX}
+            Command ${SUDO} mv ${PREFIX}/bin/scons ${PREFIX}/bin/scons-${VERSION}
+            Command ${SUDO} mv ${PREFIX}/bin/sconsign ${PREFIX}/bin/sconsign-${VERSION}
+            if test -d ${PREFIX}/lib/scons; then
+                Command ${SUDO} mv ${PREFIX}/lib/scons ${PREFIX}/lib/scons-${VERSION}
+            fi
+            ;;
+        * )
+            # Versions from 0.96.91 and later (through at least 0.97)
+            # support what we want with a --no-scons-script option.
+            Command python setup.py build
+            Command ${SUDO} python setup.py install --prefix=${PREFIX} --no-scons-script
+            ;;
+        esac
+
+        ${PRINT} cd ..
+    )
+    Command rm -rf ${SCONS}
+done
diff --git a/bin/scons-review.sh b/bin/scons-review.sh
new file mode 100755 (executable)
index 0000000..f126333
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+case "$1" in
+'')    exec svn diff --diff-cmd diff -x -c $* ;;
+-m)    svn diff --diff-cmd diff -x -c $* | alpine scons-dev ;;
+*)     echo "Error: unknown option '$1"; exit 1 ;;
+esac
+
+# OLD CODE FOR USE WITH AEGIS
+#
+#if test $# -ne 1; then
+#    echo "Usage:  scons-review change#" >&2
+#    exit 1
+#fi
+#if test "X$AEGIS_PROJECT" = "X"; then
+#    echo "scons-review:  AEGIS_PROJECT is not set" >&2
+#    exit 1
+#fi
+#DIR=`aegis -cd -dd $*`
+#if test "X${DIR}" = "X"; then
+#    echo "scons-review:  No Aegis directory for '$*'" >&2
+#    exit 1
+#fi
+#(cd ${DIR} && find * -name '*,D' | sort | xargs cat) | pine scons-dev
index 1620bf3e662686689c5eabe44473c815dfdd586e..441d471552975bd26dfd307ba84933e7722c7135 100644 (file)
@@ -81,6 +81,9 @@ local SConstruct file.
 """
 
 bootstrap_dir = 'bootstrap'
+script_dir = os.path.split(__file__)[0]
+if script_dir:
+    bootstrap_dir = os.path.join(script_dir, bootstrap_dir)
 pass_through_args = []
 update_only = None
 
index 8e13294b068e3371363d3269682bdc0ee7d83113..0c8f070d51b546dab881270ea00e1a450d28c21f 100644 (file)
@@ -33,8 +33,6 @@ Import('build_dir', 'env', 'whereis')
 
 env = env.Clone()
 
-env.TargetSignatures('content')
-
 build = os.path.join(build_dir, 'doc')
 
 #
@@ -123,7 +121,9 @@ manifest_xml_in = File('#src/engine/MANIFEST-xml.in').rstr()
 scons_doc_files = map(chop, open(manifest_xml_in).readlines())
 scons_doc_files = map(lambda x: File('#src/engine/'+x).rstr(), scons_doc_files)
 
-if jw:
+if not jw:
+    print "jw not found, skipping building User Guide."
+else:
     #
     # Always create a version.xml file containing the version information
     # for this run.  Ignore it for dependency purposes so we don't
@@ -461,7 +461,9 @@ for man_1 in man_page_list:
         tar_deps.append(html)
         tar_list.append(html)
 
-if epydoc:
+if not epydoc:
+    print "epydoc not found, skipping building API documentation."
+else:
     # XXX Should be in common with reading the same thing in
     # the SConstruct file.
     e = os.path.join('#src', 'engine')
@@ -520,6 +522,7 @@ if tar_deps:
                            tar_list))
     t = env.Command(dist_doc_tar_gz, tar_deps,
                 "tar cf${TAR_HFLAG} - -C %s %s | gzip > $TARGET" % (build, tar_list))
+    AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0644))
     Local(t)
     Alias('doc', t)
 else:
index ae252747750daea8ede20a1d32429561484b9b79..98e12e612f279f6be1d75c5a26a0960da25b023d 100644 (file)
@@ -980,6 +980,7 @@ are synonyms.
 Prints SCons version information.
 .RE
 
+.IP
 An empty line repeats the last typed command.
 Command-line editing can be used if the
 .B readline
@@ -1328,8 +1329,30 @@ These warnings are disabled by default.
 
 .TP
 --warn=deprecated, --warn=no-deprecated
-Enables or disables warnings about use of deprecated features.
+Enables or disables all warnings about use of deprecated features.
 These warnings are enabled by default.
+Warnings for some specific deprecated features
+may be enabled or disabled individually;
+see below.
+
+--warn=deprecated-copy, --warn=no-deprecated-copy
+Enables or disables warnings about use of the deprecated
+.B env.Copy()
+method.
+
+--warn=deprecated-source-signatures, --warn=no-deprecated-source-signatures
+Enables or disables warnings about use of the deprecated
+SourceSignatures() function
+or
+.B env.SourceSignatures()
+method.
+
+--warn=deprecated-target-signatures, --warn=no-deprecated-target-signatures
+Enables or disables warnings about use of the deprecated
+TargetSignatures() function
+or
+.B env.TargetSignatures()
+method.
 
 .TP
 --warn=duplicate-environment, --warn=no-duplicate-environment
@@ -1371,6 +1394,16 @@ not supporting metaclasses when the
 option is used.
 These warnings are enabled by default.
 
+.TP
+--warn=no-object-count, --warn=no-no-object-count
+Enables or disables warnings about the
+.B --debug=object
+feature not working when
+.B scons
+is run with the python
+.B \-O
+option or from optimized Python (.pyo) modules.
+
 .TP
 --warn=no-parallel-support, --warn=no-no-parallel-support
 Enables or disables warnings about the version of Python
@@ -1379,6 +1412,12 @@ not being able to support parallel builds when the
 option is used.
 These warnings are enabled by default.
 
+.TP
+--warn=python-version, --warn=no-python-version
+Enables or disables the warning about running
+SCons with a deprecated version of Python.
+These warnings are enabled by default.
+
 .TP
 --warn=reserved-variable, --warn=no-reserved-variable
 Enables or disables warnings about attempts to set the
@@ -1441,6 +1480,40 @@ function:
 env = Environment()
 .EE
 
+Variables, called
+.I construction
+.IR variables ,
+may be set in a construction environment
+either by specifyng them as keywords when the object is created
+or by assigning them a value after the object is created:
+
+.ES
+env = Environment(FOO = 'foo')
+env['BAR'] = 'bar'
+.EE
+
+As a convenience,
+construction variables may also be set or modified by the
+.I parse_flags
+keyword argument, which applies the
+.B ParseFlags
+method (described below) to the argument value
+after all other processing is completed.
+This is useful either if the exact content of the flags is unknown
+(for example, read from a control file)
+or if the flags are distributed to a number of construction variables.
+
+.ES
+env = Environment(parse_flags = '-Iinclude -DEBUG -lm')
+.EE
+
+This example adds 'include' to
+.BR CPPPATH ,
+\'EBUG' to
+.BR CPPDEFINES ,
+and 'm' to
+.BR LIBS .
+
 By default, a new construction environment is
 initialized with a set of builder methods
 and construction variables that are appropriate
@@ -1846,6 +1919,21 @@ if you want SCons to search automatically
 for dependencies on the non-standard library names;
 see the descriptions of these variables, below, for more information.)
 
+It is also possible to use the
+.I parse_flags
+keyword argument in an override:
+
+.ES
+env = Program('hello', 'hello.c', parse_flags = '-Iinclude -DEBUG -lm')
+.EE
+
+This example adds 'include' to
+.BR CPPPATH ,
+\'EBUG' to
+.BR CPPDEFINES ,
+and 'm' to
+.BR LIBS .
+
 Although the builder methods defined by
 .B scons
 are, in fact,
@@ -2168,11 +2256,14 @@ calling the functionality through a construction environment will
 substitute construction variables into
 any supplied strings.
 For example:
+
 .ES
 env = Environment(FOO = 'foo')
 Default('$FOO')
 env.Default('$FOO')
 .EE
+
+In the above example,
 the first call to the global
 .B Default()
 function will actually add a target named
@@ -2604,97 +2695,19 @@ env.SourceCode('.', env.BitKeeper())
 .RI BuildDir( build_dir ", " src_dir ", [" duplicate ])
 .TP
 .RI env.BuildDir( build_dir ", " src_dir ", [" duplicate ])
-This specifies a build directory
-.I build_dir
-in which to build all derived files
-that would normally be built under
-.IR src_dir .
-Multiple build directories can be set up for multiple build variants, for
-example. 
-.I src_dir
-must be underneath the SConstruct file's directory,
+Synonyms for
+.B VariantDir()
 and
+.BR env.VariantDir() .
+The
 .I build_dir
-may not be underneath the
-.I src_dir .
-
-The default behavior is for
-.B scons
-to duplicate all of the files in the tree underneath
-.I src_dir
-into
-.IR build_dir ,
-and then build the derived files within the copied tree.
-(The duplication is performed by
-linking or copying,
-depending on the platform; see also the
-.IR --duplicate
-option.)
-This guarantees correct builds
-regardless of whether intermediate source files
-are generated during the build,
-where preprocessors or other scanners search
-for included files,
-or whether individual compilers or other invoked tools
-are hard-coded to put derived files in the same directory as source files.
-
-This behavior of making a complete copy of the source tree
-may be disabled by setting
-.I duplicate
-to 0.
-This will cause
-.B scons
-to invoke Builders using the
-path names of source files in
-.I src_dir
-and the path names of derived files within
-.IR build_dir .
-This is always more efficient than
-.IR duplicate =1,
-and is usually safe for most builds.
-Specifying
-.IR duplicate =0,
-however,
-may cause build problems
-if source files are generated during the build,
-if any invoked tools are hard-coded to
-put derived files in the same directory as the source files.
-
-Note that specifying a
-.B BuildDir
-works most naturally
-with a subsidiary SConscript file
-in the source directory.
-However,
-you would then call the subsidiary SConscript file
-not in the source directory,
-but in the
-.I build_dir ,
-as if
-.B scons
-had made a virtual copy of the source tree
-regardless of the value of 
-.IR duplicate .
-This is how you tell
-.B scons
-which variant of a source tree to build.
-For example:
-
-.ES
-BuildDir('build-variant1', 'src')
-SConscript('build-variant1/SConscript')
-BuildDir('build-variant2', 'src')
-SConscript('build-variant2/SConscript')
-.EE
-
-.IP
-See also the
-.BR SConscript ()
-function, described below,
-for another way to 
-specify a build directory
-in conjunction with calling a subsidiary
-SConscript file.)
+argument bedomes the
+.I variant_dir
+argument of
+.B VariantDir()
+or
+.BR env.VariantDir() .
+(This will be officially deprecated some day.)
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP 
@@ -3005,12 +3018,20 @@ def MyTool(env): env['FOO'] = 'bar'
 env4 = env.Clone(tools = ['msvc', MyTool])
 .EE
 
+The
+.I parse_flags
+keyword argument is also recognized:
+
+.ES
+# create an environment for compiling programs that use wxWidgets
+wx_env = env.Clone(parse_flags = '!wx-config --cflags --cxxflags')
+.EE
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
 .RI env.Copy([ key = val ", ...])"
-A synonym for
+A now-deprecated synonym for
 .BR env.Clone() .
-(This will probably be officially deprecated some day.)
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
@@ -3133,6 +3154,7 @@ and runs the build again,
 all within a single second.
 .RE
 
+.IP
 Examples:
 
 .ES
@@ -3144,12 +3166,14 @@ Decider('timestamp-match')
 env.Decider('content')
 .EE
 
+.IP
 In addition to the above already-available functions,
 the
 .I function
 argument may be an actual Python function
 that takes the following three arguments:
 
+.RS 10
 .IP dependency
 The Node (file) which
 should cause the
@@ -3176,7 +3200,9 @@ This can be consulted to match various
 file characteristics
 such as the timestamp,
 size, or content signature.
+.RE
 
+.IP
 The
 .I function
 should return a
@@ -3322,6 +3348,12 @@ If no
 .I directory
 is specified, the current script's directory is used as the parent.
 
+If 
+.I name
+is a list, SCons returns a list of Dir nodes.
+Construction variables are expanded in
+.IR name .
+
 Directory Nodes can be used anywhere you
 would supply a string as a directory name
 to a Builder method or function.
@@ -3514,6 +3546,12 @@ can be a relative or absolute path.
 .I directory
 is an optional directory that will be used as the parent directory. 
 
+If 
+.I name
+is a list, SCons returns a list of File nodes.
+Construction variables are expanded in
+.IR name .
+
 File Nodes can be used anywhere you
 would supply a string as a file name
 to a Builder method or function.
@@ -3602,6 +3640,7 @@ FindSourceFiles()
 FindSourceFiles( 'src' )
 .EE
 
+.IP
 As you can see build support files (SConstruct in the above example)
 will also be returned by this function.
 
@@ -3632,7 +3671,7 @@ for the following reasons:
 1) The returned list will contain all appropriate directories
 found in source trees
 (when
-.BR BuildDir ()
+.BR VariantDir ()
 is used)
 or in code repositories
 (when
@@ -3841,12 +3880,113 @@ file is found.
 .RI GetOption( name )
 .TP
 .RI env.GetOption( name )
-This function provides a way to query a select subset of the scons command line
-options from a SConscript file. See 
+This function provides a way to query the value of
+SCons options set on scons command line
+(or set using the
 .IR SetOption () 
-for a description of the options available.
+function).
+The options supported are:
 
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.RS 10
+.TP 6
+.B cache_debug
+.TP 6
+which corresponds to --cache_debug;
+.TP 6
+.B cache_disable
+which corresponds to --cache_disable;
+.TP 6
+.B cache_force
+which corresponds to --cache_force;
+.TP 6
+.B cache_show
+which corresponds to --cache_show;
+.TP 6
+.B clean
+which corresponds to -c, --clean and --remove;
+.TP 6
+.B config
+which corresponds to --config;
+.TP 6
+.B directory
+which corresponds to -C and --directory;
+.TP 6
+.B diskcheck
+which corresponds to --diskcheck
+.TP 6
+.B duplicate
+which corresponds to --duplicate;
+.TP 6
+.B file
+which corresponds to -f, --file, --makefile and --sconstruct;
+.TP 6
+.B help
+which corresponds to -h and --help;
+.TP 6
+.B ignore_errors
+which corresponds to --ignore-errors;
+.TP 6
+.B implicit_cache
+which corresponds to --implicit-cache;
+.TP 6
+.B implicit_deps_changed
+which corresponds to --implicit-deps-changed;
+.TP 6
+.B implicit_deps_unchanged
+which corresponds to --implicit-deps-unchanged;
+.TP 6
+.B interactive
+which corresponds to --interact and --interactive;
+.TP 6
+.B keep_going
+which corresponds to -k and --keep-going;
+.TP 6
+.B max_drift
+which corresponds to --max-drift;
+.TP 6
+.B no_exec
+which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
+.TP 6
+.B no_site_dir
+which corresponds to --no-site-dir;
+.TP 6
+.B num_jobs
+which corresponds to -j and --jobs;
+.TP 6
+.B profile_file
+which corresponds to --profile;
+.TP 6
+.B question
+which corresponds to -q and --question;
+.TP 6
+.B random
+which corresponds to --random;
+.TP 6
+.B repository
+which corresponds to -Y, --repository and --srcdir;
+.TP 6
+.B silent
+which corresponds to -s, --silent and --quiet;
+.TP 6
+.B site_dir
+which corresponds to --site-dir;
+.TP 6
+.B stack_size
+which corresponds to --stack-size;
+.TP 6
+.B taskmastertrace_file
+which corresponds to --taskmastertrace; and
+.TP 6
+.B warn
+which corresponds to --warn and --warning.
+.RE
+
+.IP
+See the documentation for the
+corresponding command line object for information about each specific
+option.
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
 .RI Glob( pattern ", [" ondisk ", " source ", " strings ])
 .TP
@@ -3874,6 +4014,7 @@ uses Unix shell style metacharacters for matching:
   [!seq]  matches any char not in seq
 .EE
 
+.IP
 Character matches do
 .I not
 span directory separators.
@@ -3887,7 +4028,7 @@ repositories
 function)
 and source directories
 (see the
-.BR BuildDir ()
+.BR VariantDir ()
 function)
 and
 returns a Node (or string, if so configured)
@@ -3915,7 +4056,7 @@ argument may be set to
 (or any equivalent value)
 to specify that,
 when the local directory is a
-.BR BuildDir (),
+.BR VariantDir (),
 the returned Nodes should be from the
 corresponding source directory,
 not the local directory.
@@ -4100,6 +4241,8 @@ env.MergeFlags('-O3')
 # flag and merge the result into the construction variables.
 env.MergeFlags(['!pkg-config gtk+-2.0 --cflags', '-O3'])
 
+# Combine an optimization flag with the flags returned from running pkg-config
+# twice and merge the result into the construction variables.
 env.MergeFlags(['-O3',
                '!pkg-config gtk+-2.0 --cflags --libs',
                '!pkg-config libpng12 --cflags --libs'])
@@ -4830,13 +4973,13 @@ for a specific subdirectory.
 
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
-.RI SConscript( scripts ", [" exports ", " build_dir ", " src_dir ", " duplicate ])
+.RI SConscript( scripts ", [" exports ", " variant_dir ", " src_dir ", " duplicate ])
 .TP
-.RI env.SConscript( scripts ", [" exports ", " build_dir ", " src_dir ", " duplicate ])
+.RI env.SConscript( scripts ", [" exports ", " variant_dir ", " src_dir ", " duplicate ])
 .TP
-.RI SConscript(dirs= subdirs ", [name=" script ", " exports ", " build_dir ", " src_dir ", " duplicate ])
+.RI SConscript(dirs= subdirs ", [name=" script ", " exports ", " variant_dir ", " src_dir ", " duplicate ])
 .TP
-.RI env.SConscript(dirs= subdirs ", [name=" script ", " exports ", " build_dir ", " src_dir ", " duplicate ])
+.RI env.SConscript(dirs= subdirs ", [name=" script ", " exports ", " variant_dir ", " src_dir ", " duplicate ])
 This tells
 .B scons
 to execute
@@ -4895,15 +5038,15 @@ must use the
 function to import the variables.
 
 The optional
-.I build_dir
+.I variant_dir
 argument specifies that all of the target files
 (for example, object files and executables)
 that would normally be built in the subdirectory in which
 .I script
 resides should actually
 be built in
-.IR build_dir .
-.I build_dir
+.IR variant_dir .
+.I variant_dir
 is interpreted relative to the directory
 of the calling SConscript file.
 
@@ -4921,7 +5064,7 @@ of the calling SConscript file.
 By default,
 .B scons
 will link or copy (depending on the platform)
-all the source files into the build directory.
+all the source files into the variant directory tree.
 This behavior may be disabled by
 setting the optional
 .I duplicate
@@ -4954,7 +5097,7 @@ Examples:
 SConscript('subdir/SConscript')
 foo = SConscript('sub/SConscript', exports='env')
 SConscript('dir/SConscript', exports=['env', 'variable'])
-SConscript('src/SConscript', build_dir='build', duplicate=0)
+SConscript('src/SConscript', variant_dir='build', duplicate=0)
 SConscript('bld/SConscript', src_dir='src', exports='env variable')
 SConscript(dirs=['sub1', 'sub2'])
 SConscript(dirs=['sub3', 'sub4'], name='MySConscript')
@@ -5090,24 +5233,38 @@ if not env.has_key('FOO'): env['FOO'] = 'foo'
 .RI env.SetOption( name ", " value )
 This function provides a way to set a select subset of the scons command
 line options from a SConscript file. The options supported are:
+
+.RS 10
+.TP 6
 .B clean
 which corresponds to -c, --clean and --remove;
+.TP 6
 .B duplicate
 which corresponds to --duplicate;
+.TP 6
 .B help
 which corresponds to -h and --help;
+.TP 6
 .B implicit_cache
 which corresponds to --implicit-cache;
+.TP 6
 .B max_drift
 which corresponds to --max-drift;
+.TP 6
 .B no_exec
 which corresponds to -n, --no-exec, --just-print, --dry-run and --recon;
+.TP 6
 .B num_jobs
 which corresponds to -j and --jobs;
+.TP 6
 .B random
 which corresponds to --random; and
+.TP 6
 .B stack_size
 which corresponds to --stack-size.
+.RE
+
+.IP
 See the documentation for the
 corresponding command line object for information about each specific
 option.
@@ -5731,6 +5888,103 @@ env['BUILDERS']['UpdateValue'] = Builder(action = build_value)
 env.UpdateValue(target = Value(output), source = Value(input))
 .EE
 
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.RI VariantDir( variant_dir ", " src_dir ", [" duplicate ])
+.TP
+.RI env.VariantDir( variant_dir ", " src_dir ", [" duplicate ])
+This specifies a variant directory tree
+.I variant_dir
+in which to build all derived files
+that would normally be built under
+.IR src_dir .
+Multiple directory trees
+can be set up for multiple build variants.
+.I src_dir
+must be underneath the SConstruct file's directory,
+and
+.I variant_dir
+may not be underneath the
+.I src_dir .
+
+The default behavior is for
+.B scons
+to duplicate all of the files in the tree underneath
+.I src_dir
+into
+.IR variant_dir ,
+and then build the derived files within the copied tree.
+(The duplication is performed by
+linking or copying,
+depending on the platform; see also the
+.IR --duplicate
+option.)
+This guarantees correct builds
+regardless of whether intermediate source files
+are generated during the build,
+where preprocessors or other scanners search
+for included files,
+or whether individual compilers or other invoked tools
+are hard-coded to put derived files in the same directory as source files.
+
+This behavior of making a complete copy of the source tree
+may be disabled by setting
+.I duplicate
+to 0.
+This will cause
+.B scons
+to invoke Builders using the
+path names of source files in
+.I src_dir
+and the path names of derived files within
+.IR variant_dir .
+This is always more efficient than
+.IR duplicate =1,
+and is usually safe for most builds.
+Specifying
+.IR duplicate =0,
+however,
+may cause build problems
+if source files are generated during the build,
+or if any invoked tools are hard-coded to
+put derived files in the same directory as the source files.
+
+Note that specifying a
+.B VariantDir
+works most naturally
+with a subsidiary SConscript file
+in the source directory.
+However,
+you would then call the subsidiary SConscript file
+not in the source directory,
+but in the
+.I variant_dir ,
+as if
+.B scons
+had made a virtual copy of the source tree
+regardless of the value of 
+.IR duplicate .
+This is how you tell
+.B scons
+which variant of a source tree to build.
+For example:
+
+.ES
+VariantDir('build-variant1', 'src')
+SConscript('build-variant1/SConscript')
+VariantDir('build-variant2', 'src')
+SConscript('build-variant2/SConscript')
+.EE
+
+.IP
+See also the
+.BR SConscript ()
+function, described below,
+for another way to 
+specify a variant directory
+in conjunction with calling a subsidiary
+SConscript file.)
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
 .RI WhereIs( program ", [" path  ", " pathext ", " reject ])
@@ -6086,9 +6340,9 @@ specifies a file which collects the output from commands
 that are executed to check for the existence of header files, libraries, etc.
 The default is the file #/config.log.
 If you are using the
-.B BuildDir
+.B VariantDir
 method,
-you may want to specify a subdirectory under your build directory.
+you may want to specify a subdirectory under your variant directory.
 .I config_h
 specifies a C header file where the results of tests 
 will be written, e.g. #define HAVE_STDIO_H, #define HAVE_LIBM, etc. 
@@ -7116,7 +7370,7 @@ This path is relative to the top-level directory
 .B SConstruct
 file is found).
 The build path is the same as the source path if
-.I build_dir
+.I variant_dir
 is not being used.
 
 .IP abspath
@@ -7152,6 +7406,95 @@ foo = env.Program('foo.c')
 print "foo will be built in %s"%foo.path
 .EE
 
+A
+.I Dir
+Node or
+.I File
+Node can also be used to create
+file and subdirectory Nodes relative to the generating Node.
+A
+.I Dir
+Node will place the new Nodes within the directory it represents.
+A
+.I File
+node will place the new Nodes within its parent directory
+(that is, "beside" the file in question).
+If
+.I d
+is a
+.I Dir
+(directory) Node and
+.I f
+is a
+.I File
+(file) Node,
+then these methods are available:
+
+.TP
+.IR d .Dir( name )
+Returns a directory Node for a subdirectory of
+.I d
+named
+.IR name .
+
+.TP
+.IR d .File( name )
+Returns a file Node for a file within
+.I d
+named
+.IR name .
+
+.TP
+.IR d .Entry( name )
+Returns an unresolved Node within
+.I d
+named
+.IR name .
+
+.TP
+.IR f .Dir( name )
+Returns a directory named
+.I name
+within the parent directory of
+.IR f .
+
+.TP
+.IR f .File( name )
+Returns a file named
+.I name
+within the parent directory of
+.IR f .
+
+.TP
+.IR f .Entry( name )
+Returns an unresolved Node named
+.I name
+within the parent directory of
+.IR f .
+
+.RE
+For example:
+
+.ES
+# Get a Node for a file within a directory
+incl = Dir('include')
+f = incl.File('header.h')
+
+# Get a Node for a subdirectory within a directory
+dist = Dir('project-3.2.1)
+src = dist.Dir('src')
+
+# Get a Node for a file in the same directory
+cfile = File('sample.c')
+hfile = cfile.File('sample.h')
+
+# Combined example
+docs = Dir('docs')
+html = docs.Dir('html')
+index = html.File('index.html')
+css = index.File('app.css')
+.EE
+
 .SH EXTENDING SCONS
 .SS Builder Objects
 .B scons
@@ -8245,24 +8588,24 @@ when a path references a file on other (POSIX) systems.
 
 .IP srcpath
 The directory and file name to the source file linked to this file
-through BuildDir.  If this file isn't linked, it just returns the
+through VariantDir.  If this file isn't linked, it just returns the
 directory and filename unchanged.
 
 .IP srcdir
 The directory containing the source file linked to this file
-through BuildDir.  If this file isn't linked, it just returns the
+through VariantDir.  If this file isn't linked, it just returns the
 directory part of the filename.
 
 .IP rsrcpath
 The directory and file name to the source file linked to this file
-through BuildDir.  If the file does not exist locally but exists in
+through VariantDir.  If the file does not exist locally but exists in
 a Repository, the path in the Repository is returned.
 If this file isn't linked, it just returns the
 directory and filename unchanged.
 
 .IP rsrcdir
 The Repository directory containing the source file linked to this file
-through BuildDir.  If this file isn't linked, it just returns the
+through VariantDir.  If this file isn't linked, it just returns the
 directory part of the filename.
 
 .LP
@@ -8278,7 +8621,7 @@ ${TARGET.filebase}   => file
 ${TARGET.suffix}     => .x
 ${TARGET.abspath}    => /top/dir/sub/dir/file.x
 
-SConscript('src/SConscript', build_dir='sub/dir')
+SConscript('src/SConscript', variant_dir='sub/dir')
 $SOURCE              => sub/dir/file.x
 ${SOURCE.srcpath}    => src/file.x
 ${SOURCE.srcdir}     => src
@@ -9046,21 +9389,21 @@ subdirectory/SConscript:
 
 .SS Building Multiple Variants From the Same Source
 
-Use the build_dir keyword argument to
+Use the variant_dir keyword argument to
 the SConscript function to establish
-one or more separate build directories for
-a given source directory:
+one or more separate variant build directory trees
+for a given source directory:
 
 .ES
 SConstruct:
 
     cppdefines = ['FOO']
     Export("cppdefines")
-    SConscript('src/SConscript', build_dir='foo')
+    SConscript('src/SConscript', variant_dir='foo')
 
     cppdefines = ['BAR']
     Export("cppdefines")
-    SConscript('src/SConscript', build_dir='bar')
+    SConscript('src/SConscript', variant_dir='bar')
 
 src/SConscript:
 
index e590368df7c0a7d4d447adc83703657ca432c26c..739be581bf07d5b9ce3b04d79c24f810b3582110 100644 (file)
 <!ENTITY exports "<varname>exports</varname>">
 <!ENTITY source "<varname>source</varname>">
 <!ENTITY target "<varname>target</varname>">
+<!ENTITY variant_dir "<varname>variant_dir</varname>">
 
 
 
 <!ENTITY StaticLibrary "<function>StaticLibrary</function>">
 <!ENTITY StaticObject "<function>StaticObject</function>">
 <!ENTITY Tar "<function>Tar</function>">
+<!ENTITY VariantDir "<function>VariantDir</function>">
 <!ENTITY Zip "<function>Zip</function>">
 
 <!-- Obsolete, but referenced in old documents.  -->
index 18769168e4f0bc80bb6fcd79b7180590ae50b5fe..402d037fbd5e840f4958212eb28b2c251a0a0944 100644 (file)
       % <userinput>scons -Q</userinput>
       javac -d classes -sourcepath prog1 prog1/Example1.java prog1/Example2.java
       javac -d classes -sourcepath prog2 prog2/Example3.java prog2/Example4.java
-      jar cf prog1.jar classes/Example1.class classes/Example2.class
-      jar cf prog2.jar classes/Example3.class classes/Example4.class
+      jar cf prog1.jar -C classes Example1.class -C classes Example2.class
+      jar cf prog2.jar -C classes Example3.class -C classes Example4.class
     </screen>
 
   </section>
index 08bb986a03c10fc9fd9e9dba53be5c5565be9741..be7e6c5def8b6a2f717e230a76062d9c650834e7 100644 (file)
@@ -114,34 +114,46 @@ program using the F<build/foo.c> path name.
 
   It's often useful to keep any built files completely
   separate from the source files.
-  This is usually done by creating one or more separate
-  <emphasis>build directories</emphasis>
+  In &SCons;, this is usually done by creating one or more separate
+  <emphasis>variant directory trees</emphasis>
   that are used to hold the built objects files, libraries,
   and executable programs, etc.
-  for a specific flavor of build.
+  for a specific flavor, or variant, of build.
   &SCons; provides two ways to do this,
   one through the &SConscript; function that we've already seen,
-  and the second through a more flexible &BuildDir; function.
+  and the second through a more flexible &VariantDir; function.
+
+  </para>
+
+  <para>
+
+  One historical note:  the &VariantDir; function
+  used to be called &BuildDir;.
+  That name is still supported
+  but has been deprecated
+  because the &SCons; functionality
+  differs from the model of a "build directory"
+  implemented by other build systems like the GNU Autotools.
 
   </para>
 
   <section>
-  <title>Specifying a Build Directory as Part of an &SConscript; Call</title>
+  <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title>
 
     <para>
 
-    The most straightforward way to establish a build directory
+    The most straightforward way to establish a variant directory tree
     uses the fact that the usual way to
     set up a build hierarchy is to have an
     &SConscript; file in the source subdirectory.
-    If you then pass a &build_dir; argument to the
+    If you then pass a &variant_dir; argument to the
     &SConscript; function call:
 
     </para>
 
     <scons_example name="ex1">
       <file name="SConstruct" printme="1">
-      SConscript('src/SConscript', build_dir='build')
+      SConscript('src/SConscript', variant_dir='build')
       </file>
       <file name="src/SConscript">
       env = Environment()
@@ -192,11 +204,11 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>Why &SCons; Duplicates Source Files in a Build Directory</title>
+  <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title>
 
     <para>
 
-    &SCons; duplicates source files in build directories
+    &SCons; duplicates source files in variant directory trees
     because it's the most straightforward way to guarantee a correct build
     <emphasis>regardless of include-file directory paths,
     relative references between files,
@@ -209,14 +221,14 @@ program using the F<build/foo.c> path name.
     <para>
 
     The most direct reason to duplicate source files
-    in build directories
+    in variant directories
     is simply that some tools (mostly older vesions)
     are written to only build their output files
     in the same directory as the source files.
     In this case, the choices are either
     to build the output file in the source directory
-    and move it to the build directory,
-    or to duplicate the source files in the build directory.
+    and move it to the variant directory,
+    or to duplicate the source files in the variant directory.
 
     </para>
 
@@ -226,7 +238,7 @@ program using the F<build/foo.c> path name.
     relative references between files
     can cause problems if we don't
     just duplicate the hierarchy of source files
-    in the build directory.
+    in the variant directory.
     You can see this at work in
     use of the C preprocessor <literal>#include</literal>
     mechanism with double quotes, not angle brackets:
@@ -251,7 +263,7 @@ program using the F<build/foo.c> path name.
     will be found in the same directory hierarchy,
     and the simplest way to make sure
     that the right include file is found
-    is to duplicate the source files into the build directory,
+    is to duplicate the source files into the variant directory,
     which provides a correct build
     regardless of the original location(s) of the source files.
 
@@ -264,14 +276,14 @@ program using the F<build/foo.c> path name.
     it <emphasis>can</emphasis> usually be safely disabled.
     The next section describes
     how you can disable the duplication of source files
-    in the build directory.
+    in the variant directory.
 
     </para>
 
   </section>
 
   <section>
-  <title>Telling &SCons; to Not Duplicate Source Files in the Build Directory</title>
+  <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title>
 
     <para>
 
@@ -287,15 +299,15 @@ program using the F<build/foo.c> path name.
     </para>
 
     <sconstruct>
-      SConscript('src/SConscript', build_dir='build', duplicate=0)
+      SConscript('src/SConscript', variant_dir='build', duplicate=0)
     </sconstruct>
 
     <para>
 
     When this flag is specified,
-    &SCons; uses the build directory
+    &SCons; uses the variant directory
     like most people expect--that is,
-    the output files are placed in the build directory
+    the output files are placed in the variant directory
     while the source files stay in the source directory:
 
     </para>
@@ -315,11 +327,11 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>The &BuildDir; Function</title>
+  <title>The &VariantDir; Function</title>
 
     <para>
 
-    Use the &BuildDir; function to establish that target
+    Use the &VariantDir; function to establish that target
     files should be built in a separate directory
     from the source files:
 
@@ -327,7 +339,7 @@ program using the F<build/foo.c> path name.
 
     <scons_example name="ex_builddir">
       <file name="SConstruct" printme="1">
-      BuildDir('build', 'src')
+      VariantDir('build', 'src')
       env = Environment()
       env.Program('build/hello.c')
       </file>
@@ -350,9 +362,9 @@ program using the F<build/foo.c> path name.
 
     <para>
 
-    When using the &BuildDir; function directly,
+    When using the &VariantDir; function directly,
     &SCons; still duplicates the source files
-    in the build directory by default:
+    in the variant directory by default:
 
     </para>
 
@@ -371,7 +383,7 @@ program using the F<build/foo.c> path name.
 
     <scons_example name="ex_duplicate_0">
       <file name="SConstruct" printme="1">
-      BuildDir('build', 'src', duplicate=0)
+      VariantDir('build', 'src', duplicate=0)
       env = Environment()
       env.Program('build/hello.c')
       </file>
@@ -396,11 +408,11 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>Using &BuildDir; With an &SConscript; File</title>
+  <title>Using &VariantDir; With an &SConscript; File</title>
 
     <para>
 
-    Even when using the &BuildDir; function,
+    Even when using the &VariantDir; function,
     it's much more natural to use it with
     a subsidiary &SConscript; file.
     For example, if the
@@ -411,7 +423,7 @@ program using the F<build/foo.c> path name.
 
     <scons_example name="example_builddir_sconscript">
       <file name="SConstruct">
-      BuildDir('build', 'src')
+      VariantDir('build', 'src')
       SConscript('build/SConscript')
       </file>
       <file name="src/SConscript" printme="1">
@@ -457,11 +469,11 @@ program using the F<build/foo.c> path name.
   <!--
 
   <section>
-  <title>Why You'd Want to Call &BuildDir; Instead of &SConscript;</title>
+  <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title>
 
     <para>
 
-    XXX why call BuildDir() instead of SConscript(build_dir=)
+    XXX why call VariantDir() instead of SConscript(variant_dir=)
 
     </para>
 
index 57acd48bb841696e2e7580a7c69ce8f839744b3e..57ade0467f8160fa0a56b93aa2eb5c30d2ab7fd0 100644 (file)
@@ -114,33 +114,45 @@ program using the F<build/foo.c> path name.
 
   It's often useful to keep any built files completely
   separate from the source files.
-  This is usually done by creating one or more separate
-  <emphasis>build directories</emphasis>
+  In &SCons;, this is usually done by creating one or more separate
+  <emphasis>variant directory trees</emphasis>
   that are used to hold the built objects files, libraries,
   and executable programs, etc.
-  for a specific flavor of build.
+  for a specific flavor, or variant, of build.
   &SCons; provides two ways to do this,
   one through the &SConscript; function that we've already seen,
-  and the second through a more flexible &BuildDir; function.
+  and the second through a more flexible &VariantDir; function.
+
+  </para>
+
+  <para>
+
+  One historical note:  the &VariantDir; function
+  used to be called &BuildDir;.
+  That name is still supported
+  but has been deprecated
+  because the &SCons; functionality
+  differs from the model of a "build directory"
+  implemented by other build systems like the GNU Autotools.
 
   </para>
 
   <section>
-  <title>Specifying a Build Directory as Part of an &SConscript; Call</title>
+  <title>Specifying a Variant Directory Tree as Part of an &SConscript; Call</title>
 
     <para>
 
-    The most straightforward way to establish a build directory
+    The most straightforward way to establish a variant directory tree
     uses the fact that the usual way to
     set up a build hierarchy is to have an
     &SConscript; file in the source subdirectory.
-    If you then pass a &build_dir; argument to the
+    If you then pass a &variant_dir; argument to the
     &SConscript; function call:
 
     </para>
 
     <programlisting>
-      SConscript('src/SConscript', build_dir='build')
+      SConscript('src/SConscript', variant_dir='build')
     </programlisting>
 
     <para>
@@ -187,11 +199,11 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>Why &SCons; Duplicates Source Files in a Build Directory</title>
+  <title>Why &SCons; Duplicates Source Files in a Variant Directory Tree</title>
 
     <para>
 
-    &SCons; duplicates source files in build directories
+    &SCons; duplicates source files in variant directory trees
     because it's the most straightforward way to guarantee a correct build
     <emphasis>regardless of include-file directory paths,
     relative references between files,
@@ -204,14 +216,14 @@ program using the F<build/foo.c> path name.
     <para>
 
     The most direct reason to duplicate source files
-    in build directories
+    in variant directories
     is simply that some tools (mostly older vesions)
     are written to only build their output files
     in the same directory as the source files.
     In this case, the choices are either
     to build the output file in the source directory
-    and move it to the build directory,
-    or to duplicate the source files in the build directory.
+    and move it to the variant directory,
+    or to duplicate the source files in the variant directory.
 
     </para>
 
@@ -221,7 +233,7 @@ program using the F<build/foo.c> path name.
     relative references between files
     can cause problems if we don't
     just duplicate the hierarchy of source files
-    in the build directory.
+    in the variant directory.
     You can see this at work in
     use of the C preprocessor <literal>#include</literal>
     mechanism with double quotes, not angle brackets:
@@ -246,7 +258,7 @@ program using the F<build/foo.c> path name.
     will be found in the same directory hierarchy,
     and the simplest way to make sure
     that the right include file is found
-    is to duplicate the source files into the build directory,
+    is to duplicate the source files into the variant directory,
     which provides a correct build
     regardless of the original location(s) of the source files.
 
@@ -259,14 +271,14 @@ program using the F<build/foo.c> path name.
     it <emphasis>can</emphasis> usually be safely disabled.
     The next section describes
     how you can disable the duplication of source files
-    in the build directory.
+    in the variant directory.
 
     </para>
 
   </section>
 
   <section>
-  <title>Telling &SCons; to Not Duplicate Source Files in the Build Directory</title>
+  <title>Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree</title>
 
     <para>
 
@@ -282,15 +294,15 @@ program using the F<build/foo.c> path name.
     </para>
 
     <programlisting>
-      SConscript('src/SConscript', build_dir='build', duplicate=0)
+      SConscript('src/SConscript', variant_dir='build', duplicate=0)
     </programlisting>
 
     <para>
 
     When this flag is specified,
-    &SCons; uses the build directory
+    &SCons; uses the variant directory
     like most people expect--that is,
-    the output files are placed in the build directory
+    the output files are placed in the variant directory
     while the source files stay in the source directory:
 
     </para>
@@ -310,18 +322,18 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>The &BuildDir; Function</title>
+  <title>The &VariantDir; Function</title>
 
     <para>
 
-    Use the &BuildDir; function to establish that target
+    Use the &VariantDir; function to establish that target
     files should be built in a separate directory
     from the source files:
 
     </para>
 
     <programlisting>
-      BuildDir('build', 'src')
+      VariantDir('build', 'src')
       env = Environment()
       env.Program('build/hello.c')
     </programlisting>
@@ -340,9 +352,9 @@ program using the F<build/foo.c> path name.
 
     <para>
 
-    When using the &BuildDir; function directly,
+    When using the &VariantDir; function directly,
     &SCons; still duplicates the source files
-    in the build directory by default:
+    in the variant directory by default:
 
     </para>
 
@@ -364,7 +376,7 @@ program using the F<build/foo.c> path name.
     </para>
 
     <programlisting>
-      BuildDir('build', 'src', duplicate=0)
+      VariantDir('build', 'src', duplicate=0)
       env = Environment()
       env.Program('build/hello.c')
     </programlisting>
@@ -389,11 +401,11 @@ program using the F<build/foo.c> path name.
   </section>
 
   <section>
-  <title>Using &BuildDir; With an &SConscript; File</title>
+  <title>Using &VariantDir; With an &SConscript; File</title>
 
     <para>
 
-    Even when using the &BuildDir; function,
+    Even when using the &VariantDir; function,
     it's much more natural to use it with
     a subsidiary &SConscript; file.
     For example, if the
@@ -415,7 +427,7 @@ program using the F<build/foo.c> path name.
 
     
     <programlisting>
-      BuildDir('build', 'src')
+      VariantDir('build', 'src')
       SConscript('build/SConscript')
       </programlisting>
 
@@ -448,11 +460,11 @@ program using the F<build/foo.c> path name.
   <!--
 
   <section>
-  <title>Why You'd Want to Call &BuildDir; Instead of &SConscript;</title>
+  <title>Why You'd Want to Call &VariantDir; Instead of &SConscript;</title>
 
     <para>
 
-    XXX why call BuildDir() instead of SConscript(build_dir=)
+    XXX why call VariantDir() instead of SConscript(variant_dir=)
 
     </para>
 
index ca5ace81f0754bbaff6cb2e52c0fbbd868b2c26a..dc90622f4220647314dae51e2d892133143b5acb 100644 (file)
     <screen>
       % <userinput>scons</userinput>
       scons: Reading SConscript files ...
-      { 'BUILDERS': {'InstallAs': &lt;function InstallAsBuilderWrapper at 0x700000&gt;, 'Install': &lt;function InstallBuilderWrapper at 0x700000&gt;},
+      { 'BUILDERS': {'_InternalInstall': &lt;function InstallBuilderWrapper at 0x700000&gt;, '_InternalInstallAs': &lt;function InstallAsBuilderWrapper at 0x700000&gt;},
         'CONFIGUREDIR': '#/.sconf_temp',
         'CONFIGURELOG': '#/config.log',
         'CPPSUFFIXES': [ '.c',
         'INSTALL': &lt;function copyFunc at 0x700000&gt;,
         'LATEXSUFFIXES': ['.tex', '.ltx', '.latex'],
         'LIBPREFIX': 'lib',
-        'LIBPREFIXES': '$LIBPREFIX',
+        'LIBPREFIXES': ['$LIBPREFIX'],
         'LIBSUFFIX': '.a',
         'LIBSUFFIXES': ['$LIBSUFFIX', '$SHLIBSUFFIX'],
         'MAXLINELENGTH': 128072,
     <screen>
       C:\><userinput>scons</userinput>
       scons: Reading SConscript files ...
-      { 'BUILDERS': {'RES': &lt;SCons.Builder.BuilderBase instance at 0x700000&gt;, 'Object': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;, 'InstallAs': &lt;function InstallAsBuilderWrapper at 0x700000&gt;, 'PCH': &lt;SCons.Builder.BuilderBase instance at 0x700000&gt;, 'Install': &lt;function InstallBuilderWrapper at 0x700000&gt;, 'SharedObject': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;, 'StaticObject': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;},
+      { 'BUILDERS': {'_InternalInstall': &lt;function InstallBuilderWrapper at 0x700000&gt;, 'Object': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;, 'PCH': &lt;SCons.Builder.BuilderBase instance at 0x700000&gt;, 'RES': &lt;SCons.Builder.BuilderBase instance at 0x700000&gt;, 'SharedObject': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;, 'StaticObject': &lt;SCons.Builder.CompositeBuilder instance at 0x700000&gt;, '_InternalInstallAs': &lt;function InstallAsBuilderWrapper at 0x700000&gt;},
         'CC': 'cl',
         'CCCOM': &lt;SCons.Action.FunctionAction instance at 0x700000&gt;,
         'CCCOMFLAGS': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS',
       % <userinput>scons -Q --debug=stacktrace</userinput>
       scons: *** Source `prog.c' not found, needed by target `prog.o'.  Stop.
       scons: internal stack trace:
-        File "bootstrap/src/engine/SCons/Job.py", line 114, in start
-        File "bootstrap/src/engine/SCons/Script/Main.py", line 157, in prepare
+        File "bootstrap/src/engine/SCons/Job.py", line 131, in start
+        File "bootstrap/src/engine/SCons/Script/Main.py", line 169, in prepare
         File "bootstrap/src/engine/SCons/Taskmaster.py", line 169, in prepare
-        File "bootstrap/src/engine/SCons/Node/FS.py", line 2568, in prepare
+        File "bootstrap/src/engine/SCons/Node/FS.py", line 2551, in prepare
         File "bootstrap/src/engine/SCons/Node/__init__.py", line 349, in prepare
     </screen>
 
index 2bdc3941b8171a4313c7e099492a29b3bb6816eb..9980b1dd36fc6ef9241f8f0dc5f3498794688a47 100644 (file)
@@ -49,7 +49,7 @@ is pretty smart about rebuilding things when you change options.
 
   <para>
 
-  The &build_dir; keyword argument of
+  The &variant_dir; keyword argument of
   the &SConscript; function provides everything
   we need to show how easy it is to create
   variant builds using &SCons;.
@@ -79,7 +79,7 @@ is pretty smart about rebuilding things when you change options.
 
     Export('env')
 
-    env.SConscript('src/SConscript', build_dir='build/$PLATFORM')
+    env.SConscript('src/SConscript', variant_dir='build/$PLATFORM')
     </file>
     <directory name="src"></directory>
     <directory name="src/hello"></directory>
@@ -140,7 +140,7 @@ is pretty smart about rebuilding things when you change options.
     <file name="SConstruct" printme="1">
     env = Environment(OS = ARGUMENTS.get('OS'))
     for os in ['newell', 'post']:
-        SConscript('src/SConscript', build_dir='build/' + os)
+        SConscript('src/SConscript', variant_dir='build/' + os)
     </file>
   </scons_example>
 
index 672785953dcb89fc97143784f6737cfa798f9266..3b570cdff5b3b5ccd90e593a6ebff053c5de31c9 100644 (file)
@@ -49,7 +49,7 @@ is pretty smart about rebuilding things when you change options.
 
   <para>
 
-  The &build_dir; keyword argument of
+  The &variant_dir; keyword argument of
   the &SConscript; function provides everything
   we need to show how easy it is to create
   variant builds using &SCons;.
@@ -78,7 +78,7 @@ is pretty smart about rebuilding things when you change options.
 
     Export('env')
 
-    env.SConscript('src/SConscript', build_dir='build/$PLATFORM')
+    env.SConscript('src/SConscript', variant_dir='build/$PLATFORM')
   </programlisting>
 
   <para>
@@ -123,7 +123,7 @@ is pretty smart about rebuilding things when you change options.
     <file name="SConstruct" printme="1">
     env = Environment(OS = ARGUMENTS.get('OS'))
     for os in ['newell', 'post']:
-        SConscript('src/SConscript', build_dir='build/' + os)
+        SConscript('src/SConscript', variant_dir='build/' + os)
     </file>
   </scons_example>
 
index a3cf016b64de64770c5297a0b0cbc50e9ccc043a..3ff68f6dcd662951a4b1b445c10d18531a6ee602 100644 (file)
@@ -165,7 +165,9 @@ opts, args = getopt.getopt(sys.argv[1:], "ab:df:hlno:P:p:qv:Xx:t",
                             ['all', 'aegis', 'baseline=', 'builddir=',
                              'debug', 'file=', 'help',
                              'list', 'no-exec', 'noqmtest', 'output=',
-                             'version=', 'exec=', 'time',
+                             'package=', 'passed', 'python=', 'qmtest',
+                             'quiet', 'sp=', 'spe=', 'time',
+                             'version=', 'exec=',
                              'verbose=', 'xml'])
 
 for o, a in opts:
@@ -207,7 +209,7 @@ for o, a in opts:
     elif o in ['-P', '--python']:
         python = a
     elif o in ['--qmtest']:
-        qmtest = 'qmtest.py'
+        qmtest = 'qmtest'
     elif o in ['-q', '--quiet']:
         printcommand = 0
     elif o in ['--sp']:
@@ -266,7 +268,7 @@ else:
 try:
     qmtest
 except NameError:
-    q = 'qmtest.py'
+    q = 'qmtest'
     qmtest = whereis(q)
     if qmtest:
         qmtest = q
index 81b54e65c3702cf2e7dfef969e841d8b78c3ff11..dee595137c2a174db4a216440929881be9e35356 100644 (file)
@@ -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
index 7327f21bed4f7034b4c289ae1841e0a70ec6e81a..0c4f90564a207e5f0e0258d725d6a973083abea8 100644 (file)
@@ -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.
 
index cd4bf6aa0bf29781f6240fba99c7ece8599592fd..367174c3bb08df8a966a457f0655cb9ac14ea709 100644 (file)
@@ -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:
index 2ad4bef7614665e3153289f8affb270727dc0598..74664b0df8fb2250e539dddd89950919745d132b 100644 (file)
@@ -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):
index 4021f2b94d894366d06259399daddf2e1a8c5b4a..2e10a8d2052a6d815aff0021bbfeb9b42162dec3 100644 (file)
@@ -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]
index cf13025c5d73f4bd8246beff0c6aea9f934b620e..1b7bc380412c3267cb92026958ea786f5616d63b 100644 (file)
@@ -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
index 33899f60a6c67216c4d3a83442c2724af75b9eba..d3111686027f33fd4f7dd8a0d2aea65cb4c1d915 100644 (file)
@@ -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):
index 3cd47efe460738f39d75ec50e880e665d3d3f1b6..aebef3998f02e409c74fc80405219df429d9f984 100644 (file)
@@ -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):
index 02ad33244963ba6746e0dbbdeca6ccef35aab936..ce9803430a8cb9154e4b2479a656cf7d14e73339 100644 (file)
@@ -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):
index 4ffff7ad4680cb3e2c684f095abb45d6d838afad..6c10ee0ec6001c7a2a8698c984534af929a0b89b 100644 (file)
@@ -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))
index 1a3c0100c6eedc367dc1db70ac2d4eddca90a85b..f73161fde071b45bebaae7254187727774ea63e7 100644 (file)
@@ -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
index b698e876a23d1d5f59dafb0d1baedfb739b36530..cfdc978b842dce860166dc15254f904ee163a578 100644 (file)
@@ -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,
index 4ca34e01db81453fdde0194826aaca97fe0c5e62..2e136f0088334b3872c4edef0682cd2f8a3faabc 100644 (file)
@@ -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 = []
 
index 5aa508ada6d0057828e9e2e69a5dc8b1ec0a87dd..69549055c209c720c2da75744dec8e4955060765 100644 (file)
@@ -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):
index 3dc7772d22b96f55d7779910488132fa50ea2262..9389c7b7b56ae5310a9c1216fb2ce3de2167216d 100644 (file)
@@ -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:
index c5de498852c9b43ec1892880d74f6142ed09a0bd..130e0d39cbc8bf1f052c4c8b39b3084325642ee9 100644 (file)
@@ -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:
index 5d6765d0a3454c5047b8e68b65a1b7fc186d82df..cadc491aaef3d7d08a599e8f6487a4d6872ef068 100644 (file)
@@ -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
index 82db69455bcdb084ae05f5daa290de7d10a2a95d..ff63bda2e13c963a151c3df3920b54238e7119c1 100644 (file)
@@ -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
index 2332a57f31eaa16e1f63af9fa785533575815dc1..bca2ac87df2f3768af529cb0181997c48ded0cfc 100644 (file)
@@ -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
index e8d1669cd69be6562e201436c26141ade288b7bd..102205f23247e23df3c1d5353225af1a1737b94f 100644 (file)
@@ -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']
index e38c400253c0ac61832ec4b010a7c7b86dba1014..d18eec1ea083ba69a8a4c9b2b6ae1f4579e50c2d 100644 (file)
@@ -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:
index bcbd0a14e93b02513a0098553e8a5b799d2b3f64..80b9032eeb82c33f4f90947c14165b1f43780d27 100644 (file)
@@ -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__))
index 8f7116de8f23c053ecfb9c81d0ede69b82898cc9..ee34a85bb9f1f0f0d7a59062d1072e3dfb7518cd 100644 (file)
@@ -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")
 
index 5278d403e07f5425bdcd235a6f68d90f74c8ce03..36a147dba69696441635328c610331eba8667986 100644 (file)
@@ -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)
 
index 44f01b827cdf501f7e60790626873d795275439f..ddeaf9e0f6745fcdbc340529d38424b9bd336361 100644 (file)
@@ -321,6 +321,7 @@ GlobalDefaultEnvironmentFunctions = [
     'Tag',
     'TargetSignatures',
     'Value',
+    'VariantDir',
 ]
 
 GlobalDefaultBuilders = [
index 9db8138c7812ea8022f2ee05a8fbe9435e28a733..66202dc53239961a4f7fb2e67fe4562ab90800ff 100644 (file)
@@ -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()
index 0991c372d0a2609a2a30f04dd9be12e22e57aa77..d028a393447f0bd5d30fe25b72b8d0d728e0468a 100644 (file)
@@ -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
index 1675190b6025b0c5a4ec87264fa700272d747dd3..bffe09e04e8fb846cee2af61203e357880b62af9 100644 (file)
@@ -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__":
index d4e3815b3b025696bee709bd95bef5a577b54eea..1e69f1e263f45ee5c21a499557858b8890fee1ac 100644 (file)
@@ -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:
index 532301f698580bfa4527368f928c35a3cd1f6211..750013375b6d76628929647e4bd0e95ce5e5479d 100644 (file)
@@ -62,5 +62,4 @@ def generate(env):
 
 
 def exists(env):
-    import sys
-    return sys.platform == 'darwin'
+    return env['PLATFORM'] == 'darwin'
index 9996fc2dfed4f09edb4ebfa7bfbc06716b774fd2..ec95f16c063acad238e76e800191df8051d33ff3 100644 (file)
@@ -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'] = ''
index c7eee614b7b4f751418985ed3e42d86dbedaae47..983fb123ab008679d9b22cfd1df51a9d703b0486 100644 (file)
@@ -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
index c6fe461b8b01aea3dc7f451994e5f0e5e1260821..a1067c08d27e88d6ec96f33a2683e6b7f73c472a 100644 (file)
@@ -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' ) )
index d4efa74d17ad72bc75ca7332a9938a730d4f4272..ca1b5f6b988ab552d18d2d71926d3d187b20fd4e 100644 (file)
@@ -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+")
index 66fe5545b7cc16372d937b5770a71853311c441f..ea736982e312322735ed85b0ed1f2d45a7e6af06 100644 (file)
@@ -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.
index 08ce1f2adcd6b7d0736006be53e182cb24e27698..311c6a8f2622ca236874893f7e6f794d512998ff 100644 (file)
@@ -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:
index 44d6fa89c79a8cbaf2955731c92786794771ace8..8a24ef1d8b3e9cb76b5c486789a5e1ac06b596fa 100644 (file)
@@ -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,
                ]
index 53549595edb22b32c62c6661fe7577565d40d157..c9b8a261cbe1deb4856488be17408e5f1e5f1b2d 100644 (file)
@@ -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)
index 91e3776bc161c4a97451dcfeccb49c5378a54372..1d36dbc56e373984952156737a9a7ff36f693d04 100644 (file)
@@ -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:
index 33fd01d7b967b976c81910610f1ae1d4d5aa1ab4..ed1479b3d10c066e3f693ca18db5aa2a56259944 100644 (file)
@@ -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')
index fbffe68e74ca769bcf03d45bb7769ec45eef7b9a..db01549365027cbeaeef9e6efba718ad3f99aac3 100644 (file)
@@ -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()
index c446cad0a7a71688d2e662ba971fe43df39190e2..0b6344f742cbd68d5995189a39a492226bb187b6 100644 (file)
@@ -185,6 +185,7 @@ check_list = [
     CheckExpandedCopyright(
         build_src,
         remove_list = [
+            'bench/timeit.py',
             'bin',
             'config',
             'debian',
index b53b8ce451ee2085512ca4199a6d96ce65ad0d52..0af4dc265e150f0e446f17b5a6f00d834ee8f8b4 100644 (file)
@@ -133,7 +133,7 @@ test.run(arguments = 'f1.out',
 test.up_to_date(arguments = 'f1.out')
 
 test.write('SConstruct', """
-TargetSignatures('content')
+Decider('content')
 B = Builder(action = r'%(_python_)s build.py $TARGET $SOURCES')
 env = Environment()
 env['BUILDERS']['B'] = B
index f2ca950f331b8efa90ce854e99a9bf99cc23ec06..1205b29736f4ad4994ef495b177118761df126db 100644 (file)
@@ -33,7 +33,7 @@ test = TestSCons.TestSCons()
 
 test.write('SConstruct', """
 env=Environment()
-TargetSignatures('content')
+Decider('content')
 env.Alias('C', 'D')
 env.Alias('B', 'C')
 env.Alias('A', 'B')
index 225116539b71baf9b646d8643f97b465eed00ed9..2d7a15475464f95dfb4b8b98d26cce81f7ca95d9 100644 (file)
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that an Alias for a BuildDir()'s source directory works as
+Verify that an Alias for a VariantDir()'s source directory works as
 expected.
 
 This tests for a 0.96.93 bug uncovered by the LilyPond project's build.
 
 The specific problem is that, in 0.96.93, the simple act of trying to
-disambiguate a target file in the BuildDir() would call srcnode(), which
+disambiguate a target file in the VariantDir() would call srcnode(), which
 would create a "phantom" Node for the target in the *source* directory:
 
         +-minimal
@@ -81,7 +81,7 @@ Export ('env')
 
 b = 'python/out-scons'
 
-env.BuildDir(b, 'python', duplicate=0)
+env.VariantDir(b, 'python', duplicate=0)
 
 SConscript(b + '/SConscript')
 """)
index 80b4aa70d823511895bf174bbb38cacdd2e7ac9e..1146ee0935b9bd3e08198fd83a7dba2511018d1f 100644 (file)
@@ -51,7 +51,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.c')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(CPPPATH=[include, '#foobar', '#subdir'])
 SConscript('variant/SConscript', "env")
@@ -251,7 +251,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.c')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(CPPPATH=['inc2', include, '#foobar', '#subdir'])
 SConscript('variant/SConscript', "env")
index f8501c6df13ca97d13564ee06f0388ee30bb36cc..6305d0c9c463d19e414bd670caefb274e23ad926 100644 (file)
@@ -38,7 +38,7 @@ test.subdir(['src'],
             ['src', 'inc', 'inc2'])
 
 test.write('SConstruct', """\
-SConscript('src/SConscript', build_dir = 'build', duplicate = 0)
+SConscript('src/SConscript', variant_dir = 'build', duplicate = 0)
 """)
 
 test.write(['src', 'SConscript'], """\
similarity index 97%
rename from test/CacheDir/BuildDir.py
rename to test/CacheDir/VariantDir.py
index a41d397f012ca4b7247751c0fa21b86131df1d67..b5650c14e0b6126a9ba2770139c30ec2036cb57e 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test retrieving derived files from a CacheDir when a BuildDir is used.
+Test retrieving derived files from a CacheDir when a VariantDir is used.
 """
 
 import os.path
@@ -68,7 +68,7 @@ test.write(['src', 'ccc.in'], "ccc.in\n")
 test.write('SConstruct', """\
 env = Environment(TWO = '2')
 CacheDir(r'%s')
-BuildDir('build', 'src', duplicate=0)
+VariantDir('build', 'src', duplicate=0)
 SConscript('build/SConscript')
 """ % test.workpath('cache${TWO}'))
 
index 92fa6394b14125e23245f796fa83176487b83166..61d21eb283b1c18a3de63b364e414ff1121c0ca4 100644 (file)
@@ -61,6 +61,11 @@ env.Command('f6.out', 'f6.in', [Chmod('$FILE', 0666), Cat])
 env.Command('f7.out', 'f7.in', [Cat,
                                 Chmod('Chmod-$SOURCE', 0666),
                                 Chmod('${TARGET}-Chmod', 0666)])
+
+# Make sure Chmod works with a list of arguments
+env = Environment(FILE = 'f9')
+env.Command('f8.out', 'f8.in', [Chmod(['$FILE', File('f10')], 0666), Cat])
+Execute(Chmod(['d11', Dir('d12')], 0777))
 """)
 
 test.write('f1', "f1\n")
@@ -78,6 +83,11 @@ test.write('f6.in', "f6.in\n")
 test.write('f7.in', "f7.in\n")
 test.write('Chmod-f7.in', "Chmod-f7.in\n")
 test.write('f7.out-Chmod', "f7.out-Chmod\n")
+test.write('f8.in', "f8.in\n")
+test.write('f9', "f9\n")
+test.write('f10', "f10\n")
+test.subdir('d11')
+test.subdir('d12')
 
 os.chmod(test.workpath('f1'), 0444)
 os.chmod(test.workpath('f1-File'), 0444)
@@ -88,12 +98,17 @@ os.chmod(test.workpath('d4'), 0555)
 os.chmod(test.workpath('f5'), 0444)
 os.chmod(test.workpath('Chmod-f7.in'), 0444)
 os.chmod(test.workpath('f7.out-Chmod'), 0444)
+os.chmod(test.workpath('f9'), 0444)
+os.chmod(test.workpath('f10'), 0444)
+os.chmod(test.workpath('d11'), 0555)
+os.chmod(test.workpath('d12'), 0555)
 
 expect = test.wrap_stdout(read_str = """\
 Chmod("f1", 0666)
 Chmod("f1-File", 0666)
 Chmod("d2", 0777)
 Chmod("d2-Dir", 0777)
+Chmod(["d11", "d12"], 0777)
 """,
                           build_str = """\
 cat(["bar.out"], ["bar.in"])
@@ -104,6 +119,8 @@ cat(["f6.out"], ["f6.in"])
 cat(["f7.out"], ["f7.in"])
 Chmod("Chmod-f7.in", 0666)
 Chmod("f7.out-Chmod", 0666)
+Chmod(["f9", "f10"], 0666)
+cat(["f8.out"], ["f8.in"])
 """)
 test.run(options = '-n', arguments = '.', stdout = expect)
 
@@ -128,6 +145,15 @@ s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
 test.fail_test(s != 0444)
 s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
 test.fail_test(s != 0444)
+test.must_not_exist('f8.out')
+s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
+test.fail_test(s != 0444)
+s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
+test.fail_test(s != 0444)
+s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
+test.fail_test(s != 0555)
+s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
+test.fail_test(s != 0555)
 
 test.run()
 
@@ -152,5 +178,14 @@ s = stat.S_IMODE(os.stat(test.workpath('Chmod-f7.in'))[stat.ST_MODE])
 test.fail_test(s != 0666)
 s = stat.S_IMODE(os.stat(test.workpath('f7.out-Chmod'))[stat.ST_MODE])
 test.fail_test(s != 0666)
+test.must_match('f8.out', "f8.in\n")
+s = stat.S_IMODE(os.stat(test.workpath('f9'))[stat.ST_MODE])
+test.fail_test(s != 0666)
+s = stat.S_IMODE(os.stat(test.workpath('f10'))[stat.ST_MODE])
+test.fail_test(s != 0666)
+s = stat.S_IMODE(os.stat(test.workpath('d11'))[stat.ST_MODE])
+test.fail_test(s != 0777)
+s = stat.S_IMODE(os.stat(test.workpath('d12'))[stat.ST_MODE])
+test.fail_test(s != 0777)
 
 test.pass_test()
similarity index 99%
rename from test/Configure/BuildDir-SConscript.py
rename to test/Configure/VariantDir-SConscript.py
index 47b7d8227c2130f4c62647d0f300d3b80689fd89..a9371f94e844c4aa23403b4cde9dd2a80339b078 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Verify that Configure calls in SConscript files work when used
-with BuildDir.
+with VariantDir.
 """
 
 import os.path
@@ -52,7 +52,7 @@ if env['chdir'] == 'yes':
   SConscriptChdir(1)
 else:
   SConscriptChdir(0)
-BuildDir( 'build', '.' )
+VariantDir( 'build', '.' )
 SConscript( 'build/SConscript' )
 """)
 
similarity index 97%
rename from test/Configure/BuildDir.py
rename to test/Configure/VariantDir.py
index ca3c14793d08f2bb67cc5e74de793e2379731f1e..63fcb939a67ea1a1426e4241571f3b898267c5f5 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that Configure contexts work with basic use of BuildDir.
+Verify that Configure contexts work with basic use of VariantDir.
 """
 
 import os.path
@@ -45,7 +45,7 @@ test.write('SConstruct', """\
 env = Environment(LOGFILE='build/config.log')
 import os
 env.AppendENVPath('PATH', os.environ['PATH'])
-BuildDir( 'build', '.' )
+VariantDir( 'build', '.' )
 conf = env.Configure(conf_dir='build/config.tests', log_file='$LOGFILE')
 r1 = conf.CheckCHeader( 'math.h' )
 r2 = conf.CheckCHeader( 'no_std_c_header.h' ) # leads to compile error
index 82e32f6320a778238926b595604fc9a26e8b2236..339c46420db71a8f969e1cf06c54275c4f2cf9a2 100644 (file)
@@ -45,8 +45,8 @@ NCF = test.NCF  # non-cached build failure
 CF  = test.CF   # cached build failure
 
 test.write('SConstruct', """\
-if int(ARGUMENTS.get('target_signatures_content', 0)):
-    TargetSignatures('content')
+if not int(ARGUMENTS.get('target_signatures_content', 0)):
+    Decider('timestamp-newer')
 env = Environment()
 import os
 env.AppendENVPath('PATH', os.environ['PATH'])
@@ -59,6 +59,8 @@ if not (not r1 and not r2):
      Exit(1)
 """)
 
+# Verify correct behavior when we call Decider('timestamp-newer').
+
 test.run()
 test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
                        "Checking for C library no_c_library_SAFFDG... "],
@@ -71,11 +73,11 @@ test.run()
 test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
                        "Checking for C library no_c_library_SAFFDG... "],
                       ["no"]*2,
-                      [[((".c", CR), (_obj, CF))],
-                       [((".c", CR), (_obj, CR), (_exe, CF))]],
+                      [[((".c", CR), (_obj, NCF))],
+                       [((".c", CR), (_obj, CR), (_exe, NCF))]],
                       "config.log", ".sconf_temp", "SConstruct")
 
-# same should be true for TargetSignatures('content')
+# Same should be true for the default behavior of Decider('content').
 
 test.run(arguments='--config=force target_signatures_content=1')
 test.checkLogAndStdout(["Checking for C header file no_std_c_header.h... ",
index d8eac774ae8835b83bccee7a3a7e14c357e5c067..7c98d0cccfdde568db015563ead8f7e157cdd5af 100644 (file)
@@ -43,8 +43,8 @@ NCF = test.NCF  # non-cached build failure
 CF  = test.CF   # cached build failure
 
 test.write('SConstruct', """\
-if int(ARGUMENTS.get('target_signatures_content', 0)):
-    TargetSignatures('content')
+if not int(ARGUMENTS.get('target_signatures_content', 0)):
+    Decider('timestamp-newer')
 env = Environment()
 import os
 env.AppendENVPath('PATH', os.environ['PATH'])
@@ -60,6 +60,8 @@ if not (r1 and r2 and r3 and r4 and r5 and r6):
      Exit(1)
 """ % locals())
 
+# Verify correct behavior when we call Decider('timestamp-newer')
+
 test.run()
 test.checkLogAndStdout(["Checking for C library %s... " % lib,
                        "Checking for C library None... ",
@@ -87,7 +89,7 @@ test.checkLogAndStdout(["Checking for C library %s... " % lib,
                        [[((".cpp", CR), (_obj, CR))]],
                       "config.log", ".sconf_temp", "SConstruct")
 
-# same should be true for TargetSignatures('content')
+# same should be true for the default behavior of Decider('content')
 
 test.run(arguments='target_signatures_content=1 --config=force')
 test.checkLogAndStdout(["Checking for C library %s... " % lib,
index 7bc86450275a01124f8f164a18df03865290e033..95121a9ba1cb365c56e8c2b2b2b1c398d56f2e8c 100644 (file)
@@ -89,18 +89,44 @@ expected_config_h = string.replace("""\
 #ifndef CONFIG_H_SEEN
 #define CONFIG_H_SEEN
 
+
+/* Define to 1 if the system has the function `printf'. */
 #define HAVE_PRINTF 1
+
+/* Define to 1 if the system has the function `noFunctionCall'. */
 /* #undef HAVE_NOFUNCTIONCALL */
+
+/* Define to 1 if the system has the type `int'. */
 #define HAVE_INT 1
+
+/* Define to 1 if the system has the type `noType'. */
 /* #undef HAVE_NOTYPE */
+
+/* Define to 1 if you have the <stdio.h> header file. */
 #define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <hopefullynoc-header.h> header file. */
 /* #undef HAVE_HOPEFULLYNOC_HEADER_H */
+
+/* Define to 1 if you have the <vector> header file. */
 #define HAVE_VECTOR 1
+
+/* Define to 1 if you have the <hopefullynocxx-header.h> header file. */
 /* #undef HAVE_HOPEFULLYNOCXX_HEADER_H */
+
+/* Define to 1 if you have the `%(lib)s' library. */
 #define HAVE_%(LIB)s 1
+
+/* Define to 1 if you have the `hopefullynolib' library. */
 /* #undef HAVE_LIBHOPEFULLYNOLIB */
+
+/* Define to 1 if you have the `%(lib)s' library. */
 #define HAVE_%(LIB)s 1
+
+/* Define to 1 if you have the `%(lib)s' library. */
 /* #undef HAVE_%(LIB)s */
+
+/* Define to 1 if you have the `hopefullynolib2' library. */
 /* #undef HAVE_LIBHOPEFULLYNOLIB2 */
 
 #endif /* CONFIG_H_SEEN */
similarity index 73%
rename from test/Copy.py
rename to test/Copy-Action.py
index 827b9120c155be213bfd5096d0c24f9fdc1d5514..768d102c402e3e78b33dfd6a245048a73d4d4d9a 100644 (file)
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that the Delete() Action works.
+Verify that the Copy() Action works, and preserves file modification
+times and modes.
 """
 
+import os
 import os.path
+import sys
+import stat
 
 import TestSCons
 
@@ -58,6 +62,8 @@ env.Command('f9.out', 'f9.in', [Cat, Copy('${TARGET}-Copy', '$SOURCE')])
 env.CopyTo( 'd4', 'f10.in' )
 env.CopyAs( 'd4/f11.out', 'f11.in')
 env.CopyAs( 'd4/f12.out', 'd5/f12.in')
+
+env.Command('f   13.out', 'f   13.in', Copy('$TARGET', '$SOURCE'))
 """)
 
 test.write('f1.in', "f1.in\n")
@@ -78,6 +84,12 @@ test.write('f10.in', "f10.in\n")
 test.write('f11.in', "f11.in\n")
 test.subdir('d5')
 test.write(['d5', 'f12.in'], "f12.in\n")
+test.write('f   13.in', "f   13.in\n")
+
+os.chmod('f1.in', 0646)
+os.chmod('f4.in', 0644)
+
+test.sleep()
 
 d4_f10_in   = os.path.join('d4', 'f10.in')
 d4_f11_out  = os.path.join('d4', 'f11.out')
@@ -97,11 +109,13 @@ Copy("d6.out", "f6.in")
 Copy file(s): "f10.in" to "%(d4_f10_in)s"
 Copy file(s): "f11.in" to "%(d4_f11_out)s"
 Copy file(s): "%(d5_f12_in)s" to "%(d4_f12_out)s"
+Copy("f   13.out", "f   13.in")
 Copy("f7.out", "f7.in")
 cat(["f8.out"], ["f8.in"])
 cat(["f9.out"], ["f9.in"])
 Copy("f9.out-Copy", "f9.in")
 """ % locals())
+
 test.run(options = '-n', arguments = '.', stdout = expect)
 
 test.must_not_exist('f1.out')
@@ -117,6 +131,8 @@ test.must_not_exist('f9.out-Copy')
 test.must_not_exist('d4/f10.in')
 test.must_not_exist('d4/f11.out')
 test.must_not_exist('d4/f12.out')
+test.must_not_exist('f 13.out')
+test.must_not_exist('f    13.out')
 
 test.run()
 
@@ -133,5 +149,40 @@ test.must_match('f9.out-Copy', "f9.in\n")
 test.must_match('d4/f10.in', 'f10.in\n')
 test.must_match('d4/f11.out', 'f11.in\n')
 test.must_match('d4/f12.out', 'f12.in\n')
+test.must_match('f   13.out', 'f   13.in\n')
+
+errors = 0
+
+def must_be_same(f1, f2):
+    global errors
+    if type(f1) is type([]):
+        f1 = apply(os.path.join, f1)
+    if type(f2) is type([]):
+        f2 = apply(os.path.join, f2)
+    s1 = os.stat(f1)
+    s2 = os.stat(f2)
+    for value in ['ST_MODE', 'ST_MTIME']:
+        v = getattr(stat, value)
+        if s1[v] != s2[v]:
+            msg = '%s[%s] %s != %s[%s] %s\n' % \
+                  (repr(f1), value, s1[v],
+                   repr(f2), value, s2[v],)
+            sys.stderr.write(msg)
+            errors = errors + 1
+
+must_be_same('f1.out',                  'f1.in')
+must_be_same(['d2.out', 'file'],        ['d2.in', 'file'])
+must_be_same(['d3.out', 'f3.in'],       'f3.in')
+must_be_same('f4.out',                  'f4.in')
+must_be_same(['d5.out', 'file'],        ['d5.in', 'file'])
+must_be_same(['d6.out', 'f6.in'],       'f6.in')
+must_be_same('f7.out',                  'f7.in')
+must_be_same(['d4', 'f10.in'],          'f10.in')
+must_be_same(['d4', 'f11.out'],         'f11.in')
+must_be_same(['d4', 'f12.out'],         ['d5', 'f12.in'])
+must_be_same('f   13.out',              'f   13.in')
+
+if errors:
+    test.fail_test()
 
 test.pass_test()
index 31febbe072c24247a808877123ac5a252a671e75..63e4ab633a1b15a3f040373e5228b034c5bc75f1 100644 (file)
@@ -65,6 +65,10 @@ env.Command('f12-nonexistent.out', 'f12.in',
 
 env.Command(Dir('d13-nonexistent.out'), 'd13.in',
             [Delete("$TARGET", must_exist=0), Mkdir("$TARGET")])
+
+# Make sure Delete works with a list of arguments
+env = Environment(FILE='f14', DIR='d15')
+env.Command('f16.out', 'f16.in', [Delete(["$FILE", "$DIR"]), Cat])
 """)
 
 test.write('f1', "f1\n")
@@ -85,6 +89,9 @@ test.write('f10.in', "f10.in\n")
 test.subdir('d11.in')
 test.write('f12.in', "f12.in\n")
 test.subdir('d13.in')
+test.write('f14', "f14\n")
+test.subdir('d15')
+test.write('f16.in', "f16.in\n")
 
 expect = test.wrap_stdout(read_str = """\
 Delete("f1")
@@ -99,6 +106,8 @@ Delete("f10-nonexistent.out")
 cat(["f10-nonexistent.out"], ["f10.in"])
 Delete("f12-nonexistent.out")
 cat(["f12-nonexistent.out"], ["f12.in"])
+Delete(["f14", "d15"])
+cat(["f16.out"], ["f16.in"])
 cat(["f3.out"], ["f3.in"])
 Delete("f4")
 Delete("d5")
@@ -125,6 +134,9 @@ test.must_not_exist('f8.out')
 test.must_not_exist('f9.out')
 test.must_exist('Delete-f9.in')
 test.must_exist('f9.out-Delete')
+test.must_exist('f14')
+test.must_exist('d15')
+test.must_not_exist('f16.out')
 
 test.run()
 
@@ -146,6 +158,9 @@ test.must_exist('f10-nonexistent.out')
 test.must_exist('d11-nonexistent.out')
 test.must_exist('f12-nonexistent.out')
 test.must_exist('d13-nonexistent.out')
+test.must_not_exist('f14')
+test.must_not_exist('d15')
+test.must_match('f16.out', "f16.in\n")
 
 test.write("SConstruct", """\
 def cat(env, source, target):
diff --git a/test/Deprecated/BuildDir.py b/test/Deprecated/BuildDir.py
new file mode 100644 (file)
index 0000000..709ea8b
--- /dev/null
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the deprecated BuildDir() function and method still
+work to create a variant directory tree (by calling VariantDir()
+under the covers).
+
+Note that using BuildDir() does not yet print a deprecation warning.
+"""
+
+import os.path
+import string
+import sys
+import time
+import TestSCons
+
+_exe = TestSCons._exe
+
+test = TestSCons.TestSCons()
+
+foo11 = test.workpath('work1', 'build', 'var1', 'foo1' + _exe)
+foo12 = test.workpath('work1', 'build', 'var1', 'foo2' + _exe)
+foo21 = test.workpath('work1', 'build', 'var2', 'foo1' + _exe)
+foo22 = test.workpath('work1', 'build', 'var2', 'foo2' + _exe)
+foo31 = test.workpath('work1', 'build', 'var3', 'foo1' + _exe)
+foo32 = test.workpath('work1', 'build', 'var3', 'foo2' + _exe)
+foo41 = test.workpath('work1', 'build', 'var4', 'foo1' + _exe)
+foo42 = test.workpath('work1', 'build', 'var4', 'foo2' + _exe)
+foo51 = test.workpath('build', 'var5', 'foo1' + _exe)
+foo52 = test.workpath('build', 'var5', 'foo2' + _exe)
+
+test.subdir('work1')
+
+test.write(['work1', 'SConstruct'], """
+src = Dir('src')
+var2 = Dir('build/var2')
+var3 = Dir('build/var3')
+var4 = Dir('build/var4')
+var5 = Dir('../build/var5')
+var6 = Dir('../build/var6')
+
+env = Environment(BUILD = 'build', SRC = 'src')
+
+VariantDir('build/var1', src)
+VariantDir(var2, src)
+VariantDir(var3, src, duplicate=0)
+env.VariantDir("$BUILD/var4", "$SRC", duplicate=0)
+VariantDir(var5, src, duplicate=0)
+VariantDir(var6, src)
+
+env = Environment(CPPPATH='#src', FORTRANPATH='#src')
+SConscript('build/var1/SConscript', "env")
+SConscript('build/var2/SConscript', "env")
+
+env = Environment(CPPPATH=src, FORTRANPATH=src)
+SConscript('build/var3/SConscript', "env")
+SConscript(File('SConscript', var4), "env")
+
+env = Environment(CPPPATH='.', FORTRANPATH='.')
+SConscript('../build/var5/SConscript', "env")
+SConscript('../build/var6/SConscript', "env")
+""")
+
+test.subdir(['work1', 'src'])
+test.write(['work1', 'src', 'SConscript'], """
+import os
+import os.path
+
+def buildIt(target, source, env):
+    if not os.path.exists('build'):
+        os.mkdir('build')
+    f1=open(str(source[0]), 'r')
+    f2=open(str(target[0]), 'w')
+    f2.write(f1.read())
+    f2.close()
+    f1.close()
+    return 0
+Import("env")
+env.Command(target='f2.c', source='f2.in', action=buildIt)
+env.Program(target='foo2', source='f2.c')
+env.Program(target='foo1', source='f1.c')
+env.Command(target='f3.h', source='f3h.in', action=buildIt)
+env.Command(target='f4.h', source='f4h.in', action=buildIt)
+env.Command(target='f4.c', source='f4.in', action=buildIt)
+
+env2=env.Clone(CPPPATH='.')
+env2.Program(target='foo3', source='f3.c')
+env2.Program(target='foo4', source='f4.c')
+""")
+
+test.write(['work1', 'src', 'f1.c'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "f1.h"
+
+int
+main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf(F1_STR);
+        exit (0);
+}
+""")
+
+test.write(['work1', 'src', 'f2.in'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "f2.h"
+
+int
+main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf(F2_STR);
+        exit (0);
+}
+""")
+
+test.write(['work1', 'src', 'f3.c'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "f3.h"
+
+int
+main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf(F3_STR);
+        exit (0);
+}
+""")
+
+test.write(['work1', 'src', 'f4.in'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "f4.h"
+
+int
+main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf(F4_STR);
+        exit (0);
+}
+""")
+
+test.write(['work1', 'src', 'f1.h'], r"""
+#define F1_STR "f1.c\n"
+""")
+
+test.write(['work1', 'src', 'f2.h'], r"""
+#define F2_STR "f2.c\n"
+""")
+
+test.write(['work1', 'src', 'f3h.in'], r"""
+#define F3_STR "f3.c\n"
+""")
+
+test.write(['work1', 'src', 'f4h.in'], r"""
+#define F4_STR "f4.c\n"
+""")
+
+# Some releases of freeBSD seem to have library complaints about
+# tempnam().  Filter out these annoying messages before checking for
+# error output.
+def blank_output(err):
+    if not err:
+        return 1
+    stderrlines = filter(lambda l: l, string.split(err, '\n'))
+    msg = "warning: tempnam() possibly used unsafely"
+    stderrlines = filter(lambda l, msg=msg: string.find(l, msg) == -1,
+                         stderrlines)
+    return len(stderrlines) == 0
+
+test.run(chdir='work1', arguments = '. ../build', stderr=None)
+
+test.fail_test(not blank_output(test.stderr()))
+
+test.run(program = foo11, stdout = "f1.c\n")
+test.run(program = foo12, stdout = "f2.c\n")
+test.run(program = foo41, stdout = "f1.c\n")
+test.run(program = foo42, stdout = "f2.c\n")
+
+test.run(chdir='work1', arguments='. ../build', stdout=test.wrap_stdout("""\
+scons: `.' is up to date.
+scons: `%s' is up to date.
+""" % test.workpath('build')))
+
+import os
+import stat
+def equal_stats(x,y):
+    x = os.stat(x)
+    y = os.stat(y)
+    return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and
+            x[stat.ST_MTIME] ==  y[stat.ST_MTIME])
+
+# Make sure we did duplicate the source files in build/var2,
+# and that their stats are the same:
+test.must_exist(['work1', 'build', 'var2', 'f1.c'])
+test.must_exist(['work1', 'build', 'var2', 'f2.in'])
+test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f1.c'), test.workpath('work1', 'src', 'f1.c')))
+test.fail_test(not equal_stats(test.workpath('work1', 'build', 'var2', 'f2.in'), test.workpath('work1', 'src', 'f2.in')))
+# Make sure we didn't duplicate the source files in build/var3.
+test.must_not_exist(['work1', 'build', 'var3', 'f1.c'])
+test.must_not_exist(['work1', 'build', 'var3', 'f2.in'])
+test.must_not_exist(['work1', 'build', 'var3', 'b1.f'])
+test.must_not_exist(['work1', 'build', 'var3', 'b2.in'])
+
+# Make sure we didn't duplicate the source files in build/var4.
+test.must_not_exist(['work1', 'build', 'var4', 'f1.c'])
+test.must_not_exist(['work1', 'build', 'var4', 'f2.in'])
+test.must_not_exist(['work1', 'build', 'var4', 'b1.f'])
+test.must_not_exist(['work1', 'build', 'var4', 'b2.in'])
+
+# Make sure we didn't duplicate the source files in build/var5.
+test.must_not_exist(['build', 'var5', 'f1.c'])
+test.must_not_exist(['build', 'var5', 'f2.in'])
+test.must_not_exist(['build', 'var5', 'b1.f'])
+test.must_not_exist(['build', 'var5', 'b2.in'])
+
+# verify that header files in the source directory are scanned properly:
+test.write(['work1', 'src', 'f1.h'], r"""
+#define F1_STR "f1.c 2\n"
+""")
+
+test.write(['work1', 'src', 'f3h.in'], r"""
+#define F3_STR "f3.c 2\n"
+""")
+
+test.write(['work1', 'src', 'f4h.in'], r"""
+#define F4_STR "f4.c 2\n"
+""")
+
+test.run(chdir='work1', arguments = '../build/var5', stderr=None)
+
+test.fail_test(not blank_output(test.stderr()))
+
+test.run(program = foo51, stdout = "f1.c 2\n")
+test.run(program = test.workpath('build', 'var5', 'foo3' + _exe),
+                                 stdout = "f3.c 2\n")
+test.run(program = test.workpath('build', 'var5', 'foo4' + _exe),
+                                 stdout = "f4.c 2\n")
+
+test.run(chdir='work1', arguments='../build/var5', stdout=test.wrap_stdout("""\
+scons: `%s' is up to date.
+""" % test.workpath('build', 'var5')))
+
+test.pass_test()
similarity index 98%
rename from test/CacheDir/timestamp-content.py
rename to test/Deprecated/CacheDir/timestamp-content.py
index 6434d0cee67eeac9ff6711f5feebc4a9686e9a5c..850c369a53da607607c64137c6b65e74269d3463 100644 (file)
@@ -34,6 +34,7 @@ import TestSCons
 test = TestSCons.TestSCons()
 
 test.write('SConstruct', """
+SetOption('warn', 'no-deprecated')
 SourceSignatures('timestamp')
 TargetSignatures('content')
 CacheDir('cache')
similarity index 98%
rename from test/CacheDir/timestamp-timestamp.py
rename to test/Deprecated/CacheDir/timestamp-timestamp.py
index 2bef1cd908b070a08ee474df4ed4c3014efbebae..73dce091e0f4afb8d603cdb099bfdc6fb7a32bd8 100644 (file)
@@ -34,6 +34,7 @@ import TestSCons
 test = TestSCons.TestSCons()
 
 test.write(['SConstruct'], """\
+SetOption('warn', 'no-deprecated')
 SourceSignatures('timestamp')
 TargetSignatures('timestamp')
 CacheDir('cache')
diff --git a/test/Deprecated/Copy.py b/test/Deprecated/Copy.py
new file mode 100644 (file)
index 0000000..f17fc9f
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify the message about the deprecated env.Copy() message, and the
+ability to suppress it.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+test.write('SConstruct', """
+env = Environment().Copy()
+env.Copy()
+""")
+
+expect = """
+scons: warning: The env.Copy() method is deprecated; use the env.Clone() method instead.
+"""
+
+test.run(arguments = '.',
+         stderr = TestSCons.re_escape(expect) + TestSCons.file_expr)
+
+test.run(arguments = '--warn=no-deprecated .')
+
+test.run(arguments = '--warn=no-deprecated-copy .')
+
+test.pass_test()
similarity index 95%
rename from test/BuildDir/Sconscript-build_dir.py
rename to test/Deprecated/SConscript-build_dir.py
index 50e2c4f2d4d698320ae2ddfaa71cf460867064f1..1e623af0779b689773ef34e8805e595deccc4f58 100644 (file)
@@ -25,7 +25,9 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that specifying a build_dir argument to SConscript works properly.
+Verify that specifying a build_dir argument to SConscript still works.
+
+Note that the build_dir argument does not yet print a deprecation warning.
 """
 
 import TestSCons
@@ -75,7 +77,7 @@ SConscript('src/SConscript', build_dir='build/var2', src_dir=src)
 
 SConscript('src/SConscript', build_dir='build/var3', duplicate=0)
 
-#XXX We can't support var4 and var5 yet, because our BuildDir linkage
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
 #XXX is to an entire source directory.  We haven't yet generalized our
 #XXX infrastructure to be able to take the SConscript file from one source
 #XXX directory, but the rest of the files from a different one.
@@ -92,7 +94,7 @@ env.SConscript('src/SConscript', build_dir='../$BUILD/var8', duplicate=0)
 # we set the path of the SConscript accordingly.  The below is
 # equivalent to saying:
 #
-# BuildDir('build/var9', '.')
+# VariantDir('build/var9', '.')
 # SConscript('build/var9/src/SConscript')
 SConscript('src/SConscript', build_dir='build/var9', src_dir='.')
 """) 
@@ -123,7 +125,7 @@ all_alt = "test/alt/aaa.in\ntest/alt/bbb.in\ntest/alt/ccc.in\n"
 test.must_match(all1, all_src)
 test.must_match(all2, all_src)
 test.must_match(all3, all_src)
-#XXX We can't support var4 and var5 yet, because our BuildDir linkage
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
 #XXX is to an entire source directory.  We haven't yet generalized our
 #XXX infrastructure to be able to take the SConscript file from one source
 #XXX directory, but the rest of the files from a different one.
@@ -161,7 +163,7 @@ test.must_not_exist(test.workpath('test', 'build', 'var3', 'aaa.in'))
 test.must_not_exist(test.workpath('test', 'build', 'var3', 'bbb.in'))
 test.must_not_exist(test.workpath('test', 'build', 'var3', 'ccc.in'))
  
-#XXX We can't support var4 and var5 yet, because our BuildDir linkage
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
 #XXX is to an entire source directory.  We haven't yet generalized our
 #XXX infrastructure to be able to take the SConscript file from one source
 #XXX directory, but the rest of the files from a different one.
@@ -170,7 +172,7 @@ test.must_not_exist(test.workpath('test', 'build', 'var3', 'ccc.in'))
 #XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'bbb.in'))
 #XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'ccc.in'))
 
-#XXX We can't support var4 and var5 yet, because our BuildDir linkage
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
 #XXX is to an entire source directory.  We haven't yet generalized our
 #XXX infrastructure to be able to take the SConscript file from one source
 #XXX directory, but the rest of the files from a different one.
similarity index 79%
rename from test/SourceSignatures/basic.py
rename to test/Deprecated/SourceSignatures/basic.py
index 7042fac51b74e35790466467a26f30498487729e..50122963d9b132dd7156c86af0e2046b433dee3f 100644 (file)
@@ -26,14 +26,16 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import os
 import os.path
+import re
 
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 
 
 base_sconstruct_contents = """\
+SetOption('warn', 'no-deprecated-source-signatures')
 def build(env, target, source):
     open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
 B = Builder(action = build)
@@ -59,15 +61,17 @@ test.write('f2.in', "f2.in\n")
 test.write('f3.in', "f3.in\n")
 test.write('f4.in', "f4.in\n")
 
-test.run(arguments = 'f1.out f3.out')
+test.run(arguments = 'f1.out f3.out',
+         stderr = TestSCons.deprecated_python_expr)
 
 test.run(arguments = 'f1.out f2.out f3.out f4.out',
-         stdout = test.wrap_stdout("""\
+         stdout = re.escape(test.wrap_stdout("""\
 scons: `f1.out' is up to date.
 build(["f2.out"], ["f2.in"])
 scons: `f3.out' is up to date.
 build(["f4.out"], ["f4.in"])
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -79,12 +83,13 @@ os.utime(test.workpath('f3.in'),
           os.path.getmtime(test.workpath('f3.in'))+10))
 
 test.run(arguments = 'f1.out f2.out f3.out f4.out',
-         stdout = test.wrap_stdout("""\
+         stdout = re.escape(test.wrap_stdout("""\
 build(["f1.out"], ["f1.in"])
 scons: `f2.out' is up to date.
 build(["f3.out"], ["f3.in"])
 scons: `f4.out' is up to date.
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -93,7 +98,8 @@ scons: `f4.out' is up to date.
 
 write_SConstruct(test, 'MD5')
 
-test.not_up_to_date(arguments = 'f1.out f2.out f3.out f4.out')
+test.not_up_to_date(arguments = 'f1.out f2.out f3.out f4.out',
+                    stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -104,20 +110,20 @@ test.write('f2.in', "f2.in\n")
 test.write('f3.in', "f3.in\n")
 test.write('f4.in', "f4.in\n")
 
-test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out')
+test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out', stderr = None)
 
 
 
 test.touch('f1.in', os.path.getmtime(test.workpath('f1.in'))+10)
 test.touch('f3.in', os.path.getmtime(test.workpath('f3.in'))+10)
 
-test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out')
+test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out', stderr = None)
 
 
 
 write_SConstruct(test, None)
 
-test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out')
+test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out', stderr = None)
 
 
 
similarity index 82%
rename from test/SourceSignatures/env.py
rename to test/Deprecated/SourceSignatures/env.py
index 3bef2a69a6d545db8a9ebf3028a00525e385ec32..ec6d3d273a78271633079a144ae2616a77867f8f 100644 (file)
@@ -31,17 +31,19 @@ default behavior.
 
 import os
 import os.path
+import re
 
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 base_sconstruct_contents = """\
+SetOption('warn', 'no-deprecated-source-signatures')
 def build(env, target, source):
     open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
 B = Builder(action = build)
 env = Environment(BUILDERS = { 'B' : B })
-env2 = env.Copy()
+env2 = env.Clone()
 env2.SourceSignatures('%s')
 env.B(target = 'f1.out', source = 'f1.in')
 env.B(target = 'f2.out', source = 'f2.in')
@@ -64,15 +66,17 @@ test.write('f2.in', "f2.in\n")
 test.write('f3.in', "f3.in\n")
 test.write('f4.in', "f4.in\n")
 
-test.run(arguments = 'f1.out f3.out')
+test.run(arguments = 'f1.out f3.out',
+         stderr = TestSCons.deprecated_python_expr)
 
 test.run(arguments = 'f1.out f2.out f3.out f4.out',
-         stdout = test.wrap_stdout("""\
+         stdout = re.escape(test.wrap_stdout("""\
 scons: `f1.out' is up to date.
 build(["f2.out"], ["f2.in"])
 scons: `f3.out' is up to date.
 build(["f4.out"], ["f4.in"])
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -82,14 +86,15 @@ test.touch('f1.in')
 test.touch('f3.in')
 
 test.run(arguments = 'f1.out f2.out f3.out f4.out',
-         stdout = test.wrap_stdout("""\
+         stdout = re.escape(test.wrap_stdout("""\
 build(["f1.out"], ["f1.in"])
 scons: `f2.out' is up to date.
 scons: `f3.out' is up to date.
 scons: `f4.out' is up to date.
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
-test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out')
+test.up_to_date(arguments = 'f1.out f2.out f3.out f4.out', stderr = None)
 
 
 
similarity index 71%
rename from test/SourceSignatures/implicit-cache.py
rename to test/Deprecated/SourceSignatures/implicit-cache.py
index de66b72f349de80667a924308f9fb5cf85fd2eaf..44c30ce44867aa5dffe54f6ae7e823a7f5384b8e 100644 (file)
@@ -29,11 +29,14 @@ Test the simultaneous use of implicit_cache and
 SourceSignatures('timestamp')
 """
 
+import re
+
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 test.write('SConstruct', """\
+SetOption('warn', 'no-deprecated-source-signatures')
 SetOption('implicit_cache', 1)
 SourceSignatures('timestamp')
 
@@ -44,13 +47,15 @@ env = Environment(BUILDERS = { 'B' : B })
 env.B(target = 'both.out', source = 'both.in')
 """)
 
-both_out_both_in = test.wrap_stdout('build(["both.out"], ["both.in"])\n')
+both_out_both_in = re.escape(test.wrap_stdout('build(["both.out"], ["both.in"])\n'))
 
 
 
 test.write('both.in', "both.in 1\n")
 
-test.run(arguments = 'both.out', stdout = both_out_both_in)
+test.run(arguments = 'both.out',
+         stdout = both_out_both_in,
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -58,7 +63,9 @@ test.sleep(2)
 
 test.write('both.in', "both.in 2\n")
 
-test.run(arguments = 'both.out', stdout = both_out_both_in)
+test.run(arguments = 'both.out',
+         stdout = both_out_both_in,
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -66,7 +73,9 @@ test.sleep(2)
 
 test.write('both.in', "both.in 3\n")
 
-test.run(arguments = 'both.out', stdout = both_out_both_in)
+test.run(arguments = 'both.out',
+         stdout = both_out_both_in,
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -74,13 +83,15 @@ test.sleep(2)
 
 test.write('both.in', "both.in 4\n")
 
-test.run(arguments = 'both.out', stdout = both_out_both_in)
+test.run(arguments = 'both.out',
+         stdout = both_out_both_in,
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
 test.sleep(2)
 
-test.up_to_date(arguments = 'both.out')
+test.up_to_date(arguments = 'both.out', stderr = None)
 
 
 
similarity index 93%
rename from test/SourceSignatures/no-csigs.py
rename to test/Deprecated/SourceSignatures/no-csigs.py
index 37029011942fffacca11a3e9bf4bd20fbdcc8b3b..01d05daee959435a5c9721eac3016281674f8819 100644 (file)
@@ -28,12 +28,14 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import os
 import os.path
 
+import TestSCons
 import TestSConsign
 
 test = TestSConsign.TestSConsign(match = TestSConsign.match_re)
 
 
 test.write('SConstruct', """\
+SetOption('warn', 'no-deprecated-source-signatures')
 def build(env, target, source):
     open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
 B = Builder(action = build)
@@ -46,7 +48,8 @@ SourceSignatures('timestamp')
 test.write('f1.in', "f1.in\n")
 test.write('f2.in', "f2.in\n")
 
-test.run(arguments = '.')
+test.run(arguments = '.',
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
similarity index 85%
rename from test/SourceSignatures/overrides.py
rename to test/Deprecated/SourceSignatures/overrides.py
index cf83488b721ab019497c45a88be1521ca46afd5e..de1cc95b476d447543bc8580735e01c40ffefe35 100644 (file)
@@ -34,9 +34,10 @@ content signature.)
 
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 test.write('SConstruct', """\
+SetOption('warn', 'no-deprecated-source-signatures')
 DefaultEnvironment().SourceSignatures('MD5')
 env = Environment()
 env.SourceSignatures('timestamp')
@@ -45,12 +46,14 @@ env.Command('foo.out', 'foo.in', Copy('$TARGET', '$SOURCE'), FOO=1)
 
 test.write('foo.in', "foo.in 1\n")
 
-test.run(arguments = 'foo.out')
+test.run(arguments = 'foo.out',
+         stderr = TestSCons.deprecated_python_expr)
 
 test.sleep()
 
 test.write('foo.in', "foo.in 1\n")
 
-test.not_up_to_date(arguments = 'foo.out')
+test.not_up_to_date(arguments = 'foo.out',
+                    stderr = TestSCons.deprecated_python_expr)
 
 test.pass_test()
similarity index 74%
rename from test/SourceSignatures/switch-rebuild.py
rename to test/Deprecated/SourceSignatures/switch-rebuild.py
index 85c2b221d85024911c4f67f2eab3b7235c5bf658..07b59fb4b12ddf3af84437811d9398a46dade721 100644 (file)
@@ -28,12 +28,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 Test that switching SourceSignature() types no longer causes rebuilds.
 """
 
+import re
+
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 
 base_sconstruct_contents = """\
+SetOption('warn', 'no-deprecated-source-signatures')
 SourceSignatures('%s')
 
 def build(env, target, source):
@@ -52,29 +55,33 @@ write_SConstruct(test, 'MD5')
 
 test.write('switch.in', "switch.in\n")
 
-switch_out_switch_in = test.wrap_stdout('build(["switch.out"], ["switch.in"])\n')
+switch_out_switch_in = re.escape(test.wrap_stdout('build(["switch.out"], ["switch.in"])\n'))
 
-test.run(arguments = 'switch.out', stdout = switch_out_switch_in)
+test.run(arguments = 'switch.out',
+         stdout = switch_out_switch_in,
+         stderr = TestSCons.deprecated_python_expr)
 
-test.up_to_date(arguments = 'switch.out')
+test.up_to_date(arguments = 'switch.out', stderr = None)
 
 
 
 write_SConstruct(test, 'timestamp')
 
-test.up_to_date(arguments = 'switch.out')
+test.up_to_date(arguments = 'switch.out', stderr = None)
 
 
 
 write_SConstruct(test, 'MD5')
 
-test.not_up_to_date(arguments = 'switch.out')
+test.not_up_to_date(arguments = 'switch.out', stderr = None)
 
 
 
 test.write('switch.in', "switch.in 2\n")
 
-test.run(arguments = 'switch.out', stdout = switch_out_switch_in)
+test.run(arguments = 'switch.out',
+         stdout = switch_out_switch_in,
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
similarity index 85%
rename from test/TargetSignatures/build-content.py
rename to test/Deprecated/TargetSignatures/build-content.py
index 2cd7a89a6db43f9c0710efafaccc1dfb03787293..6fd031e4f3b40527f91f9e79aea3415062944910 100644 (file)
@@ -30,13 +30,16 @@ and TargetSignatures('content') settings, overriding one with
 the other in specific construction environments.
 """
 
+import re
+
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 
 
 sconstruct_contents = """\
+SetOption('warn', 'no-deprecated-target-signatures')
 env = Environment()
 
 def copy1(env, source, target):
@@ -72,14 +75,15 @@ test.write('foo.in', 'foo.in')
 test.write('bar.in', 'bar.in')
 
 test.run(arguments="bar.out foo.out",
-         stdout=test.wrap_stdout("""\
+         stdout=re.escape(test.wrap_stdout("""\
 copy2(["bar.mid"], ["bar.in"])
 copy1(["bar.out"], ["bar.mid"])
 copy2(["foo.mid"], ["foo.in"])
 copy1(["foo.out"], ["foo.mid"])
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
-test.up_to_date(arguments='bar.out foo.out')
+test.up_to_date(arguments='bar.out foo.out', stderr=None)
 
 
 
@@ -89,12 +93,13 @@ test.up_to_date(arguments='bar.out foo.out')
 write_SConstruct(test, 'x = 2 # added this line', 'build', 'content')
 
 test.run(arguments="bar.out foo.out",
-         stdout=test.wrap_stdout("""\
+         stdout=re.escape(test.wrap_stdout("""\
 copy2(["bar.mid"], ["bar.in"])
 copy1(["bar.out"], ["bar.mid"])
 copy2(["foo.mid"], ["foo.in"])
 scons: `foo.out' is up to date.
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
@@ -103,7 +108,7 @@ scons: `foo.out' is up to date.
 
 write_SConstruct(test, 'x = 2 # added this line', 'content', 'build')
 
-test.up_to_date(arguments="bar.out foo.out")
+test.up_to_date(arguments="bar.out foo.out", stderr=None)
 
 
 
@@ -113,12 +118,13 @@ test.up_to_date(arguments="bar.out foo.out")
 write_SConstruct(test, '', 'content', 'build')
 
 test.run(arguments='bar.out foo.out',
-         stdout=test.wrap_stdout("""\
+         stdout=re.escape(test.wrap_stdout("""\
 copy2(["bar.mid"], ["bar.in"])
 scons: `bar.out' is up to date.
 copy2(["foo.mid"], ["foo.in"])
 copy1(["foo.out"], ["foo.mid"])
-"""))
+""")),
+         stderr = TestSCons.deprecated_python_expr)
 
 
 
similarity index 88%
rename from test/TargetSignatures/content.py
rename to test/Deprecated/TargetSignatures/content.py
index 8d9f21373923856a5c2d7cb40694cf113cc2d2e1..4de14224601a65c0c66d41fbd6b0c6a68545e930 100644 (file)
@@ -31,11 +31,13 @@ SourceSignatures('timestamp') settings.
 
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 
 
 test.write('SConstruct', """\
+SetOption('warn', 'no-deprecated-source-signatures')
+SetOption('warn', 'no-deprecated-target-signatures')
 env = Environment()
 
 def copy(env, source, target):
@@ -65,14 +67,14 @@ test.write('foo.in', "foo.in\n")
 test.write('bar.in', "bar.in\n")
 test.write('extra.in', "extra.in 1\n")
 
-test.run()
+test.run(stderr = TestSCons.deprecated_python_expr)
 
 test.must_match('final', "foo.in\nbar.in\nextra.in 1\n")
 
 test.sleep()
 test.write('extra.in', "extra.in 2\n")
 
-test.run()
+test.run(stderr = TestSCons.deprecated_python_expr)
 
 test.must_match('final', "foo.in\nbar.in\nextra.in 1\n")
 
similarity index 90%
rename from test/TargetSignatures/overrides.py
rename to test/Deprecated/TargetSignatures/overrides.py
index 5d9dd994ab5e05a3f07ffa786d52d6c3e0812272..327218ecf94fe8b06ef8e614a2e19ed4480ca1a3 100644 (file)
@@ -33,9 +33,10 @@ behavior like infinite recursion.
 
 import TestSCons
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 test.write('SConstruct', """\
+SetOption('warn', 'no-deprecated-target-signatures')
 env = Environment()
 env.TargetSignatures('content')
 env.Command('foo.out', 'foo.mid', Copy('$TARGET', '$SOURCE'), FOO=1)
@@ -44,7 +45,8 @@ env.Command('foo.mid', 'foo.in', Copy('$TARGET', '$SOURCE'), FOO=2)
 
 test.write('foo.in', "foo.in\n")
 
-test.run(arguments = '.')
+test.run(arguments = '.',
+         stderr = TestSCons.deprecated_python_expr)
 
 test.must_match('foo.mid', "foo.in\n")
 test.must_match('foo.out', "foo.in\n")
similarity index 87%
rename from test/option/debug-dtree.py
rename to test/Deprecated/debug-dtree.py
index 3ef396ea17f6c2f04b2a6bd84e1d2ce4606eb9e9..2aec8804fa70a0f3f4eaf87267641037aa39295e 100644 (file)
@@ -35,7 +35,7 @@ import string
 import re
 import time
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 test.write('SConstruct', """
 env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx')
@@ -73,13 +73,20 @@ test.write('bar.h', """
 #endif
 """)
 
+expect = """
+scons: warning: The --debug=dtree option is deprecated; please use --tree=derived instead.
+"""
+
+stderr = TestSCons.re_escape(expect) + TestSCons.file_expr
+
 dtree1 = """
 +-foo.xxx
   +-foo.ooo
   +-bar.ooo
 """
 
-test.run(arguments = "--debug=dtree foo.xxx")
+test.run(arguments = "--debug=dtree foo.xxx",
+         stderr = stderr)
 test.fail_test(string.find(test.stdout(), dtree1) == -1)
 
 dtree2 = """
@@ -90,7 +97,8 @@ dtree2 = """
     +-foo.ooo
     +-bar.ooo
 """
-test.run(arguments = "--debug=dtree .")
+test.run(arguments = "--debug=dtree .",
+         stderr = stderr)
 test.fail_test(string.find(test.stdout(), dtree2) == -1)
 
 # Make sure we print the debug stuff even if there's a build failure.
similarity index 88%
rename from test/option/debug-stree.py
rename to test/Deprecated/debug-stree.py
index bf65dbb989fbfa56a8f60dad1509bfc7a79cb455..8907c6c286ed841721f2a7c9e8183f24430f6807 100644 (file)
@@ -35,7 +35,7 @@ import string
 import re
 import time
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 CC = test.detect('CC')
 LINK = test.detect('LINK')
@@ -77,6 +77,12 @@ test.write('bar.h', """
 #endif
 """)
 
+expect = """
+scons: warning: The --debug=stree option is deprecated; please use --tree=all,status instead.
+"""
+
+stderr = TestSCons.re_escape(expect) + TestSCons.file_expr
+
 stree = """
 [E B   C  ]+-foo.xxx
 [E B   C  ]  +-foo.ooo
@@ -92,7 +98,8 @@ stree = """
 [E     C  ]  +-%(LINK)s
 """ % locals()
 
-test.run(arguments = "--debug=stree foo.xxx")
+test.run(arguments = "--debug=stree foo.xxx",
+         stderr = stderr)
 test.fail_test(string.find(test.stdout(), stree) == -1)
 
 stree2 = """
@@ -123,7 +130,8 @@ stree2 = """
 
 test.run(arguments = '-c foo.xxx')
 
-test.run(arguments = "--no-exec --debug=stree foo.xxx")
+test.run(arguments = "--no-exec --debug=stree foo.xxx",
+         stderr = stderr)
 test.fail_test(string.find(test.stdout(), stree2) == -1)
 
 test.pass_test()
similarity index 90%
rename from test/option/debug-tree.py
rename to test/Deprecated/debug-tree.py
index f581bc484657aeb3fa3c847ce44b75642159a190..0703a167b59f95bede1a191c7a5ed2a6989cc0f9 100644 (file)
@@ -35,7 +35,7 @@ import string
 import re
 import time
 
-test = TestSCons.TestSCons()
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 CC = test.detect('CC')
 LINK = test.detect('LINK')
@@ -81,6 +81,12 @@ test.write('Bar.h', """
 #endif
 """)
 
+expect = """
+scons: warning: The --debug=tree option is deprecated; please use --tree=all instead.
+"""
+
+stderr = TestSCons.re_escape(expect) + TestSCons.file_expr
+
 tree1 = """
 +-Foo.xxx
   +-Foo.ooo
@@ -96,7 +102,8 @@ tree1 = """
   +-%(LINK)s
 """ % locals()
 
-test.run(arguments = "--debug=tree Foo.xxx")
+test.run(arguments = "--debug=tree Foo.xxx",
+         stderr = stderr)
 if string.find(test.stdout(), tree1) == -1:
     sys.stdout.write('Did not find expected tree in the following output:\n')
     sys.stdout.write(test.stdout())
@@ -133,7 +140,8 @@ tree2 = """
   +-SConstruct
 """ % locals()
 
-test.run(arguments = "--debug=tree .")
+test.run(arguments = "--debug=tree .",
+         stderr = stderr)
 if string.find(test.stdout(), tree2) == -1:
     sys.stdout.write('Did not find expected tree in the following output:\n')
     sys.stdout.write(test.stdout())
index 985266051ee08d9d2d4745ea47dc583d23e57fec..68165f30da4a12eb46e4bf64afa39b567a79036d 100644 (file)
@@ -37,10 +37,10 @@ import TestSCons
 
 test = TestSCons.TestSCons()
 
-test.subdir('bsig', [ 'bsig', 'subdir' ],
-            'csig', [ 'csig', 'subdir' ],
-            'cmd-bsig', [ 'cmd-bsig', 'subdir' ],
-            'cmd-csig', [ 'cmd-csig', 'subdir' ])
+test.subdir('tstamp', [ 'tstamp', 'subdir' ],
+            'content', [ 'content', 'subdir' ],
+            'cmd-tstamp', [ 'cmd-tstamp', 'subdir' ],
+            'cmd-content', [ 'cmd-content', 'subdir' ])
 
 test.write('SConstruct', """\
 def writeTarget(target, source, env):
@@ -57,114 +57,114 @@ env = Environment()
 env['BUILDERS']['TestDir'] = test_bld_dir
 env['BUILDERS']['TestFile'] = test_bld_file
 
-env_bsig = env.Clone()
-env_bsig.TargetSignatures('build')
-env_bsig.TestFile(source='junk.txt', target='bsig/junk.out')
-env_bsig.TestDir(source='bsig', target='bsig.out')
-env_bsig.Command('cmd-bsig-noscan.out', 'cmd-bsig', writeTarget)
-env_bsig.Command('cmd-bsig.out', 'cmd-bsig', writeTarget,
+env_tstamp = env.Clone()
+env_tstamp.Decider('timestamp-newer')
+env_tstamp.TestFile(source='junk.txt', target='tstamp/junk.out')
+env_tstamp.TestDir(source='tstamp', target='tstamp.out')
+env_tstamp.Command('cmd-tstamp-noscan.out', 'cmd-tstamp', writeTarget)
+env_tstamp.Command('cmd-tstamp.out', 'cmd-tstamp', writeTarget,
                  source_scanner=DirScanner)
 
-env_csig = env.Clone()
-env_csig.TargetSignatures('content')
-env_csig.TestFile(source='junk.txt', target='csig/junk.out')
-env_csig.TestDir(source='csig', target='csig.out')
-env_csig.Command('cmd-csig-noscan.out', 'cmd-csig', writeTarget)
-env_csig.Command('cmd-csig.out', 'cmd-csig', writeTarget,
+env_content = env.Clone()
+env_content.Decider('content')
+env_content.TestFile(source='junk.txt', target='content/junk.out')
+env_content.TestDir(source='content', target='content.out')
+env_content.Command('cmd-content-noscan.out', 'cmd-content', writeTarget)
+env_content.Command('cmd-content.out', 'cmd-content', writeTarget,
                  source_scanner=DirScanner)
 """)
 
-test.write([ 'bsig', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'bsig', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'bsig', 'subdir', 'bar.txt'], 'bar.txt 1\n')
-test.write([ 'bsig', 'subdir', '#hash.txt'], 'hash.txt 1\n')
-test.write([ 'csig', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'csig', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'csig', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'csig', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-bsig', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'cmd-bsig', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-bsig', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'cmd-bsig', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
-test.write([ 'cmd-csig', 'foo.txt' ], 'foo.txt 1\n')
-test.write([ 'cmd-csig', '#hash.txt' ], '#hash.txt 1\n')
-test.write([ 'cmd-csig', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
-test.write([ 'cmd-csig', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 1\n')
+test.write([ 'tstamp', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'tstamp', 'subdir', 'bar.txt'], 'bar.txt 1\n')
+test.write([ 'tstamp', 'subdir', '#hash.txt'], 'hash.txt 1\n')
+test.write([ 'content', 'foo.txt' ], 'foo.txt 1\n')
+test.write([ 'content', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
+test.write([ 'content', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 1\n')
+test.write([ 'cmd-tstamp', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
+test.write([ 'cmd-tstamp', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
+test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 1\n')
+test.write([ 'cmd-content', '#hash.txt' ], '#hash.txt 1\n')
+test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 1\n')
+test.write([ 'cmd-content', 'subdir', '#hash.txt' ], 'hash.txt 1\n')
 test.write('junk.txt', 'junk.txt\n')
 
 test.run(arguments=".", stderr=None)
-test.must_match('bsig.out', 'stuff\n')
-test.must_match('csig.out', 'stuff\n')
-test.must_match('cmd-bsig.out', 'stuff\n')
-test.must_match('cmd-csig.out', 'stuff\n')
-test.must_match('cmd-bsig-noscan.out', 'stuff\n')
-test.must_match('cmd-csig-noscan.out', 'stuff\n')
+test.must_match('tstamp.out', 'stuff\n')
+test.must_match('content.out', 'stuff\n')
+test.must_match('cmd-tstamp.out', 'stuff\n')
+test.must_match('cmd-content.out', 'stuff\n')
+test.must_match('cmd-tstamp-noscan.out', 'stuff\n')
+test.must_match('cmd-content-noscan.out', 'stuff\n')
 
-test.up_to_date(arguments='bsig.out')
-test.up_to_date(arguments='csig.out')
-test.up_to_date(arguments='cmd-bsig.out')
-test.up_to_date(arguments='cmd-csig.out')
-test.up_to_date(arguments='cmd-bsig-noscan.out')
-test.up_to_date(arguments='cmd-csig-noscan.out')
+test.up_to_date(arguments='tstamp.out')
+test.up_to_date(arguments='content.out')
+test.up_to_date(arguments='cmd-tstamp.out')
+test.up_to_date(arguments='cmd-content.out')
+test.up_to_date(arguments='cmd-tstamp-noscan.out')
+test.up_to_date(arguments='cmd-content-noscan.out')
 
-test.write([ 'bsig', 'foo.txt' ], 'foo.txt 2\n')
-test.not_up_to_date(arguments='bsig.out')
+test.write([ 'tstamp', 'foo.txt' ], 'foo.txt 2\n')
+test.not_up_to_date(arguments='tstamp.out')
 
-test.write([ 'bsig', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='bsig.out')
+test.write([ 'tstamp', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='tstamp.out')
 
-test.write([ 'csig', 'foo.txt' ], 'foo.txt 2\n')
-test.not_up_to_date(arguments='csig.out')
+test.write([ 'content', 'foo.txt' ], 'foo.txt 2\n')
+test.not_up_to_date(arguments='content.out')
 
-test.write([ 'csig', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='csig.out')
+test.write([ 'content', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='content.out')
 
-test.write([ 'cmd-bsig', 'foo.txt' ], 'foo.txt 2\n')
-test.not_up_to_date(arguments='cmd-bsig.out')
-test.up_to_date(arguments='cmd-bsig-noscan.out')
+test.write([ 'cmd-tstamp', 'foo.txt' ], 'foo.txt 2\n')
+test.not_up_to_date(arguments='cmd-tstamp.out')
+test.up_to_date(arguments='cmd-tstamp-noscan.out')
 
-test.write([ 'cmd-bsig', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='cmd-bsig.out')
-test.up_to_date(arguments='cmd-bsig-noscan.out')
+test.write([ 'cmd-tstamp', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='cmd-tstamp.out')
+test.up_to_date(arguments='cmd-tstamp-noscan.out')
 
-test.write([ 'cmd-csig', 'foo.txt' ], 'foo.txt 2\n')
-test.not_up_to_date(arguments='cmd-csig.out')
-test.up_to_date(arguments='cmd-csig-noscan.out')
+test.write([ 'cmd-content', 'foo.txt' ], 'foo.txt 2\n')
+test.not_up_to_date(arguments='cmd-content.out')
+test.up_to_date(arguments='cmd-content-noscan.out')
 
-test.write([ 'cmd-csig', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='cmd-csig.out')
-test.up_to_date(arguments='cmd-csig-noscan.out')
+test.write([ 'cmd-content', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='cmd-content.out')
+test.up_to_date(arguments='cmd-content-noscan.out')
 
-test.write([ 'bsig', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
-test.not_up_to_date(arguments='bsig.out')
+test.write([ 'tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.not_up_to_date(arguments='tstamp.out')
 
-test.write([ 'bsig', 'subdir', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='bsig.out')
+test.write([ 'tstamp', 'subdir', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='tstamp.out')
 
-test.write([ 'csig', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
-test.not_up_to_date(arguments='csig.out')
+test.write([ 'content', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.not_up_to_date(arguments='content.out')
 
-test.write([ 'csig', 'subdir', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='csig.out')
+test.write([ 'content', 'subdir', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='content.out')
 
-test.write([ 'cmd-bsig', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
-test.not_up_to_date(arguments='cmd-bsig.out')
-test.up_to_date(arguments='cmd-bsig-noscan.out')
+test.write([ 'cmd-tstamp', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.not_up_to_date(arguments='cmd-tstamp.out')
+test.up_to_date(arguments='cmd-tstamp-noscan.out')
 
-test.write([ 'cmd-bsig', 'subdir', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='cmd-bsig.out')
-test.up_to_date(arguments='cmd-bsig-noscan.out')
+test.write([ 'cmd-tstamp', 'subdir', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='cmd-tstamp.out')
+test.up_to_date(arguments='cmd-tstamp-noscan.out')
 
-test.write([ 'cmd-csig', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
-test.not_up_to_date(arguments='cmd-csig.out')
-test.up_to_date(arguments='cmd-csig-noscan.out')
+test.write([ 'cmd-content', 'subdir', 'bar.txt' ], 'bar.txt 2\n')
+test.not_up_to_date(arguments='cmd-content.out')
+test.up_to_date(arguments='cmd-content-noscan.out')
 
-test.write([ 'cmd-csig', 'subdir', 'new.txt' ], 'new.txt\n')
-test.not_up_to_date(arguments='cmd-csig.out')
-test.up_to_date(arguments='cmd-csig-noscan.out')
+test.write([ 'cmd-content', 'subdir', 'new.txt' ], 'new.txt\n')
+test.not_up_to_date(arguments='cmd-content.out')
+test.up_to_date(arguments='cmd-content-noscan.out')
 
 test.write('junk.txt', 'junk.txt 2\n')
-test.not_up_to_date(arguments='bsig.out')
-test.not_up_to_date(arguments='csig.out')
+test.not_up_to_date(arguments='tstamp.out')
+test.not_up_to_date(arguments='content.out')
 
 test.pass_test()
index 4dd8f515e1afeb94aca8826731bb98ed45227644..738954f02edd88373c0a313ce8d819b89a5bd242 100644 (file)
@@ -58,7 +58,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f77')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(F77PATH=[include, '#foobar', '#subdir'],
                   LIBS = %s,
@@ -246,7 +246,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f77')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(F77PATH=['inc2', include, '#foobar', '#subdir'],
                   LIBS = %s,
index f1fac46936e2009378ecfc2599394bba90e2489c..fb159cfb9cd87e96bf2272bfe6016e8317811aeb 100644 (file)
@@ -78,7 +78,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f90')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(F90 = r'%s',
                   F90PATH=[include, '#foobar', '#subdir'],
@@ -270,7 +270,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f90')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(F90 = r'%s',
                   F90PATH=['inc2', include, '#foobar', '#subdir'],
index 20a92d2f0a0e79cc34f68369f908491f785491c1..5f9d02255fffc9e30cbbd41426d2db199f9fc884 100644 (file)
@@ -56,7 +56,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(FORTRANPATH=[include, '#foobar', '#subdir'],
                   LIBS = %s)
@@ -242,7 +242,7 @@ obj = env.Object(target='foobar/prog', source='subdir/prog.f')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(FORTRANPATH=['inc2', include, '#foobar', '#subdir'],
                   LIBS = %s)
index cfadd0ddca8e7aa908d923d7b5f3fe21227bc054..789cfbfea32b34f228034fc054c8ff24838a2619 100644 (file)
@@ -98,25 +98,34 @@ test.write('f4.in', "f4.in\n")
 test.write('f5.in', "f5.in\n")
 test.write('f6.in', "f6.in\n")
 
-expect_stdout = """\
-scons: Reading SConscript files ...
-scons: done reading SConscript files.
-scons: Building targets ...
-scons: building terminated because of errors.
-f4 failed:  Error 1
-f5 failed:  Error 1
-""" % locals()
-
 expect_stderr = """\
 scons: *** [f4] Error 1
 scons: *** [f5] Error 1
 """
 
-test.run(arguments = '-j 4 .',
+test.run(arguments = '-Q -j 4 .',
          status = 2,
-         stdout = expect_stdout,
          stderr = expect_stderr)
 
+# We jump through hoops above to try to make sure that the individual
+# commands execute and exit in the order we want, but we still can't be
+# 100% sure that SCons will actually detect and record the failures in
+# that order; the thread for f5 may detect its command's failure before
+# the thread for f4.  Just sidestep the issue by allowing the failure
+# strings in the output to come in either order.  If there's a genuine
+# problem in the way things get ordered, it'll show up in stderr.
+
+f4_failed = "f4 failed:  Error 1\n"
+f5_failed = "f5 failed:  Error 1\n"
+
+failed_45 = f4_failed + f5_failed
+failed_54 = f5_failed + f4_failed
+
+if test.stdout() not in [failed_45, failed_54]:
+    print "Did not find the following output in list of expected strings:"
+    print test.stdout(),
+    test.fail_test()
+
 test.must_match(test.workpath('f3'), 'f3.in\n')
 test.must_not_exist(test.workpath('f4'))
 test.must_not_exist(test.workpath('f5'))
similarity index 94%
rename from test/Glob/BuildDir.py
rename to test/Glob/VariantDir.py
index 274ca492042d1516c69578acd1bc06d5d3bda598..5f29b21a4a4d223aea0e2cdbf6852a21dbbff4a8 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that default use of the Glob() function within a BuildDir()
+Verify that default use of the Glob() function within a VariantDir()
 finds the local file Nodes.
 """
 
@@ -36,8 +36,8 @@ test = TestSCons.TestSCons()
 test.subdir('src')
 
 test.write('SConstruct', """\
-BuildDir('var1', 'src')
-BuildDir('var2', 'src')
+VariantDir('var1', 'src')
+VariantDir('var2', 'src')
 
 SConscript('var1/SConscript')
 SConscript('var2/SConscript')
index b82e1d9e148865db647da7d9615cc3ab7055283f..4142fc04361726cc0ef269fac2ec0e0fb9f3c166 100644 (file)
@@ -25,9 +25,9 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that use of the Glob() function within a BuildDir() returns the
+Verify that use of the Glob() function within a VariantDir() returns the
 file Nodes in the source directory when the source= keyword argument is
-specified (and duplicate=0 is specified for the BuildDir()).
+specified (and duplicate=0 is specified for the VariantDir()).
 """
 
 import TestSCons
@@ -49,8 +49,8 @@ env['BUILDERS']['Concatenate'] = Builder(action=concatenate)
 
 Export("env")
 
-BuildDir('var1', 'src', duplicate=0)
-BuildDir('var2', 'src', duplicate=0)
+VariantDir('var1', 'src', duplicate=0)
+VariantDir('var2', 'src', duplicate=0)
 
 SConscript('var1/SConscript')
 SConscript('var2/SConscript')
index d9f8ff1e9cd8c97dd15a7ddc74c0f6f4ec0b34c1..4852790539c918b72a1feaf9fcdebf4e2fd82b30 100644 (file)
@@ -37,8 +37,8 @@ test = TestSCons.TestSCons()
 test.subdir('src')
 
 test.write('SConstruct', """\
-BuildDir('var1', 'src')
-BuildDir('var2', 'src')
+VariantDir('var1', 'src')
+VariantDir('var2', 'src')
 
 SConscript('var1/SConscript')
 SConscript('var2/SConscript')
index 15ac086ca5ba9c1e3b24fa8343137a96d3e47037..810edc128d3ca4e0a5e6cdae2397f460ca928ed1 100644 (file)
@@ -49,10 +49,10 @@ env = Environment(CCFLAGS = ' -nologo ',
                   MSVS_USE_MFC_DIRS = 1)
 Export('env')
 
-BuildDir('build', 'src')
+VariantDir('build', 'src')
 SConscript(os.path.join('build','SConscript'))
 
-BuildDir('build2', 'src', duplicate=0)
+VariantDir('build2', 'src', duplicate=0)
 SConscript(os.path.join('build2','SConscript'))
 """)
 
index 6d44c456251b048736309957b14d6b87ea0d94a2..c38edaa1b09aeb2892494a86766027594ceaaa59 100644 (file)
@@ -82,6 +82,11 @@ env1.Install('.', r'%(f5_txt)s')
 env1.Install('export', r'%(f5_txt)s')
 env1.Install('.', r'%(f6_sep)s')
 env1.Install('export', r'%(f6_sep)s')
+
+# test passing a keyword arg (not used, but should be accepted)
+env7 = env1.Clone(EXPORT='export')
+env7.Install(dir='$EXPORT', source='./f1.in', FOO="bar")
+
 """ % locals())
 
 test.write(['work', 'f1.in'], "f1.in\n")
@@ -103,6 +108,7 @@ test.must_match(['work', 'f6.txt'],             "f6.txt\n")
 test.must_match(['work', 'export', 'f6.txt'],   "f6.txt\n")
 
 test.must_match(['work', 'my_install.out'], os.path.join('export', 'f3.out'))
+test.must_match(['work', 'export', 'f1.in'],   "f1.in\n")
 
 # make sure the programs didn't get rebuilt, because nothing changed:
 oldtime1 = os.path.getmtime(f1_out)
index 7a6c9f6c94e487964c28734614143f73d73bb3d3..0b810f011c1a99092a63b884b8e82971bd7f713f 100644 (file)
@@ -50,6 +50,8 @@ env = Environment(INSTALLDIR=r'%(install)s', SUBDIR='subdir')
 InstallAs(r'%(install_file1_out)s', 'file1.in')
 env.InstallAs([r'%(_INSTALLDIR_file2_out)s', r'%(install_file3_out)s'],
               ['file2.in', r'%(_SUBDIR_file3_in)s'])
+# test passing a keyword arg (not used, but should be accepted)
+env.InstallAs('install/f1.out', './file1.in', FOO="bar")
 """ % locals())
 
 test.write('file1.in', "file1.in\n")
@@ -59,10 +61,12 @@ test.write(['subdir', 'file3.in'], "subdir/file3.in\n")
 install_file1_out = os.path.join('install', 'file1.out')
 install_file2_out = os.path.join('install', 'file2.out')
 install_file3_out = os.path.join('install', 'file3.out')
+install_file1a_out = os.path.join('install', 'f1.out')
 
 subdir_file3_in = os.path.join('subdir', 'file3.in')
 
 expect = test.wrap_stdout("""\
+Install file: "file1.in" as "install/f1.out"
 Install file: "file1.in" as "%(install_file1_out)s"
 Install file: "file2.in" as "%(install_file2_out)s"
 Install file: "%(subdir_file3_in)s" as "%(install_file3_out)s"
@@ -73,6 +77,7 @@ test.run(arguments = '.', stdout=expect)
 test.fail_test(test.read(install_file1_out) != "file1.in\n")
 test.fail_test(test.read(install_file2_out) != "file2.in\n")
 test.fail_test(test.read(install_file3_out) != "subdir/file3.in\n")
+test.fail_test(test.read(install_file1a_out) != "file1.in\n")
 
 test.up_to_date(arguments = '.')
 
diff --git a/test/Install/wrap-by-attribute.py b/test/Install/wrap-by-attribute.py
new file mode 100644 (file)
index 0000000..f586618
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+
+Verify that we handle the case where Install() and InstallAs()
+Builder instances are saved and then re-used from a different, Clone()d
+construction environment, after the .Install() and .InstallAs() methods
+are replaced by wrappers that fetch the saved methods from a different
+environment.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('outside', 'sub')
+
+test.write('SConstruct', """\
+def cat(env, source, target):
+    target = str(target[0])
+    source = map(str, source)
+    f = open(target, "wb")
+    for src in source:
+        f.write(open(src, "rb").read())
+    f.close()
+
+env = Environment(DESTDIR='dest')
+env.Append(BUILDERS={'Cat':Builder(action=cat)})
+
+env.SconsInternalInstallFunc = env.Install
+env.SconsInternalInstallAsFunc = env.InstallAs
+
+def InstallWithDestDir(dir, source):
+    return env.SconsInternalInstallFunc('$DESTDIR'+env.Dir(dir).abspath, source)
+def InstallAsWithDestDir(target, source):
+    return env.SconsInternalInstallAsFunc('$DESTDIR'+env.File(target).abspath, source)
+
+# Add the wrappers directly as attributes.
+env.Install = InstallWithDestDir
+env.InstallAs = InstallAsWithDestDir
+
+e1 = env
+
+t = e1.Cat(target='f1.out', source='f1.in')
+e1.Install('export', source=t)
+t = e1.Cat(target='f2.out', source='f2.in')
+e1.InstallAs('export/f2-new.out', source=t)
+
+e2 = env.Clone()
+
+t = e2.Cat(target='f3.out', source='f3.in')
+e2.Install('export', source=t)
+t = e2.Cat(target='f4.out', source='f4.in')
+e2.InstallAs('export/f4-new.out', source=t)
+
+""")
+
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+
+test.run(arguments = '.')
+
+f1_out     = test.workpath('dest') + test.workpath('export', 'f1.out')
+f2_new_out = test.workpath('dest') + test.workpath('export', 'f2-new.out')
+f3_out     = test.workpath('dest') + test.workpath('export', 'f3.out')
+f4_new_out = test.workpath('dest') + test.workpath('export', 'f4-new.out')
+
+test.must_match(f1_out,         "f1.in\n")
+test.must_match(f2_new_out,     "f2.in\n")
+test.must_match(f3_out,         "f3.in\n")
+test.must_match(f4_new_out,     "f4.in\n")
+
+test.up_to_date(arguments = '.')
+
+test.pass_test()
similarity index 94%
rename from test/Interactive/implicit-BuildDir.py
rename to test/Interactive/implicit-VariantDir.py
index 7b7aa4b4a01e3eec3ed3e8aeb1f716b5cad57826..b69264b7f90ea21339e5a1a3ba521f5df7e94e39 100644 (file)
@@ -30,8 +30,8 @@ This is a regression test for a bug in earlier versions of the
 submitted by Adam Simpkins, who created this test case).
 
 It tests to make sure that cached state is cleared between files for
-nodes in both the build tree and the source tree when BuildDirs are used.
-This is needed especially with BuildDirs created with duplicate=0, since
+nodes in both the build tree and the source tree when VariantDirs are used.
+This is needed especially with VariantDirs created with duplicate=0, since
 the scanners scan the files in the source tree.  Any cached implicit
 deps must be cleared on the source files.
 """
@@ -55,7 +55,7 @@ hdr_dir = '#build/include'
 BUILD_ENV['HDR_DIR'] = hdr_dir
 BUILD_ENV.Append(CPPPATH = hdr_dir)
 
-BUILD_ENV.BuildDir('build', 'src', duplicate = 0)
+BUILD_ENV.VariantDir('build', 'src', duplicate = 0)
 SConscript('build/SConscript')
 
 Command('1', [], Touch('$TARGET'))
index 9cac75972025ee030da2282dc6ac2d641fde266d..cfa69063492cea88e2c8b7c4ad4ebffb3727dddd 100644 (file)
@@ -35,6 +35,7 @@ test = TestSCons.TestSCons()
 
 where_javac, java_version = test.java_where_javac()
 where_javah = test.java_where_javah()
+where_java_include=test.java_where_includes()
 
 swig = test.where_is('swig')
 if not swig:
@@ -64,6 +65,7 @@ test.subdir(['src'],
 test.write(['SConstruct'], """\
 import os,sys
 env=Environment(tools = ['default', 'javac', 'javah'],
+                CPPPATH=%(where_java_include)s,                 
                 JAVAC = r'%(where_javac)s',
                 JAVAH = r'%(where_javah)s')
 Export('env')
@@ -79,7 +81,7 @@ env.Append(SWIGFLAGS=['-c++','$_CPPINCFLAGS'])
 
 env.Append(CPPPATH='.')
 
-env.BuildDir('buildout', 'src', duplicate=0)
+env.VariantDir('buildout', 'src', duplicate=0)
 
 if sys.platform=='darwin':
    env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers'])
@@ -110,7 +112,7 @@ test.write(['src', 'HelloApplet', 'Hello.html'], """\
 test.write(['src', 'HelloApplet', 'SConscript'], """\
 import os
 Import ("env")
-denv=env.Copy()
+denv=env.Clone()
 classes=denv.Java(target='classes',source=['com'])
 #set correct path for jar
 denv['JARCHDIR']=os.path.join(denv.Dir('.').get_abspath(),'classes')
@@ -165,7 +167,7 @@ public class MyID
 
 test.write(['src', 'javah', 'SConscript'], """\
 Import('env')
-denv=env.Copy()
+denv=env.Clone()
 denv['JARCHDIR']=denv.Dir('.').get_abspath()
 denv.Jar('myid','MyID.java')
 denv.JavaH(denv.Dir('.').get_abspath(),'MyID.java')
@@ -362,7 +364,7 @@ private:
 
 test.write(['src', 'jni', 'SConscript'], """\
 Import ("env")
-denv=env.Copy()
+denv=env.Clone()
 
 denv.Append(SWIGFLAGS=['-java'])
 denv.SharedLibrary('scons',['JniWrapper.cc','Sample.i'])
index 5477a2d4dc4f9815c2453eb32768a467e4a0cae4..cc5418073416e8f7b9eec256cadc43235eb3cecf 100644 (file)
@@ -42,6 +42,7 @@ if not swig:
 where_javac, java_version = test.java_where_javac()
 where_javah = test.java_where_javah()
 where_jar = test.java_where_jar()
+where_java_include=test.java_where_includes()
 
 test.subdir(['foo'],
             ['java'],
@@ -51,6 +52,7 @@ test.write(['SConstruct'], """\
 import os
 
 env = Environment(ENV = os.environ,
+                  CPPPATH=%(where_java_include)s,                 
                   JAVAC = r'%(where_javac)s',
                   JAVAH = r'%(where_javah)s')
 
@@ -92,7 +94,7 @@ import os
 Import('env')
 
 # unnecessary?
-env = env.Copy()
+env = env.Clone()
 
 env.Prepend(CPPPATH = ['#foo',])
 
index 857b6bdae1e35bcfc896f35fcc016da5f0e3581f..48e47f67ef5d0a147c6a024a2ee8843bc0d50dd7 100644 (file)
@@ -191,7 +191,7 @@ test.run(program=test.workpath('test.exe'), stdout='2003 test 2\n')
 test.subdir('src', 'build', 'out')
 
 test.write('SConstruct',"""
-BuildDir('build', 'src', duplicate=0)
+VariantDir('build', 'src', duplicate=0)
 SConscript('build/SConscript')
 """)
 
similarity index 90%
rename from test/MSVC/pdb-BuildDir-path.py
rename to test/MSVC/pdb-VariantDir-path.py
index 223e5350ac342dc73534800e9d79cb0f086eb866..028b2de0570953ea0508f61893b693bda00f86a7 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"\r
 \r
 """\r
-Verify that .pdb files get put in a build_dir correctly.\r
+Verify that .pdb files get put in a variant_dir correctly.\r
 """\r
 \r
 import sys\r
@@ -47,7 +47,7 @@ env = Environment()
 env.Append(BINDIR = '#bin')\r
 \r
 Export('env')\r
-SConscript('#src/SConscript', duplicate = 0, build_dir = '#.build')\r
+SConscript('#src/SConscript', duplicate = 0, variant_dir = '#.build')\r
 """)\r
 \r
 test.write(['src', 'SConscript'], """\\r
index 04e7c9323021ad8079c46fb9e75f666d1b1870b3..286342806e5b57a83d67ddb1aa46d6fae84103ef 100644 (file)
@@ -241,7 +241,7 @@ test.must_not_exist(test.workpath('work1', 'Test.dsw'))
 test.subdir('work2', ['work2', 'src'])
 
 test.write(['work2', 'SConstruct'], """\
-SConscript('src/SConscript', build_dir='build')
+SConscript('src/SConscript', variant_dir='build')
 """)
 
 test.write(['work2', 'src', 'SConscript'], SConscript_contents)
index aaffd7d880115c6c360e92c33e87883c02158ffa..71b16ef94a4813338fdfa7b04f13bac1c9746cd2 100644 (file)
@@ -222,7 +222,7 @@ os.environ['PYTHON_ROOT'] = ''
 test.subdir('work2', ['work2', 'src'])
 
 test.write(['work2', 'SConstruct'], """\
-SConscript('src/SConscript', build_dir='build')
+SConscript('src/SConscript', variant_dir='build')
 """)
 
 test.write(['work2', 'src', 'SConscript'], SConscript_contents)
index 98bd9da19f7feb0d02cf6d7c5ebf996c9b9cca34..e6a592630f14ff9d5462d5357ed7547312d37c48 100644 (file)
@@ -224,7 +224,7 @@ os.environ['PYTHON_ROOT'] = ''
 test.subdir('work2', ['work2', 'src'])
 
 test.write(['work2', 'SConstruct'], """\
-SConscript('src/SConscript', build_dir='build')
+SConscript('src/SConscript', variant_dir='build')
 """)
 
 test.write(['work2', 'src', 'SConscript'], SConscript_contents)
index d7aa0d96d64b174260a77b8fb3ef135396268b9a..7a4fdaaadfd52275e30e38e6af9e15f6db9a3783 100644 (file)
@@ -231,7 +231,7 @@ os.environ['PYTHON_ROOT'] = ''
 test.subdir('work2', ['work2', 'src'])
 
 test.write(['work2', 'SConstruct'], """\
-SConscript('src/SConscript', build_dir='build')
+SConscript('src/SConscript', variant_dir='build')
 """)
 
 test.write(['work2', 'src', 'SConscript'], SConscript_contents)
index 00b222b804cf046a0348ef2d7e1e0e3748599298..e6aeadca7c009ab644e1bcc096320328fa4d7f6f 100644 (file)
@@ -59,13 +59,20 @@ env.Command('f6.out', 'f6.in', [Cat,
 # directory for another target.
 env.Command(Dir('hello'), None, [Mkdir('$TARGET')])
 env.Command('hello/world', None, [Touch('$TARGET')])
+
+# Make sure Mkdir works with a list of arguments
+Execute(Mkdir(['d7', Dir('d8')]))
 """)
 
 test.write(['work1', 'f2.in'], "f2.in\n")
 test.write(['work1', 'f5.in'], "f5.in\n")
 test.write(['work1', 'f6.in'], "f6.in\n")
 
-expect = test.wrap_stdout(read_str = 'Mkdir("d1")\nMkdir("d1-Dir")\n',
+expect = test.wrap_stdout(read_str = """\
+Mkdir("d1")
+Mkdir("d1-Dir")
+Mkdir(["d7", "d8"])
+""",
                           build_str = """\
 cat(["f2.out"], ["f2.in"])
 Mkdir("d3")
@@ -88,6 +95,8 @@ test.must_not_exist(['work1', 'f5.out'])
 test.must_not_exist(['work1', 'f6.out'])
 test.must_not_exist(['work1', 'Mkdir-f6.in'])
 test.must_not_exist(['work1', 'f6.out-Mkdir'])
+test.must_not_exist(['work1', 'd7'])
+test.must_not_exist(['work1', 'd8'])
 
 test.run(chdir = 'work1')
 
@@ -102,6 +111,8 @@ test.must_exist(['work1', 'Mkdir-f6.in'])
 test.must_exist(['work1', 'f6.out-Mkdir'])
 test.must_exist(['work1', 'hello'])
 test.must_exist(['work1', 'hello/world'])
+test.must_exist(['work1', 'd7'])
+test.must_exist(['work1', 'd8'])
 
 test.write(['work1', 'd1', 'file'], "d1/file\n")
 test.write(['work1', 'd3', 'file'], "d3/file\n")
index b23a8d435cdf6c05f6a3e85c2517462cdc823313..d00f726af93cb46139d7b5862124fecc46de0593 100644 (file)
@@ -27,7 +27,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 # This test is used to verify that the Buildability of a set of nodes
 # is unaffected by various querying operations on those nodes:
 #
-# 1) Calling exists() on a Node (e.g. from find_file) in a BuildDir
+# 1) Calling exists() on a Node (e.g. from find_file) in a VariantDir
 #    will cause that node to be duplicated into the builddir.
 #    However, this should *not* occur during a dryrun (-n).  When not
 #    performed during a dryrun, this should not affect buildability.
@@ -62,7 +62,7 @@ sconstruct = r"""
 foo = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(fooflags)s', WINDOWS_INSERT_DEF=1)
 bar = Environment(SHOBJPREFIX='', SHCXXFLAGS = '%(barflags)s', WINDOWS_INSERT_DEF=1)
 src = Dir('src')
-BuildDir('bld', src, duplicate=1)
+VariantDir('bld', src, duplicate=1)
 Nodes=[]
 Nodes.extend(foo.SharedObject(target = 'foo%(_obj)s', source = 'prog.cpp'))
 Nodes.extend(bar.SharedObject(target = 'bar%(_obj)s', source = 'prog.cpp'))
@@ -82,11 +82,11 @@ fooMain = foo.Clone(LIBS='foo', LIBPATH='.')
 foo_obj = fooMain.Object(target='foomain', source='main.c')
 fooMain.Program(target='fooprog', source=foo_obj)
 
-barMain = bar.Copy(LIBS='bar', LIBPATH='.')
+barMain = bar.Clone(LIBS='bar', LIBPATH='.')
 bar_obj = barMain.Object(target='barmain', source='main.c')
 barMain.Program(target='barprog', source=bar_obj)
 
-gooMain = foo.Copy(LIBS='goo', LIBPATH='bld')
+gooMain = foo.Clone(LIBS='goo', LIBPATH='bld')
 goo_obj = gooMain.Object(target='goomain', source='main.c')
 gooMain.Program(target='gooprog', source=goo_obj)
 """
@@ -138,7 +138,7 @@ def mycopy(env, source, target):
     open(str(target[0]),'w').write(open(str(source[0]),'r').read())
 
 def exists_test(node):
-    before = os.path.exists(str(node))  # doesn't exist yet in BuildDir
+    before = os.path.exists(str(node))  # doesn't exist yet in VariantDir
     via_node = node.exists()            # side effect causes copy from src
     after = os.path.exists(str(node))
     node.is_derived()
@@ -146,12 +146,12 @@ def exists_test(node):
     if GetOption('no_exec'):
         if (before,via_node,after) != (False,False,False):
             import sys
-            sys.stderr.write('BuildDir exists() populated during dryrun!\n')
+            sys.stderr.write('VariantDir exists() populated during dryrun!\n')
             sys.exit(-2)
     else:
         if (before,via_node,after) != (False,True,True):
             import sys
-            sys.stderr.write('BuildDir exists() population did not occur! (%%s:%%s,%%s,%%s)\n'%%(str(node),before,via_node,after))
+            sys.stderr.write('VariantDir exists() population did not occur! (%%s:%%s,%%s,%%s)\n'%%(str(node),before,via_node,after))
             sys.exit(-2)
     
 goo = Environment(CPPFLAGS = '%(fooflags)s')
@@ -310,7 +310,7 @@ for name in build_nodes:
 
 cleanup_test()
 
-### Next pass: do an up-build from a BuildDir src
+### Next pass: do an up-build from a VariantDir src
 
 
 for name in build_nodes:
@@ -332,7 +332,7 @@ for name in build_nodes:
 
 cleanup_test()
 
-### Next pass: do an up-build from a BuildDir src with Node Ops
+### Next pass: do an up-build from a VariantDir src with Node Ops
 ### side-effects
 
 for name in build_nodes:
index b6ba30619ef52302b974eb886e5fa5fdf859126a..3a95b8a5cbf2c001288da2e93dbf1cafe8a7a5a9 100644 (file)
@@ -49,7 +49,8 @@ from SCons.Options import ListOption
 
 list_of_libs = Split('x11 gl qt ical')
 
-opts = Options(args=ARGUMENTS)
+optsfile = 'scons.options'
+opts = Options(optsfile, args=ARGUMENTS)
 opts.AddOptions(
     ListOption('shared',
                'libraries to build as shared libraries',
@@ -59,6 +60,7 @@ opts.AddOptions(
     )
 
 env = Environment(options=opts)
+opts.Save(optsfile, env)
 Help(opts.GenerateHelpText(env))
 
 print env['shared']
@@ -68,35 +70,45 @@ for x in  env['shared']:
     print x,
 print
 print env.subst('$shared')
+# Test subst_path() because it's used in $CPPDEFINES expansions.
+print env.subst_path('$shared')
 Default(env.Alias('dummy', None))
 """)
 
 test.run()
-check(['all', '1', 'gl ical qt x11', 'gl ical qt x11'])
+check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
+       "['gl ical qt x11']"])
+
+test.must_match(test.workpath('scons.options'), "shared = 'all'\n")
+
+check(['all', '1', 'gl ical qt x11', 'gl ical qt x11',
+       "['gl ical qt x11']"])
 
 test.run(arguments='shared=none')
-check(['none', '0', '', ''])
+check(['none', '0', '', '', "['']"])
 
 test.run(arguments='shared=')
-check(['none', '0', '', ''])
+check(['none', '0', '', '', "['']"])
 
 test.run(arguments='shared=x11,ical')
-check(['ical,x11', '1', 'ical x11', 'ical x11'])
+check(['ical,x11', '1', 'ical x11', 'ical x11',
+       "['ical x11']"])
 
 test.run(arguments='shared=x11,,ical,,')
-check(['ical,x11', '1', 'ical x11', 'ical x11'])
+check(['ical,x11', '1', 'ical x11', 'ical x11',
+       "['ical x11']"])
 
 test.run(arguments='shared=GL')
 check(['gl', '0', 'gl', 'gl'])
 
 test.run(arguments='shared=QT,GL')
-check(['gl,qt', '0', 'gl qt', 'gl qt'])
+check(['gl,qt', '0', 'gl qt', 'gl qt', "['gl qt']"])
 
 
 expect_stderr = """
 scons: *** Error converting option: shared
 Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 14)
+""" + test.python_file_line(SConstruct_path, 15)
 
 test.run(arguments='shared=foo', stderr=expect_stderr, status=2)
 
@@ -105,28 +117,28 @@ test.run(arguments='shared=foo', stderr=expect_stderr, status=2)
 expect_stderr = """
 scons: *** Error converting option: shared
 Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 14)
+""" + test.python_file_line(SConstruct_path, 15)
 
 test.run(arguments='shared=foo,ical', stderr=expect_stderr, status=2)
 
 expect_stderr = """
 scons: *** Error converting option: shared
 Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 14)
+""" + test.python_file_line(SConstruct_path, 15)
 
 test.run(arguments='shared=ical,foo', stderr=expect_stderr, status=2)
 
 expect_stderr = """
 scons: *** Error converting option: shared
 Invalid value(s) for option: foo
-""" + test.python_file_line(SConstruct_path, 14)
+""" + test.python_file_line(SConstruct_path, 15)
 
 test.run(arguments='shared=ical,foo,x11', stderr=expect_stderr, status=2)
 
 expect_stderr = """
 scons: *** Error converting option: shared
 Invalid value(s) for option: foo,bar
-""" + test.python_file_line(SConstruct_path, 14)
+""" + test.python_file_line(SConstruct_path, 15)
 
 test.run(arguments='shared=foo,x11,,,bar', stderr=expect_stderr, status=2)
 
index ba08739e8ffa584f0ddf25187ee280c5ca6588a6..5656b086eb46207885a281cdaff7d8b3308c9609 100644 (file)
@@ -134,12 +134,12 @@ env = Environment(QTDIR = r'%s',
                   QT_UIC = r'%s',
                   %s
                   tools=['default','qt'])
-if ARGUMENTS.get('build_dir', 0):
+if ARGUMENTS.get('variant_dir', 0):
     if ARGUMENTS.get('chdir', 0):
         SConscriptChdir(1)
     else:
         SConscriptChdir(0)
-    BuildDir('build', '.', duplicate=1)
+    VariantDir('build', '.', duplicate=1)
     sconscript = Dir('build').File('SConscript')
 else:
     sconscript = File('SConscript')
index d746d9e66d0950016b1000e65dccb7cfa6009418..25e8b916f0c04496ce705803359135ce669f93bb 100644 (file)
@@ -73,7 +73,7 @@ if not conf.CheckLib(env.subst("$QT_LIB"), autoadd=0):
     if not conf.CheckLib(env.subst("$QT_LIB"), autoadd=0):
          Exit(0)
 env = conf.Finish()
-BuildDir('bld', '.')
+VariantDir('bld', '.')
 env.Program('bld/test_realqt', ['bld/mocFromCpp.cpp',
                                 'bld/mocFromH.cpp',
                                 'bld/anUiFile.ui',
index 359a241017d7c54fb1535f3bf838b22436dd230d..1936a725c653bac6e11c94e4ec4c7b89ebe56a89 100644 (file)
@@ -81,15 +81,15 @@ test.not_up_to_date(options = '-n', arguments = moc)
 
 test.run(options = '-c', arguments = lib_aaa)
 
-test.run(arguments = "build_dir=1 " + test.workpath('build', lib_aaa),
+test.run(arguments = "variant_dir=1 " + test.workpath('build', lib_aaa),
          stderr=TestSCons.noisy_ar,
          match=TestSCons.match_re_dotall)
 
-test.run(arguments = "build_dir=1 chdir=1 " + test.workpath('build', lib_aaa))
+test.run(arguments = "variant_dir=1 chdir=1 " + test.workpath('build', lib_aaa))
 
 test.must_exist(test.workpath('build', moc))
 
-test.run(arguments = "build_dir=1 dup=0 " +
+test.run(arguments = "variant_dir=1 dup=0 " +
                      test.workpath('build_dup0', lib_aaa),
          stderr=TestSCons.noisy_ar,
          match=TestSCons.match_re_dotall)
index 993649069aeff68d5590ef40d5c7ce9051d1f21f..102facc828e8fc4eadd9d6d3a359ec18eaf5d7b4 100644 (file)
@@ -85,13 +85,13 @@ test.not_up_to_date(options='-n', arguments = moc)
 
 test.run(program = test.workpath(aaa_exe), stdout = 'aaa.h\n')
 
-test.run(arguments = "build_dir=1 " + build_aaa_exe)
+test.run(arguments = "variant_dir=1 " + build_aaa_exe)
 
-test.run(arguments = "build_dir=1 chdir=1 " + build_aaa_exe)
+test.run(arguments = "variant_dir=1 chdir=1 " + build_aaa_exe)
 
 test.must_exist(test.workpath('build', moc))
 
-test.run(arguments = "build_dir=1 chdir=1 dup=0 " +
+test.run(arguments = "variant_dir=1 chdir=1 dup=0 " +
                      test.workpath('build_dup0', aaa_exe) )
 
 test.must_exist(['build_dup0', moc])
index 9ffe0aa639b0adad7aaaee6f908da3817228ce00..874285d278f5aa668dcb466bad85f8c2ded73a00 100644 (file)
@@ -115,7 +115,7 @@ test.not_up_to_date(options = '-n', arguments = moc)
 # clean up
 test.run(arguments = '-c ' + aaa_dll)
 
-test.run(arguments = "build_dir=1 " +
+test.run(arguments = "variant_dir=1 " +
                      test.workpath('build', aaa_dll) )
 
 test.must_exist(test.workpath('build', moc))
@@ -128,7 +128,7 @@ test.must_not_exist(test.workpath(h))
 cppContents = test.read(test.workpath('build', cpp))
 test.fail_test(string.find(cppContents, '#include "aaa.ui.h"') == -1)
 
-test.run(arguments = "build_dir=1 chdir=1 " +
+test.run(arguments = "variant_dir=1 chdir=1 " +
                      test.workpath('build', aaa_dll) )
 
 test.must_exist(test.workpath('build', moc))
@@ -138,7 +138,7 @@ test.must_not_exist(test.workpath(moc))
 test.must_not_exist(test.workpath(cpp))
 test.must_not_exist(test.workpath(h))
 
-test.run(arguments = "build_dir=1 chdir=1 dup=0 " +
+test.run(arguments = "variant_dir=1 chdir=1 dup=0 " +
                      test.workpath('build_dup0', aaa_dll) )
 
 test.must_exist(test.workpath('build_dup0',moc))
index 67ef605d2be98c5aeb0e23e92d1d428db54320ff..e9644563cb6286ddc99853b8fe270ae5b160d14f 100644 (file)
@@ -40,6 +40,10 @@ test = TestSCons.TestSCons()
 where_javac, java_version = test.java_where_javac()
 where_java = test.java_where_java()
 
+# where_java_home=test.java_where_java_home()
+os.environ['JAVA_HOME'] = test.java_where_java_home()
+
+
 
 java = where_java
 javac = where_javac
@@ -105,7 +109,6 @@ test.writable('repository', 0)
 #
 test.run(chdir = 'work1', options = opts, arguments = ".")
 
-os.environ['JAVA_HOME'] = '/usr/lib/jvm/java-1.5.0-sun-1.5.0.11'
 
 test.run(program = java,
          arguments = "-cp %s Foo1" % work1_classes,
index 59620950313f5ffef7f6a427f5504b8a47dff5cc..b7f4e33725df6570b5aaec6812edb974b3a1024e 100644 (file)
@@ -58,7 +58,7 @@ env.Build('aaa.out', 'aaa.mid')
 Local('aaa.out')
 
 Export("env")
-BuildDir('build', 'src')
+VariantDir('build', 'src')
 SConscript('build/SConscript')
 """)
 
index 15d8abb2c493896dc8965aa7180fb95c51224909..3178fbbff21020126813aa72f2b9478eb9e67b4e 100644 (file)
@@ -57,7 +57,7 @@ opts = "-Y " + test.workpath('repository')
 test.write(['repository', 'SConstruct'], """\
 env = Environment(M4 = r'%(_python_)s %(mym4_py)s', tools=['default', 'm4'])
 env.M4(target = 'aaa.x', source = 'aaa.x.m4')
-SConscript('src/SConscript', "env", build_dir="build")
+SConscript('src/SConscript', "env", variant_dir="build")
 """ % locals())
 
 test.write(['repository', 'aaa.x.m4'], """\
similarity index 98%
rename from test/Repository/BuildDir.py
rename to test/Repository/VariantDir.py
index eaafc096e7c9253e99004dd24aac646b28b67613..2766c80a9f776348d0188ee4c6882f87e1e8d167 100644 (file)
@@ -38,8 +38,8 @@ opts = "-Y " + test.workpath('repository')
 
 #
 test.write(['repository', 'SConstruct'], r"""
-BuildDir('build0', 'src', duplicate=0)
-BuildDir('build1', 'src', duplicate=1)
+VariantDir('build0', 'src', duplicate=0)
+VariantDir('build1', 'src', duplicate=1)
 SConscript('build0/SConscript')
 SConscript('build1/SConscript')
 """)
index d124431160f96823e61f78ddf8aa7a096825fc84..a85d095ef18aa280876481bf8a4231186de2d9cc 100644 (file)
@@ -86,7 +86,7 @@ ccflags = {
 }
 env1 = Environment(CCFLAGS = default.subst('$CCFLAGS %s' % ccflags[OS]),
                    CPPPATH = build1_os)
-BuildDir(build1_os, 'src1')
+VariantDir(build1_os, 'src1')
 SConscript(build1_os + '/SConscript', "env1")
 
 SConscript('build2/foo/SConscript')
@@ -99,7 +99,7 @@ env1.Program('xxx', ['aaa.c', 'bbb.c', 'main.c'])
 """)
 
 test.write(['repository', 'build2', 'foo', 'SConscript'], r"""
-BuildDir('src2', '#src2')
+VariantDir('src2', '#src2')
 
 default = Environment()
 env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DFOO'),
@@ -109,7 +109,7 @@ SConscript('src2/xxx/SConscript', "env2")
 """)
 
 test.write(['repository', 'build2', 'bar', 'SConscript'], r"""
-BuildDir('src2', '#src2')
+VariantDir('src2', '#src2')
 
 default = Environment()
 env2 = Environment(CCFLAGS = default.subst('$CCFLAGS -DBAR'),
index d6e5f911a1f1c710685e3718d81b4fda9decca42..fd0049c354b971ea456f887da1c25a0d226bfca1 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import TestCmd
-import TestSCons
 import os
 import string
 
-test = TestSCons.TestSCons()
+import TestCmd
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestCmd.match_re_dotall)
 
 wpath = test.workpath()
 
@@ -46,12 +47,18 @@ Use scons -H for help about command-line options.
 
 os.environ['SCONSFLAGS'] = ''
 
-test.run(arguments = '-h', stdout = expect)
+test.run(arguments = '-h',
+         stdout = expect,
+         stderr = TestSCons.deprecated_python_expr)
 
 os.environ['SCONSFLAGS'] = '-h'
 
-test.run(stdout = expect)
+test.run(stdout = expect,
+         stderr = TestSCons.deprecated_python_expr)
 
+# No TestSCons.deprecated_python_expr because the -H option gets
+# processed before the SConscript files and therefore before we check
+# for the deprecation warning.
 test.run(arguments = "-H")
 
 test.fail_test(string.find(test.stdout(), 'Help text.') >= 0)
@@ -59,10 +66,12 @@ test.fail_test(string.find(test.stdout(), '-H, --help-options') == -1)
 
 os.environ['SCONSFLAGS'] = '-Z'
 
-test.run(arguments = "-H", status = 2,
-         stderr = r"""usage: scons [OPTION] [TARGET] ...
+expect = r"""usage: scons [OPTION] [TARGET] ...
 
 SCons error: no such option: -Z
-""")
+"""
+
+test.run(arguments = "-H", status = 2,
+         stderr = TestSCons.re_escape(expect))
 
 test.pass_test()
index aaf3bcb6c2ba7e090ad0bc245617410f63a85bbe..6e48e068d3cf6c2bb53e7f0e4aace53013dca601 100644 (file)
@@ -46,7 +46,7 @@ env = Environment()
 for src_dir in ['src','samples']:
     SConscript('build/glob_build.py', 
                src_dir=src_dir,
-               build_dir='build/output/'+src_dir,
+               variant_dir='build/output/'+src_dir,
                duplicate=0,
                exports=['env'])
 """)
index b638a3bdf5e2127b6a37b0b23e38731f504c8ac3..e0f3f25e46929e57b5999bd51441fdc638e76913 100644 (file)
@@ -42,10 +42,15 @@ swig = test.where_is('swig')
 if not swig:
     test.skip_test('Can not find installed "swig", skipping test.\n')
 
+where_java_include=test.java_where_includes()
 
+if not where_java_include:
+    test.skip_test('Can not find installed Java include files, skipping test.\n')
 
 test.write(['SConstruct'], """\
-env = Environment(tools = ['default', 'swig'])
+env = Environment(tools = ['default', 'swig'],
+                CPPPATH=%(where_java_include)s,                 
+                )
 
 Java_foo_interface = env.SharedLibrary(
     'Java_foo_interface', 
index 58ad0cda53b57aedce2283141d32885f079e25fc..8f122af6802c6ff35209a5847cefab45bbcacb17 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Make sure SWIG works when a BuildDir (or build_dir) is used.
+Make sure SWIG works when a VariantDir (or variant_dir) is used.
 
 Test case courtesy Joe Maruszewski.
 """
@@ -82,7 +82,7 @@ Export("env")
 #
 # Build the libraries.
 #
-SConscript("source/SConscript", build_dir = "build")
+SConscript("source/SConscript", variant_dir = "build")
 """ % locals())
 
 test.write(['source', 'SConscript'], """\
index ef91189fe11832c5dad074c3d052cca987809760..eb66fd2f3eaf96025a8c9ce1cbc4d8f9586056f4 100644 (file)
@@ -77,7 +77,7 @@ e["EXPORT_INCLUDE"] = os.path.join(experimenttop, "export", "include")
 e["EXPORT_LIB"] = os.path.join(experimenttop, "export", "lib")
 e["INSTALL_BIN"] = os.path.join(experimenttop, "install", "bin")
 
-build_dir = os.path.join(experimenttop, "tmp-bld-dir")
+variant_dir = os.path.join(experimenttop, "tmp-bld-dir")
 src_dir = os.path.join(experimenttop, "src")
 
 env.Append(CPPPATH = [e["EXPORT_INCLUDE"]])
similarity index 96%
rename from test/SideEffect/build_dir.py
rename to test/SideEffect/variant_dir.py
index d33e3d404a7d8173078c23acef540cfa286ebf86..44fbd799bc45ab1e1ab835a1f30394111793c6a1 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Verify correct operation of SideEffect() when an SConscript()
-build_dir is used.
+variant_dir is used.
 """
 
 import os.path
@@ -49,7 +49,7 @@ def build(env, source, target):
 Build = Builder(action=build)
 env = Environment(BUILDERS={'Build':Build})
 Export('env')
-SConscript('SConscript', build_dir='build', duplicate=0)""")
+SConscript('SConscript', variant_dir='build', duplicate=0)""")
 
 test.write('SConscript', """
 Import('env')
index 09f20f09afa41ccd4759974891c68c65c6e2460b..7155f9318ebf002ab3a6fce39eef0b21e2300b0c 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Test use of ${TARGET.dir} to specify a CPPPATH directory in
-combination BuildDirs and a generated .h file.
+combination VariantDirs and a generated .h file.
 """
 
 import TestSCons
@@ -51,9 +51,9 @@ def cat(env, source, target):
 env = Environment(CPPPATH='${TARGET.dir}')
 env.Append(BUILDERS = {'Cat' : Builder(action=cat)})
 Export('env')
-BuildDir('build1', 'src')
+VariantDir('build1', 'src')
 SConscript('build1/SConscript')
-BuildDir('build2', 'src')
+VariantDir('build2', 'src')
 SConscript('build2/SConscript', duplicate=0)
 """)
 
index 8df2e79f72ed1d49e13a14895b2a98c4bacb833d..01d14657a68a1641406c119e8ec52763ab61f9b9 100644 (file)
@@ -59,7 +59,7 @@ env = Environment(tools = ['pdftex', 'dvipdf', 'dvips', 'tex', 'latex'],
 # Use 'duplicate=1' because LaTeX toolchain does not work properly for
 # input/output files outside of the current directory
 
-env.BuildDir('$BUILD_DIR', 'docs', duplicate=1)
+env.VariantDir('$BUILD_DIR', 'docs', duplicate=1)
 env.SConscript('$BUILD_DIR/SConscript', exports = ['env'])
 """)
 
similarity index 97%
rename from test/TEX/build_dir.py
rename to test/TEX/variant_dir.py
index 49675336235e520e45c1f156c84bf297ea7d15e4..084fb2b06dd97445cdc2d48e063c7bf62e848d3d 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Test creation of a fully-featured TeX document (with bibliography
-and index) in a build_dir.
+and index) in a variant_dir.
 
 Test courtesy Rob Managan.
 """
@@ -50,7 +50,7 @@ env = Environment(ENV = { 'PATH' : os.environ['PATH'] },
 Export(['env'])
 
 SConscript(os.path.join('docs', 'SConscript'),
-           build_dir=os.path.join('mybuild','docs'),
+           variant_dir=os.path.join('mybuild','docs'),
            duplicate=1)
 """)
 
@@ -237,7 +237,7 @@ All done now.
 test.run(arguments = '.', stderr=None)
 
 
-# All (?) the files we expect will get created in the build_dir
+# All (?) the files we expect will get created in the variant_dir
 # (mybuild/docs) and not in the srcdir (docs).
 files = [
     'test.aux',
similarity index 97%
rename from test/TEX/build_dir_dup0.py
rename to test/TEX/variant_dir_dup0.py
index 8035957b8d3bfd2e4f10058ab23bc681217ae4b6..c37a13b5b6dffbd629aad02c883215a2934a6177 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Test creation of a fully-featured TeX document (with bibliography
-and index) in a build_dir.
+and index) in a variant_dir.
 
 Test courtesy Rob Managan.
 """
@@ -53,7 +53,7 @@ env = Environment(ENV = { 'PATH' : os.environ['PATH'] },
 Export(['env'])
 
 SConscript(os.path.join('docs', 'SConscript'),
-           build_dir=os.path.join('mybuild','docs'),
+           variant_dir=os.path.join('mybuild','docs'),
            duplicate=0)
 """)
 
@@ -233,7 +233,7 @@ All done now.
 test.run(arguments = '.', stderr=None)
 
 
-# All (?) the files we expect will get created in the build_dir
+# All (?) the files we expect will get created in the variant_dir
 # (mybuild/docs) and not in the srcdir (docs).
 files = [
     'test.aux',
index 6ecc3ff77402bca2b8843fe2bdbe303e8c0da785..fc7c3f88795191ff0a9614d1495834b99d78ce4b 100644 (file)
@@ -52,6 +52,13 @@ env.Command('f5.out', 'f5.in', [Touch("$FILE"), Cat])
 env.Command('f6.out', 'f6.in', [Cat,
                                 Touch("Touch-$SOURCE"),
                                 Touch("$TARGET-Touch")])
+
+# Make sure Touch works with a list of arguments
+env = Environment()
+env.Command('f7.out', 'f7.in', [Cat,
+                                Touch(["Touch-$SOURCE",
+                                       "$TARGET-Touch",
+                                       File("f8")])])
 """)
 
 test.write('f1', "f1\n")
@@ -59,6 +66,7 @@ test.write('f1-File', "f1-File\n")
 test.write('f2.in', "f2.in\n")
 test.write('f5.in', "f5.in\n")
 test.write('f6.in', "f6.in\n")
+test.write('f7.in', "f7.in\n")
 
 old_f1_time = os.path.getmtime(test.workpath('f1'))
 old_f1_File_time = os.path.getmtime(test.workpath('f1-File'))
@@ -75,6 +83,8 @@ cat(["f5.out"], ["f5.in"])
 cat(["f6.out"], ["f6.in"])
 Touch("Touch-f6.in")
 Touch("f6.out-Touch")
+cat(["f7.out"], ["f7.in"])
+Touch(["Touch-f7.in", "f7.out-Touch", "f8"])
 """)
 test.run(options = '-n', arguments = '.', stdout = expect)
 
@@ -92,6 +102,10 @@ test.must_not_exist(test.workpath('f5.out'))
 test.must_not_exist(test.workpath('f6.out'))
 test.must_not_exist(test.workpath('Touch-f6.in'))
 test.must_not_exist(test.workpath('f6.out-Touch'))
+test.must_not_exist(test.workpath('f7.out'))
+test.must_not_exist(test.workpath('Touch-f7.in'))
+test.must_not_exist(test.workpath('f7.out-Touch'))
+test.must_not_exist(test.workpath('f8'))
 
 test.run()
 
@@ -107,5 +121,9 @@ test.must_match('f5.out', "f5.in\n")
 test.must_match('f6.out', "f6.in\n")
 test.must_exist(test.workpath('Touch-f6.in'))
 test.must_exist(test.workpath('f6.out-Touch'))
+test.must_match('f7.out', "f7.in\n")
+test.must_exist(test.workpath('Touch-f7.in'))
+test.must_exist(test.workpath('f7.out-Touch'))
+test.must_exist(test.workpath('f8'))
 
 test.pass_test()
index fd7afb71c5fc6accd186c80cf9247629d376ec2e..72d499ed14a1fd94d5a5c94e83efd30b26ff005a 100644 (file)
@@ -38,7 +38,7 @@ test = TestSCons.TestSCons(match=TestCmd.match_re)
 python = TestSCons.python
 
 SConstruct_content = """
-SourceSignatures(r'%(source_signature)s')
+Decider(r'%(source_signature)s')
 
 class Custom:
     def __init__(self, value):  self.value = value
@@ -82,7 +82,7 @@ open(sys.argv[-1],'wb').write(string.join(sys.argv[1:-2]))
 
 # Run all of the tests with both types of source signature
 # to make sure there's no difference in behavior.
-for source_signature in ['MD5', 'timestamp']:
+for source_signature in ['MD5', 'timestamp-newer']:
 
     print "Testing Value node with source signatures:", source_signature
 
similarity index 97%
rename from test/BuildDir/CPPPATH-subdir.py
rename to test/VariantDir/CPPPATH-subdir.py
index 9d3bb983232c256b41f473a7135a245a697e8b8e..25ebb40103e98bde6254239718b0dcf5dec134b6 100644 (file)
@@ -40,7 +40,7 @@ test.subdir('src', ['src', 'glscry'])
 test.write('SConstruct', """\
 env = Environment()
 Export('env')
-SConscript(dirs=['src'], build_dir='build', duplicate=0)
+SConscript(dirs=['src'], variant_dir='build', duplicate=0)
 """)
 
 
similarity index 90%
rename from test/BuildDir/Clean.py
rename to test/VariantDir/Clean.py
index f4a8c48d5aa6dab7f5543ffebd50027bc89e946b..3f065e5dc2593b59841bb5680db2c72211060db7 100644 (file)
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that we can Clean() files in a BuildDir() that's underneath us.
+Verify that we can Clean() files in a VariantDir() that's underneath us.
 (At one point this didn't work because we were using str() instead of
 abspath to remove the files, which would interfere with the removal by
-returning a path relative to the BuildDir(), not the top-level SConstruct
+returning a path relative to the VariantDir(), not the top-level SConstruct
 directory, if the source directory was the top-level directory.)
 """
 
@@ -37,8 +37,8 @@ import TestSCons
 test = TestSCons.TestSCons()
 
 test.write('SConstruct', """\
-BuildDir('build0', '.', duplicate=0)
-BuildDir('build1', '.', duplicate=1)
+VariantDir('build0', '.', duplicate=0)
+VariantDir('build1', '.', duplicate=1)
 
 def build_sample(target, source, env):
     targetdir = str(target[0].dir)
similarity index 91%
rename from test/BuildDir/File-create.py
rename to test/VariantDir/File-create.py
index 0a838be5da39b24930b4ad0012c2e6126c3398fc..ea4e61b9240cb178fe29522fcfb19b54e9d1cf43 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that explicit use of File() Nodes in a BuildDir, followed by
+Verify that explicit use of File() Nodes in a VariantDir, followed by
 *direct* creation of the file by Python in the SConscript file itself,
 works correctly, with both duplicate=0 and duplicate=1.
 
@@ -42,8 +42,8 @@ test = TestSCons.TestSCons()
 test.subdir('src')
 
 test.write('SConstruct', """\
-SConscript('src/SConscript', build_dir='build0', chdir=1, duplicate=0)
-SConscript('src/SConscript', build_dir='build1', chdir=1, duplicate=1)
+SConscript('src/SConscript', variant_dir='build0', chdir=1, duplicate=0)
+SConscript('src/SConscript', variant_dir='build1', chdir=1, duplicate=1)
 """)
 
 test.write(['src', 'SConscript'], """\
diff --git a/test/VariantDir/SConscript-variant_dir.py b/test/VariantDir/SConscript-variant_dir.py
new file mode 100644 (file)
index 0000000..cba6c2f
--- /dev/null
@@ -0,0 +1,272 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that specifying a variant_dir argument to SConscript works properly.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+all1 = test.workpath('test', 'build', 'var1', 'all')
+all2 = test.workpath('test', 'build', 'var2', 'all')
+all3 = test.workpath('test', 'build', 'var3', 'all')
+all4 = test.workpath('test', 'build', 'var4', 'all')
+all5 = test.workpath('build', 'var5', 'all')
+all6 = test.workpath('build', 'var6', 'all')
+all7 = test.workpath('build', 'var7', 'all')
+all8 = test.workpath('build', 'var8', 'all')
+all9 = test.workpath('test', 'build', 'var9', 'src', 'all')
+
+test.subdir('test')
+
+test.write(['test', 'SConstruct'], """
+src = Dir('src')
+alt = Dir('alt')
+var1 = Dir('build/var1')
+var2 = Dir('build/var2')
+var3 = Dir('build/var3')
+var4 = Dir('build/var4')
+var5 = Dir('../build/var5')
+var6 = Dir('../build/var6')
+var7 = Dir('../build/var7')
+var8 = Dir('../build/var8')
+var9 = Dir('../build/var9')
+
+def cat(env, source, target):
+    target = str(target[0])
+    source = map(str, source)
+    f = open(target, "wb")
+    for src in source:
+        f.write(open(src, "rb").read())
+    f.close()
+
+env = Environment(BUILDERS={'Cat':Builder(action=cat)},
+                  BUILD='build')
+
+Export("env")
+
+SConscript('src/SConscript', variant_dir=var1)
+SConscript('src/SConscript', variant_dir='build/var2', src_dir=src)
+
+SConscript('src/SConscript', variant_dir='build/var3', duplicate=0)
+
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
+#XXX is to an entire source directory.  We haven't yet generalized our
+#XXX infrastructure to be able to take the SConscript file from one source
+#XXX directory, but the rest of the files from a different one.
+#XXX SConscript('src/SConscript', variant_dir=var4, src_dir=alt, duplicate=0)
+
+#XXX SConscript('src/SConscript', variant_dir='../build/var5', src_dir='alt')
+SConscript('src/SConscript', variant_dir=var6)
+
+SConscript('src/SConscript', variant_dir=var7, src_dir=src, duplicate=0)
+env.SConscript('src/SConscript', variant_dir='../$BUILD/var8', duplicate=0)
+
+# This tests the fact that if you specify a src_dir that is above
+# the dir a SConscript is in, that we do the intuitive thing, i.e.,
+# we set the path of the SConscript accordingly.  The below is
+# equivalent to saying:
+#
+# VariantDir('build/var9', '.')
+# SConscript('build/var9/src/SConscript')
+SConscript('src/SConscript', variant_dir='build/var9', src_dir='.')
+""") 
+
+test.subdir(['test', 'src'], ['test', 'alt'])
+
+test.write(['test', 'src', 'SConscript'], """
+Import("env")
+env.Cat('aaa.out', 'aaa.in')
+env.Cat('bbb.out', 'bbb.in')
+env.Cat('ccc.out', 'ccc.in')
+env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out'])
+""")
+
+test.write('test/src/aaa.in', "test/src/aaa.in\n")
+test.write('test/src/bbb.in', "test/src/bbb.in\n")
+test.write('test/src/ccc.in', "test/src/ccc.in\n")
+
+test.write('test/alt/aaa.in', "test/alt/aaa.in\n")
+test.write('test/alt/bbb.in', "test/alt/bbb.in\n")
+test.write('test/alt/ccc.in', "test/alt/ccc.in\n")
+
+test.run(chdir='test', arguments = '. ../build')
+
+all_src = "test/src/aaa.in\ntest/src/bbb.in\ntest/src/ccc.in\n"
+all_alt = "test/alt/aaa.in\ntest/alt/bbb.in\ntest/alt/ccc.in\n"
+
+test.must_match(all1, all_src)
+test.must_match(all2, all_src)
+test.must_match(all3, all_src)
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
+#XXX is to an entire source directory.  We haven't yet generalized our
+#XXX infrastructure to be able to take the SConscript file from one source
+#XXX directory, but the rest of the files from a different one.
+#XXX test.must_match(all4, all_alt)
+#XXX test.must_match(all5, all_alt)
+test.must_match(all6, all_src)
+test.must_match(all7, all_src)
+test.must_match(all8, all_src)
+test.must_match(all9, all_src)
+
+import os
+import stat
+def equal_stats(x,y):
+    x = os.stat(x)
+    y = os.stat(y)
+    return (stat.S_IMODE(x[stat.ST_MODE]) == stat.S_IMODE(y[stat.ST_MODE]) and
+            x[stat.ST_MTIME] ==  y[stat.ST_MTIME])
+
+# Make sure we did duplicate the source files in build/var1,
+# and that their stats are the same:
+for file in ['aaa.in', 'bbb.in', 'ccc.in']:
+    test.must_exist(test.workpath('test', 'build', 'var1', file))
+    test.fail_test(not equal_stats(test.workpath('test', 'build', 'var1', file),
+                                   test.workpath('test', 'src', file)))
+
+# Make sure we did duplicate the source files in build/var2,
+# and that their stats are the same:
+for file in ['aaa.in', 'bbb.in', 'ccc.in']:
+    test.must_exist(test.workpath('test', 'build', 'var2', file))
+    test.fail_test(not equal_stats(test.workpath('test', 'build', 'var2', file),
+                                   test.workpath('test', 'src', file)))
+# Make sure we didn't duplicate the source files in build/var3.
+test.must_not_exist(test.workpath('test', 'build', 'var3', 'aaa.in'))
+test.must_not_exist(test.workpath('test', 'build', 'var3', 'bbb.in'))
+test.must_not_exist(test.workpath('test', 'build', 'var3', 'ccc.in'))
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
+#XXX is to an entire source directory.  We haven't yet generalized our
+#XXX infrastructure to be able to take the SConscript file from one source
+#XXX directory, but the rest of the files from a different one.
+#XXX Make sure we didn't duplicate the source files in build/var4.
+#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'aaa.in'))
+#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'bbb.in'))
+#XXXtest.must_not_exist(test.workpath('test', 'build', 'var4', 'ccc.in'))
+
+#XXX We can't support var4 and var5 yet, because our VariantDir linkage
+#XXX is to an entire source directory.  We haven't yet generalized our
+#XXX infrastructure to be able to take the SConscript file from one source
+#XXX directory, but the rest of the files from a different one.
+#XXX Make sure we did duplicate the source files in build/var5,
+#XXX and that their stats are the same:
+#XXXfor file in ['aaa.in', 'bbb.in', 'ccc.in']:
+#XXX    test.must_exist(test.workpath('build', 'var5', file))
+#XXX    test.fail_test(not equal_stats(test.workpath('build', 'var5', file),
+#XXX                                   test.workpath('test', 'src', file)))
+
+# Make sure we did duplicate the source files in build/var6,
+# and that their stats are the same:
+for file in ['aaa.in', 'bbb.in', 'ccc.in']:
+    test.must_exist(test.workpath('build', 'var6', file))
+    test.fail_test(not equal_stats(test.workpath('build', 'var6', file),
+                                   test.workpath('test', 'src', file)))
+# Make sure we didn't duplicate the source files in build/var7.
+test.must_not_exist(test.workpath('build', 'var7', 'aaa.in'))
+test.must_not_exist(test.workpath('build', 'var7', 'bbb.in'))
+test.must_not_exist(test.workpath('build', 'var7', 'ccc.in'))
+# Make sure we didn't duplicate the source files in build/var8.
+test.must_not_exist(test.workpath('build', 'var8', 'aaa.in'))
+test.must_not_exist(test.workpath('build', 'var8', 'bbb.in'))
+test.must_not_exist(test.workpath('build', 'var8', 'ccc.in'))
+
+###################
+test.subdir('test2')
+
+test.write(['test2', 'SConstruct'], """\
+SConscript('SConscript', variant_dir='Build', src_dir='.', duplicate=0)
+""")
+
+test.write(['test2', 'SConscript'], """\
+env = Environment()
+foo_obj = env.Object('foo.c')
+env.Program('foo', [foo_obj, 'bar.c'])
+""")
+
+test.write(['test2', 'bar.c'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+bar(void) {
+        printf("bar.c\n");
+}
+""")
+
+test.write(['test2', 'foo.c'], r"""
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void
+bar(void);
+
+int
+main(int argc, char *argv[]) {
+        bar();
+        printf("foo.c\n");
+}
+""")
+
+test.run(chdir="test2")
+
+_obj = TestSCons._obj
+
+test.must_not_exist(test.workpath('test2', 'foo' + _obj))
+test.must_not_exist(test.workpath('test2', 'bar' + _obj))
+test.must_exist(test.workpath('test2', 'Build', 'foo' + _obj))
+test.must_exist(test.workpath('test2', 'Build', 'bar' + _obj))
+
+###################
+# Make sure that directories for subsidiary SConscript() calls
+# in a variant_dir get created if they don't already exist.
+test.subdir('test3')
+
+test.subdir(['test3', 'src'], ['test3', 'src', '_glscry'])
+
+test.write(['test3', 'SConstruct'], """\
+SConscript(dirs=['src'], variant_dir='build', duplicate=0)
+""")
+
+test.write(['test3', 'src', 'SConscript'], """\
+SConscript(dirs=['_glscry'])
+""")
+
+test.write(['test3', 'src', '_glscry', 'SConscript'], """\
+""")
+
+test.write(['test3', 'src', 'file.in'], "file.in\n")
+
+test.write(['test3', 'src', '_glscry', 'file.in'], "file.in\n")
+
+test.run(chdir='test3')
+
+
+test.pass_test()
similarity index 96%
rename from test/BuildDir/BuildDir.py
rename to test/VariantDir/VariantDir.py
index f3085796d33592defc61be2bf08b1aaca8a6f9d6..3906cd7516eb1fa58dff36f10bf5daebb43ea141 100644 (file)
@@ -71,12 +71,12 @@ var6 = Dir('../build/var6')
 
 env = Environment(BUILD = 'build', SRC = 'src')
 
-BuildDir('build/var1', src)
-BuildDir(var2, src)
-BuildDir(var3, src, duplicate=0)
-env.BuildDir("$BUILD/var4", "$SRC", duplicate=0)
-BuildDir(var5, src, duplicate=0)
-BuildDir(var6, src)
+VariantDir('build/var1', src)
+VariantDir(var2, src)
+VariantDir(var3, src, duplicate=0)
+env.VariantDir("$BUILD/var4", "$SRC", duplicate=0)
+VariantDir(var5, src, duplicate=0)
+VariantDir(var6, src)
 
 env = Environment(CPPPATH='#src', FORTRANPATH='#src')
 SConscript('build/var1/SConscript', "env")
@@ -356,7 +356,7 @@ test.up_to_date(chdir='work2', arguments='.')
 #
 test.write(['work2', 'SConstruct'], """\
 env = Environment()
-BuildDir('build', '.')
+VariantDir('build', '.')
 Export('env')
 SConscript('build/SConscript')
 """)
@@ -372,13 +372,13 @@ test.fail_test(not blank_output(test.stderr()))
 
 test.run(chdir='work2', arguments='.',
          stdout=test.wrap_stdout("""\
-scons: building associated BuildDir targets: build
+scons: building associated VariantDir targets: build
 scons: `.' is up to date.
 """))
 
 test.write( ['work3', 'SConstruct'], """\
 SConscriptChdir(0)
-BuildDir('build', '.', duplicate=1 ) 
+VariantDir('build', '.', duplicate=1 ) 
 SConscript( 'build/SConscript' )
 """)
 
@@ -397,7 +397,7 @@ test.write( ['work3', 'existing.h'], """\
 
 test.run(chdir='work3',
          stdout=test.wrap_stdout("""\
-scons: building associated BuildDir targets: build
+scons: building associated VariantDir targets: build
 scons: `.' is up to date.
 """),
          stderr="""\
similarity index 92%
rename from test/BuildDir/errors.py
rename to test/VariantDir/errors.py
index 3954f2bf5b6480127e8cfd25f145b55f73531b16..22a48218eb09c25b04df50173868dc4c3b830da8 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Validate successful handling of errors when duplicating things in
-BuildDirs.  This is generally when the BuildDir, or something in it,
+VariantDirs.  This is generally when the VariantDir, or something in it,
 is read-only.
 """
 
@@ -43,7 +43,7 @@ for dir in ['normal', 'ro-dir', 'ro-SConscript', 'ro-src']:
 
     test.write([dir, 'SConstruct'], """\
 import os.path
-BuildDir('build', 'src')
+VariantDir('build', 'src')
 SConscript(os.path.join('build', 'SConscript'))
 """) 
 
@@ -81,7 +81,7 @@ test.run(chdir = 'normal', arguments = ".")
 
 test.fail_test(test.read(['normal', 'build', 'file.out']) != "normal/src/file.in\n")
 
-# Verify the error when the BuildDir itself is read-only.  Don't bother
+# Verify the error when the VariantDir itself is read-only.  Don't bother
 # to test this on Windows, because the ACL (I think) still allows the
 # owner to create files in the directory even when it's read-only.
 if sys.platform != 'win32':
@@ -94,7 +94,7 @@ if sys.platform != 'win32':
              status = 2,
              stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.\n" % os.path.join('src', 'SConscript'))
 
-# Verify the error when the SConscript file within the BuildDir is
+# Verify the error when the SConscript file within the VariantDir is
 # read-only.  Note that we have to make the directory read-only too,
 # because otherwise our duplication logic will be able to unlink
 # the read-only SConscript and duplicate the new one.
@@ -119,11 +119,11 @@ test.run(chdir = 'ro-SConscript',
          status = 2,
          stderr = "scons: *** Cannot duplicate `%s' in `build': Permission denied.  Stop.\n" % os.path.join('src', 'SConscript'))
 
-# Verify the error when the source file within the BuildDir is
+# Verify the error when the source file within the VariantDir is
 # read-only.  Note that we have to make the directory read-only too,
 # because otherwise our duplication logic will be able to unlink the
 # read-only source file and duplicate the new one.  But because we've
-# made the BuildDir read-only, we must also create a writable SConscript
+# made the VariantDir read-only, we must also create a writable SConscript
 # file there so it can be duplicated from the source directory.
 dir = os.path.join('ro-src', 'build')
 test.subdir(dir)
@@ -158,8 +158,8 @@ test.subdir('duplicate', ['duplicate', 'src1'], ['duplicate', 'src2'])
 duplicate_SConstruct_path = test.workpath('duplicate', 'SConstruct')
 
 test.write(duplicate_SConstruct_path, """\
-BuildDir('build', 'src1')
-BuildDir('build', 'src2')
+VariantDir('build', 'src1')
+VariantDir('build', 'src2')
 """)
 
 expect_stderr = """
similarity index 91%
rename from test/BuildDir/guess-subdir.py
rename to test/VariantDir/guess-subdir.py
index 8523da6ac59c5381d230e11159195bdd9ad51ece..672e157088f2c0341a2a03b53080634ff5a7cb7f 100644 (file)
@@ -25,8 +25,8 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test that the logic that "guesses" the associated BuildDir for a
-subdirectory correctly builds targets in the BuildDir subdirectory.
+Test that the logic that "guesses" the associated VariantDir for a
+subdirectory correctly builds targets in the VariantDir subdirectory.
 """
 
 import TestSCons
@@ -37,7 +37,7 @@ test.subdir(['work'], ['work', 'src'])
 
 test.write(['work', 'SConstruct'], """
 c_builddir = r'%s'
-BuildDir(c_builddir, '.', duplicate=0)
+VariantDir(c_builddir, '.', duplicate=0)
 SConscript(c_builddir + '/SConscript')
 """ % test.workpath('debug'))
 
similarity index 94%
rename from test/BuildDir/nested-sconscripts.py
rename to test/VariantDir/nested-sconscripts.py
index f6dd13bf42db7ef4ca58943d250ab8c0f0a35a33..c1d1557bf044d897f7884bc94d854306a2972c41 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test that nested SConscript files in a BuildDir don't throw
+Test that nested SConscript files in a VariantDir don't throw
 an OSError exception looking for the wrong file.
 """
 
@@ -47,7 +47,7 @@ for flavor in ['prod', 'debug']:
     # In real life, we would modify build_env appropriately here
     FLAVOR_DIR = BUILD_DIR + '/' + flavor
     Export('build_env')
-    BuildDir(FLAVOR_DIR, 'md', duplicate=0)
+    VariantDir(FLAVOR_DIR, 'md', duplicate=0)
     SConscript(FLAVOR_DIR + '/SConscript')
 """)
 
similarity index 91%
rename from test/BuildDir/reflect.py
rename to test/VariantDir/reflect.py
index 9a25029a667cc4a744a7245167b1cebc144612f1..8fcca56864312e6660a497a053fe8953d5c819f2 100644 (file)
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-This test validates the correct operation of a BuildDir specification
-in avoiding reflection: reflection is the case where the build_dir is
+This test validates the correct operation of a VariantDir specification
+in avoiding reflection: reflection is the case where the variant_dir is
 located under the corresponding source dir, and trying to use elements
-in the build_dir as sources for that same build dir.
+in the variant_dir as sources for that same build dir.
 
 Test based on bug #1055521 filed by Gary Oberbrunner.
 """
@@ -58,7 +58,7 @@ env = Environment(CC = r'%(_python_)s mycc.py',
                   INCSUFFIX = '_CNI',
                   CPPPATH='%(cpppath)s')  # note no leading '#'
 Export("env")
-SConscript('SConscript', build_dir="dir1/dir2", src_dir=".")
+SConscript('SConscript', variant_dir="dir1/dir2", src_dir=".")
 """
 
 test.write('SConscript', """\
@@ -89,7 +89,7 @@ INC_CNI = re.escape(os.path.join('INC_dir1', 'dir2', 'dir1', 'dir2_CNI'))
 
 # The .+ after mycc\\.py below handles /nologo flags from Visual C/C++.
 expect = test.wrap_stdout("""\
-scons: building associated BuildDir targets: %(targets)s
+scons: building associated VariantDir targets: %(targets)s
 "%(re_python)s" mycc\\.py.* %(INC_CNI)s .+
 Compile
 "%(re_python)s" mylink\\.py .+
@@ -119,7 +119,7 @@ INC_CNI = re.escape(os.path.join('INC_dir1', 'dir2_CNI'))
 # The .* after mycc\\.py below handles /nologo flags from Visual C/C++.
 test.run(arguments = '',
          stdout=test.wrap_stdout("""\
-scons: building associated BuildDir targets: %(targets)s
+scons: building associated VariantDir targets: %(targets)s
 "%(re_python)s" mycc\\.py.* %(INC_CNI)s .+
 Compile
 "%(re_python)s" mylink\\.py .+
similarity index 97%
rename from test/BuildDir/removed-files.py
rename to test/VariantDir/removed-files.py
index 3f528a3b7c5ae2854399903908f129f63e16d60a..9f1674052aeaca0202e48648cad1e7f249e300ff 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test BuildDir handling of removal of source files.
+Test VariantDir handling of removal of source files.
 
 A C++ Program is created and compiled. First, a header is missing. Then
 the header is added and the compilation should succeed, then the header
@@ -60,7 +60,7 @@ int main(int argc, char* argv[])
 
 test.write('SConstruct', """
 env = Environment()
-env.BuildDir('bin', 'src')
+env.VariantDir('bin', 'src')
 o = env.Object('bin/dep', 'bin/dep.cpp')
 env.Program('bin/dep', o)
 """)
similarity index 88%
rename from test/BuildDir/under.py
rename to test/VariantDir/under.py
index 9a3d561d8131c37e73a5aa3c34aaeac7011d7c33..355f2b395f72128c907d4552cff94df19ce7237b 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test various combinations of build_dir when the source directory is,
+Test various combinations of variant_dir when the source directory is,
 or is not, underneath the SConstruct directory.
 """
 
@@ -45,7 +45,7 @@ test.write(['work', 'file.in'], "work/file.in\n")
 
 
 test.write(['work', 'sub', 'SConstruct'], """\
-SConscript('../SConscript', build_dir='build1')
+SConscript('../SConscript', variant_dir='build1')
 """)
 
 test.run(chdir='work/sub')
@@ -55,7 +55,7 @@ test.must_match(['work', 'sub', 'build1', 'file.out'], "work/file.in\n")
 
 
 test.write(['work', 'sub', 'SConstruct'], """
-SConscript('../SConscript', build_dir='../build2')
+SConscript('../SConscript', variant_dir='../build2')
 """)
 
 test.run(chdir='work/sub')
@@ -65,7 +65,7 @@ test.must_match(['work', 'build2', 'file.out'], "work/file.in\n")
 
 
 test.write(['work', 'sub', 'SConstruct'], """
-SConscript('../SConscript', build_dir='../../build3')
+SConscript('../SConscript', variant_dir='../../build3')
 """)
 
 test.run(chdir='work/sub')
@@ -75,7 +75,7 @@ test.must_match(['build3', 'file.out'], "work/file.in\n")
 
 
 test.write(['work', 'SConstruct'], """
-SConscript('../other/SConscript', build_dir='build4')
+SConscript('../other/SConscript', variant_dir='build4')
 """)
 
 test.write(['other', 'SConscript'], """\
index ebe230eaa2234efe4998e30f9b00d3847cb3ddd5..a7f6b3fe8e888c9d22f67c184afd031f9d10e1ca 100644 (file)
@@ -33,8 +33,8 @@ test = TestSCons.TestSCons()
 test.subdir('src')
 
 test.write('SConstruct',"""
-BuildDir('var1', 'src', duplicate=0)
-BuildDir('var2', 'src', duplicate=1)
+VariantDir('var1', 'src', duplicate=0)
+VariantDir('var2', 'src', duplicate=1)
 SConscript('src/SConscript')
 SConscript('var1/SConscript')
 SConscript('var2/SConscript')
@@ -67,7 +67,7 @@ test.write(['src', 'g.in'], 'g.in')
 test.write(['src', 'h.in'], 'h.in')
 
 # Do 'src' last so that creation of the emitter files in there doesn't
-# interfere with searching for them in the BuildDirs.
+# interfere with searching for them in the VariantDirs.
 
 test.run(arguments='var2')
 
index 3366359a23b95a896d10cad83535a55f24cedd61..e1e3aecd509498fba653826a3bdce9d8786f63ea 100644 (file)
@@ -39,6 +39,7 @@ test = TestSCons.TestSCons()
 
 test.subdir(['src'], ['src', 'subdir'])
 
+subdir_file8 = os.path.join('subdir', 'file8')
 subdir_file7 = os.path.join('subdir', 'file7')
 subdir_file7_in = os.path.join('subdir', 'file7.in')
 
@@ -91,9 +92,10 @@ kscan = Scanner(name = 'kfile',
                 skeys = ['.k'])
 
 cat = Builder(action = r'%(_python_)s %(cat_py)s $TARGET $SOURCES')
+one_cat = Builder( action = r'%(_python_)s %(cat_py)s $TARGET ${SOURCES[0]}')
 
 env = Environment()
-env.Append(BUILDERS = {'Cat':cat},
+env.Append(BUILDERS = {'Cat':cat, 'OneCat':one_cat},
            SCANNERS = kscan)
 
 Export("env")
@@ -106,7 +108,8 @@ env.InstallAs('../inc/eee', 'eee.in')
 
 test.write(['src', 'SConstruct'], SConstruct_contents)
 
-test.write(['src', 'SConscript'], """\
+def WriteInitialTest( valueDict ) :
+    test.write(['src', 'SConscript'], """\
 Import("env")
 env.Cat('file1', 'file1.in')
 env.Cat('file2', 'file2.k')
@@ -118,7 +121,11 @@ env.Cat('file5', 'file5.k')
 file6 = env.Cat('file6', 'file6.in')
 AlwaysBuild(file6)
 env.Cat('subdir/file7', 'subdir/file7.in')
-""" % locals())
+env.OneCat('subdir/file8', ['subdir/file7.in', env.Value(%(test_value)s)] )
+""" % valueDict )
+
+test_value = '"first"'
+WriteInitialTest( locals() )
 
 test.write(['src', 'aaa'], "aaa 1\n")
 test.write(['src', 'bbb.k'], """\
@@ -186,6 +193,8 @@ scons: building `file6' because it doesn't exist
 %(_python_)s %(cat_py)s file6 file6.in
 scons: building `%(subdir_file7)s' because it doesn't exist
 %(_python_)s %(cat_py)s %(subdir_file7)s %(subdir_file7_in)s
+scons: building `%(subdir_file8)s' because it doesn't exist
+%(_python_)s %(cat_py)s %(subdir_file8)s %(subdir_file7_in)s
 """ % locals())
 
 test.run(chdir='src', arguments=args, stdout=expect)
@@ -217,6 +226,9 @@ test.write(['src', 'yyy'], "yyy 2\n")
 test.write(['src', 'zzz'], "zzz 2\n")
 test.write(['src', 'bbb.k'], "bbb.k 2\ninclude ccc\n")
 
+test_value = '"second"'
+WriteInitialTest( locals() )
+
 expect = test.wrap_stdout("""\
 scons: rebuilding `file1' because `file1.in' changed
 %(_python_)s %(cat_py)s file1 file1.in
@@ -235,6 +247,10 @@ scons: rebuilding `file5' because `%(inc_bbb_k)s' changed
 %(_python_)s %(cat_py)s file5 file5.k
 scons: rebuilding `file6' because AlwaysBuild() is specified
 %(_python_)s %(cat_py)s file6 file6.in
+scons: rebuilding `%(subdir_file8)s' because:
+           `"'first'"' is no longer a dependency
+           `'second'' is a new dependency
+%(_python_)s %(cat_py)s %(subdir_file8)s %(subdir_file7_in)s
 """ % locals())
 
 test.run(chdir='src', arguments=args, stdout=expect)
index 265f589ba2d430031fdd741eb5b4a4596752153b..d03cd9b4809e15fec4426510fad927fd6c317306 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+"""
+Verify basic interactions of the --implicit-cache-* options.
+
+This test used to set TargetSignatures('build') because we were
+relying on the old behavior of non-essential changes in .h files
+propagate to cause a rebuilt executable.  We now just rely on
+the default Decider('content') behavior and only check for the
+rebuild of the object file itself when necessary.
+"""
+
 import os.path
 
 import TestSCons
@@ -34,6 +44,7 @@ _obj = TestSCons._obj
 prog = 'prog' + _exe
 subdir_prog = os.path.join('subdir', 'prog' + _exe)
 variant_prog = os.path.join('variant', 'prog' + _exe)
+variant_prog_obj = os.path.join('variant', 'prog' + _obj)
 
 args = prog + ' ' + subdir_prog + ' ' + variant_prog
 
@@ -41,19 +52,13 @@ test = TestSCons.TestSCons()
 
 test.subdir('include', 'subdir', ['subdir', 'include'], 'inc2')
 
-# Set TargetSignatures('build') because a lot of the test below expect
-# the old behavior of non-essential changes in .h files will propagate
-# and cause the executable file to be re-linked as well (even if the
-# object file was rebuilt to the exact same contents as last time).
-
 test.write('SConstruct', """
-TargetSignatures('build')
 env = Environment(CPPPATH = Split('inc2 include'))
 obj = env.Object(target='prog', source='subdir/prog.c')
 env.Program(target='prog', source=obj)
 SConscript('subdir/SConscript', "env")
 
-BuildDir('variant', 'subdir', 0)
+VariantDir('variant', 'subdir', 0)
 include = Dir('include')
 env = Environment(CPPPATH=['inc2', include])
 SConscript('variant/SConscript', "env")
@@ -278,7 +283,7 @@ test.write(['include', 'foo.h'], r"""
 """)
 
 test.not_up_to_date(options = "--implicit-deps-unchanged",
-                    arguments = variant_prog)
+                    arguments = variant_prog_obj)
 
 test.write(['include', 'baz.h'], r"""
 #define BAZ_STRING "include/baz.h 2\n"
@@ -287,7 +292,7 @@ test.write(['include', 'baz.h'], r"""
 test.up_to_date(options = "--implicit-deps-unchanged",
                 arguments = variant_prog)
 
-test.not_up_to_date(arguments = variant_prog)
+test.not_up_to_date(arguments = variant_prog_obj)
 
 
 
@@ -306,17 +311,17 @@ test.write(['include', 'foo.h'], r"""
 """)
 
 test.not_up_to_date(options = "--implicit-deps-unchanged",
-                    arguments = variant_prog)
+                    arguments = variant_prog_obj)
 
 test.write(['include', 'baz.h'], r"""
 #define BAZ_STRING "include/baz.h 2\n"
 """)
 
 test.up_to_date(options = "--implicit-deps-unchanged",
-                arguments = variant_prog)
+                arguments = variant_prog_obj)
 
 test.not_up_to_date(options = "--implicit-deps-changed",
-                    arguments = variant_prog)
+                    arguments = variant_prog_obj)
 
 
 
index 3cdea1b3195e9a6aea5383f455b49e01d853821c..168a880caeecd7a1efb2dd745692450512163548 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Test that files are correctly located in the build directory even when
+Test that files are correctly located in the variant directory even when
 Scons does not have a global view of all targets.
 
 Sometimes, it might be interesting to not tell scons about every
@@ -48,13 +48,13 @@ test.write('SConstruct', """\
 opts = Options()
 opts.AddOptions(
     BoolOption('view_all_dependencies', 'View all dependencies', True),
-    BoolOption('duplicate', 'Duplicate sources to build dir', True)
+    BoolOption('duplicate', 'Duplicate sources to variant dir', True)
 )
 
 env = Environment(options=opts)
 Export('env')
 
-SConscript(dirs='.', build_dir='build', duplicate=env['duplicate'])
+SConscript(dirs='.', variant_dir='build', duplicate=env['duplicate'])
 """ % locals())
 
 
index 3b0cc0de86a0bcee1f98ede63582bc4c76834678..4781d35b8c724926ac5eb9e6c93a0f48c8c906b5 100644 (file)
@@ -52,7 +52,7 @@ Default(env.B(target = 'sub1/foo.out', source = 'sub1/foo.in'))
 Export('env')
 SConscript('sub2/SConscript')
 Default(env.B(target = 'sub3/baz.out', source = 'sub3/baz.in'))
-BuildDir('sub2b', 'sub2')
+VariantDir('sub2b', 'sub2')
 SConscript('sub2b/SConscript')
 Default(env.B(target = 'sub2/xxx.out', source = 'xxx.in'))
 SConscript('SConscript')
index f589ae080d2b33f166e9e1059a59c17c7a76a9f2..c8874e7b7c9b2ce8430c21eaf97ea2e2597c4a2f 100644 (file)
@@ -46,7 +46,7 @@ try:
     SetOption('duplicate', duplicate)
 except KeyError:
     pass
-BuildDir('build', '.', duplicate=1)
+VariantDir('build', '.', duplicate=1)
 SConscript('build/SConscript')
 """)
 
diff --git a/test/option--warn.py b/test/option--warn.py
deleted file mode 100644 (file)
index 4b81e25..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env python
-#
-# __COPYRIGHT__
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-
-import os.path
-import sys
-
-import TestSCons
-import TestCmd
-
-test = TestSCons.TestSCons(match = TestCmd.match_re_dotall)
-
-# How to warn about deprecated features (whenever we have one again).
-#
-#test.write("SConstruct","""
-#b=Builder(name='b', action='foo')
-#""")
-#
-#test.run(arguments='.', stderr=r"""
-#scons: warning: The use of the 'name' parameter to Builder\(\) is deprecated\.
-#File "SConstruct", line 2, in \?
-#""")
-#
-#test.run(arguments='--warn=no-deprecated .', stderr='')
-#
-#test.run(arguments='--warn=no-all .', stderr='')
-#
-#test.run(arguments='--warn=no-all --warn=deprecated .', stderr=r"""
-#scons: warning: The use of the 'name' parameter to Builder\(\) is deprecated\.
-#File "SConstruct", line 2, in \?
-#""")
-
-
-
-test.write("SConstruct", """\
-import SCons.Defaults
-
-def build(target, source, env):
-    pass
-
-env=Environment()
-env['BUILDERS']['test'] = Builder(action=build,
-                                  source_scanner=SCons.Defaults.ObjSourceScan)
-env.test(target='foo', source='foo.c')
-""")
-
-test.write("foo.c","""
-#include "not_there.h"
-""")
-
-test.run(arguments='--warn=dependency .', stderr=r"""
-scons: warning: No dependency generated for file: not_there\.h \(included from: foo\.c\) \-\- file not found
-""" + TestSCons.file_expr)
-
-test.run(arguments='--warn=all .', stderr=r"""
-scons: warning: No dependency generated for file: not_there\.h \(included from: foo\.c\) \-\- file not found
-""" + TestSCons.file_expr)
-
-test.run(arguments='--warn=all --warn=no-dependency .', stderr="")
-
-test.run(arguments='--warn=no-dependency --warn=all .', stderr=r"""
-scons: warning: No dependency generated for file: not_there\.h \(included from: foo\.c\) \-\- file not found
-""" + TestSCons.file_expr)
-
-
-
-test.write("SConstruct", """\
-def build(target, source, env):
-    pass
-
-env=Environment()
-env['BUILDERS']['test'] = Builder(action=build)
-env.test(target='foo', source='foo.c')
-SConscript('no_such_file')
-""")
-
-test.run(arguments = '--warn=missing-sconscript .', stderr = r"""
-scons: warning: Ignoring missing SConscript 'no_such_file'
-""" + TestSCons.file_expr)
-
-test.run(arguments = '--warn=no-missing-sconscript .', stderr = "")
-
-
-
-test.write('SConstruct', """
-def build(env, target, source):
-    file = open(str(target[0]), 'wb')
-    for s in source:
-        file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env2 = env.Clone(DIFFERENT_VARIABLE = 'true')
-env.B(target = 'file1.out', source = 'file1a.in')
-env2.B(target = 'file1.out', source = 'file1b.in')
-""")
-
-test.write('file1a.in', 'file1a.in\n')
-test.write('file1b.in', 'file1b.in\n')
-
-test.run(arguments='file1.out', 
-         stderr=r"""
-scons: warning: Two different environments were specified for target file1.out,
-\tbut they appear to have the same action: build\(target, source, env\)
-""" + TestSCons.file_expr)
-
-test.must_match('file1.out', "file1a.in\nfile1b.in\n")
-
-test.run(arguments='--warn=duplicate-environment file1.out', 
-         stderr=r"""
-scons: warning: Two different environments were specified for target file1.out,
-\tbut they appear to have the same action: build\(target, source, env\)
-""" + TestSCons.file_expr)
-
-test.run(arguments='--warn=no-duplicate-environment file1.out')
-
-
-
-test.write('SConstruct', """
-def build(env, target, source):
-    file = open(str(target[0]), 'wb')
-    for s in source:
-        file.write(open(str(s), 'rb').read())
-
-B = Builder(action=build, multi=1)
-env = Environment(BUILDERS = { 'B' : B })
-env.B(targets = 'file3a.out', source = 'file3a.in')
-env.B(target = 'file3b.out', sources = 'file3b.in')
-""")
-
-test.write('file3a.in', 'file3a.in\n')
-test.write('file3b.out', 'file3b.out\n')
-
-test.run(arguments='.', 
-         stderr=r"""
-scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
-""" + TestSCons.file_expr + r"""
-scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
-""" + TestSCons.file_expr)
-
-test.must_match(['file3a'], 'file3a.in\n')
-test.must_match(['file3b'], 'file3b.out\n')
-
-test.run(arguments='--warn=misleading-keywords .', 
-         stderr=r"""
-scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
-""" + TestSCons.file_expr + r"""\
-scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
-""" + TestSCons.file_expr)
-
-test.run(arguments='--warn=no-misleading-keywords .')
-
-
-test.pass_test()
index d1f87f02262f4acfbafeb231c1aacd7642149c63..dd67d2790068ca6566c0a6ac450aa0b6b3451507 100644 (file)
@@ -30,7 +30,7 @@ This test verifies:
         conjunction with -c;
     3)  that files installed by the Install() method don't get
         installed when -n is used;
-    4)  that source files don't get duplicated in a BuildDir
+    4)  that source files don't get duplicated in a VariantDir
         when -n is used.
     5)  that Configure calls don't build any files. If a file
         needs to be built (i.e. is not up-to-date), a ConfigureError
@@ -67,7 +67,7 @@ env.Tool('install')
 env.MyBuild(target = 'f1.out', source = 'f1.in')
 env.MyBuild(target = 'f2.out', source = 'f2.in')
 env.Install('install', 'f3.in')
-BuildDir('build', 'src', duplicate=1)
+VariantDir('build', 'src', duplicate=1)
 SConscript('build/SConscript', "env")
 """ % locals())
 
@@ -150,7 +150,7 @@ test.write('f3.in', "f3.in again\n")
 test.run(arguments = '-n install', stdout = expect)
 test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))
 
-# Make sure duplicate source files in a BuildDir aren't created
+# Make sure duplicate source files in a VariantDir aren't created
 # when the -n option is used.
 
 # First, make sure none of the previous non-dryrun invocations caused
index 439daa2b2de1514752e10e61092ec4befb4e15a6..572433f3aa02b89233d7f753611a9357e9e55bb9 100644 (file)
@@ -57,7 +57,7 @@ Export('env')
 SConscript('sub2/SConscript')
 f3 = env.Cat(target = 'sub3/f3.out', source = 'sub3/f3.in')
 env.Alias('my_alias', f3)
-BuildDir('build', 'sub4')
+VariantDir('build', 'sub4')
 SConscript('build/SConscript')
 """)
 
@@ -119,7 +119,7 @@ test.must_not_exist(test.workpath('sub4', 'dir', 'f4b.out'))
 test.must_not_exist(test.workpath('build', 'f4a.out'))
 test.must_not_exist(test.workpath('build', 'dir', 'f4b.out'))
 
-# Verify that we build things in a linked BuildDir.
+# Verify that we build things in a linked VariantDir.
 f4a_in = os.path.join('build', 'f4a.in')
 f4a_out = os.path.join('build', 'f4a.out')
 f4b_in = os.path.join('build', 'dir', 'f4b.in')
@@ -128,7 +128,7 @@ test.run(chdir = 'sub4',
          arguments = '-u',
          stdout = "scons: Entering directory `%s'\n" % test.workpath() + \
                   test.wrap_stdout("""\
-scons: building associated BuildDir targets: build
+scons: building associated VariantDir targets: build
 cat(["%s"], ["%s"])
 cat(["%s"], ["%s"])
 scons: `sub4' is up to date.
index ad35b5d5497f53fd4295da8460a86faaa3ec1224..7d984ded77511a50b8d0539564445b453d00655e 100644 (file)
@@ -34,7 +34,7 @@ import string
 
 import TestSCons
 
-test = TestSCons.TestSCons(match = TestSCons.match_re)
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
 
 # Find out if we support metaclasses (Python 2.2 and later).
 
diff --git a/test/option/warn-dependency.py b/test/option/warn-dependency.py
new file mode 100644 (file)
index 0000000..b849bed
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify use of the --warn=dependency option.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+
+
+test.write("SConstruct", """\
+import SCons.Defaults
+
+def build(target, source, env):
+    pass
+
+env=Environment()
+env['BUILDERS']['test'] = Builder(action=build,
+                                  source_scanner=SCons.Defaults.ObjSourceScan)
+env.test(target='foo', source='foo.c')
+""")
+
+test.write("foo.c","""
+#include "not_there.h"
+""")
+
+
+
+expect = r"""
+scons: warning: No dependency generated for file: not_there\.h \(included from: foo\.c\) \-\- file not found
+"""
+
+test.run(arguments='--warn=dependency .',
+         stderr=expect + TestSCons.file_expr)
+
+test.run(arguments='--warn=dependency .',
+         stderr=expect + TestSCons.file_expr)
+
+test.run(arguments='--warn=all --warn=no-dependency .',
+         stderr=TestSCons.deprecated_python_expr)
+
+test.run(arguments='--warn=no-dependency --warn=all .',
+         stderr=TestSCons.deprecated_python_expr + expect + TestSCons.file_expr)
+
+
+
+test.pass_test()
diff --git a/test/option/warn-duplicate-environment.py b/test/option/warn-duplicate-environment.py
new file mode 100644 (file)
index 0000000..90a7506
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify use of the --warn=duplicate-environment option.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+
+
+test.write('SConstruct', """
+def build(env, target, source):
+    file = open(str(target[0]), 'wb')
+    for s in source:
+        file.write(open(str(s), 'rb').read())
+
+WARN = ARGUMENTS.get('WARN')
+if WARN:
+    SetOption('warn', WARN)
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env2 = env.Clone(DIFFERENT_VARIABLE = 'true')
+env.B(target = 'file1.out', source = 'file1a.in')
+env2.B(target = 'file1.out', source = 'file1b.in')
+""")
+
+test.write('file1a.in', 'file1a.in\n')
+test.write('file1b.in', 'file1b.in\n')
+
+expect = r"""
+scons: warning: Two different environments were specified for target file1.out,
+\tbut they appear to have the same action: build\(target, source, env\)
+"""
+
+test.run(arguments='file1.out', 
+         stderr=expect + TestSCons.file_expr)
+
+test.must_match('file1.out', "file1a.in\nfile1b.in\n")
+
+test.run(arguments='--warn=duplicate-environment file1.out', 
+         stderr=expect + TestSCons.file_expr)
+
+test.run(arguments='--warn=no-duplicate-environment file1.out')
+
+test.run(arguments='WARN=duplicate-environment file1.out', 
+         stderr=expect + TestSCons.file_expr)
+
+test.run(arguments='WARN=no-duplicate-environment file1.out',
+         stderr = TestSCons.deprecated_python_expr)
+
+
+
+test.pass_test()
diff --git a/test/option/warn-misleading-keywords.py b/test/option/warn-misleading-keywords.py
new file mode 100644 (file)
index 0000000..f92ccb0
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify use of the --warn=misleading-keywords option.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+
+
+test.write('SConstruct', """
+def build(env, target, source):
+    file = open(str(target[0]), 'wb')
+    for s in source:
+        file.write(open(str(s), 'rb').read())
+
+WARN = ARGUMENTS.get('WARN')
+if WARN:
+    SetOption('warn', WARN)
+
+B = Builder(action=build, multi=1)
+env = Environment(BUILDERS = { 'B' : B })
+env.B(targets = 'file3a.out', source = 'file3a.in')
+env.B(target = 'file3b.out', sources = 'file3b.in')
+""")
+
+test.write('file3a.in', 'file3a.in\n')
+test.write('file3b.out', 'file3b.out\n')
+
+expect = r"""
+scons: warning: Did you mean to use `(target|source)' instead of `(targets|sources)'\?
+"""
+
+test.run(arguments='.', 
+         stderr=expect + TestSCons.file_expr + expect + TestSCons.file_expr)
+
+test.must_match(['file3a'], 'file3a.in\n')
+test.must_match(['file3b'], 'file3b.out\n')
+
+test.run(arguments='--warn=misleading-keywords .', 
+         stderr=expect + TestSCons.file_expr + expect + TestSCons.file_expr)
+
+test.run(arguments='--warn=no-misleading-keywords .')
+
+test.run(arguments='WARN=misleading-keywords .', 
+         stderr=expect + TestSCons.file_expr + expect + TestSCons.file_expr)
+
+test.run(arguments='WARN=no-misleading-keywords .',
+         stderr = TestSCons.deprecated_python_expr)
+
+
+
+test.pass_test()
diff --git a/test/option/warn-missing-sconscript.py b/test/option/warn-missing-sconscript.py
new file mode 100644 (file)
index 0000000..f0aab04
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify use of the --warn=missing-sconscript option.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestSCons.match_re_dotall)
+
+
+
+test.write("SConstruct", """\
+def build(target, source, env):
+    pass
+
+env=Environment()
+env['BUILDERS']['test'] = Builder(action=build)
+env.test(target='foo', source='foo.c')
+WARN = ARGUMENTS.get('WARN')
+if WARN:
+    SetOption('warn', WARN)
+SConscript('no_such_file')
+""")
+
+test.write("foo.c","""
+#include "not_there.h"
+""")
+
+test.run(arguments = '--warn=missing-sconscript .', stderr = r"""
+scons: warning: Ignoring missing SConscript 'no_such_file'
+""" + TestSCons.file_expr)
+
+test.run(arguments = '--warn=no-missing-sconscript .', stderr = "")
+
+test.run(arguments = 'WARN=missing-sconscript .', stderr = r"""
+scons: warning: Ignoring missing SConscript 'no_such_file'
+""" + TestSCons.file_expr)
+
+test.run(arguments = 'WARN=no-missing-sconscript .',
+         stderr = TestSCons.deprecated_python_expr)
+
+
+
+test.pass_test()
index 50a569a54a03d5e73122550ad5ddba1578ac0a3f..4d7e887a8c02c4766bdf6afb3d1ea40d1ee62f57 100644 (file)
@@ -49,7 +49,7 @@ test.subdir('build')
 test.write('src/main.c', '')
 
 test.write('SConstruct', """
-BuildDir('build', 'src')
+VariantDir('build', 'src')
 env=Environment(tools=['default', 'packaging'])
 env.Package( NAME        = 'libfoo',
              PACKAGEROOT = 'build/libfoo',
@@ -64,7 +64,7 @@ test.run(stderr = None)
 test.must_exist( 'build/libfoo-1.2.3.zip' )
 
 # TEST: builddir not placed in archive
-# XXX: BuildDir should be stripped.
+# XXX: VariantDir should be stripped.
 #
 test.subdir('src')
 test.subdir('build')
@@ -73,7 +73,7 @@ test.subdir('temp')
 test.write('src/main.c', '')
 
 test.write('SConstruct', """
-BuildDir('build', 'src')
+VariantDir('build', 'src')
 env=Environment(tools=['default', 'packaging'])
 env.Package( NAME        = 'libfoo',
              VERSION     = '1.2.3',
diff --git a/test/python-version.py b/test/python-version.py
new file mode 100644 (file)
index 0000000..a75ccd5
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify the behavior of our check for unsupported or deprecated versions
+of Python.
+"""
+
+import os
+import re
+import string
+import sys
+
+import TestCmd
+import TestSCons
+
+test = TestSCons.TestSCons(match = TestCmd.match_re_dotall)
+
+test.write('SConstruct', "\n")
+
+test.write('SetOption-deprecated', "SetOption('warn', 'no-deprecated')\n")
+
+test.write('SetOption-python', "SetOption('warn', ['no-python-version'])\n")
+
+if TestSCons.unsupported_python_version():
+
+    error = "scons: \*\*\* SCons version \S+ does not run under Python version %s."
+    error = error % re.escape(TestSCons.python_version_string()) + "\n"
+    test.run(arguments = '-Q', status = 1, stderr = error)
+
+else:
+
+    if TestSCons.deprecated_python_version():
+
+        sconsflags = os.environ.get('SCONSFLAGS')
+        if sconsflags:
+            sconsflags = string.replace(sconsflags, '--warn=no-python-version', '')
+            os.environ['SCONSFLAGS'] = sconsflags
+
+        test.run(arguments = '-Q', stderr = TestSCons.deprecated_python_expr)
+
+    else:
+
+        test.run(arguments = '-Q')
+
+    test.run(arguments = '-Q --warn=no-deprecated')
+
+    test.run(arguments = '-f SetOption-deprecated -Q')
+
+    test.run(arguments = '-f SetOption-python -Q')
+
+test.pass_test()
index ab91e8771d2df6b86c8279d7512272d13f1854e3..f575bc811fd503c7f7930b58f183446ffdbfdc18 100644 (file)
@@ -51,7 +51,7 @@ test.write_passing_test(['test', 'pass.py'])
 # NOTE:  The "test/fail.py : FAIL" and "test/pass.py : PASS" lines both
 # have spaces at the end.
 
-expect = r"""qmtest.py run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test
+expect = r"""qmtest run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test
 --- TEST RESULTS -------------------------------------------------------------
 
   %(test_fail_py)s                                  : FAIL    
index b61e5dad6fbc476cff072db66a819e6c0e2dae0b..3a5092581d2afb560b84e8cc43571611655af027 100644 (file)
@@ -38,7 +38,7 @@ test.write_failing_test(['test', 'fail.py'])
 
 # NOTE:  The "test/fail.py   : FAIL" line has spaces at the end.
 
-expect = r"""qmtest.py run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/fail.py
+expect = r"""qmtest run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/fail.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/fail.py                                  : FAIL    
index 9ef815d8516b6308132405b4bba0560e569a866d..9b1782cf0f4627771da8f0fdc9c04865282cff60 100644 (file)
@@ -36,7 +36,7 @@ test.subdir('test')
 
 test.write_no_result_test(['test', 'no_result.py'])
 
-expect = r"""qmtest.py run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/no_result.py
+expect = r"""qmtest run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/no_result.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/no_result.py                             : NO_RESULT
index f574e573fbf1e920493c41c404fa310666c85ffc..1bc6af12ecd24672ce076f4eb3a59753ccea918c 100644 (file)
@@ -38,7 +38,7 @@ test.write_passing_test(['test', 'pass.py'])
 
 # NOTE:  The "test/pass.py   : PASS" line has spaces at the end.
 
-expect = r"""qmtest.py run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/pass.py
+expect = r"""qmtest run --output baseline.qmr --format none --result-stream="scons_tdb.AegisBaselineStream" test/pass.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/pass.py                                  : PASS    
index 8b6ae4210010a7add263917129fdb6771290aef0..76aebe60c9b2c0ad5f23291f12445d78e082e7fc 100644 (file)
@@ -26,7 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Test that runtest.py falls back (with a warning) using --noqmtest
-if it can't find qmtest.py on the $PATH.
+if it can't find qmtest on the $PATH.
 """
 
 import os
@@ -41,14 +41,16 @@ _python_ = TestRuntest._python_
 
 test = TestRuntest.TestRuntest(noqmtest=1)
 
-qmtest_py = test.where_is('qmtest.py')
-
-if qmtest_py:
-    dir = os.path.split(qmtest_py)[0]
+# qmtest may be in more than one location in your path
+while test.where_is('qmtest'):
+    qmtest=test.where_is('qmtest')
+    dir = os.path.split(qmtest)[0]
     path = string.split(os.environ['PATH'], os.pathsep)
     path.remove(dir)
     os.environ['PATH'] = string.join(path, os.pathsep)
 
+print "PATH: %s"%os.environ['PATH']
+
 test.subdir('test')
 
 test_pass_py = os.path.join('test', 'pass.py')
@@ -92,7 +94,7 @@ NO RESULT from the following test:
 """ % locals()
 
 expect_stderr = """\
-Warning:  qmtest.py not found on $PATH, assuming --noqmtest option.
+Warning:  qmtest not found on $PATH, assuming --noqmtest option.
 FAILING TEST STDERR
 NO RESULT TEST STDERR
 PASSING TEST STDERR
index 39bf810afb3cabc7eb08587840dee65be1f6a245..0abfe9329a9812bef71e2827942a810d84fb0f8a 100644 (file)
@@ -52,7 +52,7 @@ test.write_passing_test(['test', 'pass.py'])
 # NOTE:  The "test/fail.py : FAIL" and "test/pass.py : PASS" lines both
 # have spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream\(print_time='1'\)" test
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream\(print_time='1'\)" test
 --- TEST RESULTS -------------------------------------------------------------
 
   %(test_fail_py)s                                  : FAIL    
index 95b5f0f4f41dcd7884adc7d76585b01d9d52dca6..aa1af2213bf855690c12ef3d2686603f65df7f4b 100644 (file)
@@ -52,7 +52,7 @@ test.write_passing_test(['test', 'pass.py'])
 
 # NOTE:  The "test/pass.py : PASS" line has spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" --context python="%(mypython)s" test
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" --context python="%(mypython)s" test
 --- TEST RESULTS -------------------------------------------------------------
 
   %(test_pass_py)s                                  : PASS    
index 58d2f27d127bb9058829fa312221b9f1f973c7c8..6bee872fe75e32db715e2c0caf7826895035142c 100644 (file)
@@ -51,7 +51,7 @@ test.write_passing_test(['test', 'pass.py'])
 # NOTE:  The "test/fail.py : FAIL" and "test/pass.py : PASS" lines both
 # have spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test
 --- TEST RESULTS -------------------------------------------------------------
 
   %(test_fail_py)s                                  : FAIL    
index ec9f53234101c6fb1e6881b7afb25b6e37020d09..1e8e7b6ed94db920ade0af5740bef9a604749513 100644 (file)
@@ -38,7 +38,7 @@ test.write_failing_test(['test', 'fail.py'])
 
 # NOTE:  The "test/fail.py   : FAIL" line has spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/fail.py
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/fail.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/fail.py                                  : FAIL    
index 4ec6e78bfebc35d695310728146e0e676012750a..16499c824c62fdaa6a5b01dc47c188357d689aea 100644 (file)
@@ -36,7 +36,7 @@ test.subdir('test')
 
 test.write_no_result_test(['test', 'no_result.py'])
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/no_result.py
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/no_result.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/no_result.py                             : NO_RESULT
index c3a8b02be0f5a7548426f0fd001340f0678e93e5..561665ab2fd893c555e80bb65b4df7150b8c7cec 100644 (file)
@@ -38,7 +38,7 @@ test.write_passing_test(['test', 'pass.py'])
 
 # NOTE:  The "test/pass.py   : PASS" line has spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/pass.py
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" test/pass.py
 --- TEST RESULTS -------------------------------------------------------------
 
   test/pass.py                                  : PASS    
index 3063a4eb49cf9356189c88954ae71229924f3109..eebdce4d2889ff5e0e2f82fb1084e96321a125db 100644 (file)
@@ -52,7 +52,7 @@ test.write_passing_test(['src', 'suite', 'passTests.py'])
 # NOTE:  The "test/pass.py : PASS" and "test/passTests.py : PASS" lines
 # both have spaces at the end.
 
-expect = r"""qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" src
+expect = r"""qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" src
 --- TEST RESULTS -------------------------------------------------------------
 
   %(src_passTests_py)s                              : PASS    
index d73853042c85e8286f55cd6c7885ba61ced67b19..0ca822db0130b97f631286091f7e8b1c4f9ccdcb 100644 (file)
@@ -55,7 +55,7 @@ test.write('t.txt', """\
 # NOTE:  The "test/fail.py : FAIL" and "test/pass.py : PASS" lines both
 # have spaces at the end.
 
-expect = """qmtest.py run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" %(test_pass_py)s
+expect = """qmtest run --output results.qmr --format none --result-stream="scons_tdb.AegisChangeStream" %(test_pass_py)s
 --- TEST RESULTS -------------------------------------------------------------
 
   %(test_pass_py)s                                  : PASS    
index 45426add44a04245ba65a678a576a540a0f6122d..3fdc9c0f571e57a8a02dbd9c7ac51e0d19d38a4a 100644 (file)
@@ -58,7 +58,7 @@ def cat(target, source, env):
 env=Environment()
 Export('env')
 env['BUILDERS']['Cat']=Builder(action=cat, multi=1)
-SConscript('src/SConscript',build_dir='build')
+SConscript('src/SConscript',variant_dir='build')
 """)
 
 test.subdir('src')
index 27e48679f5a7cd730c5457961c52ebd085ec2e2f..269056137e5c39f05f103667b19cfb116833c176 100644 (file)
@@ -27,8 +27,10 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 """
 Verify that the sconsign script works when using a .sconsign file in
 each subdirectory (SConsignFile(None)) written with the non-default
-SourceSignatures() and TargetSignatures() values (timestamp and content,
-respectively).
+value of Decider('timestamp-newer').
+
+This used to test the non-default combination of
+SourceSignatures('timestamp') with TargetSignatures('content').
 """
 
 import TestSCons
@@ -95,8 +97,7 @@ sys.exit(0)
 
 test.write('SConstruct', """
 SConsignFile(None)
-SourceSignatures('timestamp')
-TargetSignatures('content')
+Decider('timestamp-newer')
 env1 = Environment(PROGSUFFIX = '.exe',
                    OBJSUFFIX = '.obj',
                    CCCOM = r'%(_python_)s fake_cc.py sub2 $TARGET $SOURCE',
index 1b359e238c08d08dfea05b5f95d5da330ce47bb1..a21ede0497b75bdca96b272c4b66caf618d72474 100644 (file)
@@ -48,8 +48,7 @@ sub1_hello_obj  = 'sub1/hello.obj'
 
 test.write('SConstruct', """
 SConsignFile('my_sconsign')
-SourceSignatures('timestamp')
-TargetSignatures('content')
+Decider('timestamp-newer')
 env1 = Environment(PROGSUFFIX = '.exe', OBJSUFFIX = '.obj')
 env1.Program('sub1/hello.c')
 env2 = env1.Clone(CPPPATH = ['sub2'])
index 7c2e510c666cb13ef389859b13b5a4c60852f9d8..0b56442bf358553c04d07839b19a8b8f9a6015c1 100644 (file)
@@ -27,6 +27,11 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 """
 Test changing the C source files based on an always-executed revision
 extraction and substitution.
+
+This makes sure we evaluate the content of intermediate files as
+expected.  We used to configure this explicitly using
+TargetSignatures('content') but we now rely on the default behavior
+being the equivalent of Decider('content').
 """
 
 import os.path
@@ -60,7 +65,6 @@ SubRevision = Action(subrevision)
 
 env=Environment()
 content_env=env.Clone()
-content_env.TargetSignatures('content')
 content_env.Command('revision.in', [], '%(_python_)s getrevision > $TARGET')
 content_env.AlwaysBuild('revision.in')
 env.Precious('main.c')
index 72c776662203d466e1e91eea7b3f25d25c33dc19..64f914a0f1c655f847c1f6d16944e1e752cbbee8 100644 (file)
@@ -26,8 +26,13 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
 Verify that rebuilds do not occur when SConsignFile(None) is used to
-put a .sconsign file in each directory, and TargetSignatures('content')
-is used to subdivide a dependency tree.
+put a .sconsign file in each directory and we subdvide the dependency
+tree with subsidiary *SConstruct* files in various subdirectories.
+
+This depends on using content signatures for evaluation of intermediate
+Nodes.  We used to configure this explicitly using
+TargetSignatures('content'), but we now rely on the default behavior
+being the equivalent of Decider('content').
 """
 
 import os.path
@@ -66,7 +71,6 @@ for s in sys.argv[2:]:
 
 test.write('SConstruct', """\
 SConsignFile(None)
-TargetSignatures('content')
 env = Environment(PROGSUFFIX = '.exe',
                   OBJSUFFIX = '.obj',
                   CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES',
@@ -77,7 +81,6 @@ env.Object('foo.c')
 
 test.write(['src', 'SConstruct'], """\
 SConsignFile(None)
-TargetSignatures('content')
 env = Environment(PROGSUFFIX = '.exe',
                   OBJSUFFIX = '.obj',
                   CCCOM = r'%(_python_)s fake_cc.py $TARGET $SOURCES',
similarity index 98%
rename from test/symlink/BuildDir.py
rename to test/symlink/VariantDir.py
index 6394e0a57902b0b6625b96a120c1e7b1ec3c3d71..a6dd30be53efe5d482c120abb6441b1bd5213c43 100644 (file)
@@ -45,7 +45,7 @@ test.subdir('obj',
 
 test.write('SConstruct', """
 env = Environment()
-BuildDir('obj/subdir', 'src')
+VariantDir('obj/subdir', 'src')
 Program('hello', ['obj/subdir/main.c'])
 """)
 
similarity index 93%
rename from test/toolpath/BuildDir.py
rename to test/toolpath/VariantDir.py
index a8b8b8a410ae08c2bbbe5871de2d353608f1b8ae..30f126bbad9b99e39fd3a119cdef54e9f85bdcf4 100644 (file)
@@ -25,7 +25,7 @@
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 """
-Verify that toolpath works with BuildDir() for an SConscript.
+Verify that toolpath works with VariantDir() for an SConscript.
 """
 
 import TestSCons
@@ -35,7 +35,7 @@ test = TestSCons.TestSCons()
 test.subdir('subdir', ['subdir', 'src'], ['subdir', 'src', 'tools'])
 
 test.write('SConstruct', """\
-BuildDir('build', 'subdir', duplicate=0)
+VariantDir('build', 'subdir', duplicate=0)
 SConscript('build/SConscript')
 """)
 
@@ -65,7 +65,7 @@ test.must_match(['build', 'src', 'file.out'], "subdir/src/file.in\n")
 # We should look for the underlying tool in both the build/src/tools
 # (which doesn't exist) and subdir/src/tools (which still does).  If we
 # don't, the following would fail because the execution directory is
-# now relative to the created BuildDir.
+# now relative to the created VariantDir.
 test.run()
 
 test.pass_test()