From 59e64828f020d3f654718821030a23200947bacc Mon Sep 17 00:00:00 2001 From: stevenknight Date: Mon, 31 Mar 2008 17:03:04 +0000 Subject: [PATCH] Merged revisions 2647-2719 via svnmerge from http://scons.tigris.org/svn/scons/branches/core ........ r2649 | stevenknight | 2008-02-08 06:43:30 -0800 (Fri, 08 Feb 2008) | 3 lines Make the "bootstrap" copy directory relative to the script location regardless of where the user is when executing. ........ r2650 | stevenknight | 2008-02-09 09:26:40 -0800 (Sat, 09 Feb 2008) | 3 lines Chdir back to the original directory before removing our temporary directory, to avoid "Permission denied" errors on Windows. ........ r2651 | stevenknight | 2008-02-09 10:02:09 -0800 (Sat, 09 Feb 2008) | 3 lines Fix floating-point numbers confusing our notion of the .class files that will be generated in certain configurations. ........ r2652 | stevenknight | 2008-02-09 10:26:48 -0800 (Sat, 09 Feb 2008) | 4 lines Issue 1868: change the RootDir "lookup path" from '/' to '' so that looking up '/foo' returns the same node as looking up 'foo' when the current directory is the root. ........ r2653 | stevenknight | 2008-02-09 11:16:17 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1902: Document all the values that can now be fetched with GetOption. Additional formatting cleanups. ........ r2654 | stevenknight | 2008-02-09 11:37:50 -0800 (Sat, 09 Feb 2008) | 3 lines Fix handling file names that contain substrings of multiple spaces when using ActionFactory instances like Copy() and Move(). ........ r2655 | stevenknight | 2008-02-09 13:36:14 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1898: Fix use of a variable expansion in a source file name (like foo$OBJSUFFIX) when trying to match source builder suffixes. ........ r2656 | stevenknight | 2008-02-09 20:58:32 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1903: don't allow Java generics syntax to interfere with identifying an anonymous inner class. ........ r2657 | stevenknight | 2008-02-09 21:02:37 -0800 (Sat, 09 Feb 2008) | 3 lines Left out the \w from the regular expression that matches generics, so we wouldn't match alphanumerics, only alphabetics. ........ r2658 | stevenknight | 2008-02-09 23:33:03 -0800 (Sat, 09 Feb 2008) | 3 lines Issue 1899: Enhance Chmod(), Delete(), Mkdir() and Touch() to take lists of Nodes or strings. ........ r2659 | stevenknight | 2008-02-10 00:15:24 -0800 (Sun, 10 Feb 2008) | 4 lines Issue 1878: Add comment lines to the generated config.h file describing the intent of the various #define/#undef lines. (David Cournapeau) ........ r2660 | stevenknight | 2008-02-11 18:15:27 -0800 (Mon, 11 Feb 2008) | 3 lines Issue 1682: Fix the ability to save and restore the ListOption value 'all' in newer Python versions that have an all() built-in function. ........ r2661 | stevenknight | 2008-02-27 07:25:18 -0800 (Wed, 27 Feb 2008) | 3 lines Issue 1919: Optimize the SCons.Util.is_*() and SCons.Util.flatten() functions. More efficient suffix selection in Selector.__call__() method. ........ r2662 | stevenknight | 2008-02-28 06:43:29 -0800 (Thu, 28 Feb 2008) | 3 lines Fix SCons.Util.is_List() method to use the passed-in ListTypes variable. (Daniel Svensson) ........ r2663 | stevenknight | 2008-02-28 06:57:44 -0800 (Thu, 28 Feb 2008) | 4 lines Issue 1884: avoid an infinite loop when trying to use saved copies of the ToolInitializer objects that we use to initialize the env.Install() and env.InstallAs() methods. ........ r2664 | garyo | 2008-02-28 07:25:25 -0800 (Thu, 28 Feb 2008) | 1 line Fix long-style command-line args in runtest.py (they were missing from getopt call). ........ r2665 | garyo | 2008-02-28 09:31:42 -0800 (Thu, 28 Feb 2008) | 1 line runtest.py: Use qmtest instead of qmtest.py; newer QMTest releases may only have qmtest in /usr/bin. ........ r2666 | stevenknight | 2008-02-28 12:10:02 -0800 (Thu, 28 Feb 2008) | 3 lines Remove dead code that was at one time apparently intended to grab the external environment's %INCLUDE% values. ........ r2667 | stevenknight | 2008-02-28 12:16:40 -0800 (Thu, 28 Feb 2008) | 3 lines Move the regular expression and function that check for whether a construction variable name is legal from Util.py to Environment.py. ........ r2668 | stevenknight | 2008-02-28 20:24:36 -0800 (Thu, 28 Feb 2008) | 2 lines Fix qmtest.py references (replace with qmtest) in tests and infrastructure. ........ r2669 | stevenknight | 2008-02-28 20:27:05 -0800 (Thu, 28 Feb 2008) | 7 lines Speed up the SubstitionEnvironment.__setitem__() method by: 1) avoiding checking for whether the variable name is legal if it already exists; 2) use the regular expression directly when checking the form for illegality; 3) more efficient check for whether a variable name is special. Add a timing script so we can document why we implemented it as we did and revisit it in the future if need be. ........ r2670 | stevenknight | 2008-02-28 20:51:44 -0800 (Thu, 28 Feb 2008) | 2 lines Add a shell script that generates context-diff output for review. ........ r2671 | GregNoel | 2008-03-01 00:40:16 -0800 (Sat, 01 Mar 2008) | 1 line add test to env.__setitem__ benchmark ........ r2672 | GregNoel | 2008-03-01 02:00:12 -0800 (Sat, 01 Mar 2008) | 1 line compatibility changes for env.__setitem__ benchmark ........ r2673 | stevenknight | 2008-03-01 09:56:57 -0800 (Sat, 01 Mar 2008) | 3 lines Capture a vanilla copy of the Python 2.[45] timeit.py module, as a basis for being able to use this to time Python 2.2 (and earlier). ........ r2674 | stevenknight | 2008-03-01 10:04:11 -0800 (Sat, 01 Mar 2008) | 3 lines Work around a race in the order in which we detect and report the build failures by letting the error messages show up in either order on stdout. ........ r2675 | stevenknight | 2008-03-01 10:05:24 -0800 (Sat, 01 Mar 2008) | 3 lines Back-port the captured timeit.py module, and the env.__setitem__.py script itself, to Python versions before 2.3. ........ r2676 | GregNoel | 2008-03-01 14:01:03 -0800 (Sat, 01 Mar 2008) | 1 line add banner information, remove inadvertent tabs ........ r2677 | stevenknight | 2008-03-02 05:04:52 -0800 (Sun, 02 Mar 2008) | 3 lines Don't look for a Copyright string in the source-packaged bench/timeit.py module that we captured. ........ r2678 | stevenknight | 2008-03-02 14:59:39 -0800 (Sun, 02 Mar 2008) | 6 lines Issue 1884: Allow env.{Install,InstallAs}() to be replaced by user- supplied wrappers that call the underlying builder. Fix how environment cloning so it only clones dynamically-added method attributes that the user hasn't also overwritten explicity. ........ r2679 | stevenknight | 2008-03-04 07:48:53 -0800 (Tue, 04 Mar 2008) | 3 lines Fix env.{Dir,Entry,File}() when the input is a list, broken last December when env.subst() was modified to return lists as-is. ........ r2680 | stevenknight | 2008-03-04 08:24:06 -0800 (Tue, 04 Mar 2008) | 2 lines Fix printing Python Value Nodes in --debug=explain output. (Jim Randall) ........ r2681 | garyo | 2008-03-04 12:37:39 -0800 (Tue, 04 Mar 2008) | 1 line Make File(), Dir() and Entry() return lists when passed a sequence. ........ r2682 | garyo | 2008-03-05 15:24:00 -0800 (Wed, 05 Mar 2008) | 1 line InstallBuilderWrapper and InstallBuilderWrapper should accept keyword args and pass them to the base builder, like other builders. ........ r2683 | stevenknight | 2008-03-06 06:32:13 -0800 (Thu, 06 Mar 2008) | 2 lines Python 1.5.2 compatibility: use apply() instead of **kw. ........ r2684 | garyo | 2008-03-14 13:07:09 -0700 (Fri, 14 Mar 2008) | 1 line Fix QMTest problem with $TERM variable in user's environment causing test failures. ........ r2685 | bdbaddog | 2008-03-14 13:16:20 -0700 (Fri, 14 Mar 2008) | 13 lines * Added java_where_includes - gets path list for java JDK's include dirs * Added java_where_java_home - gets JAVA_HOME path * Added path's to find java for sun's JDK rpm install to java_where_jar * moved paths() to be outside of java_ENV() routine and available for other routines to use as well as tests * set TERM to be dumb to fix broken readline causing massive failures on FC8 (only updated Gary's comments to include note about broken FC8 readline, as Gary committed the TERM just prior to my checkin) * Modified the following tests to use the above changes: * test/SWIG/SWIGOUTDIR.py * test/Java/swig-dependencies.py * test/Java/multi-step.py * test/Repository/Java.py * test/runtest/fallback.py [ This test also has been changed to remove more than one qmtest in your PATH, previously it would only remove one path which had qmtest, my system had a local and a system version ] ........ r2686 | stevenknight | 2008-03-15 20:50:07 -0700 (Sat, 15 Mar 2008) | 4 lines Add a warning about deprecating support for Python versions 1.5, 2.0 and 2.1. Fix the ability to SetOption('warn') so people can disable the warning by adding something to a SConscript file. ........ r2687 | stevenknight | 2008-03-15 21:48:26 -0700 (Sat, 15 Mar 2008) | 3 lines Issue 1942: Document the Dir(), File() and Entry() methods of Dir and File Nodes. (Greg Noel) ........ r2688 | GregNoel | 2008-03-16 00:05:04 -0700 (Sun, 16 Mar 2008) | 1 line Add parse_flags keyword option ........ r2689 | stevenknight | 2008-03-16 00:32:33 -0700 (Sun, 16 Mar 2008) | 3 lines Print a message if we're skipping the build of a package because the necessary underlying tool doesn't exist. ........ r2690 | stevenknight | 2008-03-16 00:40:28 -0700 (Sun, 16 Mar 2008) | 7 lines Add --warn=no-python-version to the $SCONSFLAGS variable when running tests under deprecated Python versions, so the warning doesn't interfere with running normal tests under those version. Have the test/python-version.py remove --warn=no-python-version from the $SCONSFLAGS variable, since it's explicitly testing that behavior. ........ r2691 | stevenknight | 2008-03-16 08:20:54 -0700 (Sun, 16 Mar 2008) | 4 lines Handle ripple effects from setting $SCONSFLAGS to suppress the deprecation under older Python versions by commonizing and moving much of the logic in QMTest/TestSCons.py. ........ r2692 | stevenknight | 2008-03-16 08:47:52 -0700 (Sun, 16 Mar 2008) | 5 lines Update the warning message for running under a deprecated Python version (text courtesy Greg Noel). Make that warning a subclass of the DeprecatedWarning class, so the message can also be disabled by setting --warn=no-deprecated. ........ r2693 | stevenknight | 2008-03-16 11:19:52 -0700 (Sun, 16 Mar 2008) | 4 lines Shorten the deprecated-python-version warning. Use sys.version_info to check, instead of hard-coded string comparisons. Edit the release note. ........ r2694 | stevenknight | 2008-03-16 11:29:10 -0700 (Sun, 16 Mar 2008) | 3 lines Have the warning mention both that 2.2 is the base un-deprecated version and the version they're running without getting too wordy. ........ r2695 | stevenknight | 2008-03-16 12:00:22 -0700 (Sun, 16 Mar 2008) | 2 lines Skip test/SWIG/SWIGOUTDIR.py if no installed jni.h files are found. ........ r2696 | stevenknight | 2008-03-18 18:01:46 -0700 (Tue, 18 Mar 2008) | 2 lines Remove old, commented-out deprecation test code. ........ r2697 | stevenknight | 2008-03-19 17:54:55 -0700 (Wed, 19 Mar 2008) | 2 lines Deprecate env.Copy() with a suppressable message. ........ r2699 | stevenknight | 2008-03-20 08:20:22 -0700 (Thu, 20 Mar 2008) | 2 lines Move the debug-nomemoizer.py test to the test/Deprecated subdirectory. ........ r2700 | stevenknight | 2008-03-20 08:37:51 -0700 (Thu, 20 Mar 2008) | 2 lines Issue 1954: Adds deprecation warnings for --debug={dtree,stree,tree}. ........ r2701 | stevenknight | 2008-03-23 00:33:25 -0700 (Sun, 23 Mar 2008) | 7 lines Add VariantDir() as a replacement for BuildDir(). Change "build directory" references in text (comments and documentation) to "variant directory." Move and rename tests that named BuildDir in their path. Add a release note about the forthcoming deprecation of BuildDir(). Add a test/Deprecated/BuildDir.py to track backwards compatibility. ........ r2702 | stevenknight | 2008-03-24 11:23:39 -0700 (Mon, 24 Mar 2008) | 4 lines Change the VariantDir() and SConscrip "build_dir" keyword to "variant_dir." Still support "build_dir" for (you guessed it) backwards compatibility. Add documentation update and release note. ........ r2703 | garyo | 2008-03-25 07:57:01 -0700 (Tue, 25 Mar 2008) | 1 line Improve Install error message when target and source list lengths don't match. ........ r2704 | garyo | 2008-03-25 08:10:24 -0700 (Tue, 25 Mar 2008) | 1 line Allow executing main scons.py script without running scons, using standard if __name__==__main__ idiom. ........ r2705 | stevenknight | 2008-03-26 08:51:58 -0700 (Wed, 26 Mar 2008) | 3 lines Update scripts that use {Source,Target}Signatures() to use Decider() or the default behavior. Update test condition checks as necessary. ........ r2706 | stevenknight | 2008-03-27 14:13:50 -0700 (Thu, 27 Mar 2008) | 2 lines Update some leftover uses of env.Copy() in some test scripts to env.Clone(). ........ r2707 | stevenknight | 2008-03-27 14:20:33 -0700 (Thu, 27 Mar 2008) | 6 lines Fix use of SetOption('warn') to disable warning messages. Refactor the Script.Main._setup_warn() function into Warnings.process_warn_strings(). Split test/option--warn.py into separate test/option/warn-*.py scripts for the individual subtests it contained. ........ r2708 | stevenknight | 2008-03-27 15:17:44 -0700 (Thu, 27 Mar 2008) | 5 lines Deprecate the {Target,Source}Signatures() functions and methods. Move the test scripts underneath the test/Deprecated directory. Update man page with the new --warn=* options (and some that were overlooked on previous checkins). Add a release note. ........ r2709 | stevenknight | 2008-03-27 23:22:38 -0700 (Thu, 27 Mar 2008) | 2 lines More conversion of env.Copy() calls to env.Clone(). ........ r2710 | stevenknight | 2008-03-28 00:09:40 -0700 (Fri, 28 Mar 2008) | 3 lines Test updates for old Python versions (1.5.2) now that we generate a warning message about the deprecation. ........ r2711 | stevenknight | 2008-03-28 22:11:03 -0700 (Fri, 28 Mar 2008) | 3 lines Chmod the built packages in build/dist to 0644 so they're publicy readable when they're copied over to the snapshot system. ........ r2712 | stevenknight | 2008-03-28 22:11:54 -0700 (Fri, 28 Mar 2008) | 3 lines Issue 1951: have Copy() preserve file times and mode when copying over individual files. (Leanid Nazdrynau) ........ r2713 | stevenknight | 2008-03-29 06:49:27 -0700 (Sat, 29 Mar 2008) | 3 lines Don't bother checking for equivalent file access times. Under system load it can vary because we do actually access the file. ........ r2714 | GregNoel | 2008-03-29 17:24:25 -0700 (Sat, 29 Mar 2008) | 1 line Fix regression test using Python 1.5.2 on OS X ........ r2715 | GregNoel | 2008-03-29 20:44:19 -0700 (Sat, 29 Mar 2008) | 1 line 'Copy' conflicts with 'copy' on case-insensitive file systems ........ r2716 | stevenknight | 2008-03-29 21:00:13 -0700 (Sat, 29 Mar 2008) | 3 lines Capture scripts for downloading and installing different versions of Python and SCons. ........ r2717 | stevenknight | 2008-03-30 08:48:28 -0700 (Sun, 30 Mar 2008) | 3 lines Fix a regression in how subst_path() handles lists (like a ListOption) in expansions of things like $CPPDEFINES and $CPPPATH. ........ r2718 | stevenknight | 2008-03-30 10:02:21 -0700 (Sun, 30 Mar 2008) | 6 lines User's Guide updates: -- Paragraph about deprecated BuildDir(). -- Updated output using the jar -C option. -- Updated default environment Dump(). -- Updated --debug=stacktrace output. ........ r2719 | stevenknight | 2008-03-31 00:50:08 -0700 (Mon, 31 Mar 2008) | 2 lines Update the branch for 0.98. ........ git-svn-id: http://scons.tigris.org/svn/scons/trunk@2721 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- QMTest/TestRuntest.py | 6 +- QMTest/TestSCons.py | 113 +++- README | 40 +- SConstruct | 26 +- bench/env.__setitem__.py | 362 +++++++++++ bench/timeit.py | 297 +++++++++ bin/install-python.sh | 119 ++++ bin/install-scons.sh | 176 ++++++ bin/scons-review.sh | 24 + bootstrap.py | 3 + doc/SConscript | 11 +- doc/man/scons.1 | 585 ++++++++++++++---- doc/scons.mod | 2 + doc/user/java.xml | 4 +- doc/user/separate.in | 74 ++- doc/user/separate.xml | 74 ++- doc/user/troubleshoot.xml | 12 +- doc/user/variants.in | 6 +- doc/user/variants.xml | 6 +- runtest.py | 8 +- src/CHANGES.txt | 84 ++- src/RELEASE.txt | 299 ++++++++- src/engine/SCons/Action.py | 19 +- src/engine/SCons/ActionTests.py | 19 +- src/engine/SCons/Builder.py | 9 +- src/engine/SCons/BuilderTests.py | 36 +- src/engine/SCons/Conftest.py | 39 +- src/engine/SCons/Defaults.py | 104 ++-- src/engine/SCons/Environment.py | 149 ++++- src/engine/SCons/EnvironmentTests.py | 149 ++++- src/engine/SCons/Node/FS.py | 69 ++- src/engine/SCons/Node/FSTests.py | 108 ++-- src/engine/SCons/Node/__init__.py | 9 +- src/engine/SCons/Options/ListOption.py | 2 +- src/engine/SCons/Options/__init__.py | 27 +- src/engine/SCons/SConf.py | 2 +- src/engine/SCons/Scanner/CTests.py | 8 +- src/engine/SCons/Scanner/FortranTests.py | 6 +- src/engine/SCons/Scanner/IDLTests.py | 6 +- src/engine/SCons/Scanner/Prog.py | 4 +- src/engine/SCons/Script/Interactive.py | 4 +- src/engine/SCons/Script/Main.py | 91 ++- src/engine/SCons/Script/SConsOptions.py | 51 +- src/engine/SCons/Script/SConscript.py | 14 +- src/engine/SCons/Script/__init__.py | 1 + src/engine/SCons/Taskmaster.py | 4 +- src/engine/SCons/Tool/JavaCommon.py | 14 +- src/engine/SCons/Tool/JavaCommonTests.py | 69 +++ src/engine/SCons/Tool/__init__.py | 119 +++- src/engine/SCons/Tool/applelink.py | 3 +- src/engine/SCons/Tool/dvips.py | 2 +- src/engine/SCons/Tool/install.py | 25 +- src/engine/SCons/Tool/msvc.py | 4 - src/engine/SCons/Tool/msvs.py | 2 +- src/engine/SCons/Tool/qt.xml | 4 +- src/engine/SCons/Util.py | 149 ++++- src/engine/SCons/UtilTests.py | 61 +- src/engine/SCons/Warnings.py | 69 ++- src/engine/SCons/compat/__init__.py | 10 + src/engine/SCons/cppTests.py | 2 +- src/script/scons.py | 5 +- src/test_strings.py | 1 + test/Alias/Alias.py | 2 +- test/Alias/errors.py | 2 +- test/Alias/srcdir.py | 6 +- test/CPPPATH/CPPPATH.py | 4 +- test/CPPPATH/match-dir.py | 2 +- test/CacheDir/{BuildDir.py => VariantDir.py} | 4 +- test/Chmod.py | 35 ++ ...SConscript.py => VariantDir-SConscript.py} | 4 +- test/Configure/{BuildDir.py => VariantDir.py} | 4 +- test/Configure/cache-not-ok.py | 12 +- test/Configure/cache-ok.py | 8 +- test/Configure/config-h.py | 26 + test/{Copy.py => Copy-Action.py} | 53 +- test/Delete.py | 15 + test/Deprecated/BuildDir.py | 277 +++++++++ .../CacheDir/timestamp-content.py | 1 + .../CacheDir/timestamp-timestamp.py | 1 + test/Deprecated/Copy.py | 52 ++ .../SConscript-build_dir.py} | 14 +- .../SourceSignatures/basic.py | 26 +- test/{ => Deprecated}/SourceSignatures/env.py | 21 +- .../SourceSignatures/implicit-cache.py | 25 +- .../SourceSignatures/no-csigs.py | 5 +- .../SourceSignatures/overrides.py | 9 +- .../SourceSignatures/switch-rebuild.py | 21 +- .../TargetSignatures/build-content.py | 24 +- .../TargetSignatures/content.py | 8 +- .../TargetSignatures/overrides.py | 6 +- test/{option => Deprecated}/debug-dtree.py | 14 +- .../debug-nomemoizer.py | 0 test/{option => Deprecated}/debug-stree.py | 14 +- test/{option => Deprecated}/debug-tree.py | 14 +- test/Dir/source.py | 172 ++--- test/Fortran/F77PATH.py | 4 +- test/Fortran/F90PATH.py | 4 +- test/Fortran/FORTRANPATH.py | 4 +- test/GetBuildFailures/parallel.py | 31 +- test/Glob/{BuildDir.py => VariantDir.py} | 6 +- test/Glob/source.py | 8 +- test/Glob/strings.py | 4 +- test/IDL/midl.py | 4 +- test/Install/Install.py | 6 + test/Install/InstallAs.py | 5 + test/Install/wrap-by-attribute.py | 101 +++ ...cit-BuildDir.py => implicit-VariantDir.py} | 6 +- test/Java/multi-step.py | 10 +- test/Java/swig-dependencies.py | 4 +- test/MSVC/msvc.py | 2 +- ...uildDir-path.py => pdb-VariantDir-path.py} | 4 +- test/MSVS/vs-6.0-files.py | 2 +- test/MSVS/vs-7.0-files.py | 2 +- test/MSVS/vs-7.1-files.py | 2 +- test/MSVS/vs-8.0-files.py | 2 +- test/Mkdir.py | 13 +- test/NodeOps.py | 18 +- test/Options/ListOption.py | 36 +- test/QT/QTFLAGS.py | 4 +- test/QT/installed.py | 2 +- test/QT/moc-from-cpp.py | 6 +- test/QT/moc-from-header.py | 6 +- test/QT/source-from-ui.py | 6 +- test/Repository/Java.py | 5 +- test/Repository/Local.py | 2 +- test/Repository/M4.py | 2 +- .../Repository/{BuildDir.py => VariantDir.py} | 4 +- test/Repository/variants.py | 6 +- test/SCONSFLAGS.py | 25 +- test/SConscript/src_dir.py | 2 +- test/SWIG/SWIGOUTDIR.py | 7 +- test/SWIG/build-dir.py | 4 +- test/Scanner/generated.py | 2 +- .../{build_dir.py => variant_dir.py} | 4 +- test/TARGET-dir.py | 6 +- test/TEX/auxiliaries.py | 2 +- test/TEX/{build_dir.py => variant_dir.py} | 6 +- ...{build_dir_dup0.py => variant_dir_dup0.py} | 6 +- test/Touch.py | 18 + test/Value.py | 4 +- .../CPPPATH-subdir.py | 2 +- test/{BuildDir => VariantDir}/Clean.py | 8 +- test/{BuildDir => VariantDir}/File-create.py | 6 +- test/VariantDir/SConscript-variant_dir.py | 272 ++++++++ .../BuildDir.py => VariantDir/VariantDir.py} | 20 +- test/{BuildDir => VariantDir}/errors.py | 16 +- test/{BuildDir => VariantDir}/guess-subdir.py | 6 +- .../nested-sconscripts.py | 4 +- test/{BuildDir => VariantDir}/reflect.py | 12 +- .../{BuildDir => VariantDir}/removed-files.py | 4 +- test/{BuildDir => VariantDir}/under.py | 10 +- test/emitter.py | 6 +- test/explain/basic.py | 22 +- test/implicit-cache/basic.py | 29 +- test/no-global-dependencies.py | 6 +- test/option--U.py | 2 +- test/option--duplicate.py | 2 +- test/option--warn.py | 176 ------ test/option-n.py | 6 +- test/option-u.py | 6 +- test/option/debug-memoizer.py | 2 +- test/option/warn-dependency.py | 73 +++ test/option/warn-duplicate-environment.py | 80 +++ test/option/warn-misleading-keywords.py | 79 +++ test/option/warn-missing-sconscript.py | 69 +++ test/packaging/use-builddir.py | 6 +- test/python-version.py | 75 +++ test/runtest/baseline/combined.py | 2 +- test/runtest/baseline/fail.py | 2 +- test/runtest/baseline/no_result.py | 2 +- test/runtest/baseline/pass.py | 2 +- test/runtest/fallback.py | 14 +- test/runtest/print_time.py | 2 +- test/runtest/python.py | 2 +- test/runtest/simple/combined.py | 2 +- test/runtest/simple/fail.py | 2 +- test/runtest/simple/no_result.py | 2 +- test/runtest/simple/pass.py | 2 +- test/runtest/src.py | 2 +- test/runtest/testlistfile.py | 2 +- test/sconsign/ghost-entries.py | 2 +- test/sconsign/script/Signatures.py | 9 +- test/sconsign/script/dblite.py | 3 +- test/srcchange.py | 6 +- test/subdivide.py | 11 +- test/symlink/{BuildDir.py => VariantDir.py} | 2 +- test/toolpath/{BuildDir.py => VariantDir.py} | 6 +- 187 files changed, 4869 insertions(+), 1295 deletions(-) create mode 100644 bench/env.__setitem__.py create mode 100644 bench/timeit.py create mode 100644 bin/install-python.sh create mode 100644 bin/install-scons.sh create mode 100755 bin/scons-review.sh rename test/CacheDir/{BuildDir.py => VariantDir.py} (97%) rename test/Configure/{BuildDir-SConscript.py => VariantDir-SConscript.py} (99%) rename test/Configure/{BuildDir.py => VariantDir.py} (97%) rename test/{Copy.py => Copy-Action.py} (73%) create mode 100644 test/Deprecated/BuildDir.py rename test/{ => Deprecated}/CacheDir/timestamp-content.py (98%) rename test/{ => Deprecated}/CacheDir/timestamp-timestamp.py (98%) create mode 100644 test/Deprecated/Copy.py rename test/{BuildDir/Sconscript-build_dir.py => Deprecated/SConscript-build_dir.py} (95%) rename test/{ => Deprecated}/SourceSignatures/basic.py (79%) rename test/{ => Deprecated}/SourceSignatures/env.py (82%) rename test/{ => Deprecated}/SourceSignatures/implicit-cache.py (71%) rename test/{ => Deprecated}/SourceSignatures/no-csigs.py (93%) rename test/{ => Deprecated}/SourceSignatures/overrides.py (85%) rename test/{ => Deprecated}/SourceSignatures/switch-rebuild.py (74%) rename test/{ => Deprecated}/TargetSignatures/build-content.py (85%) rename test/{ => Deprecated}/TargetSignatures/content.py (88%) rename test/{ => Deprecated}/TargetSignatures/overrides.py (90%) rename test/{option => Deprecated}/debug-dtree.py (87%) rename test/{option => Deprecated}/debug-nomemoizer.py (100%) rename test/{option => Deprecated}/debug-stree.py (88%) rename test/{option => Deprecated}/debug-tree.py (90%) rename test/Glob/{BuildDir.py => VariantDir.py} (94%) create mode 100644 test/Install/wrap-by-attribute.py rename test/Interactive/{implicit-BuildDir.py => implicit-VariantDir.py} (94%) rename test/MSVC/{pdb-BuildDir-path.py => pdb-VariantDir-path.py} (90%) rename test/Repository/{BuildDir.py => VariantDir.py} (98%) rename test/SideEffect/{build_dir.py => variant_dir.py} (96%) rename test/TEX/{build_dir.py => variant_dir.py} (97%) rename test/TEX/{build_dir_dup0.py => variant_dir_dup0.py} (97%) rename test/{BuildDir => VariantDir}/CPPPATH-subdir.py (97%) rename test/{BuildDir => VariantDir}/Clean.py (90%) rename test/{BuildDir => VariantDir}/File-create.py (91%) create mode 100644 test/VariantDir/SConscript-variant_dir.py rename test/{BuildDir/BuildDir.py => VariantDir/VariantDir.py} (96%) rename test/{BuildDir => VariantDir}/errors.py (92%) rename test/{BuildDir => VariantDir}/guess-subdir.py (91%) rename test/{BuildDir => VariantDir}/nested-sconscripts.py (94%) rename test/{BuildDir => VariantDir}/reflect.py (91%) rename test/{BuildDir => VariantDir}/removed-files.py (97%) rename test/{BuildDir => VariantDir}/under.py (88%) delete mode 100644 test/option--warn.py create mode 100644 test/option/warn-dependency.py create mode 100644 test/option/warn-duplicate-environment.py create mode 100644 test/option/warn-misleading-keywords.py create mode 100644 test/option/warn-missing-sconscript.py create mode 100644 test/python-version.py rename test/symlink/{BuildDir.py => VariantDir.py} (98%) rename test/toolpath/{BuildDir.py => VariantDir.py} (93%) diff --git a/QMTest/TestRuntest.py b/QMTest/TestRuntest.py index ee33b250..e44cd27b 100644 --- a/QMTest/TestRuntest.py +++ b/QMTest/TestRuntest.py @@ -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', diff --git a/QMTest/TestSCons.py b/QMTest/TestSCons.py index 6b6f5ed7..d5aa057f 100644 --- a/QMTest/TestSCons.py +++ b/QMTest/TestSCons.py @@ -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 36dbe230..5cb92013 100644 --- 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. diff --git a/SConstruct b/SConstruct index 72e3e064..226513b9 100644 --- a/SConstruct +++ b/SConstruct @@ -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 index 00000000..3826176f --- /dev/null +++ b/bench/env.__setitem__.py @@ -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 index 00000000..d5e33bb1 --- /dev/null +++ b/bench/timeit.py @@ -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 = "" +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 index 00000000..699a2807 --- /dev/null +++ b/bin/install-python.sh @@ -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 <&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 index 00000000..50c1ccec --- /dev/null +++ b/bin/install-scons.sh @@ -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 index 00000000..f126333e --- /dev/null +++ b/bin/scons-review.sh @@ -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 diff --git a/bootstrap.py b/bootstrap.py index 1620bf3e..441d4715 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -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 diff --git a/doc/SConscript b/doc/SConscript index 8e13294b..0c8f070d 100644 --- a/doc/SConscript +++ b/doc/SConscript @@ -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: diff --git a/doc/man/scons.1 b/doc/man/scons.1 index ae252747..98e12e61 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -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: diff --git a/doc/scons.mod b/doc/scons.mod index e590368d..739be581 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -311,6 +311,7 @@ exports"> source"> target"> +variant_dir"> @@ -351,6 +352,7 @@ StaticLibrary"> StaticObject"> Tar"> +VariantDir"> Zip"> diff --git a/doc/user/java.xml b/doc/user/java.xml index 18769168..402d037f 100644 --- a/doc/user/java.xml +++ b/doc/user/java.xml @@ -231,8 +231,8 @@ % scons -Q 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 diff --git a/doc/user/separate.in b/doc/user/separate.in index 08bb986a..be7e6c5d 100644 --- a/doc/user/separate.in +++ b/doc/user/separate.in @@ -114,34 +114,46 @@ program using the F 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 - build directories + In &SCons;, this is usually done by creating one or more separate + variant directory trees 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. + + + + + + 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.
- Specifying a Build Directory as Part of an &SConscript; Call + Specifying a Variant Directory Tree as Part of an &SConscript; Call - 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: - SConscript('src/SConscript', build_dir='build') + SConscript('src/SConscript', variant_dir='build') env = Environment() @@ -192,11 +204,11 @@ program using the F path name.
- Why &SCons; Duplicates Source Files in a Build Directory + Why &SCons; Duplicates Source Files in a Variant Directory Tree - &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 regardless of include-file directory paths, relative references between files, @@ -209,14 +221,14 @@ program using the F path name. 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. @@ -226,7 +238,7 @@ program using the F 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 #include mechanism with double quotes, not angle brackets: @@ -251,7 +263,7 @@ program using the F 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 path name. it can 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.
- Telling &SCons; to Not Duplicate Source Files in the Build Directory + Telling &SCons; to Not Duplicate Source Files in the Variant Directory Tree @@ -287,15 +299,15 @@ program using the F path name. - SConscript('src/SConscript', build_dir='build', duplicate=0) + SConscript('src/SConscript', variant_dir='build', duplicate=0) 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: @@ -315,11 +327,11 @@ program using the F path name.
- The &BuildDir; Function + The &VariantDir; Function - 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 path name. - BuildDir('build', 'src') + VariantDir('build', 'src') env = Environment() env.Program('build/hello.c') @@ -350,9 +362,9 @@ program using the F path name. - 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: @@ -371,7 +383,7 @@ program using the F path name. - BuildDir('build', 'src', duplicate=0) + VariantDir('build', 'src', duplicate=0) env = Environment() env.Program('build/hello.c') @@ -396,11 +408,11 @@ program using the F path name.
- Using &BuildDir; With an &SConscript; File + Using &VariantDir; With an &SConscript; File - 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 path name. - BuildDir('build', 'src') + VariantDir('build', 'src') SConscript('build/SConscript') @@ -457,11 +469,11 @@ program using the F path name.