Merged revisions 1784-1824 via svnmerge from
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 11 Feb 2007 05:02:05 +0000 (05:02 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 11 Feb 2007 05:02:05 +0000 (05:02 +0000)
http://scons.tigris.org/svn/scons/branches/core

........
  r1786 | stevenknight | 2007-01-25 15:29:15 -0600 (Thu, 25 Jan 2007) | 1 line

  0.96.D555 - Doc string updates for TaskMaster to better describe the architecture. Get rid of some no-longer-used code.
........
  r1787 | stevenknight | 2007-01-25 23:24:31 -0600 (Thu, 25 Jan 2007) | 1 line

  0.96.D556 - Packaging changes to support building packages in an arbitrary directory.
........
  r1788 | stevenknight | 2007-01-30 20:35:39 -0600 (Tue, 30 Jan 2007) | 1 line

  0.96.D557 - Make the Scanner.Base class able to handle Scanner.Selector functionality (i.e., a dictionary to select other scanners) and prepare to deprecate Scanner.Selector and Scanner.Scanner() in the future.
........
  r1789 | stevenknight | 2007-01-30 20:45:23 -0600 (Tue, 30 Jan 2007) | 1 line

  0.96.D558 - Add support for a site-scons subdirectory. (Gary Oberbrunner)
........
  r1790 | stevenknight | 2007-01-31 00:36:20 -0600 (Wed, 31 Jan 2007) | 1 line

  0.96.D559 - Clean up various module imports and other pychecker-detected problems.
........
  r1791 | stevenknight | 2007-01-31 11:51:04 -0600 (Wed, 31 Jan 2007) | 1 line

  0.96.D560 - Fix detection of Java anonymous classes if a newline precedes the opening brace. (Leanid Nazdrynau)
........
  r1792 | stevenknight | 2007-02-02 11:57:59 -0600 (Fri, 02 Feb 2007) | 1 line

  0.96.D561 - Add a --bootstrap_src option to bootstrap.py; search the bootstrap.py directory by default. (Greg Noel)
........
  r1793 | stevenknight | 2007-02-02 18:04:52 -0600 (Fri, 02 Feb 2007) | 1 line

  0.96.D562 - Don't check the build/*/gentoo directories for copyright strings.
........
  r1794 | stevenknight | 2007-02-02 18:12:43 -0600 (Fri, 02 Feb 2007) | 1 line

  0.96.D563 - Fix pychecker clean-ups on later Python versions.
........
  r1795 | stevenknight | 2007-02-02 18:38:47 -0600 (Fri, 02 Feb 2007) | 1 line

  0.96.D564 - Add a NoCache() function to allow marking targets as not being suitable for propagating/ to (or retrieving from) CacheDir(). (Dave Vitek)
........
  r1796 | stevenknight | 2007-02-02 20:08:33 -0600 (Fri, 02 Feb 2007) | 1 line

  0.96.D565 - Add a --tree= option, to make the interface to dumping dependency graphs a little clearner, and give it a 'prune' option to avoid repeating the dependency walk for Nodes we've already visited.
........
  r1797 | stevenknight | 2007-02-03 20:37:25 -0600 (Sat, 03 Feb 2007) | 1 line

  0.96.D566 - Packaging fix: don't add '#' to the beginning of a build_dir name if it's already an absolute path.
........
  r1798 | stevenknight | 2007-02-03 20:53:42 -0600 (Sat, 03 Feb 2007) | 1 line

  0.96.D567 - Add backwards-compatibility for set() types, and restore the line that used them in the compatibility _subprocess.py module.
........
  r1799 | stevenknight | 2007-02-05 10:30:28 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D568 - Capture outline and build configuration for a possible future Developer's Guide.
........
  r1800 | stevenknight | 2007-02-05 11:03:37 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D569 - Exclude the new developer guide MANIFEST from Copyright string checks.
........
  r1801 | stevenknight | 2007-02-05 11:16:04 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D570 - Track fix in upstream subprocess.py. (Ralf W. Grosse-Kunstleve)
........
  r1802 | stevenknight | 2007-02-05 20:05:59 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D571 - Change the Windows installer to register scons.bat as an 'App Path', so the directory doesn't need to be added to %PATH%.
........
  r1803 | stevenknight | 2007-02-05 21:33:01 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D572 - Prepare SConf for use with the subprocess module by refactoring the Unbuffered class.
........
  r1804 | stevenknight | 2007-02-05 22:37:09 -0600 (Mon, 05 Feb 2007) | 1 line

  0.96.D573 - Get rid of left-over Node.Node.{pre,post}_actions attributes.
........
  r1805 | stevenknight | 2007-02-06 12:04:14 -0600 (Tue, 06 Feb 2007) | 1 line

  0.96.D574 - Remove leftover print in the test/CacheDir/NoCache.py test.
........
  r1806 | stevenknight | 2007-02-06 17:11:03 -0600 (Tue, 06 Feb 2007) | 1 line

  0.96.D575 - Support the ability to evaluate a ${} construction variable to select the spawner function.
........
  r1809 | stevenknight | 2007-02-07 00:30:10 -0600 (Wed, 07 Feb 2007) | 1 line

  0.96.D576 - Documentation fixes and updates.
........
  r1810 | stevenknight | 2007-02-07 15:51:20 -0600 (Wed, 07 Feb 2007) | 1 line

  0.96.D577 - Don't expect a bootstrap.py runtest.py file to be generated when swig -noproxy is used.
........
  r1811 | stevenknight | 2007-02-07 16:55:06 -0600 (Wed, 07 Feb 2007) | 1 line

  0.96.D578 - Make --srcdir a synonym for -Y/--repository.
........
  r1812 | stevenknight | 2007-02-07 23:46:22 -0600 (Wed, 07 Feb 2007) | 1 line

  0.96.D579 - More doc updates: PathAccept, #include+Repository double-quote limitation.
........
  r1817 | stevenknight | 2007-02-08 12:46:42 -0600 (Thu, 08 Feb 2007) | 1 line

  0.96.D580 - Fix use of toolpath with BuildDir.
........
  r1818 | stevenknight | 2007-02-08 12:59:23 -0600 (Thu, 08 Feb 2007) | 1 line

  0.96.D581 - Enable build of the text version of the User's Guide.
........
  r1819 | stevenknight | 2007-02-08 14:21:31 -0600 (Thu, 08 Feb 2007) | 1 line

  0.96.D582 - Fix handling of Java inner classes with JARCHDIR.
........
  r1820 | stevenknight | 2007-02-08 14:39:33 -0600 (Thu, 08 Feb 2007) | 1 line

  0.96.D583 - Add linking with -lm to the dmd.py Tool smart linker. (Anonymous)
........
  r1821 | stevenknight | 2007-02-08 17:26:29 -0600 (Thu, 08 Feb 2007) | 1 line

  0.96.D584 - Fix ParseConfig() when *FLAGS variables have been replaced with strings.
........
  r1822 | stevenknight | 2007-02-09 12:21:17 -0600 (Fri, 09 Feb 2007) | 1 line

  0.96.D585 - Fix installation of file names beginning with #. (Dave Weber)
........
  r1823 | stevenknight | 2007-02-09 14:14:47 -0600 (Fri, 09 Feb 2007) | 1 line

  0.96.D586 - Post-review improvements to recent toolpath and MergeFlags() changes. (Gary Oberbrunner, Greg Noel)
........
  r1824 | stevenknight | 2007-02-10 00:53:13 -0600 (Sat, 10 Feb 2007) | 1 line

  0.96.D587 - Commonize flags initialization between the c and c++ Tools.
........

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

144 files changed:
HOWTO/release.txt
HOWTO/subrelease.txt
QMTest/SConscript
SConstruct
bin/check [deleted file]
bin/sconsoutput.py
bootstrap.py
config
doc/SConscript
doc/developer/MANIFEST [new file with mode: 0644]
doc/developer/architecture.sgml [new file with mode: 0644]
doc/developer/branches.sgml [new file with mode: 0644]
doc/developer/copyright.sgml [new file with mode: 0644]
doc/developer/cycle.sgml [new file with mode: 0644]
doc/developer/main.sgml [new file with mode: 0644]
doc/developer/packaging.sgml [new file with mode: 0644]
doc/developer/preface.sgml [new file with mode: 0644]
doc/developer/sourcetree.sgml [new file with mode: 0644]
doc/developer/testing.sgml [new file with mode: 0644]
doc/man/scons.1
doc/user/ENV.sgml
doc/user/alias.sgml
doc/user/builders-built-in.sgml
doc/user/builders-writing.sgml
doc/user/caching.sgml
doc/user/command-line.sgml
doc/user/depends.sgml
doc/user/environments.sgml
doc/user/hierarchy.sgml
doc/user/install.sgml
doc/user/less-simple.sgml
doc/user/libraries.sgml
doc/user/nodes.in
doc/user/nodes.sgml
doc/user/preface.sgml
doc/user/repositories.in
doc/user/repositories.sgml
doc/user/separate.sgml
doc/user/simple.sgml
doc/user/sourcecode.sgml
doc/user/troubleshoot.sgml
doc/user/variants.sgml
runtest.py
src/CHANGES.txt
src/engine/MANIFEST.in
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/BuilderTests.py
src/engine/SCons/Conftest.py
src/engine/SCons/Defaults.py
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Executor.py
src/engine/SCons/Job.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Options/BoolOption.py
src/engine/SCons/Options/BoolOptionTests.py
src/engine/SCons/Options/PackageOption.py
src/engine/SCons/Options/PackageOptionTests.py
src/engine/SCons/Options/__init__.py
src/engine/SCons/PathList.py
src/engine/SCons/Platform/darwin.py
src/engine/SCons/Platform/win32.py
src/engine/SCons/SConf.py
src/engine/SCons/SConsign.py
src/engine/SCons/Scanner/Dir.py
src/engine/SCons/Scanner/ScannerTests.py
src/engine/SCons/Scanner/__init__.py
src/engine/SCons/Script/Main.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Script/__init__.py
src/engine/SCons/Subst.py
src/engine/SCons/SubstTests.py
src/engine/SCons/Taskmaster.py
src/engine/SCons/TaskmasterTests.py
src/engine/SCons/Tool/BitKeeper.py
src/engine/SCons/Tool/JavaCommon.py
src/engine/SCons/Tool/JavaCommonTests.py
src/engine/SCons/Tool/ToolTests.py
src/engine/SCons/Tool/__init__.py
src/engine/SCons/Tool/c++.py
src/engine/SCons/Tool/cc.py
src/engine/SCons/Tool/cvf.py
src/engine/SCons/Tool/dmd.py
src/engine/SCons/Tool/dvi.py
src/engine/SCons/Tool/f77.py
src/engine/SCons/Tool/f90.py
src/engine/SCons/Tool/f95.py
src/engine/SCons/Tool/fortran.py
src/engine/SCons/Tool/intelc.py
src/engine/SCons/Tool/jar.py
src/engine/SCons/Tool/mingw.py
src/engine/SCons/Tool/msvs.py
src/engine/SCons/Tool/mwcc.py
src/engine/SCons/Tool/mwld.py
src/engine/SCons/Tool/pdf.py
src/engine/SCons/Tool/qt.py
src/engine/SCons/Tool/swig.py
src/engine/SCons/Tool/tex.py
src/engine/SCons/Tool/zip.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
src/engine/SCons/Warnings.py
src/engine/SCons/__init__.py
src/engine/SCons/compat/__init__.py
src/engine/SCons/compat/_sets.py [new file with mode: 0644]
src/engine/SCons/compat/_sets15.py [new file with mode: 0644]
src/engine/SCons/compat/_subprocess.py
src/engine/SCons/cpp.py
src/script/scons-post-install.py [new file with mode: 0644]
src/script/scons.bat
src/setup.cfg
src/setup.py
src/test_pychecker.py [new file with mode: 0644]
src/test_strings.py
test/CXX/CC-variables.py [new file with mode: 0644]
test/CacheDir/NoCache.py [new file with mode: 0644]
test/Install/no-top-relative.py [new file with mode: 0644]
test/Java/JARCHDIR.py
test/Options/BoolOption.py
test/Options/PackageOption.py
test/Options/help.py
test/ParseConfig.py
test/SPAWN.py
test/SWIG/SWIG.py
test/SWIG/implicit-dependencies.py [new file with mode: 0644]
test/SWIG/live.py [new file with mode: 0644]
test/SWIG/noproxy.py [new file with mode: 0644]
test/SWIG/remove-modules.py [new file with mode: 0644]
test/Scanner/dictionary.py [new file with mode: 0644]
test/Script-import.py
test/option/debug-stree.py
test/option/repository.py [new file with mode: 0644]
test/option/srcdir.py [new file with mode: 0644]
test/option/tree-all.py [new file with mode: 0644]
test/option/tree-derived.py [new file with mode: 0644]
test/site_scons/basic.py [new file with mode: 0644]
test/site_scons/no-site-dir.py [new file with mode: 0644]
test/site_scons/nonexistent.py [new file with mode: 0644]
test/site_scons/override.py [new file with mode: 0644]
test/site_scons/site-dir.py [new file with mode: 0644]
test/toolpath/BuildDir.py [new file with mode: 0644]
test/toolpath/basic.py [moved from test/toolpath.py with 100% similarity]

index cff44b9e04418a953bd544c3a49ae6626c852183..64c62afceee1005611c3661170c8bff9a32e72da 100644 (file)
@@ -45,6 +45,12 @@ Things to do to release a new X.Y version of SCons:
 
         Check in any changes necessary to make everything work
 
+    Update the user's guide
+
+        sh bin/docdiff
+
+        sh bin/docupdate
+
     END THE CURRENT DEVELOPMENT BRANCH
 
         ae_p scons.0
index fbba52a29666fc957a2c3b5fde3bd7370a153ad3..7b9254b14ca71e86a097261635cdca2e3b3060df 100644 (file)
@@ -8,6 +8,14 @@ see the document HOWTO/release.txt.
 
 Things to do to release a new X.Y.Z version of SCons:
 
+    BEFORE STARTING THE SUB-BRANCH:
+    
+        Update the user's guide on the parent
+
+            sh bin/docdiff
+
+            sh bin/docupdate
+
     START THE NEW SUB-BRANCH FOR SUBRELEASE
 
         aenbr -p scons.0.{94} {1}
index 309f0dc234a79d22e5a118c16dfec361f1dbf0b2..3aa7d9cb40b5a6057e93cf2c452c1e1101688adc 100644 (file)
@@ -27,7 +27,7 @@
 
 import os.path
 
-Import('env')
+Import('build_dir', 'env')
 
 files = [
     'classes.qmc',
@@ -51,9 +51,10 @@ for file in files:
     # Guarantee that real copies of these files always exist in
     # build/QMTest.  If there's a symlink there, then this is an Aegis
     # build and we blow them away now so that they'll get "built" later.
-    p = os.path.join('build', 'QMTest', file)
+    p = os.path.join(build_dir, 'QMTest', file)
     if os.path.islink(p):
         os.unlink(p)
-    sp = '#' + p
-    env.Command(sp, file, copy)
-    Local(sp)
+    if not os.path.isabs(p):
+        p = '#' + p
+    env.Command(p, file, copy)
+    Local(p)
index 374cef0cdbe814cfcf86ac4865c8ccae2cdea431..76ec535ddb7694c4a929e8b626b025c98e4e9232 100644 (file)
@@ -48,8 +48,6 @@ project = 'scons'
 default_version = '0.96.94'
 copyright = "Copyright (c) %s The SCons Foundation" % copyright_years
 
-Default('.')
-
 SConsignFile()
 
 #
@@ -155,7 +153,11 @@ for key in ['AEGIS_PROJECT', 'LOGNAME', 'PYTHONPATH']:
     if os.environ.has_key(key):
         ENV[key] = os.environ[key]
 
-cwd_build = os.path.join(os.getcwd(), "build")
+build_dir = ARGUMENTS.get('BUILDDIR', 'build')
+if not os.path.isabs(build_dir):
+    build_dir = os.path.normpath(os.path.join(os.getcwd(), build_dir))
+
+Default('.', build_dir)
 
 packaging_flavors = [
     'deb',
@@ -168,17 +170,17 @@ packaging_flavors = [
     'local-zip',
 ]
 
-test_deb_dir          = os.path.join(cwd_build, "test-deb")
-test_rpm_dir          = os.path.join(cwd_build, "test-rpm")
-test_tar_gz_dir       = os.path.join(cwd_build, "test-tar-gz")
-test_src_tar_gz_dir   = os.path.join(cwd_build, "test-src-tar-gz")
-test_local_tar_gz_dir = os.path.join(cwd_build, "test-local-tar-gz")
-test_zip_dir          = os.path.join(cwd_build, "test-zip")
-test_src_zip_dir      = os.path.join(cwd_build, "test-src-zip")
-test_local_zip_dir    = os.path.join(cwd_build, "test-local-zip")
+test_deb_dir          = os.path.join(build_dir, "test-deb")
+test_rpm_dir          = os.path.join(build_dir, "test-rpm")
+test_tar_gz_dir       = os.path.join(build_dir, "test-tar-gz")
+test_src_tar_gz_dir   = os.path.join(build_dir, "test-src-tar-gz")
+test_local_tar_gz_dir = os.path.join(build_dir, "test-local-tar-gz")
+test_zip_dir          = os.path.join(build_dir, "test-zip")
+test_src_zip_dir      = os.path.join(build_dir, "test-src-zip")
+test_local_zip_dir    = os.path.join(build_dir, "test-local-zip")
 
-unpack_tar_gz_dir     = os.path.join(cwd_build, "unpack-tar-gz")
-unpack_zip_dir        = os.path.join(cwd_build, "unpack-zip")
+unpack_tar_gz_dir     = os.path.join(build_dir, "unpack-tar-gz")
+unpack_zip_dir        = os.path.join(build_dir, "unpack-zip")
 
 if platform == "win32":
     tar_hflag = ''
@@ -305,6 +307,7 @@ env = Environment(
                    ENV                 = ENV,
 
                    BUILD               = build_id,
+                   BUILDDIR            = build_dir,
                    BUILDSYS            = build_system,
                    COPYRIGHT           = copyright,
                    DATE                = date,
@@ -501,14 +504,15 @@ scons = {
                             'sconsign.1',
                             'scons-time.1',
                             'script/scons.bat',
+                            'script/scons-post-install.py',
                             'setup.cfg',
                             'setup.py',
                           ],
 
         'filemap'       : {
-                            'scons.1' : '../build/doc/man/scons.1',
-                            'sconsign.1' : '../build/doc/man/sconsign.1',
-                            'scons-time.1' : '../build/doc/man/scons-time.1',
+                            'scons.1' : '$BUILDDIR/doc/man/scons.1',
+                            'sconsign.1' : '$BUILDDIR/doc/man/sconsign.1',
+                            'scons-time.1' : '$BUILDDIR/doc/man/scons-time.1',
                           },
 
         'buildermap'    : {
@@ -525,7 +529,7 @@ scons = {
                            },
 }
 
-scripts = ['scons', 'sconsign']
+scripts = ['scons', 'sconsign', 'scons-time']
 
 src_deps = []
 src_files = []
@@ -541,7 +545,7 @@ for p in [ scons ]:
     if p.has_key('src_subdir'):
         src = os.path.join(src, p['src_subdir'])
 
-    build = os.path.join('build', pkg)
+    build = os.path.join(build_dir, pkg)
 
     tar_gz = os.path.join(build, 'dist', "%s.tar.gz" % pkg_version)
     platform_tar_gz = os.path.join(build,
@@ -629,8 +633,10 @@ for p in [ scons ]:
     #
     for b in src_files:
         s = p['filemap'].get(b, b)
+        if not s[0] == '$' and not os.path.isabs(s):
+            s = os.path.join(src, s)
         builder = p['buildermap'].get(b, env.SCons_revision)
-        x = builder(os.path.join(build, b), os.path.join(src, s))
+        x = builder(os.path.join(build, b), s)
         Local(x)
 
     #
@@ -720,7 +726,7 @@ for p in [ scons ]:
         #
         # Generate portage files for submission to Gentoo Linux.
         #
-        gentoo = os.path.join('build', 'gentoo')
+        gentoo = os.path.join(build, 'gentoo')
         ebuild = os.path.join(gentoo, 'scons-%s.ebuild' % version)
         digest = os.path.join(gentoo, 'files', 'digest-scons-%s' % version)
         env.Command(ebuild, os.path.join('gentoo', 'scons.ebuild.in'), SCons_revision)
@@ -791,10 +797,10 @@ for p in [ scons ]:
         ])
 
     if rpmbuild:
-        topdir = os.path.join(os.getcwd(), build, 'build',
+        topdir = os.path.join(build, 'build',
                               'bdist.' + platform, 'rpm')
 
-        buildroot = os.path.join(os.getcwd(), 'build', 'rpm-buildroot')
+        buildroot = os.path.join(build_dir, 'rpm-buildroot')
 
         BUILDdir = os.path.join(topdir, 'BUILD', pkg + '-' + version)
         RPMSdir = os.path.join(topdir, 'RPMS', 'noarch')
@@ -846,7 +852,7 @@ for p in [ scons ]:
     if dh_builddeb and fakeroot:
         # Our Debian packaging builds directly into build/dist,
         # so we don't need to add the .debs to install_targets.
-        deb = os.path.join('build', 'dist', "%s_%s-1_all.deb" % (pkg, version))
+        deb = os.path.join(build_dir, 'dist', "%s_%s-1_all.deb" % (pkg, version))
         for d in p['debian_deps']:
             b = env.SCons_revision(os.path.join(build, d), d)
             env.Depends(deb, b)
@@ -898,38 +904,38 @@ for p in [ scons ]:
     #
     s_l_v = '%s-local-%s' % (pkg, version)
 
-    local = os.path.join('build', pkg + '-local')
-    cwd_local = os.path.join(os.getcwd(), local)
-    cwd_local_slv = os.path.join(os.getcwd(), local, s_l_v)
+    local = pkg + '-local'
+    build_dir_local = os.path.join(build_dir, local)
+    build_dir_local_slv = os.path.join(build_dir, local, s_l_v)
 
-    local_tar_gz = os.path.join('build', 'dist', "%s.tar.gz" % s_l_v)
-    local_zip = os.path.join('build', 'dist', "%s.zip" % s_l_v)
+    local_tar_gz = os.path.join(build_dir, 'dist', "%s.tar.gz" % s_l_v)
+    local_zip = os.path.join(build_dir, 'dist', "%s.zip" % s_l_v)
 
     commands = [
-        Delete(local),
+        Delete(build_dir_local),
         '$PYTHON $PYTHONFLAGS $SETUP_PY install "--install-script=%s" "--install-lib=%s" --no-install-man --no-compile --standalone-lib --no-version-script' % \
-                                                (cwd_local, cwd_local_slv),
+                                                (build_dir_local, build_dir_local_slv),
     ]
 
     for script in scripts:
         #commands.append("mv %s/%s %s/%s.py" % (local, script, local, script))
-        local_script = os.path.join(local, script)
+        local_script = os.path.join(build_dir_local, script)
         commands.append(Move(local_script + '.py', local_script))
 
     rf = filter(lambda x: not x in scripts, raw_files)
     rf = map(lambda x, slv=s_l_v: os.path.join(slv, x), rf)
     for script in scripts:
         rf.append("%s.py" % script)
-    local_targets = map(lambda x, s=local: os.path.join(s, x), rf)
+    local_targets = map(lambda x, s=build_dir_local: os.path.join(s, x), rf)
 
     env.Command(local_targets, build_src_files, commands)
 
-    scons_LICENSE = os.path.join(local, 'scons-LICENSE')
+    scons_LICENSE = os.path.join(build_dir_local, 'scons-LICENSE')
     l = env.SCons_revision(scons_LICENSE, 'LICENSE-local')
     local_targets.append(l)
     Local(l)
 
-    scons_README = os.path.join(local, 'scons-README')
+    scons_README = os.path.join(build_dir_local, 'scons-README')
     l = env.SCons_revision(scons_README, 'README-local')
     local_targets.append(l)
     Local(l)
@@ -937,7 +943,7 @@ for p in [ scons ]:
     if gzip:
         env.Command(local_tar_gz,
                     local_targets,
-                    "cd %s && tar czf $( ${TARGET.abspath} $) *" % local)
+                    "cd %s && tar czf $( ${TARGET.abspath} $) *" % build_dir_local)
 
         unpack_targets = map(lambda x, d=test_local_tar_gz_dir:
                                     os.path.join(d, x),
@@ -950,7 +956,7 @@ for p in [ scons ]:
 
     if zipit:
         env.Command(local_zip, local_targets, zipit,
-                    CD = local, PSV = '.')
+                    CD = build_dir_local, PSV = '.')
 
         unpack_targets = map(lambda x, d=test_local_zip_dir:
                                     os.path.join(d, x),
@@ -966,13 +972,13 @@ for p in [ scons ]:
     # And, lastly, install the appropriate packages in the
     # appropriate subdirectory.
     #
-    b_d_files = env.Install(os.path.join('build', 'dist'), install_targets)
+    b_d_files = env.Install(os.path.join(build_dir, 'dist'), install_targets)
     Local(b_d_files)
 
 #
 #
 #
-Export('env')
+Export('build_dir', 'env')
 
 SConscript('QMTest/SConscript')
 
@@ -992,17 +998,18 @@ for file in files:
     # Guarantee that real copies of these files always exist in
     # build/.  If there's a symlink there, then this is an Aegis
     # build and we blow them away now so that they'll get "built" later.
-    p = os.path.join('build', file)
+    p = os.path.join(build_dir, file)
     if os.path.islink(p):
         os.unlink(p)
-    sp = '#' + p
-    env.Command(sp, file, copy)
+    if not os.path.isabs(p):
+        p = '#' + p
+    sp = env.Command(p, file, copy)
     Local(sp)
 
 #
 # Documentation.
 #
-Export('env', 'whereis')
+Export('build_dir', 'env', 'whereis')
 
 SConscript('doc/SConscript')
 
@@ -1040,12 +1047,12 @@ if change:
     if sfiles:
         ps = "%s-src" % project
         psv = "%s-%s" % (ps, version)
-        b_ps = os.path.join('build', ps)
-        b_psv = os.path.join('build', psv)
+        b_ps = os.path.join(build_dir, ps)
+        b_psv = os.path.join(build_dir, psv)
         b_psv_stamp = b_psv + '-stamp'
 
-        src_tar_gz = os.path.join('build', 'dist', '%s.tar.gz' % psv)
-        src_zip = os.path.join('build', 'dist', '%s.zip' % psv)
+        src_tar_gz = os.path.join(build_dir, 'dist', '%s.tar.gz' % psv)
+        src_zip = os.path.join(build_dir, 'dist', '%s.zip' % psv)
 
         Local(src_tar_gz, src_zip)
 
diff --git a/bin/check b/bin/check
deleted file mode 100644 (file)
index f32494e..0000000
--- a/bin/check
+++ /dev/null
@@ -1,26 +0,0 @@
-#! /bin/sh
-
-# This script runs pychecker on the SCons source and creates a file called
-# checks.txt with the results. It must be run in the src/engine directory.
-
-base=`basename $PWD`
-if [ "$base" != "engine" ]; then
-   echo "You must run this script from the engine directory."
-   exit
-fi
-
-DEVDIR=../../doc/developer
-SRCFILE=../../bin/files
-CHKFILE=checks.txt
-
-rm -f $CHKFILE
-for f in `cat $SRCFILE` ; do
-   echo >> $CHKFILE
-   echo " --- $f ---" >> $CHKFILE
-   env PYTHONPATH=. pychecker -T -z -Z --deprecated $f >> $CHKFILE
-done
-
-if [ -e $CHKFILE ]; then
-   sed -e "s|$PWD/||" $CHKFILE > /tmp/tmpchk
-   mv -f /tmp/tmpchk $CHKFILE
-fi
index 974646c4e1c550250be80121d09b0f599676a6a9..a9c502b435d23898d6070dcff058b977e3712b0e 100644 (file)
@@ -101,8 +101,8 @@ import string
 import sys
 import time
 
-sys.path.append(os.path.join(os.getcwd(), 'etc'))
-sys.path.append(os.path.join(os.getcwd(), 'build', 'etc'))
+sys.path.append(os.path.join(os.getcwd(), 'QMTest'))
+sys.path.append(os.path.join(os.getcwd(), 'build', 'QMTest'))
 
 scons_py = os.path.join('bootstrap', 'src', 'script', 'scons.py')
 if not os.path.exists(scons_py):
@@ -341,7 +341,7 @@ def JarCom(target, source, env):
 ToolList = {
     'posix' :   [('cc', ['CCCOM', 'SHCCCOM'], CCCom, ['CCFLAGS', 'CPPDEFINES', 'COLOR', 'COLORS', 'PACKAGE']),
                  ('link', ['LINKCOM', 'SHLINKCOM'], Cat, []),
-                 ('ar', 'ARCOM', Cat, []),
+                 ('ar', ['ARCOM', 'RANLIBCOM'], Cat, []),
                  ('tar', 'TARCOM', Null, []),
                  ('zip', 'ZIPCOM', Null, []),
                  ('BitKeeper', 'BITKEEPERCOM', Cat, []),
@@ -416,7 +416,10 @@ def command_scons(args, c, test, dict):
     os.environ.update(save_vals)
     for key in delete_keys:
         del(os.environ[key])
-    out = string.replace(test.stdout(), test.workpath('ROOT'), '')
+    out = test.stdout()
+    out = string.replace(out, test.workpath('ROOT'), '')
+    out = string.replace(out, test.workpath('WORK/SConstruct'),
+                              '/home/my/project/SConstruct')
     lines = string.split(out, '\n')
     if lines:
         while lines[-1] == '':
index 9a88c1c85823e9fd9dd4ea5ff57a4c0d541a5b61..1620bf3e662686689c5eabe44473c815dfdd586e 100644 (file)
@@ -23,7 +23,6 @@
 
 import os
 import os.path
-import getopt
 import string
 import sys
 
@@ -50,14 +49,31 @@ All of these begin with the string "bootstrap_":
         bootstrap.py script only updates the bootstrap copy if the
         content of the source copy is different.
 
+    --bootstrap_src=DIR
+
+        Searches for the SCons files relative to the specified DIR,
+        then relative to the directory in which this bootstrap.py
+        script is found.
+
     --bootstrap_update
 
         Only updates the bootstrap subdirectory, and then exits.
 
 In addition to the above options, the bootstrap.py script understands
-the -Y and --repository= options, which are used under Aegis to specify
-a search path for the source files that may not have been copied in to
-the Aegis change.
+the following SCons options:
+
+    -C, --directory
+
+        Changes to the specified directory before invoking SCons.
+        Because we change directory right away to the specified directory,
+        the SCons script itself doesn't need to, so this option gets
+        "eaten" by the bootstrap.py script.
+
+    -Y, --repository
+
+        These options are used under Aegis to specify a search path
+        for the source files that may not have been copied in to the
+        Aegis change.
 
 This is essentially a minimal build of SCons to bootstrap ourselves into
 executing it for the full build of all the packages, as specified in our
@@ -66,18 +82,23 @@ local SConstruct file.
 
 bootstrap_dir = 'bootstrap'
 pass_through_args = []
-search = ['.']
 update_only = None
 
 requires_an_argument = 'bootstrap.py:  %s requires an argument\n'
 
-command_line_args = sys.argv[1:]
-
 def must_copy(dst, src):
     if not os.path.exists(dst):
         return 1
     return open(dst, 'rb').read() != open(src, 'rb').read()
 
+search = [os.path.dirname(sys.argv[0])]
+if search[0] == '': search[0] = '.'
+
+# Note:  We don't use the getopt module to process the command-line
+# arguments because we'd have to teach it about all of the SCons options.
+
+command_line_args = sys.argv[1:]
+
 while command_line_args:
     arg = command_line_args.pop(0)
 
@@ -87,7 +108,6 @@ while command_line_args:
         except IndexError:
             sys.stderr.write(requires_an_argument % arg)
             sys.exit(1)
-
     elif arg[:16] == '--bootstrap_dir=':
         bootstrap_dir = arg[16:]
 
@@ -95,9 +115,31 @@ while command_line_args:
         def must_copy(dst, src):
             return 1
 
+    elif arg == '--bootstrap_src':
+        try:
+            search.insert(0, command_line_args.pop(0))
+        except IndexError:
+            sys.stderr.write(requires_an_argument % arg)
+            sys.exit(1)
+    elif arg[:16] == '--bootstrap_src=':
+        search.insert(0, arg[16:])
+
     elif arg == '--bootstrap_update':
         update_only = 1
 
+    elif arg in ('-C', '--directory'):
+        try:
+            dir = command_line_args.pop(0)
+        except IndexError:
+            sys.stderr.write(requires_an_argument % arg)
+            sys.exit(1)
+        else:
+            os.chdir(dir)
+    elif arg[:2] == '-C':
+        os.chdir(arg[2:])
+    elif arg[:12] == '--directory=':
+        os.chdir(arg[12:])
+
     elif arg in ('-Y', '--repository'):
         try:
             dir = command_line_args.pop(0)
@@ -107,11 +149,9 @@ while command_line_args:
         else:
             search.append(dir)
         pass_through_args.extend([arg, dir])
-
     elif arg[:2] == '-Y':
         search.append(arg[2:])
         pass_through_args.append(arg)
-
     elif arg[:13] == '--repository=':
         search.append(arg[13:])
         pass_through_args.append(arg)
@@ -122,8 +162,8 @@ while command_line_args:
 def find(file, search=search):
     for dir in search:
         f = os.path.join(dir, file)
-       if os.path.exists(f):
-           return os.path.normpath(f)
+        if os.path.exists(f):
+            return os.path.normpath(f)
     sys.stderr.write("could not find `%s' in search path:\n" % file)
     sys.stderr.write("\t" + string.join(search, "\n\t") + "\n")
     sys.exit(2)
diff --git a/config b/config
index b055bdb279db7b37b1e50800a32947900c0de254..3af477ce54d6911d9453b8d1be69a3f6d2639f65 100644 (file)
--- a/config
+++ b/config
@@ -50,7 +50,7 @@
  *
  * Look in aesub(5) for more information about command substitutions.
  */
-build_command = "python2.1 ${Source bootstrap.py} -Y${SUBSTitute : \\ -Y $Search_Path} date='${DAte %Y/%m/%d %H:%M:%S}' developer=${DEVeloper} version=${VERsion} change=${Change}";
+build_command = "python2.4 ${Source bootstrap.py} -Y${SUBSTitute : \\ -Y $Search_Path} date='${DAte %Y/%m/%d %H:%M:%S}' developer=${DEVeloper} version=${VERsion} change=${Change}";
 
 /*
  * SCons removes its targets before constructing them, which qualifies it
index 43d34036ad0c5ad8508f345f21faa451ba0d5e9a..bf620241788d3d1b48145f5b1c6dc7a33d790a65 100644 (file)
@@ -29,18 +29,18 @@ import os.path
 import re
 import string
 
-Import('env', 'whereis')
+Import('build_dir', 'env', 'whereis')
 
 env = env.Clone()
 
 env.TargetSignatures('content')
 
-build = os.path.join('#build', 'doc')
+build = os.path.join(build_dir, 'doc')
 
 #
 #
 #
-doc_tar_gz = os.path.join('#build',
+doc_tar_gz = os.path.join(build_dir,
                           'dist',
                           'scons-doc-%s.tar.gz' % env.Dictionary('VERSION'))
 
@@ -210,12 +210,21 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
                 'pdf'       : 1,
                 'text'      : 0,
         },
+        # For whenever (if ever?) we start putting developer guide
+        # information in a printable document instead of the wiki.
+        #'developer' : {
+        #        'htmlindex' : 'book1.html',
+        #        'html'      : 1,
+        #        'ps'        : 1,
+        #        'pdf'       : 1,
+        #        'text'      : 0,
+        #},
         'user' : {
                 'htmlindex' : 'book1.html',
                 'html'      : 1,
                 'ps'        : 1,
                 'pdf'       : 1,
-                'text'      : 0,
+                'text'      : 1,
                 'graphics'  : [
                                 'SCons-win32-install-1.jpg',
                                 'SCons-win32-install-2.jpg',
@@ -268,7 +277,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
 
         # Hard-coding the scons-src path is a bit of a hack.  This can
         # be reworked when a better solution presents itself.
-        scons_src_main = os.path.join('#build', 'scons-src', 'doc', main)
+        scons_src_main = os.path.join(build_dir, 'scons-src', 'doc', main)
         env.Ignore(scons_src_main, version_sgml)
 
         htmldir = os.path.join(build, 'HTML', 'scons-%s' % doc)
@@ -379,7 +388,7 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE.  DO NOT EDIT.
 man_page_list = ['scons.1', 'sconsign.1', 'scons-time.1']
 
 for m in man_page_list:
-    orig_env.SCons_revision(os.path.join(build, 'man', m),
+    x = orig_env.SCons_revision(os.path.join(build, 'man', m),
                             os.path.join('man', m))
 
 man_i_files = ['builders.man', 'tools.man', 'variables.man']
@@ -425,7 +434,7 @@ for man_1 in man_page_list:
             return 0
 
         cmds = [
-            "( cd build/doc/man && cp %s .. )" % string.join(man_i_files),
+            "( cd %s/man && cp %s .. )" % (build, string.join(man_i_files)),
             "( cd ${SOURCE.dir} && man2html ${SOURCE.file} ) > $TARGET",
             Action(strip_to_first_html_tag),
         ]
diff --git a/doc/developer/MANIFEST b/doc/developer/MANIFEST
new file mode 100644 (file)
index 0000000..12a4de0
--- /dev/null
@@ -0,0 +1,9 @@
+architecture.sgml
+branches.sgml
+copyright.sgml
+cycle.sgml
+main.sgml
+packaging.sgml
+preface.sgml
+sourcetree.sgml
+testing.sgml
diff --git a/doc/developer/architecture.sgml b/doc/developer/architecture.sgml
new file mode 100644 (file)
index 0000000..0fc357f
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>Architecture</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
diff --git a/doc/developer/branches.sgml b/doc/developer/branches.sgml
new file mode 100644 (file)
index 0000000..abba398
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>&SCons; Branches</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
diff --git a/doc/developer/copyright.sgml b/doc/developer/copyright.sgml
new file mode 100644 (file)
index 0000000..d926f5b
--- /dev/null
@@ -0,0 +1,32 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+<blockquote>
+ <para>
+
+  SCons Developer's Guide Copyright (c) 2007 Steven Knight
+
+ </para>
+</blockquote>
diff --git a/doc/developer/cycle.sgml b/doc/developer/cycle.sgml
new file mode 100644 (file)
index 0000000..629a1a8
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>Development Cycle</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
diff --git a/doc/developer/main.sgml b/doc/developer/main.sgml
new file mode 100644 (file)
index 0000000..949287a
--- /dev/null
@@ -0,0 +1,107 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+<!doctype book PUBLIC "-//OASIS//DTD DocBook V4.1//EN"
+[
+
+    <!ENTITY % version SYSTEM "../version.sgml">
+    %version;
+
+    <!ENTITY % scons SYSTEM "../scons.mod">
+    %scons;
+
+    <!ENTITY architecture SYSTEM "architecture.sgml">
+    <!ENTITY branches SYSTEM "branches.sgml">
+    <!ENTITY copyright SYSTEM "copyright.sgml">
+    <!ENTITY cycle SYSTEM "cycle.sgml">
+    <!ENTITY packaging SYSTEM "packaging.sgml">
+    <!ENTITY preface SYSTEM "preface.sgml">
+    <!ENTITY sourcetree SYSTEM "sourcetree.sgml">
+    <!ENTITY testing SYSTEM "testing.sgml">
+
+]>
+
+<book>
+  <bookinfo>
+    <title>SCons Developer's Guide &buildversion;</title>
+
+    <author>
+      <firstname>Steven</firstname>
+      <surname>Knight</surname>
+    </author>
+
+    <edition>Revision &buildrevision; (&builddate;)</edition>
+
+    <pubdate>2007</pubdate>
+
+    <copyright>
+      <year>2007</year>
+      <holder>Steven Knight</holder>
+    </copyright>
+
+    <legalnotice>
+      &copyright;
+    </legalnotice>
+
+    <releaseinfo>version &buildversion;</releaseinfo>
+
+  </bookinfo>
+
+  <preface id="chap-preface">
+    <title>Preface</title>
+    &preface;
+  </preface>
+
+  <chapter id="chap-development-cycle">
+    <title>Development Cycle</title>
+    &cycle;
+  </chapter>
+
+  <chapter id="chap-source-tree">
+    <title>Source Tree</title>
+    &sourcetree;
+  </chapter>
+
+  <chapter id="chap-testing">
+    <title>Testing</title>
+    &testing;
+  </chapter>
+
+  <chapter id="chap-branches">
+    <title>Branches</title>
+    &branches;
+  </chapter>
+
+  <chapter id="chap-packaging">
+    <title>Packaging</title>
+    &packaging;
+  </chapter>
+
+  <chapter id="chap-architecture">
+    <title>Architecture</title>
+    &architecture;
+  </chapter>
+
+</book>
diff --git a/doc/developer/packaging.sgml b/doc/developer/packaging.sgml
new file mode 100644 (file)
index 0000000..3860ee7
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>Packaging</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
diff --git a/doc/developer/preface.sgml b/doc/developer/preface.sgml
new file mode 100644 (file)
index 0000000..5784cee
--- /dev/null
@@ -0,0 +1,175 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  This document assumes that you already know how &SCons;
+  and that you want to learn how to work on the code.
+
+  </para>
+
+  <section>
+  <title>&SCons; Principles</title>
+
+    <para>
+
+    There are a few overriding principles
+    we try to live up to in designing and implementing &SCons:
+
+    </para>
+
+    <variablelist>
+
+      <varlistentry>
+      <term>Correctness</term>
+
+      <listitem>
+      <para>
+
+      First and foremost,
+      by default, &SCons; guarantees a correct build
+      even if it means sacrificing performance a little.
+      We strive to guarantee the build is correct
+      regardless of how the software being built is structured,
+      how it may have been written,
+      or how unusual the tools are that build it.
+
+      </para>
+      </listitem>
+      </varlistentry>
+
+      <varlistentry>
+      <term>Performance</term>
+
+      <listitem>
+      <para>
+
+      Given that the build is correct,
+      we try to make &SCons; build software
+      as quickly as possible.
+      In particular, wherever we may have needed to slow
+      down the default &SCons; behavior to guarantee a correct build,
+      we also try to make it easy to speed up &SCons;
+      through optimization options that let you trade off
+      guaranteed correctness in all end cases for
+      a speedier build in the usual cases.
+
+      </para>
+      </listitem>
+      </varlistentry>
+
+      <varlistentry>
+      <term>Convenience</term>
+
+      <listitem>
+      <para>
+
+      &SCons; tries to do as much for you out of the box as reasonable,
+      including detecting the right tools on your system
+      and using them correctly to build the software.
+
+      </para>
+      </listitem>
+      </varlistentry>
+
+    </variablelist>
+
+    <para>
+
+    In a nutshell, we try hard to make &SCons; just
+    "do the right thing" and build software correctly,
+    with a minimum of hassles.
+
+    </para>
+
+  </section>
+
+  <section>
+  <title>Acknowledgements</title>
+
+    <para>
+
+    &SCons; would not exist without a lot of help
+    from a lot of people,
+    many of whom may not even be aware
+    that they helped or served as inspiration.
+    So in no particular order,
+    and at the risk of leaving out someone:
+
+    </para>
+
+    <para>
+
+    First and foremost,
+    &SCons; owes a tremendous debt to Bob Sidebotham,
+    the original author of the classic Perl-based &Cons; tool
+    which Bob first released to the world back around 1996.
+    Bob's work on Cons classic provided the underlying architecture
+    and model of specifying a build configuration
+    using a real scripting language.
+    My real-world experience working on Cons
+    informed many of the design decisions in SCons,
+    including the improved parallel build support,
+    making Builder objects easily definable by users,
+    and separating the build engine from the wrapping interface.
+
+    </para>
+
+    <para>
+
+    Greg Wilson was instrumental in getting
+    &SCons; started as a real project
+    when he initiated the Software Carpentry design
+    competition in February 2000.
+    Without that nudge,
+    marrying the advantages of the Cons classic
+    architecture with the readability of Python
+    might have just stayed no more than a nice idea.
+
+    </para>
+
+    <para>
+
+    Thanks to Peter Miller
+    for his splendid change management system, &Aegis;,
+    which has provided the &SCons; project
+    with a robust development methodology from day one,
+    and which showed me how you could
+    integrate incremental regression tests into
+    a practical development cycle
+    (years before eXtreme Programming arrived on the scene).
+
+    </para>
+
+    <para>
+
+    And last, thanks to Guido van Rossum
+    for his elegant scripting language,
+    which is the basis not only for the &SCons; implementation,
+    but for the interface itself.
+
+    </para>
+
+  </section>
diff --git a/doc/developer/sourcetree.sgml b/doc/developer/sourcetree.sgml
new file mode 100644 (file)
index 0000000..be1c45a
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>Source Tree</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
diff --git a/doc/developer/testing.sgml b/doc/developer/testing.sgml
new file mode 100644 (file)
index 0000000..c577c5c
--- /dev/null
@@ -0,0 +1,40 @@
+<!--
+
+  __COPYRIGHT__
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-->
+
+  <para>
+
+  XXX
+
+  </para>
+
+  <section>
+  <title>Testing</title>
+
+    <para>
+
+    XXX
+    </para>
+
+  </section>
index 0a76affda1068cb858957f04b4adfcee5b854fe7..862cde55cf32d260c3fef6f79631dbedddaa9b17 100644 (file)
@@ -92,6 +92,26 @@ rules exist for building common software components (executable
 programs, object files, libraries), so that for most software
 projects, only the target and input files need be specified.
 
+Before reading the
+.I SConstruct
+file,
+.B scons
+adds looks for a dir named
+.I site_scons
+in the dir containing the
+.I SConstruct
+file; it adds that
+.I site_scons
+to sys.path, reads the file
+.IR site_scons/site_init.py ,
+and adds the directory
+.I site_scons/site_tools
+to the default toolpath, if those exist.  See the
+.I --no-site-dir
+and
+.I --site-dir
+options for more details.
+
 .B scons
 reads and executes the SConscript files as Python scripts,
 so you may use normal Python scripting capabilities
@@ -570,8 +590,11 @@ This only works when run under Python 2.1 or later.
 
 .TP
 --debug=dtree
-Print the dependency tree
-after each top-level target is built. This prints out only derived files.
+A synonym for the newer
+.B --tree=derived
+option.
+This will be deprecated in some future release
+and ultimately removed.
 
 .TP
 --debug=explain
@@ -650,9 +673,11 @@ when encountering an otherwise unexplained error.
 
 .TP
 --debug=stree
-Print the dependency tree along with status information.  This is the
-same as the debug=tree option, but additional status information is
-provided for each node in the tree.
+A synonym for the newer
+.B --tree=all,status
+option.
+This will be deprecated in some future release
+and ultimately removed.
 
 .TP
 --debug=time
@@ -663,10 +688,11 @@ SConscript files, and the total time spent executing SCons itself.
 
 .TP
 --debug=tree
-Print the dependency tree
-after each top-level target is built. This prints out the complete
-dependency tree including implicit dependencies and ignored
-dependencies.
+A synonym for the newer
+.B --tree=all
+option.
+This will be deprecated in some future release
+and ultimately removed.
 
 .TP
 .RI --diskcheck= types
@@ -748,6 +774,18 @@ imported Python modules.  If several
 options
 are used, the directories are searched in the order specified.
 
+.TP 
+.RI --no-site-dir
+Prevents the automatic addition of the standard
+.I site_scons
+dir to
+.IR sys.path .
+Also prevents loading the
+.I site_scons/site_init.py
+module if it exists, and prevents adding
+.I site_scons/site_tools
+to the toolpath.
+
 .TP
 --implicit-cache
 Cache implicit dependencies. This can cause 
@@ -939,6 +977,18 @@ Also suppresses SCons status messages.
 Ignored for compatibility with GNU 
 .BR make .
 
+.TP 
+.RI --site-dir= dir
+Uses the named dir as the site dir rather than the default
+.I site_scons
+dir.  This dir will get prepended to
+.IR sys.path ,
+the module
+.IR dir /site_init.py
+will get loaded if it exists, and
+.IR dir /site_tools
+will get added to the default toolpath.
+
 .TP
 -t, --touch
 Ignored for compatibility with GNU
@@ -957,6 +1007,56 @@ A file name of
 .B -
 may be used to specify the standard output.
 
+.TP
+.RI -tree= options
+Prints a tree of the dependencies
+after each top-level target is built.
+This prints out some or all of the tree,
+in various formats,
+depending on the
+.I options
+specified:
+
+.TP
+--tree=all
+Print the entire dependency tree
+after each top-level target is built.
+This prints out the complete dependency tree,
+including implicit dependencies and ignored dependencies.
+
+.TP
+--tree=derived
+Restricts the tree output to only derived (target) files,
+not source files.
+
+.TP
+--tree=status
+Prints status information for each displayed node.
+
+.TP
+--tree=prune
+Prunes the tree to avoid repeating dependency information
+for nodes that have already been displayed.
+Any node that has already been displayed
+will have its name printed in
+.BR "[square brackets]" ,
+as an indication that the dependencies
+for that node can be found by searching
+for the relevant output higher up in the tree.
+
+.IP
+Multiple options may be specified,
+separated by commas:
+
+.ES
+# Prints only derived files, with status information:
+scons --tree=derived,status
+
+# Prints all dependencies of target, with status information
+# and pruning dependencies of already-visited Nodes:
+scons --tree=all,prune,status target
+.EE
+
 .TP
 -u, --up, --search-up
 Walks up the directory structure until an 
@@ -993,6 +1093,10 @@ Then exit.
 Print a message containing the working directory before and
 after other processing.
 
+.TP
+--no-print-directory
+Turn off -w, even if it was turned on implicitly.
+
 .TP
 .RI --warn= type ", --warn=no-" type
 Enable or disable warnings.
@@ -1003,6 +1107,20 @@ specifies the type of warnings to be enabled or disabled:
 --warn=all, --warn=no-all
 Enables or disables all warnings.
 
+.TP
+--warn=cache-write-error, --warn=no-cache-write-error
+Enables or disables warnings about errors trying to
+write a copy of a built file to a specified
+.BR CacheDir ().
+These warnings are disabled by default.
+
+.TP
+--warn=corrupt-sconsign, --warn=no-corrupt-sconsign
+Enables or disables warnings about unfamiliar signature data in
+.B .sconsign
+files.
+These warnings are enabled by default.
+
 .TP
 --warn=dependency, --warn=no-dependency
 Enables or disables warnings about dependencies.
@@ -1014,13 +1132,63 @@ Enables or disables warnings about use of deprecated features.
 These warnings are enabled by default.
 
 .TP
---warn=missing-sconscript, --warn=no-missing-sconscript
+--warn=duplicate-environment, --warn=no-duplicate-environment
 Enables or disables warnings about missing SConscript files.
+
+.TP
+--warn=misleading-keywords, --warn=no-misleading-keywords
+Enables or disables warnings about use of the misspelled keywords
+.B targets
+and
+.B sources
+when calling Builders.
+(Note the last
+.B s
+characters, the correct spellings are
+.B target
+and
+.B source.)
 These warnings are enabled by default.
 
 .TP
---no-print-directory
-Turn off -w, even if it was turned on implicitly.
+--warn=missing-sconscript, --warn=no-missing-sconscript
+Enables or disables warnings about attempts to specify a build
+of a target with two different construction environments
+that use the same action.
+These warnings are enabled by default.
+
+.TP
+--warn=no-md5-module, --warn=no-no-md5-module
+Enables or disables warnings about the version of Python
+not having an MD5 checksum module available.
+These warnings are enabled by default.
+
+.TP
+--warn=no-metaclass-support, --warn=no-no-metaclass-support
+Enables or disables warnings about the version of Python
+not supporting metaclasses when the
+.B --debug=memoizer
+option is used.
+These warnings are enabled by default.
+
+.TP
+--warn=no-parallel-support, --warn=no-no-parallel-support
+Enables or disables warnings about the version of Python
+not being able to support parallel builds when the
+.B -j
+option is used.
+These warnings are enabled by default.
+
+.TP
+--warn=reserved-variable, --warn=no-reserved-variable
+Enables or disables warnings about attempts to set the
+reserved construction variable names
+.BR TARGET ,
+.BR TARGETS ,
+.BR SOURCE
+or
+.BR SOURCES .
+These warnings are disabled by default.
 
 .\" .TP
 .\" .RI --write-filenames= file
@@ -1045,7 +1213,7 @@ Turn off -w, even if it was turned on implicitly.
 .\" Warn when an undefined variable is referenced.
 
 .TP 
-.RI -Y " repository" ", --repository=" repository
+.RI -Y " repository" ", --repository=" repository ", --srcdir=" repository
 Search the specified repository for any input and target
 files not found in the local directory hierarchy.  Multiple
 .B -Y
@@ -2174,6 +2342,12 @@ that are equivalent regardless of whether
 a given derived file has been built in-place
 or retrieved from the cache.
 
+The
+.BR NoCache ()
+method can be used to disable caching of specific files.  This can be
+useful if inputs and/or outputs of some tool are impossible to
+predict or prohibitively large.
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP 
 .RI Clean( targets ", " files_or_dirs )
@@ -2282,6 +2456,7 @@ env.Command('baz.out', 'baz.in',
             rename ])
 .EE
 
+.IP
 Note that the
 .BR Command ()
 function will usually assume, by default,
@@ -2304,6 +2479,7 @@ env['DISTDIR'] = 'destination/directory'
 env.Command(env.Dir('$DISTDIR')), None, make_distdir)
 .EE
 
+.IP
 (Also note that SCons will usually
 automatically create any directory necessary to hold a target file,
 so you normally don't need to create directories by hand.)
@@ -2513,6 +2689,7 @@ This SConstruct:
 env=Environment()
 print env.Dump('CCCOM')
 .EE
+.IP
 will print:
 .ES
 '$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
@@ -2522,6 +2699,7 @@ will print:
 env=Environment()
 print env.Dump()
 .EE
+.IP
 will print:
 .ES
 { 'AR': 'ar',
@@ -3024,6 +3202,46 @@ env.MergeFlags(['-O3',
                '!pkg-config libpng12 --cflags --libs'])
 .EE
 
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.RI NoCache( target ", ...)"
+.TP
+.RI env.NoCache( target ", ...)"
+Specifies a list of files which should
+.I not
+be cached whenever the 
+.BR CacheDir ()
+method has been activated.
+The specified targets may be a list
+or an individual target.
+Multiple calls to
+.BR NoCache ()
+are legal,
+and prevent each specified target
+from being removed by calls to the
+.B -c
+option.
+
+Multiple files should be specified
+either as separate arguments to the
+.BR NoCache ()
+method, or as a list.
+.BR NoCache ()
+will also accept the return value of any of the construction environment
+Builder methods.
+
+Calling
+.BR NoCache ()
+on directories and other non-File Node types has no effect because
+only File Nodes are cached.
+
+Examples:
+
+.ES
+NoCache('foo.elf')
+NoCache(env.Program('hello', 'hello.c'))
+.EE
+
 '\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .TP
 .RI NoClean( target ", ...)"
@@ -3214,6 +3432,7 @@ and added to the following construction variables:
 +                   CCFLAGS, LINKFLAGS
 .EE
 
+.IP
 Any other strings not associated with options
 are assumed to be the names of libraries
 and added to the
@@ -5347,10 +5566,15 @@ which verifies that the specified path exists;
 which verifies that the specified path is an existing file;
 .BR PathOption.PathIsDir ,
 which verifies that the specified path is an existing directory;
-and
 .BR PathOption.PathIsDirCreate ,
-which verifies that the specified path is a directory,
-and will create the specified directory if the path does not exist.
+which verifies that the specified path is a directory
+and will create the specified directory if the path does not exist;
+and
+.BR PathOption.PathAccept ,
+which simply accepts the specific path name argument without validation,
+and which is suitable if you want your users
+to be able to specify a directory path that will be
+created as part of the build process, for example.
 You may supply your own
 .I validator
 function,
@@ -5636,6 +5860,7 @@ env.Append(BUILDERS = {'MakeDirectory':MakeDirectoryBuilder})
 env.MakeDirectory('new_directory', [])
 .EE
 
+.IP
 Note that the call to the MakeDirectory Builder
 needs to specify an empty source list
 to make the string represent the builder's target;
@@ -6739,16 +6964,23 @@ new file types for implicit dependencies.
 Scanner accepts the following arguments:
 
 .IP function
-A Python function that will process
+This can be either:
+1) a Python function that will process
 the Node (file)
 and return a list of strings (file names)
 representing the implicit
-dependencies found in the contents.
-The function takes three or four arguments:
+dependencies found in the contents;
+or:
+2) a dictionary that maps keys
+(typically the file suffix, but see below for more discussion)
+to other Scanners that should be called.
+
+If the argument is actually a Python function,
+the function must take three or four arguments:
 
     def scanner_function(node, env, path):
 
-    def scanner_function(node, env, path, arg):
+    def scanner_function(node, env, path, arg=None):
 
 The
 .B node
index aa65ebd9d1c8871c2aeb671a4ecbe050b159f8cd..d84327633bce78c2e651192e65dd9b8993b584e0 100644 (file)
@@ -57,7 +57,7 @@
     on a POSIX system
     is <literal>/usr/local/bin:/bin:/usr/bin</literal>.
     The default value of the &PATH; environment variable
-    on a Win32 system comes from the Windows registry
+    on a Windows system comes from the Windows registry
     value for the command interpreter.
     If you want to execute any commands--compilers, linkers, etc.--that
     are not in these default locations,
index 4471605ef916d4c8a84f4ad216ae4573797d6c72..f285d70d83e85f0516ab56d8a2ef7c39074e03b3 100644 (file)
@@ -46,7 +46,7 @@
 
   <screen>
      % <userinput>scons -Q install</userinput>
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
      Install file: "hello" as "/usr/bin/hello"
   </screen>
 
   <screen>
      % <userinput>scons -Q install-bin</userinput>
-     cc -c -o foo.o foo.c
+     cc -o foo.o -c foo.c
      cc -o foo foo.o
      Install file: "foo" as "/usr/bin/foo"
      % <userinput>scons -Q install-lib</userinput>
-     cc -c -o bar.o bar.c
-     ar r libbar.a bar.o
+     cc -o bar.o -c bar.c
+     ar rc libbar.a bar.o
      ranlib libbar.a
      Install file: "libbar.a" as "/usr/lib/libbar.a"
      % <userinput>scons -Q -c /</userinput>
      Removed libbar.a
      Removed /usr/lib/libbar.a
      % <userinput>scons -Q install</userinput>
-     cc -c -o foo.o foo.c
+     cc -o foo.o -c foo.c
      cc -o foo foo.o
      Install file: "foo" as "/usr/bin/foo"
-     cc -c -o bar.o bar.c
-     ar r libbar.a bar.o
+     cc -o bar.o -c bar.c
+     ar rc libbar.a bar.o
      ranlib libbar.a
      Install file: "libbar.a" as "/usr/lib/libbar.a"
   </screen>
index 84877a33c80fe534085073a378a731d17f6789df..9c0a3b873d874c79dc7c776846999e7a84f8de54 100644 (file)
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o goodbye.o goodbye.c
-      cc -c -o hello.o hello.c
+      cc -o goodbye.o -c goodbye.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o goodbye.o -L/usr/dir1 -Ldir2 -lfoo1 -lfoo2
     </screen>
 
index 9085c0e53848fa5b6c57ac1aa14f8927842a3793..327650a88ef3547678763962f7bc0d84e1a31546 100644 (file)
@@ -266,7 +266,7 @@ This functionality could be invoked as in the following example:
     <screen>
       % <userinput>scons -Q</userinput>
       foobuild &lt; file.input &gt; file.foo
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
index eac69115896dfaed656f685000b6eaaff9c91f9e..d87e493293c3f43eb65965220fb70966306d204c 100644 (file)
@@ -82,7 +82,7 @@
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       % <userinput>scons -Q -c</userinput>
       Removed hello.o
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       % <userinput>scons -Q -c</userinput>
       Removed hello.o
       Removed hello
       % <userinput>scons -Q --cache-show</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       % <userinput>scons -Q -c</userinput>
       Removed hello.o
       Removed hello.o
       Removed hello
       % <userinput>scons -Q --cache-disable</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
 
     <screen>
       % <userinput>scons -Q --cache-disable</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       % <userinput>scons -Q -c</userinput>
       Removed hello.o
       Removed hello
       % <userinput>scons -Q --cache-disable</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       % <userinput>scons -Q --cache-force</userinput>
       scons: `.' is up to date.
index 565d9f89c5a8d63f10f24187004134857ec9df8f..1953690e130f175d3246adf5cb03184aa4b9ef16 100644 (file)
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o foo.o foo.c
+      cc -o foo.o -c foo.c
       cc -o foo foo.o
       % <userinput>scons -Q bar</userinput>
       Don't forget to copy `bar' to the archive!
-      cc -c -o bar.o bar.c
+      cc -o bar.o -c bar.c
       cc -o bar bar.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        % <userinput>scons -Q</userinput>
        scons: `hello' is up to date.
        % <userinput>scons -Q goodbye</userinput>
-       cc -c -o goodbye.o goodbye.c
+       cc -o goodbye.o -c goodbye.c
        cc -o goodbye goodbye.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q .</userinput>
-       cc -c -o goodbye.o goodbye.c
+       cc -o goodbye.o -c goodbye.c
        cc -o goodbye goodbye.o
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o prog1.o prog1.c
+       cc -o prog1.o -c prog1.c
        cc -o prog1 prog1.o
-       cc -c -o prog3.o prog3.c
+       cc -o prog3.o -c prog3.c
        cc -o prog3 prog3.o
        % <userinput>scons -Q .</userinput>
-       cc -c -o prog2.o prog2.c
+       cc -o prog2.o -c prog2.c
        cc -o prog2 prog2.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o prog1/foo.o prog1/foo.c
-       cc -c -o prog1/main.o prog1/main.c
+       cc -o prog1/foo.o -c prog1/foo.c
+       cc -o prog1/main.o -c prog1/main.c
        cc -o prog1/main prog1/main.o prog1/foo.o
        % <userinput>scons -Q</userinput>
        scons: `prog1' is up to date.
        % <userinput>scons -Q .</userinput>
-       cc -c -o prog2/bar.o prog2/bar.c
-       cc -c -o prog2/main.o prog2/main.c
+       cc -o prog2/bar.o -c prog2/bar.c
+       cc -o prog2/main.o -c prog2/main.c
        cc -o prog2/main prog2/main.o prog2/bar.o
     </screen>
 
        % <userinput>scons -Q</userinput>
        scons: *** No targets specified and no Default() targets found.  Stop.
        % <userinput>scons -Q .</userinput>
-       cc -c -o prog1.o prog1.c
+       cc -o prog1.o -c prog1.c
        cc -o prog1 prog1.o
-       cc -c -o prog2.o prog2.c
+       cc -o prog2.o -c prog2.c
        cc -o prog2 prog2.o
     </screen>
 
          DEFAULT_TARGETS is ['prog1']
          scons: done reading SConscript files.
          scons: Building targets ...
-         cc -c -o prog1.o prog1.c
+         cc -o prog1.o -c prog1.c
          cc -o prog1 prog1.o
          scons: done building targets.
       </screen>
          DEFAULT_TARGETS is now ['prog1', 'prog2']
          scons: done reading SConscript files.
          scons: Building targets ...
-         cc -c -o prog1.o prog1.c
+         cc -o prog1.o -c prog1.c
          cc -o prog1 prog1.o
-         cc -c -o prog2.o prog2.c
+         cc -o prog2.o -c prog2.c
          cc -o prog2 prog2.o
          scons: done building targets.
       </screen>
     <screen>
       % <userinput>scons -Q</userinput>
       BUILD_TARGETS is ['prog1']
-      cc -c -o prog1.o prog1.c
+      cc -o prog1.o -c prog1.c
       cc -o prog1 prog1.o
       % <userinput>scons -Q prog2</userinput>
       BUILD_TARGETS is ['prog2']
-      cc -c -o prog2.o prog2.c
+      cc -o prog2.o -c prog2.c
       cc -o prog2 prog2.o
       % <userinput>scons -Q -c .</userinput>
       BUILD_TARGETS is ['.']
 
     <screen>
        % <userinput>scons -Q debug=0</userinput>
-       cc -c -o prog.o prog.c
+       cc -o prog.o -c prog.c
        cc -o prog prog.o
        % <userinput>scons -Q debug=0</userinput>
        scons: `.' is up to date.
        % <userinput>scons -Q debug=1</userinput>
-       cc -g -c -o prog.o prog.c
+       cc -o prog.o -c -g prog.c
        cc -o prog prog.o
        % <userinput>scons -Q debug=1</userinput>
        scons: `.' is up to date.
 
     <screen>
       % <userinput>scons -Q RELEASE=1</userinput>
-      cc -DRELEASE_BUILD=1 -c -o bar.o bar.c
-      cc -DRELEASE_BUILD=1 -c -o foo.o foo.c
+      cc -o bar.o -c -DRELEASE_BUILD=1 bar.c
+      cc -o foo.o -c -DRELEASE_BUILD=1 foo.c
       cc -o foo foo.o bar.o
     </screen>
 
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -DRELEASE_BUILD=1 -c -o bar.o bar.c
-      cc -DRELEASE_BUILD=1 -c -o foo.o foo.c
+      cc -o bar.o -c -D['RELEASE_BUILD=', 1] bar.c
+      cc -o foo.o -c -D['RELEASE_BUILD=', 1] foo.c
       cc -o foo foo.o bar.o
     </screen>
 
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -DRELEASE_BUILD=0 -c -o bar.o bar.c
-      cc -DRELEASE_BUILD=0 -c -o foo.o foo.c
+      cc -o bar.o -c -D['RELEASE_BUILD=', 0] bar.c
+      cc -o foo.o -c -D['RELEASE_BUILD=', 0] foo.c
       cc -o foo foo.o bar.o
     </screen>
 
 
       <screen>
         % <userinput>scons -Q RELEASE=yes foo.o</userinput>
-        cc -DRELEASE_BUILD=1 -c -o foo.o foo.c
+        cc -o foo.o -c -D['RELEASE_BUILD=', True] foo.c
       </screen>
 
       <screen>
         % <userinput>scons -Q RELEASE=t foo.o</userinput>
-        cc -DRELEASE_BUILD=1 -c -o foo.o foo.c
+        cc -o foo.o -c -D['RELEASE_BUILD=', True] foo.c
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q RELEASE=no foo.o</userinput>
-        cc -DRELEASE_BUILD=0 -c -o foo.o foo.c
+        cc -o foo.o -c -D['RELEASE_BUILD=', False] foo.c
       </screen>
 
       <screen>
         % <userinput>scons -Q RELEASE=f foo.o</userinput>
-        cc -DRELEASE_BUILD=0 -c -o foo.o foo.c
+        cc -o foo.o -c -D['RELEASE_BUILD=', False] foo.c
       </screen>
 
       <para>
         
         scons: *** Error converting option: RELEASE
         Invalid value for boolean option: bad_value
-        File "SConstruct", line 4, in ?
+        File "/home/my/project/SConstruct", line 4, in ?
       </screen>
 
     </section>
 
       <screen>
         % <userinput>scons -Q COLOR=red foo.o</userinput>
-        cc -DCOLOR="red" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="red" foo.c
         % <userinput>scons -Q COLOR=blue foo.o</userinput>
-        cc -DCOLOR="blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="blue" foo.c
         % <userinput>scons -Q COLOR=green foo.o</userinput>
-        cc -DCOLOR="green" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="green" foo.c
       </screen>
 
       <para>
         % <userinput>scons -Q COLOR=magenta foo.o</userinput>
         
         scons: *** Invalid value for option COLOR: magenta
-        File "SConstruct", line 5, in ?
+        File "/home/my/project/SConstruct", line 5, in ?
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q COLOR=navy foo.o</userinput>
-        cc -DCOLOR="blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="blue" foo.c
       </screen>
 
       <para>
         % <userinput>scons -Q COLOR=Red foo.o</userinput>
         
         scons: *** Invalid value for option COLOR: Red
-        File "SConstruct", line 5, in ?
+        File "/home/my/project/SConstruct", line 5, in ?
         % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
         
         scons: *** Invalid value for option COLOR: BLUE
-        File "SConstruct", line 5, in ?
+        File "/home/my/project/SConstruct", line 5, in ?
         % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
         
         scons: *** Invalid value for option COLOR: nAvY
-        File "SConstruct", line 5, in ?
+        File "/home/my/project/SConstruct", line 5, in ?
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q COLOR=Red foo.o</userinput>
-        cc -DCOLOR="Red" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="Red" foo.c
         % <userinput>scons -Q COLOR=BLUE foo.o</userinput>
-        cc -DCOLOR="BLUE" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="BLUE" foo.c
         % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
-        cc -DCOLOR="blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="blue" foo.c
         % <userinput>scons -Q COLOR=green foo.o</userinput>
-        cc -DCOLOR="green" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="green" foo.c
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q COLOR=Red foo.o</userinput>
-        cc -DCOLOR="red" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="red" foo.c
         % <userinput>scons -Q COLOR=nAvY foo.o</userinput>
-        cc -DCOLOR="blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="blue" foo.c
         % <userinput>scons -Q COLOR=GREEN foo.o</userinput>
-        cc -DCOLOR="green" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLOR="green" foo.c
       </screen>
 
     </section>
 
       <screen>
         % <userinput>scons -Q COLORS=red,blue foo.o</userinput>
-        cc -DCOLORS="red blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLORS="red blue" foo.c
         % <userinput>scons -Q COLORS=blue,green,red foo.o</userinput>
-        cc -DCOLORS="blue green red" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLORS="blue green red" foo.c
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q COLORS=all foo.o</userinput>
-        cc -DCOLORS="red green blue" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLORS="red green blue" foo.c
         % <userinput>scons -Q COLORS=none foo.o</userinput>
-        cc -DCOLORS="" -c -o foo.o foo.c
+        cc -o foo.o -c -DCOLORS="" foo.c
       </screen>
 
       <para>
         
         scons: *** Error converting option: COLORS
         Invalid value(s) for option: magenta
-        File "SConstruct", line 5, in ?
+        File "/home/my/project/SConstruct", line 5, in ?
       </screen>
 
     </section>
 
       <screen>
         % <userinput>scons -Q foo.o</userinput>
-        cc -DCONFIG_FILE="/etc/my_config" -c -o foo.o foo.c
+        cc -o foo.o -c -DCONFIG_FILE="/etc/my_config" foo.c
         % <userinput>scons -Q CONFIG=/usr/local/etc/other_config foo.o</userinput>
         scons: `foo.o' is up to date.
       </screen>
         % <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput>
         
         scons: *** Path for option CONFIG does not exist: /does/not/exist
-        File "SConstruct", line 6, in ?
+        File "/home/my/project/SConstruct", line 6, in ?
       </screen>
 
       <para>
 
       <screen>
         % <userinput>scons -Q foo.o</userinput>
-        cc -DPACKAGE="/opt/location" -c -o foo.o foo.c
+        cc -o foo.o -c -DPACKAGE="/opt/location" foo.c
         % <userinput>scons -Q PACKAGE=/usr/local/location foo.o</userinput>
-        cc -DPACKAGE="/usr/local/location" -c -o foo.o foo.c
+        cc -o foo.o -c -DPACKAGE="/usr/local/location" foo.c
         % <userinput>scons -Q PACKAGE=yes foo.o</userinput>
-        cc -DPACKAGE="1" -c -o foo.o foo.c
+        cc -o foo.o -c -D['PACKAGE="', True, '"'] foo.c
         % <userinput>scons -Q PACKAGE=no foo.o</userinput>
-        cc -DPACKAGE="0" -c -o foo.o foo.c
+        cc -o foo.o -c -D['PACKAGE="', False, '"'] foo.c
       </screen>
 
     </section>
index 3d74025184f7a4fe31e3ab4ca2cc0896ee6ded46..10a93b692884173370988b9ad205bcd6ad5d6698 100644 (file)
@@ -61,7 +61,7 @@ operating system on which the build is performed (as reported by C<uname
 
   <screen>
      % <userinput>scons -Q</userinput>
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
      % <userinput>scons -Q</userinput>
      scons: `.' is up to date.
@@ -80,7 +80,7 @@ operating system on which the build is performed (as reported by C<uname
 
   <screen>
      % <userinput>scons -Q hello</userinput>
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
      % <userinput>scons -Q hello</userinput>
      scons: `hello' is up to date.
@@ -132,7 +132,7 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>touch hello.c</userinput>
          % <userinput>scons -Q hello</userinput>
@@ -157,12 +157,12 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>edit hello.c</userinput>
              [CHANGE THE CONTENTS OF hello.c]
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
       </screen>
 
@@ -212,11 +212,11 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>touch hello.c</userinput>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
       </screen>
 
@@ -259,12 +259,12 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>edit hello.c</userinput>
              [CHANGE THE CONTENTS OF hello.c]
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
       </screen>
 
@@ -346,12 +346,12 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>edit hello.c</userinput>
            [CHANGE A COMMENT IN hello.c]
          % <userinput>scons -Q hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          scons: `hello' is up to date.
       </screen>
 
@@ -433,14 +433,14 @@ operating system on which the build is performed (as reported by C<uname
 
     <screen>
        % <userinput>scons -Q hello</userinput>
-       cc -I. -c -o hello.o hello.c
+       cc -o hello.o -c -I. hello.c
        cc -o hello hello.o
        % <userinput>scons -Q hello</userinput>
        scons: `hello' is up to date.
        % <userinput>edit hello.h</userinput>
            [CHANGE THE CONTENTS OF hello.h]
        % <userinput>scons -Q hello</userinput>
-       cc -I. -c -o hello.o hello.c
+       cc -o hello.o -c -I. hello.c
        cc -o hello hello.o
     </screen>
 
@@ -499,7 +499,7 @@ operating system on which the build is performed (as reported by C<uname
 
     <screen>
        % <userinput>scons -Q hello</userinput>
-       cc -Iinclude -I/home/project/inc -c -o hello.o hello.c
+       cc -o hello.o -c -Iinclude -I/home/project/inc hello.c
        cc -o hello hello.o
     </screen>
 
@@ -567,7 +567,7 @@ operating system on which the build is performed (as reported by C<uname
 
     <screen>
        % <userinput>scons -Q --implicit-cache hello</userinput>
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        % <userinput>scons -Q hello</userinput>
        scons: `hello' is up to date.
@@ -626,7 +626,7 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q --implicit-deps-changed hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>scons -Q hello</userinput>
          scons: `hello' is up to date.
@@ -664,7 +664,7 @@ operating system on which the build is performed (as reported by C<uname
 
       <screen>
          % <userinput>scons -Q --implicit-deps-unchanged hello</userinput>
-         cc -c -o hello.o hello.c
+         cc -o hello.o -c hello.c
          cc -o hello hello.o
          % <userinput>scons -Q hello</userinput>
          scons: `hello' is up to date.
index 90f6e3f5f8d5028b56dfb279db18402b253bdc0c..9404c233f978221c79fcadaa0561497072c6523c 100644 (file)
@@ -125,7 +125,7 @@ UNIX system are:
   ENV          => { 'PATH' => '/bin:/usr/bin' },
 
 
-And on a Win32 system (Windows NT), the default construction variables
+And on a Windows system (Windows NT), the default construction variables
 are (unless the default rule style is set using the B<DefaultRules>
 method):
 
@@ -473,7 +473,7 @@ environment undisturbed.
 
  <screen>
     % <userinput>scons -Q</userinput>
-    gcc -O2 -c -o foo.o foo.c
+    gcc -o foo.o -c -O2 foo.c
     gcc -o foo foo.o
  </screen>
 
@@ -505,9 +505,9 @@ environment undisturbed.
 
    <screen>
       % <userinput>scons -Q</userinput>
-      cc -g -c -o bar.o bar.c
+      cc -o bar.o -c -g bar.c
       cc -o bar bar.o
-      cc -O2 -c -o foo.o foo.c
+      cc -o foo.o -c -O2 foo.c
       cc -o foo foo.o
    </screen>
 
@@ -540,7 +540,7 @@ environment undisturbed.
       % <userinput>scons -Q</userinput>
       
       scons: *** Two environments with different actions were specified for the same target: foo.o
-      File "SConstruct", line 6, in ?
+      File "/home/my/project/SConstruct", line 6, in ?
    </screen>
 
    <para>
@@ -593,9 +593,9 @@ environment undisturbed.
 
    <screen>
       % <userinput>scons -Q</userinput>
-      cc -g -c -o foo-dbg.o foo.c
+      cc -o foo-dbg.o -c -g foo.c
       cc -o foo-dbg foo-dbg.o
-      cc -O2 -c -o foo-opt.o foo.c
+      cc -o foo-opt.o -c -O2 foo.c
       cc -o foo-opt foo-opt.o
    </screen>
 
@@ -653,11 +653,11 @@ environment undisturbed.
 
    <screen>
       % <userinput>scons -Q</userinput>
-      gcc -c -o foo.o foo.c
+      gcc -o foo.o -c foo.c
       gcc -o foo foo.o
-      gcc -g -c -o foo-dbg.o foo.c
+      gcc -o foo-dbg.o -c -g foo.c
       gcc -o foo-dbg foo-dbg.o
-      gcc -O2 -c -o foo-opt.o foo.c
+      gcc -o foo-opt.o -c -O2 foo.c
       gcc -o foo-opt foo-opt.o
    </screen>
 
@@ -728,7 +728,7 @@ environment undisturbed.
 
    <para>
 
-   And on Win32:
+   And on Windows:
 
    </para>
 
@@ -889,7 +889,7 @@ environment undisturbed.
 
      <screen>
         % <userinput>scons -Q</userinput>
-        cc -DDEFINE2 -c -o foo.o foo.c
+        cc -o foo.o -c -DDEFINE2 foo.c
         cc -o foo foo.o
      </screen>
 
@@ -965,9 +965,9 @@ environment undisturbed.
         CCFLAGS = -DDEFINE2
         scons: done reading SConscript files.
         scons: Building targets ...
-        cc -DDEFINE2 -c -o bar.o bar.c
+        cc -o bar.o -c -DDEFINE2 bar.c
         cc -o bar bar.o
-        cc -DDEFINE2 -c -o foo.o foo.c
+        cc -o foo.o -c -DDEFINE2 foo.c
         cc -o foo foo.o
         scons: done building targets.
      </screen>
@@ -1014,7 +1014,7 @@ environment undisturbed.
 
      <screen>
         % <userinput>scons -Q</userinput>
-        cc -DMY_VALUE -DLAST -c -o foo.o foo.c
+        cc -o foo.o -c -DMY_VALUE -DLAST foo.c
         cc -o foo foo.o
      </screen>
 
@@ -1071,7 +1071,7 @@ environment undisturbed.
 
      <screen>
         % <userinput>scons -Q</userinput>
-        cc -DFIRST -DMY_VALUE -c -o foo.o foo.c
+        cc -o foo.o -c -DFIRST -DMY_VALUE foo.c
         cc -o foo foo.o
      </screen>
 
index 047545d919f24eb89a1ce63b8c65e0cab4e166af..0ce243000eac6e5aede32d18686df599dca5b6b9 100644 (file)
@@ -317,13 +317,13 @@ make no difference to the build.
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o prog1/foo1.o prog1/foo1.c
-       cc -c -o prog1/foo2.o prog1/foo2.c
-       cc -c -o prog1/main.o prog1/main.c
+       cc -o prog1/foo1.o -c prog1/foo1.c
+       cc -o prog1/foo2.o -c prog1/foo2.c
+       cc -o prog1/main.o -c prog1/main.c
        cc -o prog1/prog1 prog1/main.o prog1/foo1.o prog1/foo2.o
-       cc -c -o prog2/bar1.o prog2/bar1.c
-       cc -c -o prog2/bar2.o prog2/bar2.c
-       cc -c -o prog2/main.o prog2/main.c
+       cc -o prog2/bar1.o -c prog2/bar1.c
+       cc -o prog2/bar2.o -c prog2/bar2.c
+       cc -o prog2/main.o -c prog2/main.c
        cc -o prog2/prog2 prog2/main.o prog2/bar1.o prog2/bar2.o
     </screen>
 
@@ -382,9 +382,9 @@ make no difference to the build.
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o lib/foo1.o lib/foo1.c
-       cc -c -o src/prog/foo2.o src/prog/foo2.c
-       cc -c -o src/prog/main.o src/prog/main.c
+       cc -o lib/foo1.o -c lib/foo1.c
+       cc -o src/prog/foo2.o -c src/prog/foo2.c
+       cc -o src/prog/main.o -c src/prog/main.c
        cc -o src/prog/prog src/prog/main.o lib/foo1.o src/prog/foo2.o
     </screen>
 
@@ -423,9 +423,9 @@ make no difference to the build.
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o src/prog/foo2.o src/prog/foo2.c
-       cc -c -o src/prog/main.o src/prog/main.c
-       cc -c -o /usr/joe/lib/foo1.o /usr/joe/lib/foo1.c
+       cc -o src/prog/foo2.o -c src/prog/foo2.c
+       cc -o src/prog/main.o -c src/prog/main.c
+       cc -o /usr/joe/lib/foo1.o -c /usr/joe/lib/foo1.c
        cc -o src/prog/prog src/prog/main.o /usr/joe/lib/foo1.o src/prog/foo2.o
     </screen>
 
@@ -716,9 +716,9 @@ make no difference to the build.
 
       <screen>
         % <userinput>scons -Q</userinput>
-        cc -c -o bar/bar.o bar/bar.c
-        cc -c -o foo/foo.o foo/foo.c
-        ar r libprog.a foo/foo.o bar/bar.o
+        cc -o bar/bar.o -c bar/bar.c
+        cc -o foo/foo.o -c foo/foo.c
+        ar rc libprog.a foo/foo.o bar/bar.o
         ranlib libprog.a
       </screen>
 
index 430b336d7813be4286d0649eb1250733394def4b..2a6d1b89107dbc6fbce2b5b1a227e82c7877051a 100644 (file)
@@ -58,7 +58,7 @@
 
   <screen>
      % <userinput>scons -Q</userinput>
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
      % <userinput>scons -Q /usr/bin</userinput>
      Install file: "hello" as "/usr/bin/hello"
@@ -95,7 +95,7 @@
 
   <screen>
      % <userinput>scons -Q</userinput>
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
      % <userinput>scons -Q install</userinput>
      Install file: "hello" as "/usr/bin/hello"
 
     <screen>
        % <userinput>scons -Q install</userinput>
-       cc -c -o goodbye.o goodbye.c
+       cc -o goodbye.o -c goodbye.c
        cc -o goodbye goodbye.o
        Install file: "goodbye" as "/usr/bin/goodbye"
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        Install file: "hello" as "/usr/bin/hello"
     </screen>
 
     <screen>
        % <userinput>scons -Q install</userinput>
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        Install file: "hello" as "/usr/bin/hello-new"
     </screen>
 
     <screen>
        % <userinput>scons -Q install</userinput>
-       cc -c -o goodbye.o goodbye.c
+       cc -o goodbye.o -c goodbye.c
        cc -o goodbye goodbye.o
        Install file: "goodbye" as "/usr/bin/goodbye-new"
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        Install file: "hello" as "/usr/bin/hello-new"
     </screen>
index 1aa993d768c3966cefefcd50445b6ca0d9736ddf..ad208124d382cacc281606b0a00b63ed7a4168f5 100644 (file)
@@ -87,7 +87,7 @@
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o new_hello hello.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o file1.o file1.c
-       cc -c -o file2.o file2.c
-       cc -c -o main.o main.c
+       cc -o file1.o -c file1.c
+       cc -o file2.o -c file2.c
+       cc -o main.o -c main.c
        cc -o main main.o file1.o file2.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o file1.o file1.c
-       cc -c -o file2.o file2.c
-       cc -c -o main.o main.c
+       cc -o file1.o -c file1.c
+       cc -o file2.o -c file2.c
+       cc -o main.o -c main.c
        cc -o program main.o file1.o file2.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o bar1.o bar1.c
-       cc -c -o bar2.o bar2.c
+       cc -o bar1.o -c bar1.c
+       cc -o bar2.o -c bar2.c
        cc -o bar bar1.o bar2.o
-       cc -c -o foo.o foo.c
+       cc -o foo.o -c foo.c
        cc -o foo foo.o
     </screen>
 
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -c -o bar1.o bar1.c
-       cc -c -o bar2.o bar2.c
-       cc -c -o common1.o common1.c
-       cc -c -o common2.o common2.c
+       cc -o bar1.o -c bar1.c
+       cc -o bar2.o -c bar2.c
+       cc -o common1.o -c common1.c
+       cc -o common2.o -c common2.c
        cc -o bar bar1.o bar2.o common1.o common2.o
-       cc -c -o foo.o foo.c
+       cc -o foo.o -c foo.c
        cc -o foo foo.o common1.o common2.o
     </screen>
 
index aab30450ffa4e6af09d8bcfe44b07143272f91b4..ca2cb9734e5f74ca92ef58e4f0e4c372edf70732 100644 (file)
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o f1.o f1.c
-      cc -c -o f2.o f2.c
-      cc -c -o f3.o f3.c
-      ar r libfoo.a f1.o f2.o f3.o
+      cc -o f1.o -c f1.c
+      cc -o f2.o -c f2.c
+      cc -o f3.o -c f3.c
+      ar rc libfoo.a f1.o f2.o f3.o
       ranlib libfoo.a
     </screen>
 
 
       <screen>
         % <userinput>scons -Q</userinput>
-        cc -c -o f1.os f1.c
-        cc -c -o f2.os f2.c
-        cc -c -o f3.os f3.c
-        cc -shared -o libfoo.so f1.os f2.os f3.os
+        cc -o f1.os -c f1.c
+        cc -o f2.os -c f2.c
+        cc -o f3.os -c f3.c
+        cc -o libfoo.so -shared f1.os f2.os f3.os
       </screen>
 
       <para>
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o f1.o f1.c
-      cc -c -o f2.o f2.c
-      cc -c -o f3.o f3.c
-      ar r libfoo.a f1.o f2.o f3.o
+      cc -o f1.o -c f1.c
+      cc -o f2.o -c f2.c
+      cc -o f3.o -c f3.c
+      ar rc libfoo.a f1.o f2.o f3.o
       ranlib libfoo.a
-      cc -c -o prog.o prog.c
+      cc -o prog.o -c prog.c
       cc -o prog prog.o -L. -lfoo -lbar
     </screen>
 
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o prog.o prog.c
+      cc -o prog.o -c prog.c
       cc -o prog prog.o -L/usr/lib -L/usr/local/lib -lm
     </screen>
 
index f5faf5ae7d885a2a27fcf57967ed8b4bc2838e68..4b8aa0f930c50fbd2fe4c726123510193dd93fb5 100644 (file)
 
     </para>
 
-    <scons_output example="print" os="posix">
+    <scons_output example="exists" os="posix">
       <scons_output_command>scons -Q</scons_output_command>
     </scons_output>
 
 
     </para>
 
-    <scons_example name="exists">
+    <scons_example name="read">
       <file name="SConstruct" printme="1">
       hello_c = File('hello.c')
       contents = hello_c.read()
 
     </para>
 
-    <scons_output example="print" os="posix">
+    <scons_output example="read" os="posix">
       <scons_output_command>scons -Q</scons_output_command>
     </scons_output>
 
index 114e9e0a8448115ee564886e177053c96bb0ca53..c8756c55db69802ef24737ce30d9b12a8bb56bad 100644 (file)
 
     <screen>
        % <userinput>scons -Q</userinput>
-       cc -DGOODBYE -c -o goodbye.o goodbye.c
-       cc -DHELLO -c -o hello.o hello.c
+       cc -o goodbye.o -c -DGOODBYE goodbye.c
+       cc -o hello.o -c -DHELLO hello.c
        cc -o hello hello.o goodbye.o
     </screen>
 
       % <userinput>scons -Q</userinput>
       The object file is: hello.o
       The program file is: hello
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
 
     <screen>
       % <userinput>scons -Q</userinput>
-      The object file is: hello.o
-      The program file is: hello
-      cc -c -o hello.o hello.c
+      hello does not exist!
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
 
     </para>
 
-    <scons_example name="exists">
+    <scons_example name="read">
       <file name="SConstruct" printme="1">
       hello_c = File('hello.c')
       contents = hello_c.read()
 
     </para>
 
-    <scons_output example="print" os="posix">
+    <scons_output example="read" os="posix">
       <scons_output_command>scons -Q</scons_output_command>
     </scons_output>
 
index 47dbd983732a11a7a1c27f77b65ae82ee209b254..ba5d1a34c54ea8a9099cce2f08c870696841d4f5 100644 (file)
 
     &SCons; has received contributions
     from many other people, of course:
-    Matt Balvin (extending long command-line support on Win32),
+    Matt Balvin (extending long command-line support on Windows),
     Allen Bierbaum (extensions and fixes to Options),
     Steve Christensen (help text sorting and function action signature fixes),
     Michael Cook (avoiding losing signal bits from executed commands),
     Derrick 'dman' Hudson (),
-    Alex Jacques (work on the Win32 scons.bat file),
+    Alex Jacques (work on the Windows scons.bat file),
     Stephen Kennedy (performance enhancements),
     Lachlan O'Dea (SharedObject() support for masm
     and normalized paths for the WhereIs() function),
index d2c9236969ced8ecb23b5be0017de9b03128fdd9..a667a9113559effb4f1743923b1b5d6abf5119ee 100644 (file)
   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
--->
-
-<!--
-
-
-=head2 Repository dependency analysis
-
-Due to its built-in scanning, Cons will search the specified repository
-trees for included F<.h> files.  Unless the compiler also knows about the
-repository trees, though, it will be unable to find F<.h> files that only
-exist in a repository.  If, for example, the F<hello.c> file includes the
-F<hello.h> file in its current directory:
-
-  % cons -R /usr/all/repository hello
-  gcc -c /usr/all/repository/hello.c -o hello.o
-  /usr/all/repository/hello.c:1: hello.h: No such file or directory
-
-Solving this problem forces some requirements onto the way construction
-environments are defined and onto the way the C C<#include> preprocessor
-directive is used to include files.
-
-In order to inform the compiler about the repository trees, Cons will add
-appropriate C<-I> flags to the compilation commands.  This means that the
-C<CPPPATH> variable in the construction environment must explicitly specify
-all subdirectories which are to be searched for included files, including the
-current directory.  Consequently, we can fix the above example by changing
-the environment creation in the F<Construct> file as follows:
-
-  $env = new cons(
-       CC      => 'gcc',
-       CPPPATH => '.',
-       LIBS    => 'libworld.a',
-  );
-
-Due to the definition of the C<CPPPATH> variable, this yields, when we
-re-execute the command:
-
-  % cons -R /usr/all/repository hello
-  gcc -c -I. -I/usr/all/repository /usr/all/repository/hello.c -o hello.o
-  gcc -o hello hello.o /usr/all/repository/libworld.a
-
-The order of the C<-I> flags replicates, for the C preprocessor, the same
-repository-directory search path that Cons uses for its own dependency
-analysis.  If there are multiple repositories and multiple C<CPPPATH>
-directories, Cons will append the repository directories to the beginning of
-each C<CPPPATH> directory, rapidly multiplying the number of C<-I> flags.
-As an extreme example, a F<Construct> file containing:
-
-  Repository qw(
-       /u1
-       /u2
-  );
-
-  $env = new cons(
-       CPPPATH => 'a:b:c',
-  );
-
-Would yield a compilation command of:
-
-  cc -Ia -I/u1/a -I/u2/a -Ib -I/u1/b -I/u2/b -Ic -I/u1/c -I/u2/c -c hello.c -o hello.o
-
-In order to shorten the command lines as much as possible, Cons will
-remove C<-I> flags for any directories, locally or in the repositories,
-which do not actually exist.  (Note that the C<-I> flags are not included
-in the MD5 signature calculation for the target file, so the target will
-not be recompiled if the compilation command changes due to a directory
-coming into existence.)
-
-Because Cons relies on the compiler's C<-I> flags to communicate the
-order in which repository directories must be searched, Cons' handling
-of repository directories is fundamentally incompatible with using
-double-quotes on the C<#include> directives in any C source code that
-you plan to modify:
-
-  #include "file.h"    /* DON'T USE DOUBLE-QUOTES LIKE THIS */
-
-This is because most C preprocessors, when faced with such a directive, will
-always first search the directory containing the source file.  This
-undermines the elaborate C<-I> options that Cons constructs to make the
-preprocessor conform to its preferred search path.
-
-Consequently, when using repository trees in Cons, B<always> use
-angle-brackets for included files in any C source (.c or .h) files that
-you plan to modify locally:
-
-  #include <file.h>    /* USE ANGLE-BRACKETS INSTEAD */
-
-Code that will not change can still safely use double quotes on #include
-lines.
-
-
-=head2 Repository_List
-
-Cons provides a C<Repository_List> command to return a list of all
-repository directories in their current search order.  This can be used for
-debugging, or to do more complex Perl stuff:
-
-  @list = Repository_List;
-  print join(' ', @list), "\n";
-
-
-=head2 Repository interaction with other Cons features
-
-Cons' handling of repository trees interacts correctly with other Cons
-features, which is to say, it generally does what you would expect.
-
-Most notably, repository trees interact correctly, and rather powerfully,
-with the 'Link' command.  A repository tree may contain one or more
-subdirectories for version builds established via C<Link> to a source
-subdirectory.  Cons will search for derived files in the appropriate build
-subdirectories under the repository tree.
-
 -->
 
   <para>
@@ -170,11 +58,13 @@ subdirectories under the repository tree.
     a directory copy of the source code tree.
     (Note that this is not the sort of repository
     maintained by a source code management system
-    like BitKeeper, CVS, or Subversion.
+    like BitKeeper, CVS, or Subversion.)
+    <!--
     For information about using &SCons;
     with these systems, see the section,
     "Fetching Files From Source Code Management Systems,"
     below.)
+    -->
     You use the &Repository; method
     to tell &SCons; to search one or more
     central code repositories (in order)
@@ -187,7 +77,7 @@ subdirectories under the repository tree.
       <file name="SConstruct" printme="1">
        env = Environment()
        env.Program('hello.c')
-       Repository('/usr/repository1', '/usr/repository2')
+       Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
       </file>
       <file name="hello.c">
       int main() { printf("Hello, world!\n"); }
@@ -256,17 +146,15 @@ subdirectories under the repository tree.
       <file name="SConstruct">
        env = Environment()
        env.Program('hello.c')
-       Repository('/usr/repository1', '/usr/repository2')
+       Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
       </file>
-      <file name="hello.c">
+      <file name="__ROOT__/usr/repository1/hello.c">
       int main() { printf("Hello, world!\n"); }
       </file>
     </scons_example>
 
     <scons_output example="ex2">
       <scons_output_command>scons -Q</scons_output_command>
-      gcc -c /usr/repository1/hello.c -o hello.o
-      gcc -o hello hello.o
     </scons_output>
 
     <para>
@@ -281,9 +169,9 @@ subdirectories under the repository tree.
       <file name="SConstruct">
        env = Environment()
        env.Program('hello.c')
-       Repository('/usr/repository1', '/usr/repository2')
+       Repository('__ROOT__/usr/repository1', '__ROOT__/usr/repository2')
       </file>
-      <file name="hello.c">
+      <file name="__ROOT__/usr/repository2/hello.c">
       int main() { printf("Hello, world!\n"); }
       </file>
     </scons_example>
@@ -298,6 +186,252 @@ subdirectories under the repository tree.
 
   </section>
 
+  <section>
+  <title>Finding <literal>#include</literal> files in repositories</title>
+
+    <para>
+
+    We've already seen that SCons will scan the contents of
+    a source file for <literal>#include</literal> file names
+    and realize that targets built from that source file
+    also depend on the <literal>#include</literal> file(s).
+    For each directory in the &cv-CPPPATH; list,
+    &SCons; will actually search the corresponding directories
+    in any repository trees and establish the
+    correct dependencies on any
+    <literal>#include</literal> files that it finds
+    in repository directory.
+
+    </para>
+
+    <para>
+
+    Unless the C compiler also knows about these directories
+    in the repository trees, though,
+    it will be unable to find the <literal>#include</literal> files.
+    If, for example, the &hello_c; file in
+    our previous example includes the &hello.h;
+    in its current directory,
+    and the &hello.h; only exists in the repository:
+
+    </para>
+
+    <screen>
+      % <userinput>scons -Q</userinput>
+      cc -o hello.o -c hello.c
+      hello.c:1: hello.h: No such file or directory
+    </screen>
+
+    <para>
+
+    In order to inform the C compiler about the repositories,
+    &SCons; will add appropriate
+    <literal>-I</literal> flags to the compilation commands
+    for each directory in the &cv-CPPPATH; list.
+    So if we add the current directory to the
+    construction environment &cv-CPPPATH; like so:
+
+    </para>
+
+    <scons_example name="CPPPATH">
+      <file name="SConstruct" printme="1">
+       env = Environment(CPPPATH = ['.'])
+       env.Program('hello.c')
+       Repository('__ROOT__/usr/repository1')
+      </file>
+      <file name="hello.c">
+      int main() { printf("Hello, world!\n"); }
+      </file>
+    </scons_example>
+
+    <para>
+
+    Then re-executing &SCons; yields:
+
+    </para>
+
+    <scons_output example="CPPPATH">
+      <scons_output_command>scons -Q</scons_output_command>
+    </scons_output>
+
+    <para>
+
+    The order of the <literal>-I</literal> options replicates,
+    for the C preprocessor,
+    the same repository-directory search path
+    that &SCons; uses for its own dependency analysis.
+    If there are multiple repositories and multiple &cv-CPPPATH;
+    directories, &SCons; will add the repository directories
+    to the beginning of each &cv-CPPPATH; directory,
+    rapidly multiplying the number of <literal>-I</literal> flags.
+    If, for example, the &cv-CPPPATH; contains three directories
+    (and shorter repository path names!):
+
+    </para>
+
+    <scons_example name="CPPPATH3">
+      <file name="SConstruct" printme="1">
+       env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3'])
+       env.Program('hello.c')
+       Repository('__ROOT__/r1', '__ROOT__/r2')
+      </file>
+      <file name="hello.c">
+      int main() { printf("Hello, world!\n"); }
+      </file>
+    </scons_example>
+
+    <para>
+
+    Then we'll end up with nine <literal>-I</literal> options
+    on the command line,
+    three (for each of the &cv-CPPPATH; directories)
+    times three (for the local directory plus the two repositories):
+
+    </para>
+
+    <scons_output example="CPPPATH3">
+      <scons_output_command>scons -Q</scons_output_command>
+    </scons_output>
+
+<!--
+
+Cons classic did the following, does SCons?
+
+In order to shorten the command lines as much as possible, Cons will
+remove C<-I> flags for any directories, locally or in the repositories,
+which do not actually exist.  (Note that the C<-I> flags are not included
+in the MD5 signature calculation for the target file, so the target will
+not be recompiled if the compilation command changes due to a directory
+coming into existence.)
+
+-->
+
+    <section>
+    <title>Limitations on <literal>#include</literal> files in repositories</title>
+
+      <para>
+
+      &SCons; relies on the C compiler's
+      <literal>-I</literal> options to control the order in which
+      the preprocessor will search the repository directories
+      for <literal>#include</literal> files.
+      This causes a problem, however, with how the C preprocessor
+      handles <literal>#include</literal> lines with
+      the file name included in double-quotes.
+
+      </para>
+
+      <para>
+
+      As we've seen,
+      &SCons; will compile the &hello_c; file from
+      the repository if it doesn't exist in
+      the local directory.
+      If, however, the &hello_c; file in the repository contains
+      a <literal>#include</literal> line with the file name in
+      double quotes:
+
+      </para>
+
+      <programlisting>
+        #include "hello.h"
+        int
+        main(int argc, char *argv[])
+        {
+            printf(HELLO_MESSAGE);
+            return (0);
+        }
+      </programlisting>
+
+      <para>
+
+      Then the C preprocessor will <emphasis>always</emphasis>
+      use a &hello_h; file from the repository directory first,
+      even if there is a &hello_h; file in the local directory,
+      despite the fact that the command line specifies
+      <literal>-I</literal> as the first option:
+
+      </para>
+
+      <scons_example name="quote1">
+        <file name="SConstruct">
+         env = Environment(CPPPATH = ['.'])
+         env.Program('hello.c')
+         Repository('__ROOT__/usr/repository1')
+        </file>
+        <file name="__ROOT__/usr/repository1/hello.c">
+        int main() { printf("Hello, world!\n"); }
+        </file>
+      </scons_example>
+
+      <scons_output example="quote1">
+        <scons_output_command>scons -Q</scons_output_command>
+      </scons_output>
+
+      <para>
+
+      This behavior of the C preprocessor--always search
+      for a <literal>#include</literal> file in double-quotes
+      first in the same directory as the source file,
+      and only then search the <literal>-I</literal>--can
+      not, in general, be changed.
+      In other words, it's a limitation
+      that must be lived with if you want to use
+      code repositories in this way.
+      There are three ways you can possibly
+      work around this C preprocessor behavior:
+
+      </para>
+
+      <orderedlist>
+
+        <listitem>
+        <para>
+
+        Some modern versions of C compilers do have an option
+        to disable or control this behavior.
+        If so, add that option to &cv-CFLAGS;
+        (or &cv-CXXFLAGS; or both) in your construction environment(s).
+        Make sure the option is used for all construction
+        environments that use C preprocessing!
+
+        </para>
+        </listitem>
+
+        <listitem>
+        <para>
+
+        Change all occurrences of <literal>#include "file.h"</literal>
+        to <literal>#include &amp;lt;file.h&amp;gt;</literal>.
+        Use of <literal>#include</literal> with angle brackets
+        does not have the same behavior--the <literal>-I</literal>
+        directories are searched first
+        for <literal>#include</literal> files--which
+        gives &SCons; direct control over the list of
+        directories the C preprocessor will search.
+
+        </para>
+        </listitem>
+
+        <listitem>
+        <para>
+
+        Require that everyone working with compilation from
+        repositories check out and work on entire directories of files,
+        not individual files.
+        (If you use local wrapper scripts around
+        your source code control system's command,
+        you could add logic to enforce this restriction there.
+
+        </para>
+        </listitem>
+
+      </orderedlist>
+
+    </section>
+
+  </section>
+
   <section>
   <title>Finding the &SConstruct; file in repositories</title>
 
index 03928536ecc38ec299e94248ac4e5b37656dbf22..c659aa22e3136b20bc69c42d96c8fe068c45d779 100644 (file)
   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
--->
-
-<!--
-
-
-=head2 Repository dependency analysis
-
-Due to its built-in scanning, Cons will search the specified repository
-trees for included F<.h> files.  Unless the compiler also knows about the
-repository trees, though, it will be unable to find F<.h> files that only
-exist in a repository.  If, for example, the F<hello.c> file includes the
-F<hello.h> file in its current directory:
-
-  % cons -R /usr/all/repository hello
-  gcc -c /usr/all/repository/hello.c -o hello.o
-  /usr/all/repository/hello.c:1: hello.h: No such file or directory
-
-Solving this problem forces some requirements onto the way construction
-environments are defined and onto the way the C C<#include> preprocessor
-directive is used to include files.
-
-In order to inform the compiler about the repository trees, Cons will add
-appropriate C<-I> flags to the compilation commands.  This means that the
-C<CPPPATH> variable in the construction environment must explicitly specify
-all subdirectories which are to be searched for included files, including the
-current directory.  Consequently, we can fix the above example by changing
-the environment creation in the F<Construct> file as follows:
-
-  $env = new cons(
-       CC      => 'gcc',
-       CPPPATH => '.',
-       LIBS    => 'libworld.a',
-  );
-
-Due to the definition of the C<CPPPATH> variable, this yields, when we
-re-execute the command:
-
-  % cons -R /usr/all/repository hello
-  gcc -c -I. -I/usr/all/repository /usr/all/repository/hello.c -o hello.o
-  gcc -o hello hello.o /usr/all/repository/libworld.a
-
-The order of the C<-I> flags replicates, for the C preprocessor, the same
-repository-directory search path that Cons uses for its own dependency
-analysis.  If there are multiple repositories and multiple C<CPPPATH>
-directories, Cons will append the repository directories to the beginning of
-each C<CPPPATH> directory, rapidly multiplying the number of C<-I> flags.
-As an extreme example, a F<Construct> file containing:
-
-  Repository qw(
-       /u1
-       /u2
-  );
-
-  $env = new cons(
-       CPPPATH => 'a:b:c',
-  );
-
-Would yield a compilation command of:
-
-  cc -Ia -I/u1/a -I/u2/a -Ib -I/u1/b -I/u2/b -Ic -I/u1/c -I/u2/c -c hello.c -o hello.o
-
-In order to shorten the command lines as much as possible, Cons will
-remove C<-I> flags for any directories, locally or in the repositories,
-which do not actually exist.  (Note that the C<-I> flags are not included
-in the MD5 signature calculation for the target file, so the target will
-not be recompiled if the compilation command changes due to a directory
-coming into existence.)
-
-Because Cons relies on the compiler's C<-I> flags to communicate the
-order in which repository directories must be searched, Cons' handling
-of repository directories is fundamentally incompatible with using
-double-quotes on the C<#include> directives in any C source code that
-you plan to modify:
-
-  #include "file.h"    /* DON'T USE DOUBLE-QUOTES LIKE THIS */
-
-This is because most C preprocessors, when faced with such a directive, will
-always first search the directory containing the source file.  This
-undermines the elaborate C<-I> options that Cons constructs to make the
-preprocessor conform to its preferred search path.
-
-Consequently, when using repository trees in Cons, B<always> use
-angle-brackets for included files in any C source (.c or .h) files that
-you plan to modify locally:
-
-  #include <file.h>    /* USE ANGLE-BRACKETS INSTEAD */
-
-Code that will not change can still safely use double quotes on #include
-lines.
-
-
-=head2 Repository_List
-
-Cons provides a C<Repository_List> command to return a list of all
-repository directories in their current search order.  This can be used for
-debugging, or to do more complex Perl stuff:
-
-  @list = Repository_List;
-  print join(' ', @list), "\n";
-
-
-=head2 Repository interaction with other Cons features
-
-Cons' handling of repository trees interacts correctly with other Cons
-features, which is to say, it generally does what you would expect.
-
-Most notably, repository trees interact correctly, and rather powerfully,
-with the 'Link' command.  A repository tree may contain one or more
-subdirectories for version builds established via C<Link> to a source
-subdirectory.  Cons will search for derived files in the appropriate build
-subdirectories under the repository tree.
-
 -->
 
   <para>
@@ -170,11 +58,13 @@ subdirectories under the repository tree.
     a directory copy of the source code tree.
     (Note that this is not the sort of repository
     maintained by a source code management system
-    like BitKeeper, CVS, or Subversion.
+    like BitKeeper, CVS, or Subversion.)
+    <!--
     For information about using &SCons;
     with these systems, see the section,
     "Fetching Files From Source Code Management Systems,"
     below.)
+    -->
     You use the &Repository; method
     to tell &SCons; to search one or more
     central code repositories (in order)
@@ -236,7 +126,7 @@ subdirectories under the repository tree.
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
     </screen>
 
@@ -253,10 +143,8 @@ subdirectories under the repository tree.
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c /usr/repository1/hello.c
       cc -o hello hello.o
-      gcc -c /usr/repository1/hello.c -o hello.o
-      gcc -o hello hello.o
     </screen>
 
     <para>
@@ -271,14 +159,247 @@ subdirectories under the repository tree.
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c /usr/repository2/hello.c
+      cc -o hello hello.o
+    </screen>
+
+    <para>
+
+    </para>
+
+  </section>
+
+  <section>
+  <title>Finding <literal>#include</literal> files in repositories</title>
+
+    <para>
+
+    We've already seen that SCons will scan the contents of
+    a source file for <literal>#include</literal> file names
+    and realize that targets built from that source file
+    also depend on the <literal>#include</literal> file(s).
+    For each directory in the &cv-CPPPATH; list,
+    &SCons; will actually search the corresponding directories
+    in any repository trees and establish the
+    correct dependencies on any
+    <literal>#include</literal> files that it finds
+    in repository directory.
+
+    </para>
+
+    <para>
+
+    Unless the C compiler also knows about these directories
+    in the repository trees, though,
+    it will be unable to find the <literal>#include</literal> files.
+    If, for example, the &hello_c; file in
+    our previous example includes the &hello;.h;
+    in its current directory,
+    and the &hello;.h; only exists in the repository:
+
+    </para>
+
+    <screen>
+      % <userinput>scons -Q</userinput>
+      cc -o hello.o -c hello.c
+      hello.c:1: hello.h: No such file or directory
+    </screen>
+
+    <para>
+
+    In order to inform the C compiler about the repositories,
+    &SCons; will add appropriate
+    <literal>-I</literal> flags to the compilation commands
+    for each directory in the &cv-CPPPATH; list.
+    So if we add the current directory to the
+    construction environment &cv-CPPPATH; like so:
+
+    </para>
+
+    <programlisting>
+       env = Environment(CPPPATH = ['.'])
+       env.Program('hello.c')
+       Repository('/usr/repository1')
+    </programlisting>
+
+    <para>
+
+    Then re-executing &SCons; yields:
+
+    </para>
+
+    <screen>
+      % <userinput>scons -Q</userinput>
+      cc -o hello.o -c -I. -I/usr/repository1 hello.c
       cc -o hello hello.o
     </screen>
 
     <para>
 
+    The order of the <literal>-I</literal> options replicates,
+    for the C preprocessor,
+    the same repository-directory search path
+    that &SCons; uses for its own dependency analysis.
+    If there are multiple repositories and multiple &cv-CPPPATH;
+    directories, &SCons; will add the repository directories
+    to the beginning of each &cv-CPPPATH; directory,
+    rapidly multiplying the number of <literal>-I</literal> flags.
+    If, for example, the &cv-CPPPATH; contains three directories
+    (and shorter repository path names!):
+
     </para>
 
+    <programlisting>
+       env = Environment(CPPPATH = ['dir1', 'dir2', 'dir3'])
+       env.Program('hello.c')
+       Repository('/r1', '/r2')
+    </programlisting>
+
+    <para>
+
+    Then we'll end up with nine <literal>-I</literal> options
+    on the command line,
+    three (for each of the &cv-CPPPATH; directories)
+    times three (for the local directory plus the two repositories):
+
+    </para>
+
+    <screen>
+      % <userinput>scons -Q</userinput>
+      cc -o hello.o -c -Idir1 -I/r1/dir1 -I/r2/dir1 -Idir2 -I/r1/dir2 -I/r2/dir2 -Idir3 -I/r1/dir3 -I/r2/dir3 hello.c
+      cc -o hello hello.o
+    </screen>
+
+<!--
+
+Cons classic did the following, does SCons?
+
+In order to shorten the command lines as much as possible, Cons will
+remove C<-I> flags for any directories, locally or in the repositories,
+which do not actually exist.  (Note that the C<-I> flags are not included
+in the MD5 signature calculation for the target file, so the target will
+not be recompiled if the compilation command changes due to a directory
+coming into existence.)
+
+-->
+
+    <section>
+    <title>Limitations on <literal>#include</literal> files in repositories</title>
+
+      <para>
+
+      &SCons; relies on the C compiler's
+      <literal>-I</literal> options to control the order in which
+      the preprocessor will search the repository directories
+      for <literal>#include</literal> files.
+      This causes a problem, however, with how the C preprocessor
+      handles <literal>#include</literal> lines with
+      the file name included in double-quotes.
+
+      </para>
+
+      <para>
+
+      As we've seen,
+      &SCons; will compile the &hello_c; file from
+      the repository if it doesn't exist in
+      the local directory.
+      If, however, the &hello_c; file in the repository contains
+      a <literal>#include</literal> line with the file name in
+      double quotes:
+
+      </para>
+
+      <programlisting>
+        #include "hello.h"
+        int
+        main(int argc, char *argv[])
+        {
+            printf(HELLO_MESSAGE);
+            return (0);
+        }
+      </programlisting>
+
+      <para>
+
+      Then the C preprocessor will <emphasis>always</emphasis>
+      use a &hello_h; file from the repository directory first,
+      even if there is a &hello_h; file in the local directory,
+      despite the fact that the command line specifies
+      <literal>-I</literal> as the first option:
+
+      </para>
+
+      
+
+      <screen>
+        % <userinput>scons -Q</userinput>
+        cc -o hello.o -c -I. -I/usr/repository1 /usr/repository1/hello.c
+        cc -o hello hello.o
+      </screen>
+
+      <para>
+
+      This behavior of the C preprocessor--always search
+      for a <literal>#include</literal> file in double-quotes
+      first in the same directory as the source file,
+      and only then search the <literal>-I</literal>--can
+      not, in general, be changed.
+      In other words, it's a limitation
+      that must be lived with if you want to use
+      code repositories in this way.
+      There are three ways you can possibly
+      work around this C preprocessor behavior:
+
+      </para>
+
+      <orderedlist>
+
+        <listitem>
+        <para>
+
+        Some modern versions of C compilers do have an option
+        to disable or control this behavior.
+        If so, add that option to &cv-CFLAGS;
+        (or &cv-CXXFLAGS; or both) in your construction environment(s).
+        Make sure the option is used for all construction
+        environments that use C preprocessing!
+
+        </para>
+        </listitem>
+
+        <listitem>
+        <para>
+
+        Change all occurrences of <literal>#include "file.h"</literal>
+        to <literal>#include &lt;file.h&gt;</literal>.
+        Use of <literal>#include</literal> with angle brackets
+        does not have the same behavior--the <literal>-I</literal>
+        directories are searched first
+        for <literal>#include</literal> files--which
+        gives &SCons; direct control over the list of
+        directories the C preprocessor will search.
+
+        </para>
+        </listitem>
+
+        <listitem>
+        <para>
+
+        Require that everyone working with compilation from
+        repositories check out and work on entire directories of files,
+        not individual files.
+        (If you use local wrapper scripts around
+        your source code control system's command,
+        you could add logic to enforce this restriction there.
+
+        </para>
+        </listitem>
+
+      </orderedlist>
+
+    </section>
+
   </section>
 
   <section>
@@ -346,9 +467,9 @@ subdirectories under the repository tree.
     <screen>
       % <userinput>cd /usr/repository1</userinput>
       % <userinput>scons -Q</userinput>
-      cc -c -o file1.o file1.c
-      cc -c -o file2.o file2.c
-      cc -c -o hello.o hello.c
+      cc -o file1.o -c file1.c
+      cc -o file2.o -c file2.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o file1.o file2.o
     </screen>
 
index 1c04f8ae2b14608ddb6f5cd8f2f9aea34b80bc8b..5f0341d6d78ec8e21825f9060fbe18410b9776a4 100644 (file)
@@ -154,7 +154,7 @@ program using the F<build/foo.c> path name.
       % <userinput>ls src</userinput>
       SConscript  hello.c
       % <userinput>scons -Q</userinput>
-      cc -c -o build/hello.o build/hello.c
+      cc -o build/hello.o -c build/hello.c
       cc -o build/hello build/hello.o
       % <userinput>ls build</userinput>
       SConscript  hello  hello.c  hello.o
@@ -350,7 +350,7 @@ program using the F<build/foo.c> path name.
       % <userinput>ls src</userinput>
       hello.c
       % <userinput>scons -Q</userinput>
-      cc -c -o build/hello.o build/hello.c
+      cc -o build/hello.o -c build/hello.c
       cc -o build/hello build/hello.o
       % <userinput>ls build</userinput>
       hello  hello.c  hello.o
@@ -380,7 +380,7 @@ program using the F<build/foo.c> path name.
       % <userinput>ls src</userinput>
       hello.c
       % <userinput>scons -Q</userinput>
-      cc -c -o build/hello.o src/hello.c
+      cc -o build/hello.o -c src/hello.c
       cc -o build/hello build/hello.o
       % <userinput>ls build</userinput>
       hello  hello.o
@@ -429,7 +429,7 @@ program using the F<build/foo.c> path name.
       % <userinput>ls src</userinput>
       SConscript  hello.c
       % <userinput>scons -Q</userinput>
-      cc -c -o build/hello.o build/hello.c
+      cc -o build/hello.o -c build/hello.c
       cc -o build/hello build/hello.o
       % <userinput>ls build</userinput>
       SConscript  hello  hello.c  hello.o
index fc68d1700572402bdde50703acc6345360c2e798..9d3617d4d072f7baaa036fdd85eb6b657233e182 100644 (file)
@@ -91,7 +91,7 @@
       scons: Reading SConscript files ...
       scons: done reading SConscript files.
       scons: Building targets ...
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       scons: done building targets.
    </screen>
       scons: Reading SConscript files ...
       scons: done reading SConscript files.
       scons: Building targets ...
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       scons: done building targets.
    </screen>
 
       scons: Reading SConscript files ...
       scons: done reading SConscript files.
       scons: Building targets ...
-      cc -c -o hello.o hello.c
+      cc -o hello.o -c hello.c
       cc -o hello hello.o
       scons: done building targets.
       % <userinput>scons -c</userinput>
        Finished calling Program()
        scons: done reading SConscript files.
        scons: Building targets ...
-       cc -c -o goodbye.o goodbye.c
+       cc -o goodbye.o -c goodbye.c
        cc -o goodbye goodbye.o
-       cc -c -o hello.o hello.c
+       cc -o hello.o -c hello.c
        cc -o hello hello.o
        scons: done building targets.
      </screen>
index 6ea0b21f88aec488cab7e60dc2a91f16a2475a51..6cb41626bc81db637818713532a4911c9346d511 100644 (file)
@@ -52,7 +52,7 @@
      % <userinput>scons -Q</userinput>
      bk get -
      bk get hello.c
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
    </screen>
 
@@ -77,7 +77,7 @@
      % <userinput>scons -Q</userinput>
      cvs -d /usr/local/CVS co -
      cvs -d /usr/local/CVS co hello.c
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
    </screen>
 
      % <userinput>scons -Q</userinput>
      co -
      co hello.c
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
    </screen>
 
      % <userinput>scons -Q</userinput>
      sccs get -
      sccs get hello.c
-     cc -c -o hello.o hello.c
+     cc -o hello.o -c hello.c
      cc -o hello hello.o
    </screen>
 
index 5cd1c9e5fae468f356a5d901bc326ba7979cbc29..f019baa2aa5e689077416cf1f4868fdd16e5dcdc 100644 (file)
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -c -o file1.o file1.c
-      cc -c -o file2.o file2.c
-      cc -c -o file3.o file3.c
+      cc -o file1.o -c file1.c
+      cc -o file2.o -c file2.c
+      cc -o file3.o -c file3.c
       cc -o prog file1.o file2.o file3.o
       % <userinput>edit file2.c</userinput>
           [CHANGE THE CONTENTS OF file2.c]
       % <userinput>scons -Q --debug=explain</userinput>
       scons: rebuilding `file2.o' because `file2.c' changed
-      cc -c -o file2.o file2.c
+      cc -o file2.o -c file2.c
       scons: rebuilding `prog' because `file2.o' changed
       cc -o prog file1.o file2.o file3.o
     </screen>
 
     <screen>
       % <userinput>scons -Q</userinput>
-      cc -I. -c -o file1.o file1.c
-      cc -I. -c -o file2.o file2.c
-      cc -I. -c -o file3.o file3.c
+      cc -o file1.o -c -I. file1.c
+      cc -o file2.o -c -I. file2.c
+      cc -o file3.o -c -I. file3.c
       cc -o prog file1.o file2.o file3.o
       % <userinput>edit hello.h</userinput>
           [CHANGE THE CONTENTS OF hello.h]
       % <userinput>scons -Q --debug=explain</userinput>
       scons: rebuilding `file1.o' because `hello.h' changed
-      cc -I. -c -o file1.o file1.c
+      cc -o file1.o -c -I. file1.c
       scons: rebuilding `file3.o' because `hello.h' changed
-      cc -I. -c -o file3.o file3.c
+      cc -o file3.o -c -I. file3.c
       scons: rebuilding `prog' because:
                  `file1.o' changed
                  `file3.o' changed
       % <userinput>scons</userinput>
       scons: Reading SConscript files ...
       { 'BUILDERS': {},
+        'CONFIGUREDIR': '#/.sconf_temp',
+        'CONFIGURELOG': '#/config.log',
         'CPPSUFFIXES': [ '.c',
                          '.C',
                          '.cxx',
                          '.F',
                          '.fpp',
                          '.FPP',
+                         '.m',
+                         '.mm',
                          '.S',
                          '.spp',
                          '.SPP'],
         'DSUFFIXES': ['.d'],
-        'Dir': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829dcb4&gt;,
-        'ENV': {'PATH': '/usr/local/bin:/bin:/usr/bin'},
-        'ESCAPE': &lt;function escape at 0x837d2a4&gt;,
-        'File': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829e0fc&gt;,
+        'Dir': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c43bec&gt;,
+        'Dirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c43c0c&gt;,
+        'ENV': {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'},
+        'ESCAPE': &lt;function escape at 0xb7b66c34&gt;,
+        'File': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c43c2c&gt;,
         'IDLSUFFIXES': ['.idl', '.IDL'],
-        'INSTALL': &lt;function copyFunc at 0x829db9c&gt;,
+        'INSTALL': &lt;function installFunc at 0xb7c41f0c&gt;,
+        'INSTALLSTR': &lt;function installStr at 0xb7c41f44&gt;,
+        'LATEXSUFFIXES': ['.tex', '.ltx', '.latex'],
         'LIBPREFIX': 'lib',
         'LIBPREFIXES': '$LIBPREFIX',
         'LIBSUFFIX': '.a',
         'LIBSUFFIXES': ['$LIBSUFFIX', '$SHLIBSUFFIX'],
+        'MAXLINELENGTH': 128072,
         'OBJPREFIX': '',
         'OBJSUFFIX': '.o',
-        'PDFPREFIX': '',
-        'PDFSUFFIX': '.pdf',
         'PLATFORM': 'posix',
         'PROGPREFIX': '',
         'PROGSUFFIX': '',
-        'PSPAWN': &lt;function piped_env_spawn at 0x837d384&gt;,
-        'PSPREFIX': '',
-        'PSSUFFIX': '.ps',
-        'RDirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829e46c&gt;,
+        'PSPAWN': &lt;function piped_env_spawn at 0xb7b66fb4&gt;,
+        'RDirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c43c4c&gt;,
         'SCANNERS': [],
         'SHELL': 'sh',
         'SHLIBPREFIX': '$LIBPREFIX',
         'SHLIBSUFFIX': '.so',
         'SHOBJPREFIX': '$OBJPREFIX',
         'SHOBJSUFFIX': '$OBJSUFFIX',
-        'SPAWN': &lt;function spawnvpe_spawn at 0x8377fdc&gt;,
-        'TEMPFILE': &lt;class SCons.Defaults.NullCmdGenerator at 0x829ddec&gt;,
+        'SPAWN': &lt;function spawnvpe_spawn at 0xb7b66a74&gt;,
+        'TEMPFILE': &lt;class SCons.Platform.TempFileMunge at 0xb7bd37ac&gt;,
+        'TEMPFILEPREFIX': '@',
         'TOOLS': [],
         '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
-        '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET)} $)',
-        '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET)} $)',
+        '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+        '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
         '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
         '__RPATH': '$_RPATH',
-        '_concat': &lt;function _concat at 0x829dc0c&gt;,
-        '_defines': &lt;function _defines at 0x829dc7c&gt;,
-        '_stripixes': &lt;function _stripixes at 0x829dc44&gt;}
+        '_concat': &lt;function _concat at 0xb7c41fb4&gt;,
+        '_defines': &lt;function _defines at 0xb7c47064&gt;,
+        '_installStr': &lt;function installStr at 0xb7c41f44&gt;,
+        '_stripixes': &lt;function _stripixes at 0xb7c4702c&gt;}
       scons: done reading SConscript files.
       scons: Building targets ...
       scons: `.' is up to date.
     <screen>
       C:\><userinput>scons</userinput>
       scons: Reading SConscript files ...
-      { 'BUILDERS': {'Object': &lt;SCons.Memoize.MultiStepBuilder object at 0x83493e4&gt;, 'SharedObject': &lt;SCons.Memoize.MultiStepBuilder object at 0x8349fec&gt;, 'StaticObject': &lt;SCons.Memoize.MultiStepBuilder object at 0x83493e4&gt;, 'PCH': &lt;SCons.Memoize.BuilderBase object at 0x83418cc&gt;, 'RES': &lt;SCons.Memoize.BuilderBase object at 0x8367cec&gt;},
+      { 'BUILDERS': {'Object': &lt;SCons.Builder.CompositeBuilder instance at 0xb7b6024c&gt;, 'SharedObject': &lt;SCons.Builder.CompositeBuilder instance at 0xb7b603cc&gt;, 'StaticObject': &lt;SCons.Builder.CompositeBuilder instance at 0xb7b6024c&gt;, 'PCH': &lt;SCons.Builder.BuilderBase instance at 0xb7bd2eac&gt;, 'RES': &lt;SCons.Builder.BuilderBase instance at 0xb7b596ec&gt;},
         'CC': 'cl',
-        'CCCOM': &lt;SCons.Memoize.FunctionAction object at 0x8340454&gt;,
+        'CCCOM': &lt;SCons.Action.FunctionAction instance at 0xb7b6086c&gt;,
         'CCCOMFLAGS': '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS',
         'CCFLAGS': ['/nologo'],
         'CCPCHFLAGS': ['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'],
         'CCPDBFLAGS': ['${(PDB and "/Z7") or ""}'],
         'CFILESUFFIX': '.c',
+        'CFLAGS': [],
+        'CONFIGUREDIR': '#/.sconf_temp',
+        'CONFIGURELOG': '#/config.log',
         'CPPDEFPREFIX': '/D',
         'CPPDEFSUFFIX': '',
         'CPPSUFFIXES': [ '.c',
                          '.F',
                          '.fpp',
                          '.FPP',
+                         '.m',
+                         '.mm',
                          '.S',
                          '.spp',
                          '.SPP'],
         'CXXFILESUFFIX': '.cc',
         'CXXFLAGS': ['$CCFLAGS', '$(', '/TP', '$)'],
         'DSUFFIXES': ['.d'],
-        'Dir': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829dcb4&gt;,
+        'Dir': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c58bec&gt;,
+        'Dirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c58c0c&gt;,
         'ENV': { 'INCLUDE': 'C:\\Program Files\\Microsoft Visual Studio/VC98\\include',
                  'LIB': 'C:\\Program Files\\Microsoft Visual Studio/VC98\\lib',
                  'PATH': 'C:\\Program Files\\Microsoft Visual Studio\\Common\\tools\\WIN95;C:\\Program Files\\Microsoft Visual Studio\\Common\\MSDev98\\bin;C:\\Program Files\\Microsoft Visual Studio\\Common\\tools;C:\\Program Files\\Microsoft Visual Studio/VC98\\bin',
-                 'PATHEXT': '.COM;.EXE;.BAT;.CMD'},
-        'ESCAPE': &lt;function &lt;lambda&gt; at 0x82339ec&gt;,
-        'File': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829e0fc&gt;,
+                 'PATHEXT': '.COM;.EXE;.BAT;.CMD',
+                 'SystemRoot': 'C:/WINDOWS'},
+        'ESCAPE': &lt;function escape at 0xb7bc917c&gt;,
+        'File': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c58c2c&gt;,
         'IDLSUFFIXES': ['.idl', '.IDL'],
         'INCPREFIX': '/I',
         'INCSUFFIX': '',
-        'INSTALL': &lt;function copyFunc at 0x829db9c&gt;,
+        'INSTALL': &lt;function installFunc at 0xb7c56f0c&gt;,
+        'INSTALLSTR': &lt;function installStr at 0xb7c56f44&gt;,
+        'LATEXSUFFIXES': ['.tex', '.ltx', '.latex'],
         'LIBPREFIX': '',
         'LIBPREFIXES': ['$LIBPREFIX'],
         'LIBSUFFIX': '.lib',
         'OBJSUFFIX': '.obj',
         'PCHCOM': '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS',
         'PCHPDBFLAGS': ['${(PDB and "/Yd") or ""}'],
-        'PDFPREFIX': '',
-        'PDFSUFFIX': '.pdf',
         'PLATFORM': 'win32',
         'PROGPREFIX': '',
         'PROGSUFFIX': '.exe',
-        'PSPAWN': &lt;function piped_spawn at 0x8372bc4&gt;,
-        'PSPREFIX': '',
-        'PSSUFFIX': '.ps',
+        'PSPAWN': &lt;function piped_spawn at 0xb7bc90d4&gt;,
         'RC': 'rc',
         'RCCOM': '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES',
         'RCFLAGS': [],
-        'RDirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0x829e46c&gt;,
+        'RDirs': &lt;SCons.Defaults.Variable_Method_Caller instance at 0xb7c58c4c&gt;,
         'SCANNERS': [],
         'SHCC': '$CC',
-        'SHCCCOM': &lt;SCons.Memoize.FunctionAction object at 0x83494bc&gt;,
+        'SHCCCOM': &lt;SCons.Action.FunctionAction instance at 0xb7b608cc&gt;,
         'SHCCFLAGS': ['$CCFLAGS'],
+        'SHCFLAGS': ['$CFLAGS'],
         'SHCXX': '$CXX',
         'SHCXXCOM': '$SHCXX $SHCXXFLAGS $CCCOMFLAGS',
         'SHCXXFLAGS': ['$CXXFLAGS'],
         'SHLIBSUFFIX': '.dll',
         'SHOBJPREFIX': '$OBJPREFIX',
         'SHOBJSUFFIX': '$OBJSUFFIX',
-        'SPAWN': &lt;function spawn at 0x8374c34&gt;,
+        'SPAWN': &lt;function spawn at 0xb7bc9144&gt;,
         'STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME': 1,
-        'TEMPFILE': &lt;class SCons.Platform.win32.TempFileMunge at 0x835edc4&gt;,
+        'TEMPFILE': &lt;class SCons.Platform.TempFileMunge at 0xb7be87ac&gt;,
+        'TEMPFILEPREFIX': '@',
         'TOOLS': ['msvc'],
         '_CPPDEFFLAGS': '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
-        '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET)} $)',
-        '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET)} $)',
+        '_CPPINCFLAGS': '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
+        '_LIBDIRFLAGS': '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
         '_LIBFLAGS': '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
-        '_concat': &lt;function _concat at 0x829dc0c&gt;,
-        '_defines': &lt;function _defines at 0x829dc7c&gt;,
-        '_stripixes': &lt;function _stripixes at 0x829dc44&gt;}
+        '_concat': &lt;function _concat at 0xb7c56fb4&gt;,
+        '_defines': &lt;function _defines at 0xb7c5c064&gt;,
+        '_installStr': &lt;function installStr at 0xb7c56f44&gt;,
+        '_stripixes': &lt;function _stripixes at 0xb7c5c02c&gt;}
       scons: done reading SConscript files.
       scons: Building targets ...
       scons: `.' is up to date.
     <screen>
       % <userinput>scons</userinput>
       scons: Reading SConscript files ...
-      {'PATH': '/usr/local/bin:/bin:/usr/bin'}
+      {'PATH': '/usr/local/bin:/opt/bin:/bin:/usr/bin'}
       scons: done reading SConscript files.
       scons: Building targets ...
       scons: `.' is up to date.
       { 'INCLUDE': 'C:\\Program Files\\Microsoft Visual Studio/VC98\\include',
         'LIB': 'C:\\Program Files\\Microsoft Visual Studio/VC98\\lib',
         'PATH': 'C:\\Program Files\\Microsoft Visual Studio\\Common\\tools\\WIN95;C:\\Program Files\\Microsoft Visual Studio\\Common\\MSDev98\\bin;C:\\Program Files\\Microsoft Visual Studio\\Common\\tools;C:\\Program Files\\Microsoft Visual Studio/VC98\\bin',
-        'PATHEXT': '.COM;.EXE;.BAT;.CMD'}
+        'PATHEXT': '.COM;.EXE;.BAT;.CMD',
+        'SystemRoot': 'C:/WINDOWS'}
       scons: done reading SConscript files.
       scons: Building targets ...
       scons: `.' is up to date.
index 57d96e0237998c361afc6d470e6d47b44c5c34c7..672785953dcb89fc97143784f6737cfa798f9266 100644 (file)
@@ -91,9 +91,9 @@ is pretty smart about rebuilding things when you change options.
   <screen>
     % <userinput>scons -Q OS=linux</userinput>
     Install file: "build/linux/world/world.h" as "export/linux/include/world.h"
-    cc -Iexport/linux/include -c -o build/linux/hello/hello.o build/linux/hello/hello.c
-    cc -Iexport/linux/include -c -o build/linux/world/world.o build/linux/world/world.c
-    ar r build/linux/world/libworld.a build/linux/world/world.o
+    cc -o build/linux/hello/hello.o -c -Iexport/linux/include build/linux/hello/hello.c
+    cc -o build/linux/world/world.o -c -Iexport/linux/include build/linux/world/world.c
+    ar rc build/linux/world/libworld.a build/linux/world/world.o
     ranlib build/linux/world/libworld.a
     Install file: "build/linux/world/libworld.a" as "export/linux/lib/libworld.a"
     cc -o build/linux/hello/hello build/linux/hello/hello.o -Lexport/linux/lib -lworld
index 7ee1fea5682dcc3c277a206918e2b48529d9288f..0d9519e9317e7a35b0627cb34c38c83da88c4509 100644 (file)
@@ -99,8 +99,11 @@ import time
 if not hasattr(os, 'WEXITSTATUS'):
     os.WEXITSTATUS = lambda x: x
 
+cwd = os.getcwd()
+
 all = 0
 baseline = 0
+builddir = os.path.join(cwd, 'build')
 debug = ''
 execute_tests = 1
 format = None
@@ -118,14 +121,13 @@ python = None
 sp = None
 spe = None
 
-cwd = os.getcwd()
-
 helpstr = """\
 Usage: runtest.py [OPTIONS] [TEST ...]
 Options:
   -a, --all                   Run all tests.
   --aegis                     Print results in Aegis format.
   -b BASE, --baseline BASE    Run test scripts against baseline BASE.
+  --builddir DIR              Directory in which packages were built.
   -d, --debug                 Run test scripts under the Python debugger.
   -f FILE, --file FILE        Run tests in specified FILE.
   -h, --help                  Print this message and exit.
@@ -160,7 +162,7 @@ Options:
 """
 
 opts, args = getopt.getopt(sys.argv[1:], "ab:df:hlno:P:p:qv:Xx:t",
-                            ['all', 'aegis', 'baseline=',
+                            ['all', 'aegis', 'baseline=', 'builddir=',
                              'debug', 'file=', 'help',
                              'list', 'no-exec', 'noqmtest', 'output=',
                              'package=', 'passed', 'python=',
@@ -173,6 +175,10 @@ for o, a in opts:
         all = 1
     elif o in ['-b', '--baseline']:
         baseline = a
+    elif o in ['--builddir']:
+        builddir = a
+        if not os.path.isabs(builddir):
+            builddir = os.path.normpath(os.path.join(cwd, builddir))
     elif o in ['-d', '--debug']:
         for dir in sys.path:
             pdb = os.path.join(dir, 'pdb.py')
@@ -288,6 +294,7 @@ if sp is None:
 if spe is None:
     spe = []
 
+sp.append(builddir)
 sp.append(cwd)
 
 #
@@ -413,7 +420,7 @@ if package:
         sys.stderr.write("Unknown package '%s'\n" % package)
         sys.exit(2)
 
-    test_dir = os.path.join(cwd, 'build', 'test-%s' % package)
+    test_dir = os.path.join(builddir, 'test-%s' % package)
 
     if dir[package] is None:
         scons_script_dir = test_dir
@@ -433,7 +440,7 @@ if package:
         scons_lib_dir = os.path.join(test_dir, dir[package], 'lib', l)
         pythonpath_dir = scons_lib_dir
 
-    scons_runtest_dir = os.path.join(cwd, 'build')
+    scons_runtest_dir = builddir
 
 else:
     sd = None
@@ -616,7 +623,7 @@ if qmtest:
     qmtest_args = [ qmtest, ]
 
     if format == '--aegis':
-        dir = os.path.join(cwd, 'build')
+        dir = builddir
         if not os.path.isdir(dir):
             dir = cwd
         qmtest_args.extend(['-D', dir])
index c4671e51ad278bc6564c3b1bc4371150a15528c1..b17ba4e228b56784264db47e50160cf89da2a677 100644 (file)
 
 RELEASE 0.97 - XXX
 
+  From Anatoly:
+
+  - Add the scons.org URL and a package description to the setup.py
+    arguments.
+
+  - Have the Windows installer add a registry entry for scons.bat in the
+    "App Paths" key, so scons.bat can be executed without adding the
+    directory to the %PATH%.  (Python itself works this way.)
+
   From Anonymous:
 
   - Fix looking for default paths in Visual Studio 8.0 (and later).
 
+  - Add -lm to the list of default D libraries for linking.
+
   From Matt Doar:
 
   - Provide a more complete write-your-own-Scanner example in the man page.
 
+  From Ralf W. Grosse-Kunstleve:
+
+  - Contributed upstream Python change to our copied subprocess.py module
+    for more efficient standard input processing.
+
   From Steven Knight:
 
   - Fix the Node.FS.Base.rel_path() method when the two nodes are on
     different drive letters.  (This caused an infinite loop when
     trying to write .sconsign files.)
 
+  - Fully support Scanners that use a dictionary to map file suffixes
+    to other scanners.
+
+  - Support delayed evaluation of the $SPAWN variable to allow selection
+    of a function via ${} string expansions.
+
+  - Add --srcdir as a synonym for -Y/--repository.
+
+  - Document limitations of #include "file.h" with Repository().
+
+  - Fix use of a toolpath under the source directory of a BuildDir().
+
+  - Fix env.Install() with a file name portion that begins with '#'.
+
+  - Fix ParseConfig()'s handling of multiple options in a string that's
+    replaced a *FLAGS construction variable.
+
+  - Have the C++ tools initialize common C compilation variables ($CCFLAGS,
+    $SHCCFLAGS and $_CCCOMCOM) even if the 'cc' Tool isn't loaded.
+
+  From Leanid Nazdrynau:
+
+  - Fix detection of Java anonymous classes if a newline precedes the
+    opening brace.
+
   From Gary Oberbrunner:
 
   - Document use of ${} to execute arbitrary Python code.
 
+  - Add support for:
+    1) automatically adding a site_scons subdirectory (in the top-level
+       SConstruct directory) to sys.path (PYTHONPATH);
+    2) automatically importing site_scons/site_init.py;
+    3) automatically adding site_scons/site_tools to the toolpath.
+
   From John Pye:
 
   - Change ParseConfig() to preserve white space in arguments passed in
     as a list.
 
+  From a smith:
+
+  - Fix adding explicitly-named Java inner class files (and any
+    other file names that may contain a '$') to Jar files.
+
+  From David Vitek:
+
+  - Add a NoCache() function to mark targets as unsuitable for propagating
+    to (or retrieving from) a CacheDir().
+
+  From Ben Webb:
+
+  - If the swig -noproxy option is used, it won't generate a .py file,
+    so don't emit it as a target that we expect to be built.
+
 
 
 RELEASE 0.96.94 - Sun, 07 Jan 2007 18:36:20 -0600
index 029217e917ffea4c29dddec300a970a28c4b9db1..2484877b20a41c249f2a8dae1cda98021adf967d 100644 (file)
@@ -2,6 +2,8 @@ SCons/__init__.py
 SCons/Action.py
 SCons/Builder.py
 SCons/compat/__init__.py
+SCons/compat/_sets.py
+SCons/compat/_sets15.py
 SCons/compat/_subprocess.py
 SCons/compat/_UserString.py
 SCons/compat/builtins.py
index 503dc9f7cb0f2259bf97f90e6f1528af6422c621..dd7009c7432939b05bc1b38e11ffef337155c5ed 100644 (file)
@@ -100,12 +100,12 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import dis
 import os
 import os.path
-import re
 import string
 import sys
 
 from SCons.Debug import logInstanceCreation
 import SCons.Errors
+import SCons.Executor
 import SCons.Util
 
 class _Null:
@@ -403,7 +403,8 @@ class CommandAction(_ActionAction):
 
     def strfunction(self, target, source, env):
         if not self.cmdstr is None:
-            c = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target, source)
+            from SCons.Subst import SUBST_RAW
+            c = env.subst(self.cmdstr, SUBST_RAW, target, source)
             if c:
                 return c
         cmd_list, ignore, silent = self.process(target, source, env)
@@ -421,7 +422,10 @@ class CommandAction(_ActionAction):
         externally.
         """
         from SCons.Subst import escape_list
-        from SCons.Util import is_String, is_List, flatten
+        import SCons.Util
+        flatten = SCons.Util.flatten
+        is_String = SCons.Util.is_String
+        is_List = SCons.Util.is_List
 
         try:
             shell = env['SHELL']
@@ -432,6 +436,9 @@ class CommandAction(_ActionAction):
             spawn = env['SPAWN']
         except KeyError:
             raise SCons.Errors.UserError('Missing SPAWN construction variable.')
+        else:
+            if is_String(spawn):
+                spawn = env.subst(spawn, raw=1, conv=lambda x: x)
 
         escape = env.get('ESCAPE', lambda x: x)
 
@@ -618,7 +625,8 @@ class FunctionAction(_ActionAction):
         if self.cmdstr is None:
             return None
         if not self.cmdstr is _null:
-            c = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target, source)
+            from SCons.Subst import SUBST_RAW
+            c = env.subst(self.cmdstr, SUBST_RAW, target, source)
             if c:
                 return c
         def array(a):
index 2c6d9159bafd82efe61f2c80ba38107187628c27..8339610602bae7848d5c3c7456ebd144351738ac 100644 (file)
@@ -135,11 +135,13 @@ class Environment:
         for k, v in kw.items():
             self.d[k] = v
     # Just use the underlying scons_subst*() utility methods.
-    def subst(self, strSubst, raw=0, target=[], source=[]):
-        return SCons.Subst.scons_subst(strSubst, self, raw, target, source, self.d)
+    def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
+        return SCons.Subst.scons_subst(strSubst, self, raw,
+                                       target, source, self.d, conv=conv)
     subst_target_source = subst
-    def subst_list(self, strSubst, raw=0, target=[], source=[]):
-        return SCons.Subst.scons_subst_list(strSubst, self, raw, target, source, self.d)
+    def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
+        return SCons.Subst.scons_subst_list(strSubst, self, raw,
+                                       target, source, self.d, conv=conv)
     def __getitem__(self, item):
         return self.d[item]
     def __setitem__(self, item, value):
@@ -1150,6 +1152,11 @@ class CommandActionTestCase(unittest.TestCase):
         a([], [], e)
         assert t.executed == [ 'xyzzy' ], t.executed
 
+        a = SCons.Action.CommandAction(["xyzzy"])
+        e = Environment(SPAWN = '$FUNC', FUNC = func)
+        a([], [], e)
+        assert t.executed == [ 'xyzzy' ], t.executed
+
         a = SCons.Action.CommandAction(["xyzzy"])
         e = Environment(SPAWN = func, SHELL = 'fake shell')
         a([], [], e)
index acf07220b163f1a3fe57d550a5b9c900212f5d60..77ac9f4177a230e10e7f9de817db161d0301e4ca 100644 (file)
@@ -864,7 +864,7 @@ class BuilderTestCase(unittest.TestCase):
         def func(self):
             pass
         
-        scanner = SCons.Scanner.Scanner(func, name='fooscan')
+        scanner = SCons.Scanner.Base(func, name='fooscan')
 
         b1 = SCons.Builder.Builder(action='bld', target_scanner=scanner)
         b2 = SCons.Builder.Builder(action='bld', target_scanner=scanner)
index ddb1a992f0e306251fb0be4c577588d3dacf07d9..81a8ee4d12d448b7c4cf1b5ac020bf46e02d1921 100644 (file)
@@ -341,7 +341,6 @@ def CheckLib(context, libs, func_name = None, header = None,
     sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
     Returns an empty string for success, an error message for failure.
     """
-    from SCons.Debug import Trace
     # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
     if context.headerfilename:
         includetext = '#include "%s"' % context.headerfilename
index 96c3cf84022e7c29f28e4c43baa5cb06c632cb4d..11bace3f232fe2e9f1772f2fe86c95caa5e05952 100644 (file)
@@ -40,7 +40,6 @@ import os
 import os.path
 import shutil
 import stat
-import string
 import time
 import types
 import sys
index 6c392a5ca985c8503d9d1e702bf44ea48fda408f..e5eb40c9d6286ab4385c974f5df330045eed731b 100644 (file)
@@ -38,7 +38,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import copy
 import os
 import os.path
-import popen2
 import string
 from UserDict import UserDict
 
@@ -47,6 +46,7 @@ import SCons.Builder
 from SCons.Debug import logInstanceCreation
 import SCons.Defaults
 import SCons.Errors
+import SCons.Memoize
 import SCons.Node
 import SCons.Node.Alias
 import SCons.Node.FS
@@ -54,7 +54,6 @@ import SCons.Node.Python
 import SCons.Platform
 import SCons.SConsign
 import SCons.Sig
-import SCons.Sig.TimeStamp
 import SCons.Subst
 import SCons.Tool
 import SCons.Util
@@ -508,17 +507,17 @@ class SubstitutionEnvironment:
         the result of that evaluation is then added to the dict.
         """
         dict = {
-            'ASFLAGS'       : [],
-            'CFLAGS'        : [],
-            'CCFLAGS'       : [],
+            'ASFLAGS'       : SCons.Util.CLVar(''),
+            'CFLAGS'        : SCons.Util.CLVar(''),
+            'CCFLAGS'       : SCons.Util.CLVar(''),
             'CPPDEFINES'    : [],
-            'CPPFLAGS'      : [],
+            'CPPFLAGS'      : SCons.Util.CLVar(''),
             'CPPPATH'       : [],
-            'FRAMEWORKPATH' : [],
-            'FRAMEWORKS'    : [],
+            'FRAMEWORKPATH' : SCons.Util.CLVar(''),
+            'FRAMEWORKS'    : SCons.Util.CLVar(''),
             'LIBPATH'       : [],
             'LIBS'          : [],
-            'LINKFLAGS'     : [],
+            'LINKFLAGS'     : SCons.Util.CLVar(''),
             'RPATH'         : [],
         }
 
@@ -620,7 +619,7 @@ class SubstitutionEnvironment:
                     if arg[2:]:
                         append_define(arg[2:])
                     else:
-                        appencd_next_arg_to = 'CPPDEFINES'
+                        append_next_arg_to = 'CPPDEFINES'
                 elif arg == '-framework':
                     append_next_arg_to = 'FRAMEWORKS'
                 elif arg[:14] == '-frameworkdir=':
@@ -665,7 +664,7 @@ class SubstitutionEnvironment:
             apply(self.Append, (), args)
             return self
         for key, value in args.items():
-            if value == '':
+            if not value:
                 continue
             try:
                 orig = self[key]
@@ -673,10 +672,24 @@ class SubstitutionEnvironment:
                 orig = value
             else:
                 if not orig:
-                    orig = []
-                elif not SCons.Util.is_List(orig): 
-                    orig = [orig]
-                orig = orig + value
+                    orig = value
+                elif value:
+                    # Add orig and value.  The logic here was lifted from
+                    # part of env.Append() (see there for a lot of comments
+                    # about the order in which things are tried) and is
+                    # used mainly to handle coercion of strings to CLVar to
+                    # "do the right thing" given (e.g.) an original CCFLAGS
+                    # string variable like '-pipe -Wall'.
+                    try:
+                        orig = orig + value
+                    except (KeyError, TypeError):
+                        try:
+                            add_to_orig = orig.append
+                        except AttributeError:
+                            value.insert(0, orig)
+                            orig = value
+                        else:
+                            add_to_orig(value)
             t = []
             if key[-4:] == 'PATH':
                 ### keep left-most occurence
@@ -1314,12 +1327,15 @@ class Base(SubstitutionEnvironment):
                 del kw[k]
         apply(self.Replace, (), kw)
 
+    def _find_toolpath_dir(self, tp):
+        return self.fs.Dir(self.subst(tp)).srcnode().abspath
+
     def Tool(self, tool, toolpath=None, **kw):
         if SCons.Util.is_String(tool):
             tool = self.subst(tool)
             if toolpath is None:
                 toolpath = self.get('toolpath', [])
-            toolpath = map(self.subst, toolpath)
+            toolpath = map(self._find_toolpath_dir, toolpath)
             tool = apply(SCons.Tool.Tool, (tool, toolpath), kw)
         tool(self)
 
@@ -1514,6 +1530,15 @@ class Base(SubstitutionEnvironment):
             t.set_noclean()
         return tlist
 
+    def NoCache(self, *targets):
+        """Tags a target so that it will not be cached"""
+        tlist = []
+        for t in targets:
+            tlist.extend(self.arg2nodes(t, self.fs.Entry))
+        for t in tlist:
+            t.set_nocache()
+        return tlist
+
     def Entry(self, name, *args, **kw):
         """
         """
@@ -1575,7 +1600,10 @@ class Base(SubstitutionEnvironment):
         tgt = []
         for dnode in dnodes:
             for src in sources:
-                target = self.fs.Entry(src.name, dnode)
+                # Prepend './' so the lookup doesn't interpret an initial
+                # '#' on the file name portion as meaning the Node should
+                # be relative to the top-level SConstruct directory.
+                target = self.fs.Entry('.'+os.sep+src.name, dnode)
                 tgt.extend(InstallBuilder(self, target, src))
         return tgt
 
@@ -1631,7 +1659,7 @@ class Base(SubstitutionEnvironment):
                 arg = self.subst(arg)
             nargs.append(arg)
         nkw = self.subst_kw(kw)
-        return apply(SCons.Scanner.Scanner, nargs, nkw)
+        return apply(SCons.Scanner.Base, nargs, nkw)
 
     def SConsignFile(self, name=".sconsign", dbm_module=None):
         if not name is None:
@@ -1746,7 +1774,7 @@ class OverrideEnvironment(Base):
     def __getattr__(self, name):
         return getattr(self.__dict__['__subject'], name)
     def __setattr__(self, name, value):
-        return setattr(self.__dict__['__subject'], name, value)
+        setattr(self.__dict__['__subject'], name, value)
 
     # Methods that make this class act like a dictionary.
     def __getitem__(self, key):
index c015bc1ed0e6f3fb30e63be817b82bfe7836cbb6..70f90264c15bce9122959dda34386613194f8d83 100644 (file)
@@ -695,7 +695,7 @@ sys.exit(1)
             "-pthread " + \
             "-mno-cygwin -mwindows " + \
             "-arch i386 -isysroot /tmp +DD64 " + \
-            "-DFOO -DBAR=value"
+            "-DFOO -DBAR=value -D BAZ"
 
         d = env.ParseFlags(s)
 
@@ -705,7 +705,7 @@ sys.exit(1)
                                   '-pthread', '-mno-cygwin',
                                   ('-arch', 'i386'), ('-isysroot', '/tmp'),
                                   '+DD64'], d['CCFLAGS']
-        assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value']], d['CPPDEFINES']
+        assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES']
         assert d['CPPFLAGS'] == ['-Wp,-cpp'], d['CPPFLAGS']
         assert d['CPPPATH'] == ['/usr/include/fum', 'bar'], d['CPPPATH']
         assert d['FRAMEWORKPATH'] == ['fwd1', 'fwd2', 'fwd3'], d['FRAMEWORKPATH']
@@ -725,7 +725,7 @@ sys.exit(1)
         """
         env = SubstitutionEnvironment()
         env.MergeFlags('')
-        assert env['CCFLAGS'] == [], env['CCFLAGS']
+        assert not env.has_key('CCFLAGS'), env['CCFLAGS']
         env.MergeFlags('-X')
         assert env['CCFLAGS'] == ['-X'], env['CCFLAGS']
         env.MergeFlags('-X')
@@ -2805,6 +2805,9 @@ def generate(env):
         for tnode in tgt:
             assert tnode.builder == InstallBuilder
 
+        tgt = env.Install('export', 'subdir/#file')
+        assert str(tgt[0]) == os.path.normpath('export/#file'), str(tgt[0])
+
         env.File('export/foo1')
 
         exc_caught = None
index 4b150102abe7041335b8d2114c3f8fe39d829eb8..12114bc9040ffa0545e8c2726ab01086cb24b15f 100644 (file)
@@ -33,7 +33,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import string
 
 from SCons.Debug import logInstanceCreation
-import SCons.Util
+import SCons.Memoize
 
 
 class Executor:
@@ -63,8 +63,10 @@ class Executor:
         self._memo = {}
 
     def set_action_list(self, action):
+        import SCons.Util
         if not SCons.Util.is_List(action):
             if not action:
+                import SCons.Errors
                 raise SCons.Errors.UserError, "Executor must have an action."
             action = [action]
         self.action_list = action
index 8dde905a94a3ca8542fed754c331bb74458d306c..9832f1464dae86f9853849b937768b8e088fab3e 100644 (file)
@@ -170,7 +170,7 @@ else:
             self.resultsQueue = Queue.Queue(0)
 
             # Create worker threads
-            for i in range(num):
+            for _ in range(num):
                 Worker(self.requestQueue, self.resultsQueue)
 
         def put(self, obj):
index 9e0e6f67c0eca5548cbb03d498311cfa87db2ab1..4d269d2f0e82538e1711d1e660bdc56f8fddee67 100644 (file)
@@ -47,6 +47,7 @@ import cStringIO
 import SCons.Action
 from SCons.Debug import logInstanceCreation
 import SCons.Errors
+import SCons.Memoize
 import SCons.Node
 import SCons.Subst
 import SCons.Util
@@ -249,6 +250,8 @@ CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None)
 
 def CachePushFunc(target, source, env):
     t = target[0]
+    if t.nocache:
+        return
     fs = t.fs
     cachedir, cachefile = t.cachepath()
     if fs.exists(cachefile):
@@ -829,7 +832,7 @@ class Entry(Base):
         morph this Entry."""
         try:
             self = self.disambiguate(must_exist=1)
-        except SCons.Errors.UserError, e:
+        except SCons.Errors.UserError:
             # There was nothing on disk with which to disambiguate
             # this entry.  Leave it as an Entry, but return a null
             # string so calls to get_contents() in emitters and the
@@ -1054,7 +1057,7 @@ class FS(LocalFS):
         path_norm = string.split(_my_normcase(name), os.sep)
 
         first_orig = path_orig.pop(0)   # strip first element
-        first_norm = path_norm.pop(0)   # strip first element
+        unused = path_norm.pop(0)   # strip first element
 
         drive, path_first = os.path.splitdrive(first_orig)
         if path_first:
@@ -1477,9 +1480,11 @@ class Dir(Base):
         return result
 
     def get_env_scanner(self, env, kw={}):
+        import SCons.Defaults
         return SCons.Defaults.DirEntryScanner
 
     def get_target_scanner(self):
+        import SCons.Defaults
         return SCons.Defaults.DirEntryScanner
 
     def get_found_includes(self, env, scanner, path):
@@ -2033,6 +2038,8 @@ class File(Base):
 
         Returns true iff the node was successfully retrieved.
         """
+        if self.nocache:
+            return None
         b = self.is_derived()
         if not b and not self.has_src_builder():
             return None
@@ -2298,7 +2305,7 @@ class File(Base):
         return str(self.rfile())
 
     def cachepath(self):
-        if not self.fs.CachePath:
+        if self.nocache or not self.fs.CachePath:
             return None, None
         ninfo = self.get_binfo().ninfo
         if not hasattr(ninfo, 'bsig'):
index 405010c9bbce543dc4dd8bf3b9b440cecb646181..fa682a201fa225abaa48f95548b66e81594052d1 100644 (file)
@@ -52,6 +52,7 @@ import UserList
 
 from SCons.Debug import logInstanceCreation
 import SCons.Executor
+import SCons.Memoize
 import SCons.SConsign
 import SCons.Util
 
@@ -202,14 +203,13 @@ class Node:
         self.state = no_state
         self.precious = None
         self.noclean = 0
+        self.nocache = 0
         self.always_build = None
         self.found_includes = {}
         self.includes = None
         self.attributes = self.Attrs() # Generic place to stick information about the Node.
         self.side_effect = 0 # true iff this node is a side effect
         self.side_effects = [] # the side effects of building this target
-        self.pre_actions = []
-        self.post_actions = []
         self.linked = 0 # is this node linked to the build directory?
 
         self.clear_memoized_values()
@@ -765,6 +765,12 @@ class Node:
         # output in Util.py can use it as an index.
         self.noclean = noclean and 1 or 0
 
+    def set_nocache(self, nocache = 1):
+        """Set the Node's nocache value."""
+        # Make sure nocache is an integer so the --debug=stree
+        # output in Util.py can use it as an index.
+        self.nocache = nocache and 1 or 0
+
     def set_always_build(self, always_build = 1):
         """Set the Node's always_build value."""
         self.always_build = always_build
index f38bf0295f37498909541adc2ebb6a703bb4e406..80b607d437a56cf2d1a6ab17fa0a40a79c9e1d0e 100644 (file)
@@ -36,18 +36,16 @@ Usage example:
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-__all__ = ('BoolOption', 'True', 'False')
+__all__ = ('BoolOption')
 
 import string
 
+import SCons.compat
 import SCons.Errors
 
 __true_strings  = ('y', 'yes', 'true', 't', '1', 'on' , 'all' )
 __false_strings = ('n', 'no', 'false', 'f', '0', 'off', 'none')
 
-# we need this since SCons should work version indepentant
-True, False = 1, 0
-
 
 def _text2bool(val):
     """
index 845f251e21511a35ab6894a1163ca83b5bf49266..07b5b7952b72e317a6f1d49b735692fb1ec76141 100644 (file)
@@ -23,6 +23,8 @@
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import SCons.compat
+
 import sys
 import unittest
 
@@ -91,8 +93,8 @@ class BoolOptionTestCase(unittest.TestCase):
         o = opts.options[0]
 
         env = {
-            'T' : SCons.Options.True,
-            'F' : SCons.Options.False,
+            'T' : True,
+            'F' : False,
             'N' : 'xyzzy',
         }
 
index 9ecb42a323417a3b3d47b5559e41a2e355fc9d8f..3b4f0cec8a841a90fcb999511351ad4baf45fcf8 100644 (file)
@@ -52,15 +52,15 @@ Usage example:
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-__all__ = ('PackageOption', 'True', 'False')
+__all__ = ('PackageOption')
 
 import string
 
-from BoolOption import True, False
+import SCons.compat
 import SCons.Errors
 
-__enable_strings  = (str(True), 'yes', 'true',  'on', 'enable', 'search')
-__disable_strings = (str(False), 'no',  'false', 'off', 'disable')
+__enable_strings  = ('1', 'yes', 'true',  'on', 'enable', 'search')
+__disable_strings = ('0', 'no',  'false', 'off', 'disable')
 
 def _converter(val):
     """
@@ -78,12 +78,10 @@ def _validator(key, val, env, searchfunc):
     """
     # todo: write validator, check for path
     import os
-    if env[key] == False:
-        pass
-    elif env[key] == True:
+    if env[key] is True:
         if searchfunc:
             env[key] = searchfunc(key, val)
-    elif not os.path.exists(val):
+    elif env[key] and not os.path.exists(val):
         raise SCons.Errors.UserError(
             'Path does not exist for option %s: %s' % (key, val))
 
index 7c868e5b83a527e0972db454c074d52ba1d4004c..68f14e5d73ab94e5d0d515eed0a61c59c136d493 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import SCons.compat
+
 import sys
 import unittest
 
 import SCons.Errors
 import SCons.Options
-from SCons.Options.BoolOption import True, False
 
 import TestCmd
 
@@ -96,7 +97,7 @@ class PackageOptionTestCase(unittest.TestCase):
 
         o = opts.options[0]
 
-        env = {'F':0, 'T':1, 'X':'x'}
+        env = {'F':False, 'T':True, 'X':'x'}
 
         exists = test.workpath('exists')
         does_not_exist = test.workpath('does_not_exist')
index 5c30be60194ea1a592c20c0c313e76af8f8d6b1d..66c214352df544147611e8b5d3d367b28a1ae090 100644 (file)
@@ -36,7 +36,7 @@ import SCons.Errors
 import SCons.Util
 import SCons.Warnings
 
-from BoolOption import BoolOption, True, False  # okay
+from BoolOption import BoolOption  # okay
 from EnumOption import EnumOption  # okay
 from ListOption import ListOption  # naja
 from PackageOption import PackageOption # naja
@@ -227,8 +227,6 @@ class Options:
               of the options.
         """
 
-        help_text = ""
-
         if sort:
             options = self.options[:]
             options.sort(lambda x,y,func=sort: func(x.key,y.key))
index b757bd3bedde7348b46c2fdf1cacc327e40ad050..81b8135925e675484cdda1f6c4219c1d63e9fe0c 100644 (file)
@@ -35,6 +35,7 @@ Do the Right Thing (almost) regardless of how the variable is specified.
 import os
 import string
 
+import SCons.Memoize
 import SCons.Util
 
 #
index 7883795a65535030c3a4c0f608c5cb5b19ea0383..fc4c773f274ecc705ad32f653762935d5e9bdade 100644 (file)
@@ -33,7 +33,6 @@ selection method.
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import posix
-import os
 
 def generate(env):
     posix.generate(env)
index 148d9df8f92809e8eb5f0655384f955474567523..8d35a8d1fc4412e780fed132093b77947ebfd971 100644 (file)
@@ -93,7 +93,6 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
             try:
                 ret = exitvalmap[e[0]]
             except KeyError:
-                result = 127
                 sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1]))
             if stderr != None:
                 stderr.write("scons: %s: %s\n" % (cmd, e[1]))
index 5c20f264c18045224ae5c43bc2c4fd20446b253e..21305b9396bc85e52f3588eea7340e3cac98a62e 100644 (file)
@@ -39,6 +39,7 @@ import types
 import SCons.Action
 import SCons.Builder
 import SCons.Errors
+import SCons.Job
 import SCons.Node.FS
 import SCons.Taskmaster
 import SCons.Util
@@ -141,7 +142,6 @@ def _createSource( target, source, env ):
     fd.write(source[0].get_contents())
     fd.close()
 def _stringSource( target, source, env ):
-    import string
     return (str(target[0]) + ' <-\n  |' +
             string.replace( source[0].get_contents(),
                             '\n', "\n  |" ) )
@@ -188,6 +188,11 @@ class Streamer:
         Return everything written to orig since the Streamer was created.
         """
         return self.s.getvalue()
+
+    def flush(self):
+        if self.orig:
+            self.orig.flush()
+        self.s.flush()
         
 
 class SConfBuildTask(SCons.Taskmaster.Task):
@@ -229,7 +234,6 @@ class SConfBuildTask(SCons.Taskmaster.Task):
             except AttributeError:
                 # Earlier versions of Python don't have sys.excepthook...
                 def excepthook(type, value, tb):
-                    import traceback
                     traceback.print_tb(tb)
                     print type, value
             apply(excepthook, self.exc_info())
@@ -597,7 +601,8 @@ class SConf:
             else:
                 _ac_config_logs[self.logfile] = None
                 log_mode = "w"
-            self.logstream = open(str(self.logfile), log_mode)
+            fp = open(str(self.logfile), log_mode)
+            self.logstream = SCons.Util.Unbuffered(fp)
             # logfile may stay in a build directory, so we tell
             # the build system not to override it with a eventually
             # existing file with the same name in the source directory
index 67b2affab7c81d824c26e9d9a260bf85960147d6..dcd6979ec75e0091ae33a0ad4271245aa8f4ebff 100644 (file)
@@ -32,8 +32,6 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import cPickle
 import os
 import os.path
-import string
-import time
 
 import SCons.dblite
 import SCons.Sig
index fb23d1b131d76681c012bdac4944540f5f0c1b42..535150a69664bf2fd351d1b6b6d6359337ae114c 100644 (file)
@@ -23,8 +23,6 @@
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import string
-
 import SCons.Node.FS
 import SCons.Scanner
 
index bd8546f933cb9ff00338be4538f184921bb433e3..30dc1dfd7d70a8cd15615c4aa3a83b3849a9ee1d 100644 (file)
@@ -82,29 +82,37 @@ class FindPathDirsTestCase(unittest.TestCase):
 class ScannerTestCase(unittest.TestCase):
 
     def test_creation(self):
-        """Test creation of Scanner objects through the Scanner() function"""
+        """Test creation of Scanner objects"""
         def func(self):
             pass
-        s = SCons.Scanner.Scanner(func)
+        s = SCons.Scanner.Base(func)
+        assert isinstance(s, SCons.Scanner.Base), s
+        s = SCons.Scanner.Base({})
         assert isinstance(s, SCons.Scanner.Base), s
-        s = SCons.Scanner.Scanner({})
-        assert isinstance(s, SCons.Scanner.Selector), s
 
-        s = SCons.Scanner.Scanner(func, name='fooscan')
+        s = SCons.Scanner.Base(func, name='fooscan')
         assert str(s) == 'fooscan', str(s)
-        s = SCons.Scanner.Scanner({}, name='barscan')
+        s = SCons.Scanner.Base({}, name='barscan')
         assert str(s) == 'barscan', str(s)
 
-        s = SCons.Scanner.Scanner(func, name='fooscan', argument=9)
+        s = SCons.Scanner.Base(func, name='fooscan', argument=9)
         assert str(s) == 'fooscan', str(s)
         assert s.argument == 9, s.argument
-        s = SCons.Scanner.Scanner({}, name='fooscan', argument=888)
+        s = SCons.Scanner.Base({}, name='fooscan', argument=888)
         assert str(s) == 'fooscan', str(s)
         assert s.argument == 888, s.argument
 
         
 class BaseTestCase(unittest.TestCase):
 
+    class skey_node:
+        def __init__(self, key):
+            self.key = key
+        def scanner_key(self):
+            return self.key
+        def rexists(self):
+            return 1
+
     def func(self, filename, env, target, *args):
         self.filename = filename
         self.env = env
@@ -132,6 +140,29 @@ class BaseTestCase(unittest.TestCase):
         else:
             self.failIf(hasattr(self, "arg"), "an argument was given when it shouldn't have been")
 
+    def test___call__dict(self):
+        """Test calling Scanner.Base objects with a dictionary"""
+        called = []
+        def s1func(node, env, path, called=called):
+            called.append('s1func')
+            called.append(node)
+            return []
+        def s2func(node, env, path, called=called):
+            called.append('s2func')
+            called.append(node)
+            return []
+        s1 = SCons.Scanner.Base(s1func)
+        s2 = SCons.Scanner.Base(s2func)
+        selector = SCons.Scanner.Base({'.x' : s1, '.y' : s2})
+        nx = self.skey_node('.x')
+        env = DummyEnvironment()
+        selector(nx, env, [])
+        assert called == ['s1func', nx], called
+        del called[:]
+        ny = self.skey_node('.y')
+        selector(ny, env, [])
+        assert called == ['s2func', ny], called
+
     def test_path(self):
         """Test the Scanner.Base path() method"""
         def pf(env, cwd, target, source, argument=None):
@@ -277,6 +308,23 @@ class BaseTestCase(unittest.TestCase):
         s = scanner.select('.x')
         assert s is scanner, s
 
+        selector = SCons.Scanner.Base({'.x' : 1, '.y' : 2})
+        s = selector.select(self.skey_node('.x'))
+        assert s == 1, s
+        s = selector.select(self.skey_node('.y'))
+        assert s == 2, s
+        s = selector.select(self.skey_node('.z'))
+        assert s is None, s
+
+    def test_add_scanner(self):
+        """Test the Scanner.Base add_scanner() method"""
+        selector = SCons.Scanner.Base({'.x' : 1, '.y' : 2})
+        s = selector.select(self.skey_node('.z'))
+        assert s is None, s
+        selector.add_scanner('.z', 3)
+        s = selector.select(self.skey_node('.z'))
+        assert s == 3, s
+
     def test___str__(self):
         """Test the Scanner.Base __str__() method"""
         scanner = SCons.Scanner.Base(function = self.func)
index 679efca5a70d27fac6f96401642dacced1e31423..db93f615b7e8a6d9d38ca3cc72e5387768efe31c 100644 (file)
@@ -45,9 +45,17 @@ class _Null:
 _null = _Null
 
 def Scanner(function, *args, **kw):
-    """Public interface factory function for creating different types
+    """
+    Public interface factory function for creating different types
     of Scanners based on the different types of "functions" that may
-    be supplied."""
+    be supplied.
+
+    TODO:  Deprecate this some day.  We've moved the functionality
+    inside the Base class and really don't need this factory function
+    any more.  It was, however, used by some of our Tool modules, so
+    the call probably ended up in various people's custom modules
+    patterned on SCons code.
+    """
     if SCons.Util.is_Dict(function):
         return apply(Selector, (function,) + args, kw)
     else:
@@ -83,7 +91,7 @@ class Base:
                  function,
                  name = "NONE",
                  argument = _null,
-                 skeys = [],
+                 skeys = _null,
                  path_function = None,
                  node_class = SCons.Node.FS.Entry,
                  node_factory = None,
@@ -159,7 +167,14 @@ class Base:
         self.path_function = path_function
         self.name = name
         self.argument = argument
+
+        if skeys is _null:
+            if SCons.Util.is_Dict(function):
+                skeys = function.keys()
+            else:
+                skeys = []
         self.skeys = skeys
+
         self.node_class = node_class
         self.node_factory = node_factory
         self.scan_check = scan_check
@@ -188,10 +203,13 @@ class Base:
         if self.scan_check and not self.scan_check(node, env):
             return []
 
+        self = self.select(node)
+
         if not self.argument is _null:
             list = self.function(node, env, path, self.argument)
         else:
             list = self.function(node, env, path)
+
         kw = {}
         if hasattr(node, 'dir'):
             kw['directory'] = node.dir
@@ -221,12 +239,19 @@ class Base:
         self.skeys.append(skey)
 
     def get_skeys(self, env=None):
-        if SCons.Util.is_String(self.skeys):
+        if env and SCons.Util.is_String(self.skeys):
             return env.subst_list(self.skeys)[0]
         return self.skeys
 
     def select(self, node):
-        return self
+        if SCons.Util.is_Dict(self.function):
+            key = node.scanner_key()
+            try:
+                return self.function[key]
+            except KeyError:
+                return None
+        else:
+            return self
 
     def _recurse_all_nodes(self, nodes):
         return nodes
@@ -236,15 +261,27 @@ class Base:
 
     recurse_nodes = _recurse_no_nodes
 
+    def add_scanner(self, skey, scanner):
+        self.function[skey] = scanner
+        self.add_skey(skey)
+
 
 class Selector(Base):
     """
     A class for selecting a more specific scanner based on the
     scanner_key() (suffix) for a specific Node.
+
+    TODO:  This functionality has been moved into the inner workings of
+    the Base class, and this class will be deprecated at some point.
+    (It was never exposed directly as part of the public interface,
+    although it is used by the Scanner() factory function that was
+    used by various Tool modules and therefore was likely a template
+    for custom modules that may be out there.)
     """
     def __init__(self, dict, *args, **kw):
         apply(Base.__init__, (self, None,)+args, kw)
         self.dict = dict
+        self.skeys = dict.keys()
 
     def __call__(self, node, env, path = ()):
         return self.select(node)(node, env, path)
@@ -257,6 +294,7 @@ class Selector(Base):
 
     def add_scanner(self, skey, scanner):
         self.dict[skey] = scanner
+        self.add_skey(skey)
 
 
 class Current(Base):
index 96f152618329446efaa927c444fd338c98f0fbef..6a0ad81211e9cc087b9dfc1ecc0ea834003c406b 100644 (file)
@@ -36,6 +36,8 @@ it goes here.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import SCons.compat
+
 import os
 import os.path
 import random
@@ -62,6 +64,7 @@ import SCons.Node
 import SCons.Node.FS
 from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
 import SCons.SConf
+import SCons.Script
 import SCons.Sig
 import SCons.Taskmaster
 import SCons.Util
@@ -180,15 +183,8 @@ class BuildTask(SCons.Taskmaster.Task):
     def postprocess(self):
         if self.top:
             t = self.targets[0]
-            if print_tree:
-                print
-                SCons.Util.print_tree(t, get_all_children)
-            if print_stree:
-                print
-                SCons.Util.print_tree(t, get_all_children, showtags=2)
-            if print_dtree:
-                print
-                SCons.Util.print_tree(t, get_derived_children)
+            for tp in tree_printers:
+                tp.display(t)
             if print_includes:
                 tree = t.render_include_tree()
                 if tree:
@@ -291,18 +287,37 @@ class QuestionTask(SCons.Taskmaster.Task):
     def executed(self):
         pass
 
+
+class TreePrinter:
+    def __init__(self, derived=False, prune=False, status=False):
+        self.derived = derived
+        self.prune = prune
+        self.status = status
+    def get_all_children(self, node):
+        return node.all_children()
+    def get_derived_children(self, node):
+        children = node.all_children(None)
+        return filter(lambda x: x.has_builder(), children)
+    def display(self, t):
+        if self.derived:
+            func = self.get_derived_children
+        else:
+            func = self.get_all_children
+        s = self.status and 2 or 0
+        SCons.Util.print_tree(t, func, prune=self.prune, showtags=s)
+
+
 # Global variables
 
+tree_printers = []
+
 keep_going_on_error = 0
-print_dtree = 0
 print_explanations = 0
 print_includes = 0
 print_objects = 0
 print_memoizer = 0
 print_stacktrace = 0
-print_stree = 0
 print_time = 0
-print_tree = 0
 ignore_errors = 0
 sconscript_time = 0
 command_time = 0
@@ -390,12 +405,6 @@ memory_stats = MemStats()
 
 # utility functions
 
-def get_all_children(node): return node.all_children()
-
-def get_derived_children(node):
-    children = node.all_children(None)
-    return filter(lambda x: x.has_builder(), children)
-
 def _scons_syntax_error(e):
     """Handle syntax errors. Print out a message and show where the error
     occurred.
@@ -538,10 +547,10 @@ def _SConstruct_exists(dirname=''):
 
 def _set_globals(options):
     global keep_going_on_error, ignore_errors
-    global count_stats, print_dtree
+    global count_stats
     global print_explanations, print_includes, print_memoizer
-    global print_objects, print_stacktrace, print_stree
-    global print_time, print_tree
+    global print_objects, print_stacktrace, print_time
+    global tree_printers
     global memory_stats
 
     keep_going_on_error = options.keep_going
@@ -555,7 +564,7 @@ def _set_globals(options):
         if "count" in debug_values:
             count_stats.enable(sys.stdout)
         if "dtree" in debug_values:
-            print_dtree = 1
+            tree_printers.append(TreePrinter(derived=True))
         if "explain" in debug_values:
             print_explanations = 1
         if "findlibs" in debug_values:
@@ -573,11 +582,11 @@ def _set_globals(options):
         if "stacktrace" in debug_values:
             print_stacktrace = 1
         if "stree" in debug_values:
-            print_stree = 1
+            tree_printers.append(TreePrinter(status=True))
         if "time" in debug_values:
             print_time = 1
         if "tree" in debug_values:
-            print_tree = 1
+            tree_printers.append(TreePrinter())
     ignore_errors = options.ignore_errors
 
 def _create_path(plist):
@@ -589,6 +598,47 @@ def _create_path(plist):
             path = path + '/' + d
     return path
 
+def _load_site_scons_dir(topdir, site_dir_name=None):
+    """Load the site_scons dir under topdir.
+    Adds site_scons to sys.path, imports site_scons/site_init.py,
+    and adds site_scons/site_tools to default toolpath."""
+    if site_dir_name:
+        err_if_not_found = True       # user specified: err if missing
+    else:
+        site_dir_name = "site_scons"
+        err_if_not_found = False
+        
+    site_dir = os.path.join(topdir.path, site_dir_name)
+    if not os.path.exists(site_dir):
+        if err_if_not_found:
+            raise SCons.Errors.UserError, "site dir %s not found."%site_dir
+        return
+
+    site_init_filename = "site_init.py"
+    site_init_modname = "site_init"
+    site_tools_dirname = "site_tools"
+    sys.path = [site_dir] + sys.path
+    site_init_file = os.path.join(site_dir, site_init_filename)
+    site_tools_dir = os.path.join(site_dir, site_tools_dirname)
+    if os.path.exists(site_init_file):
+        import imp
+        try:
+            fp, pathname, description = imp.find_module(site_init_modname,
+                                                        [site_dir])
+            try:
+                imp.load_module(site_init_modname, fp, pathname, description)
+            finally:
+                if fp:
+                    fp.close()
+        except ImportError, e:
+            sys.stderr.write("Can't import site init file '%s': %s\n"%(site_init_file, e))
+            raise
+        except Exception, e:
+            sys.stderr.write("Site init file '%s' raised exception: %s\n"%(site_init_file, e))
+            raise
+    if os.path.exists(site_tools_dir):
+        SCons.Tool.DefaultToolpath.append(os.path.abspath(site_tools_dir))
+
 def version_string(label, module):
     fmt = "\t%s: v%s.%s, %s, by %s on %s\n"
     return fmt % (label,
@@ -676,7 +726,9 @@ class OptParser(OptionParser):
                          "pdb", "presub", "stacktrace", "stree",
                          "time", "tree"]
 
-        deprecated_debug_options = [ "nomemoizer", ]
+        deprecated_debug_options = {
+            "nomemoizer" : ' and has no effect',
+        }
 
         def opt_debug(option, opt, value, parser, debug_options=debug_options, deprecated_debug_options=deprecated_debug_options):
             if value in debug_options:
@@ -686,8 +738,9 @@ class OptParser(OptionParser):
                 except AttributeError:
                     parser.values.debug = []
                 parser.values.debug.append(value)
-            elif value in deprecated_debug_options:
-                w = "The --debug=%s option is deprecated and has no effect." % value
+            elif value in deprecated_debug_options.keys():
+                msg = deprecated_debug_options[value]
+                w = "The --debug=%s option is deprecated%s." % (value, msg)
                 delayed_warnings.append((SCons.Warnings.DeprecatedWarning, w))
             else:
                 raise OptionValueError("Warning:  %s is not a valid debug type" % value)
@@ -773,6 +826,10 @@ class OptParser(OptionParser):
                         '--recon', action="store_true", dest='noexec',
                         default=0, help="Don't build; just print commands.")
 
+        self.add_option('--no-site-dir', action="store_true",
+                        dest='no_site_dir', default=0,
+                        help="Don't search or use the usual site_scons dir.")
+
         self.add_option('--profile', action="store",
                         dest="profile_file", metavar="FILE",
                         help="Profile SCons and put results in FILE.")
@@ -790,10 +847,36 @@ class OptParser(OptionParser):
         self.add_option('-s', '--silent', '--quiet', action="store_true",
                         default=0, help="Don't print commands.")
 
+        self.add_option('--site-dir', action="store",
+                        dest='site_dir', metavar="DIR",
+                        help="Use DIR instead of the usual site_scons dir.")
+
         self.add_option('--taskmastertrace', action="store",
                         dest="taskmastertrace_file", metavar="FILE",
                         help="Trace Node evaluation to FILE.")
 
+        tree_options = ["all", "derived", "prune", "status"]
+
+        def opt_tree(option, opt, value, parser, tree_options=tree_options):
+            tp = TreePrinter()
+            for o in string.split(value, ','):
+                if o == 'all':
+                    tp.derived = False
+                elif o == 'derived':
+                    tp.derived = True
+                elif o == 'prune':
+                    tp.prune = True
+                elif o == 'status':
+                    tp.status = True
+                else:
+                    raise OptionValueError("Warning:  %s is not a valid --tree option" % o)
+            tree_printers.append(tp)
+
+        self.add_option('--tree', action="callback", type="string",
+                        callback=opt_tree, nargs=1, metavar="OPTIONS",
+                        help="Print a dependency tree in various formats: "
+                             "%s." % string.join(tree_options, ", "))
+
         self.add_option('-u', '--up', '--search-up', action="store_const",
                         dest="climb_up", default=0, const=1,
                         help="Search up directory tree for SConstruct,       "
@@ -811,7 +894,8 @@ class OptParser(OptionParser):
                         metavar="WARNING-SPEC",
                         help="Enable or disable warnings.")
 
-        self.add_option('-Y', '--repository', nargs=1, action="append",
+        self.add_option('-Y', '--repository', '--srcdir',
+                        nargs=1, action="append",
                         help="Search REPOSITORY for source and target files.")
 
         self.add_option('-e', '--environment-overrides', action="callback",
@@ -1076,6 +1160,11 @@ def _main(args, parser):
     if options.cache_show:
         fs.cache_show = 1
 
+    if options.site_dir:
+        _load_site_scons_dir(d, options.site_dir)
+    elif not options.no_site_dir:
+        _load_site_scons_dir(d)
+        
     if options.include_dir:
         sys.path = options.include_dir + sys.path
 
@@ -1092,16 +1181,7 @@ def _main(args, parser):
     SCons.Script._Add_Targets(targets)
     SCons.Script._Add_Arguments(xmit_args)
 
-    class Unbuffered:
-        def __init__(self, file):
-            self.file = file
-        def write(self, arg):
-            self.file.write(arg)
-            self.file.flush()
-        def __getattr__(self, attr):
-            return getattr(self.file, attr)
-
-    sys.stdout = Unbuffered(sys.stdout)
+    sys.stdout = SCons.Util.Unbuffered(sys.stdout)
 
     memory_stats.append('before reading SConscript files:')
     count_stats.append(('pre-', 'read'))
index 749be6d789d4b2512b059c48b1e354c2e47d64c5..d25e44c6e67872dec9a6d9321e636c1c9b59eab0 100644 (file)
@@ -301,12 +301,12 @@ def SConscript_exception(file=sys.stderr):
 def annotate(node):
     """Annotate a node with the stack frame describing the
     SConscript file and line number that created it."""
-    tb = exc_tb = sys.exc_info()[2]
+    tb = sys.exc_info()[2]
     while tb and not tb.tb_frame.f_locals.has_key(stack_bottom):
         tb = tb.tb_next
     if not tb:
         # We did not find any exec of an SConscript file: what?!
-        raise InternalError, "could not find SConscript stack frame"
+        raise SCons.Errors.InternalError, "could not find SConscript stack frame"
     node.creator = traceback.extract_stack(tb)[0]
 
 # The following line would cause each Node to be annotated using the
index 067f540ebd2076b49c1a554183c6b1e4f5b985d3..35bbbf7d49025cfb04f20bd605f835b28ad538d1 100644 (file)
@@ -109,12 +109,12 @@ OptParser               = Main.OptParser
 SConscriptSettableOptions = Main.SConscriptSettableOptions
 
 keep_going_on_error     = Main.keep_going_on_error
-print_dtree             = Main.print_dtree
+#print_dtree             = Main.print_dtree
 print_explanations      = Main.print_explanations
 print_includes          = Main.print_includes
 print_objects           = Main.print_objects
 print_time              = Main.print_time
-print_tree              = Main.print_tree
+#print_tree              = Main.print_tree
 memory_stats            = Main.memory_stats
 ignore_errors           = Main.ignore_errors
 #sconscript_time         = Main.sconscript_time
@@ -289,6 +289,7 @@ GlobalDefaultEnvironmentFunctions = [
     'Depends',
     'Dir',
     'NoClean',
+    'NoCache',
     'Entry',
     'Execute',
     'File',
@@ -341,6 +342,7 @@ GlobalDefaultBuilders = [
 
 for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
     exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
+del name
 
 # There are a handful of variables that used to live in the
 # Script/SConscript.py module that some SConscript files out there were
@@ -352,6 +354,10 @@ for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
 # this way by hanging some attributes off the "SConscript" object here.
 SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
 
+# Make SConscript look enough like the module it used to be so
+# that pychecker doesn't barf.
+SConscript.__name__ = 'SConscript'
+
 SConscript.Arguments = ARGUMENTS
 SConscript.ArgList = ARGLIST
 SConscript.BuildTargets = BUILD_TARGETS
index 2a993beee83c3fec4803ec7990519d370ef65d9b..989f1dd5f15555803842c9ffe9d0a96058396d45 100644 (file)
@@ -442,7 +442,9 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
                     # This probably indicates that it's a callable
                     # object that doesn't match our calling arguments
                     # (like an Action).
-                    s = str(s)
+                    if self.mode == SUBST_RAW:
+                        return s
+                    s = self.conv(s)
                 return self.substitute(s, lvars)
             elif s is None:
                 return ''
@@ -646,7 +648,10 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv
                     # This probably indicates that it's a callable
                     # object that doesn't match our calling arguments
                     # (like an Action).
-                    s = str(s)
+                    if self.mode == SUBST_RAW:
+                        self.append(s)
+                        return
+                    s = self.conv(s)
                 self.substitute(s, lvars, within_list)
             elif s is None:
                 self.this_word()
index e8419f1dbe0fbaa1676e67fdf6d726b14716f80b..7ba24779d596b68393864b01f89206c83e071a6c 100644 (file)
@@ -145,6 +145,8 @@ class SubstTestCase(unittest.TestCase):
                    MyNode("/bar/ack.cpp"),
                    MyNode("../foo/ack.c") ]
 
+        callable_object = TestCallable('callable-1')
+
         loc = {
             'xxx'       : None,
             'null'      : '',
@@ -203,7 +205,7 @@ class SubstTestCase(unittest.TestCase):
             'SSS'       : '$RRR',
 
             # Test callables that don't match the calling arguments.
-            'CALLABLE'  : TestCallable('callable-1'),
+            'CALLABLE'  : callable_object,
         }
 
         env = DummyEnv(loc)
@@ -514,6 +516,16 @@ class SubstTestCase(unittest.TestCase):
         else:
             raise AssertionError, "did not catch expected UserError"
 
+        # Test that the combination of SUBST_RAW plus a pass-through
+        # conversion routine allows us to fetch a function through the
+        # dictionary.  CommandAction uses this to allow delayed evaluation
+        # of $SPAWN variables.
+        x = lambda x: x
+        r = scons_subst("$CALLABLE", env, mode=SUBST_RAW, conv=x, gvars=gvars)
+        assert r is callable_object, repr(r)
+        r = scons_subst("$CALLABLE", env, mode=SUBST_RAW, gvars=gvars)
+        assert r == 'callable-1', repr(r)
+
         # Test how we handle overriding the internal conversion routines.
         def s(obj):
             return obj
@@ -594,6 +606,8 @@ class SubstTestCase(unittest.TestCase):
                    MyNode("/bar/ack.cpp"),
                    MyNode("../foo/ack.c") ]
 
+        callable_object = TestCallable('callable-2')
+
         def _defines(defs):
             l = []
             for d in defs:
@@ -653,7 +667,7 @@ class SubstTestCase(unittest.TestCase):
             'SSS'       : '$RRR',
 
             # Test callable objects that don't match our calling arguments.
-            'CALLABLE'  : TestCallable('callable-2'),
+            'CALLABLE'  : callable_object,
 
             '_defines'  : _defines,
             'DEFS'      : [ ('Q1', '"q1"'), ('Q2', '"$AAA"') ],
@@ -792,8 +806,6 @@ class SubstTestCase(unittest.TestCase):
             # Test callables that don't match our calling arguments.
             '$CALLABLE',            [['callable-2']],
 
-            # Test
-
             # Test handling of quotes.
             # XXX Find a way to handle this in the future.
             #'aaa "bbb ccc" ddd',    [['aaa', 'bbb ccc', 'ddd']],
@@ -991,6 +1003,15 @@ class SubstTestCase(unittest.TestCase):
         else:
             raise AssertionError, "did not catch expected SyntaxError"
 
+        # Test that the combination of SUBST_RAW plus a pass-through
+        # conversion routine allows us to fetch a function through the
+        # dictionary.
+        x = lambda x: x
+        r = scons_subst_list("$CALLABLE", env, mode=SUBST_RAW, conv=x, gvars=gvars)
+        assert r == [[callable_object]], repr(r)
+        r = scons_subst_list("$CALLABLE", env, mode=SUBST_RAW, gvars=gvars)
+        assert r == [['callable-2']], repr(r)
+
         # Test we handle overriding the internal conversion routines.
         def s(obj):
             return obj
index 04ed19a882659eccca01ff8ba21ea8d7fa021d6b..7439168a02fca5e4c53433eec2d8ab5a4b167cd8 100644 (file)
@@ -41,7 +41,8 @@ interface and the SCons build engine.  There are two key classes here:
         which has Task subclasses that handle its specific behavior,
         like printing "`foo' is up to date" when a top-level target
         doesn't need to be built, and handling the -c option by removing
-        targets as its "build" action.
+        targets as its "build" action.  There is also a separate subclass
+        for suppressing this output when the -q option is used.
 
         The Taskmaster instantiates a Task object for each (set of)
         target(s) that it decides need to be evaluated and/or built.
@@ -58,6 +59,8 @@ import SCons.Errors
 
 StateString = SCons.Node.StateString
 
+
+
 # A subsystem for recording stats about how different Nodes are handled by
 # the main Taskmaster loop.  There's no external control here (no need for
 # a --debug= option); enable it by changing the value of CollectStats.
@@ -68,7 +71,7 @@ class Stats:
     """
     A simple class for holding statistics about the disposition of a
     Node by the Taskmaster.  If we're collecting statistics, each Node
-    processed by the Taskmaster gets one of these attached, in which
+    processed by the Taskmaster gets one of these attached, in which case
     the Taskmaster records its decision each time it processes the Node.
     (Ideally, that's just once per Node.)
     """
@@ -100,8 +103,11 @@ def dump_stats():
     for n in StatsNodes:
         print (fmt % n.stats.__dict__) + str(n)
 
+
+
 class Task:
-    """Default SCons build engine task.
+    """
+    Default SCons build engine task.
 
     This controls the interaction of the actual building of node
     and the rest of the engine.
@@ -116,7 +122,8 @@ class Task:
 
     Note that it's generally a good idea for sub-classes to call
     these methods explicitly to update state, etc., rather than
-    roll their own interaction with Taskmaster from scratch."""
+    roll their own interaction with Taskmaster from scratch.
+    """
     def __init__(self, tm, targets, top, node):
         self.tm = tm
         self.targets = targets
@@ -125,15 +132,26 @@ class Task:
         self.exc_clear()
 
     def display(self, message):
-        """Allow the calling interface to display a message
+        """
+        Hook to allow the calling interface to display a message.
+
+        This hook gets called as part of preparing a task for execution
+        (that is, a Node to be built).  As part of figuring out what Node
+        should be built next, the actually target list may be altered,
+        along with a message describing the alteration.  The calling
+        interface can subclass Task and provide a concrete implementation
+        of this method to see those messages.
         """
         pass
 
     def prepare(self):
-        """Called just before the task is executed.
+        """
+        Called just before the task is executed.
 
-        This unlinks all targets and makes all directories before
-        building anything."""
+        This is mainly intended to give the target Nodes a chance to
+        unlink underlying files and make all necessary directories before
+        the Action is actually called to build the targets.
+        """
 
         # Now that it's the appropriate time, give the TaskMaster a
         # chance to raise any exceptions it encountered while preparing
@@ -155,11 +173,13 @@ class Task:
         return self.node
 
     def execute(self):
-        """Called to execute the task.
+        """
+        Called to execute the task.
 
         This method is called from multiple threads in a parallel build,
         so only do thread safe stuff here.  Do thread unsafe stuff in
-        prepare(), executed() or failed()."""
+        prepare(), executed() or failed().
+        """
 
         try:
             everything_was_cached = 1
@@ -183,13 +203,13 @@ class Task:
                                                    sys.exc_info())
 
     def executed(self):
-        """Called when the task has been successfully executed.
+        """
+        Called when the task has been successfully executed.
 
-        This may have been a do-nothing operation (to preserve
-        build order), so check the node's state before updating
-        things.  Most importantly, this calls back to the
-        Taskmaster to put any node tasks waiting on this one
-        back on the pending list."""
+        This may have been a do-nothing operation (to preserve build
+        order), so we have to check the node's state before deciding
+        whether it was "built" or just "visited."
+        """
         for t in self.targets:
             if t.get_state() == SCons.Node.executing:
                 t.set_state(SCons.Node.executed)
@@ -197,17 +217,18 @@ class Task:
             else:
                 t.visited()
 
-        self.tm.executed(self.node)
-
     def failed(self):
-        """Default action when a task fails:  stop the build."""
+        """
+        Default action when a task fails:  stop the build.
+        """
         self.fail_stop()
 
     def fail_stop(self):
-        """Explicit stop-the-build failure."""
+        """
+        Explicit stop-the-build failure.
+        """
         for t in self.targets:
             t.set_state(SCons.Node.failed)
-        self.tm.failed(self.node)
         self.tm.stop()
 
         # We're stopping because of a build failure, but give the
@@ -217,7 +238,8 @@ class Task:
         self.top = 1
 
     def fail_continue(self):
-        """Explicit continue-the-build failure.
+        """
+        Explicit continue-the-build failure.
 
         This sets failure status on the target nodes and all of
         their dependent parent nodes.
@@ -228,10 +250,9 @@ class Task:
             def set_state(node): node.set_state(SCons.Node.failed)
             t.call_for_all_waiting_parents(set_state)
 
-        self.tm.executed(self.node)
-
     def make_ready_all(self):
-        """Mark all targets in a task ready for execution.
+        """
+        Marks all targets in a task ready for execution.
 
         This is used when the interface needs every target Node to be
         visited--the canonical example being the "scons -c" option.
@@ -243,7 +264,8 @@ class Task:
                 s.set_state(SCons.Node.executing)
 
     def make_ready_current(self):
-        """Mark all targets in a task ready for execution if any target
+        """
+        Marks all targets in a task ready for execution if any target
         is not current.
 
         This is the default behavior for building only what's necessary.
@@ -261,11 +283,28 @@ class Task:
     make_ready = make_ready_current
 
     def postprocess(self):
-        """Post process a task after it's been executed."""
+        """
+        Post-processes a task after it's been executed.
+
+        This examines all the targets just built (or not, we don't care
+        if the build was successful, or even if there was no build
+        because everything was up-to-date) to see if they have any
+        waiting parent Nodes, or Nodes waiting on a common side effect,
+        that can be put back on the candidates list.
+        """
+
+        # We may have built multiple targets, some of which may have
+        # common parents waiting for this build.  Count up how many
+        # targets each parent was waiting for so we can subtract the
+        # values later, and so we *don't* put waiting side-effect Nodes
+        # back on the candidates list if the Node is also a waiting
+        # parent.
+
         parents = {}
         for t in self.targets:
             for p in t.waiting_parents.keys():
                 parents[p] = parents.get(p, 0) + 1
+
         for t in self.targets:
             for s in t.side_effects:
                 if s.get_state() == SCons.Node.executing:
@@ -276,21 +315,47 @@ class Task:
                 for p in s.waiting_s_e.keys():
                     if p.ref_count == 0:
                         self.tm.candidates.append(p)
+
         for p, subtract in parents.items():
             p.ref_count = p.ref_count - subtract
             if p.ref_count == 0:
                 self.tm.candidates.append(p)
+
         for t in self.targets:
             t.postprocess()
 
+    # Exception handling subsystem.
+    #
+    # Exceptions that occur while walking the DAG or examining Nodes
+    # must be raised, but must be raised at an appropriate time and in
+    # a controlled manner so we can, if necessary, recover gracefully,
+    # possibly write out signature information for Nodes we've updated,
+    # etc.  This is done by having the Taskmaster tell us about the
+    # exception, and letting
+
     def exc_info(self):
+        """
+        Returns info about a recorded exception.
+        """
         return self.exception
 
     def exc_clear(self):
+        """
+        Clears any recorded exception.
+
+        This also changes the "exception_raise" attribute to point
+        to the appropriate do-nothing method.
+        """
         self.exception = (None, None, None)
         self.exception_raise = self._no_exception_to_raise
 
     def exception_set(self, exception=None):
+        """
+        Records an exception to be raised at the appropriate time.
+
+        This also changes the "exception_raise" attribute to point
+        to the method that will, in fact
+        """
         if not exception:
             exception = sys.exc_info()
         self.exception = exception
@@ -300,14 +365,17 @@ class Task:
         pass
 
     def _exception_raise(self):
-        """Raise a pending exception that was recorded while
-        getting a Task ready for execution."""
-        self.tm.exception_raise(self.exc_info())
-
-
-def order(dependencies):
-    """Re-order a list of dependencies (if we need to)."""
-    return dependencies
+        """
+        Raises a pending exception that was recorded while getting a
+        Task ready for execution.
+        """
+        exc = self.exc_info()[:]
+        try:
+            exc_type, exc_value, exc_traceback = exc
+        except ValueError:
+            exc_type, exc_value = exc
+            exc_traceback = None
+        raise exc_type, exc_value, exc_traceback
 
 
 def find_cycle(stack):
@@ -322,24 +390,41 @@ def find_cycle(stack):
 
 
 class Taskmaster:
-    """A generic Taskmaster for handling a bunch of targets.
-
-    Classes that override methods of this class should call
-    the base class method, so this class can do its thing.
+    """
+    The Taskmaster for walking the dependency DAG.
     """
 
-    def __init__(self, targets=[], tasker=Task, order=order, trace=None):
+    def __init__(self, targets=[], tasker=Task, order=None, trace=None):
         self.top_targets = targets[:]
         self.top_targets.reverse()
         self.candidates = []
         self.tasker = tasker
-        self.ready = None # the next task that is ready to be executed
+        if not order:
+            order = lambda l: l
         self.order = order
         self.message = None
         self.trace = trace
         self.next_candidate = self.find_next_candidate
 
     def find_next_candidate(self):
+        """
+        Returns the next candidate Node for (potential) evaluation.
+
+        The candidate list (really a stack) initially consists of all of
+        the top-level (command line) targets provided when the Taskmaster
+        was initialized.  While we walk the DAG, visiting Nodes, all the
+        children that haven't finished processing get pushed on to the
+        candidate list.  Each child can then be popped and examined in
+        turn for whether *their* children are all up-to-date, in which
+        case a Task will be created for their actual evaluation and
+        potential building.
+
+        Here is where we also allow candidate Nodes to alter the list of
+        Nodes that should be examined.  This is used, for example, when
+        invoking SCons in a source directory.  A source directory Node can
+        return its corresponding build directory Node, essentially saying,
+        "Hey, you really need to build this thing over here instead."
+        """
         try:
             return self.candidates.pop()
         except IndexError:
@@ -358,13 +443,32 @@ class Taskmaster:
         return node
 
     def no_next_candidate(self):
+        """
+        Stops Taskmaster processing by not returning a next candidate.
+        """
         return None
 
     def _find_next_ready_node(self):
-        """Find the next node that is ready to be built"""
-
-        if self.ready:
-            return
+        """
+        Finds the next node that is ready to be built.
+
+        This is *the* main guts of the DAG walk.  We loop through the
+        list of candidates, looking for something that has no un-built
+        children (i.e., that is a leaf Node or has dependencies that are
+        all leaf Nodes or up-to-date).  Candidate Nodes are re-scanned
+        (both the target Node itself and its sources, which are always
+        scanned in the context of a given target) to discover implicit
+        dependencies.  A Node that must wait for some children to be
+        built will be put back on the candidates list after the children
+        have finished building.  A Node that has been put back on the
+        candidates list in this way may have itself (or its sources)
+        re-scanned, in order to handle generated header files (e.g.) and
+        the implicit dependencies therein.
+
+        Note that this method does not do any signature calculation or
+        up-to-date check itself.  All of that is handled by the Task
+        class.  This is purely concerned with the dependency graph walk.
+        """
 
         self.ready_exc = None
 
@@ -373,8 +477,7 @@ class Taskmaster:
         while 1:
             node = self.next_candidate()
             if node is None:
-                self.ready = None
-                break
+                return None
 
             node = node.disambiguate()
             state = node.get_state()
@@ -405,9 +508,8 @@ class Taskmaster:
                 exc_value = sys.exc_info()[1]
                 e = SCons.Errors.ExplicitExit(node, exc_value.code)
                 self.ready_exc = (SCons.Errors.ExplicitExit, e)
-                self.ready = node
                 if T: T.write(' SystemExit\n')
-                break
+                return node
             except KeyboardInterrupt:
                 if T: T.write(' KeyboardInterrupt\n')
                 raise
@@ -417,10 +519,9 @@ class Taskmaster:
                 # BuildDir, or a Scanner threw something).  Arrange to
                 # raise the exception when the Task is "executed."
                 self.ready_exc = sys.exc_info()
-                self.ready = node
                 if S: S.problem = S.problem + 1
                 if T: T.write(' exception\n')
-                break
+                return node
 
             if T and children:
                 c = map(str, children)
@@ -516,7 +617,7 @@ class Taskmaster:
                 continue
 
             # Skip this node if it has side-effects that are currently being
-            # built  themselves or waiting for something else being built.
+            # built themselves or waiting for something else being built.
             side_effects = filter(lambda N:
                                   N.get_state() == SCons.Node.executing,
                                   node.side_effects)
@@ -531,17 +632,20 @@ class Taskmaster:
 
             # The default when we've gotten through all of the checks above:
             # this node is ready to be built.
-            self.ready = node
             if S: S.build = S.build + 1
             if T: T.write(' evaluating %s\n' % node)
-            break
+            return node
 
-    def next_task(self):
-        """Return the next task to be executed."""
+        return None
 
-        self._find_next_ready_node()
+    def next_task(self):
+        """
+        Returns the next task to be executed.
 
-        node = self.ready
+        This simply asks for the next Node to be evaluated, and then wraps
+        it in the specific Task subclass with which we were initialized.
+        """
+        node = self._find_next_ready_node()
 
         if node is None:
             return None
@@ -563,27 +667,12 @@ class Taskmaster:
         if self.ready_exc:
             task.exception_set(self.ready_exc)
 
-        self.ready = None
         self.ready_exc = None
 
         return task
 
     def stop(self):
-        """Stop the current build completely."""
+        """
+        Stops the current build completely.
+        """
         self.next_candidate = self.no_next_candidate
-        self.ready = None
-
-    def failed(self, node):
-        pass
-
-    def executed(self, node):
-        pass
-
-    def exception_raise(self, exception):
-        exc = exception[:]
-        try:
-            exc_type, exc_value, exc_traceback = exc
-        except ValueError:
-            exc_type, exc_value = exc
-            exc_traceback = None
-        raise exc_type, exc_value, exc_traceback
index 1803eee25495a7111ac7d80886e5599d67042ea0..f74cf347392194b68fdbaacd817ad7eef832c44e 100644 (file)
@@ -681,16 +681,6 @@ class TaskmasterTestCase(unittest.TestCase):
         assert built_text == "MyTM.stop()"
         assert tm.next_task() is None
 
-    def test_failed(self):
-        """Test when a task has failed
-        """
-        n1 = Node("n1")
-        tm = SCons.Taskmaster.Taskmaster([n1])
-        t = tm.next_task()
-        assert t.targets == [n1], map(str, t.targets)
-        tm.failed(n1)
-        assert t.targets == [n1], map(str, t.targets)
-
     def test_executed(self):
         """Test when a task has been executed
         """
@@ -974,20 +964,6 @@ class TaskmasterTestCase(unittest.TestCase):
         else:
             assert 0, "did not catch expected exception"
 
-        t.exception_set(("exception 4", "XYZZY"))
-        def fw_exc(exc):
-            raise 'exception_forwarded', exc
-        tm.exception_raise = fw_exc
-        try:
-            t.exception_raise()
-        except:
-            exc_type, exc_value = sys.exc_info()[:2]
-            assert exc_type == 'exception_forwarded', exc_type
-            assert exc_value[0] == "exception 4", exc_value[0]
-            assert exc_value[1] == "XYZZY", exc_value[1]
-        else:
-            assert 0, "did not catch expected exception"
-
     def test_postprocess(self):
         """Test postprocessing targets to give them a chance to clean up
         """
index 2c2bfdda538f6a62987c28a0aa2db8b3cb81b449..b6561f4fd46b0584acccc48aece67291ab38ae81 100644 (file)
@@ -34,8 +34,6 @@ selection method.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import os.path
-
 import SCons.Action
 import SCons.Builder
 import SCons.Util
index 77363f040719105da6cbfd73154a894967d5f1cc..09ce1d17c3347f1a4c77955aa8c42d1a5e5b6b5e 100644 (file)
@@ -148,8 +148,10 @@ if java_parsing:
             self.outer_state = outer_state
             self.tokens_to_find = 2
         def parseToken(self, token):
-            # This is an anonymous class if and only if the next token
-            # is a bracket
+            # This is an anonymous class if and only if the next  
+            # non-whitespace token is a bracket            
+            if token == '\n':
+                return self
             if token == '{':
                 self.outer_state.addAnonClass()
             elif token in ['"', "'"]:
index 6d9fc43b18a20099d2ddc7df439784d5e3ee04ec..4a7f9cfc99b6bb986e84b6fdd2b2b11f30a88af0 100644 (file)
@@ -265,6 +265,27 @@ public enum a {}
         assert classes == ['a'], classes
 
 
+    def test_anon_classes(self):
+        """Test anonymous classes"""
+        pkg_dir, classes = SCons.Tool.JavaCommon.parse_java("""\
+public abstract class TestClass
+{
+    public void completed()
+    {
+        new Thread()
+        {
+        }.start();
+
+        new Thread()
+        {
+        }.start();
+    }
+}
+""")
+        assert pkg_dir == None, pkg_dir
+        assert classes == ['TestClass$1', 'TestClass$2', 'TestClass'], classes
+
+
 
 if __name__ == "__main__":
     suite = unittest.TestSuite()
index 5ddac19396be1686d6588f343d26ec6dd01b23d7..52c032fea53324c61b1b8c916ffbc859758f15c5 100644 (file)
@@ -45,6 +45,8 @@ class ToolTestCase(unittest.TestCase):
                 return self.dict[key]
             def __setitem__(self, key, val):
                 self.dict[key] = val
+            def has_key(self, key):
+                return self.dict.has_key(key)
         env = Environment()
         env['BUILDERS'] = {}
         env['ENV'] = {}
index d36478d410b6e05e02eb52445ddc05aa50193ea6..b2e2eff95b1306887c2e8ab35c3abe0357511346 100644 (file)
@@ -41,6 +41,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import imp
 import sys
 
+import SCons.Builder
 import SCons.Errors
 import SCons.Scanner
 import SCons.Scanner.C
@@ -48,11 +49,13 @@ import SCons.Scanner.D
 import SCons.Scanner.LaTeX
 import SCons.Scanner.Prog
 
+DefaultToolpath=[]
+
 CScanner = SCons.Scanner.C.CScanner()
 DScanner = SCons.Scanner.D.DScanner()
 LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner()
 ProgramScanner = SCons.Scanner.Prog.ProgramScanner()
-SourceFileScanner = SCons.Scanner.Scanner({}, name='SourceFileScanner')
+SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner')
 
 CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
              ".h", ".H", ".hxx", ".hpp", ".hh",
@@ -78,7 +81,7 @@ for suffix in LaTeXSuffixes:
 class Tool:
     def __init__(self, name, toolpath=[], **kw):
         self.name = name
-        self.toolpath = toolpath
+        self.toolpath = toolpath + DefaultToolpath
         # remember these so we can merge them into the call
         self.init_kw = kw
 
index a44fa6de9f1878ff2706b3212a7f4c981780ef49..d9370b051b130161a11c98a6e9e94c1a0ed5451c 100644 (file)
@@ -60,6 +60,8 @@ def generate(env):
     Add Builders and construction variables for Visual Age C++ compilers
     to an Environment.
     """
+    import SCons.Tool
+    import SCons.Tool.cc
     static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
 
     for suffix in CXXSuffixes:
@@ -67,6 +69,8 @@ def generate(env):
         shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
         static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
         shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
+
+    SCons.Tool.cc.add_common_cc_variables(env)
         
     env['CXX']        = 'c++'
     env['CXXFLAGS']   = SCons.Util.CLVar('$CCFLAGS')
index 62b945f67f3e9edc4bb3e18dad76c288b1bdaaef..d1a287abf51998f05c8337a1aaeee26055ceb789 100644 (file)
@@ -40,6 +40,28 @@ CSuffixes = ['.c', '.m']
 if not SCons.Util.case_sensitive_suffixes('.c', '.C'):
     CSuffixes.append('.C')
 
+def add_common_cc_variables(env):
+    """
+    Add underlying common "C compiler" variables that
+    are used by multiple tools (specifically, c++).
+    """
+    if not env.has_key('_CCCOMCOM'):
+        env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
+        # It's a hack to test for darwin here, but the alternative
+        # of creating an applecc.py to contain this seems overkill.
+        # Maybe someday the Apple platform will require more setup and
+        # this logic will be moved.
+        env['FRAMEWORKS'] = SCons.Util.CLVar('')
+        env['FRAMEWORKPATH'] = SCons.Util.CLVar('')
+        if env['PLATFORM'] == 'darwin':
+            env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH'
+
+    if not env.has_key('CCFLAGS'):
+        env['CCFLAGS']   = SCons.Util.CLVar('')
+
+    if not env.has_key('SHCCFLAGS'):
+        env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
+
 def generate(env):
     """
     Add Builders and construction variables for C compilers to an Environment.
@@ -51,22 +73,13 @@ def generate(env):
         shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
         static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
         shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
-        
-    env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
-    # It's a hack to test for darwin here, but the alternative of creating
-    # an applecc.py to contain this seems overkill.  Maybe someday the Apple
-    # platform will require more setup and this logic will be moved.
-    env['FRAMEWORKS'] = SCons.Util.CLVar('')
-    env['FRAMEWORKPATH'] = SCons.Util.CLVar('')
-    if env['PLATFORM'] == 'darwin':
-        env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH'
+
+    add_common_cc_variables(env)
 
     env['CC']        = 'cc'
-    env['CCFLAGS']   = SCons.Util.CLVar('')
     env['CFLAGS']    = SCons.Util.CLVar('')
     env['CCCOM']     = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
     env['SHCC']      = '$CC'
-    env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
     env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
     env['SHCCCOM']   = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
 
index 28a1915b9eebb1d8ccac96d5b0199933d0f8fc24..4bca52bb7473741c8486b56aab196bb77d45739e 100644 (file)
@@ -29,7 +29,6 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import SCons.Util
 import fortran
 
 compilers = ['f90']
index cae264b7ba3bb79086f895a32853f9df92f4666e..64ffb68053037f66b7bb3abcbb00d8bea0768660 100644 (file)
@@ -201,6 +201,8 @@ def generate(env):
                         env.Append(LIBS = ['phobos'])
                     if 'pthread' not in libs:
                         env.Append(LIBS = ['pthread'])
+                    if 'm' not in libs:
+                        env.Append(LIBS = ['m'])
                 return defaultLinker
             env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink
 
index fce98509175fe6f1981fbd12dbab9d7d909afb4e..78fb4c2dba1aa681a188d0ee6a37e4e4f375ad1f 100644 (file)
@@ -36,7 +36,7 @@ DVIBuilder = None
 
 def generate(env):
     try:
-        bld = env['BUILDERS']['DVI']
+        env['BUILDERS']['DVI']
     except KeyError:
         global DVIBuilder
 
index 75c3c2dd129a10dc52b533dc6500d453689b36a1..bd1e870eb70e9e03351994307e7c2811fc289fb4 100644 (file)
@@ -54,6 +54,7 @@ F77Scan = SCons.Scanner.Fortran.FortranScan("F77PATH")
 
 for suffix in F77Suffixes + F77PPSuffixes:
     SCons.Tool.SourceFileScanner.add_scanner(suffix, F77Scan)
+del suffix
 
 #
 fVLG = fortran.VariableListGenerator
index cb450b6dd92b4a762143c7fa320429e1efe3ab52..fab4ccb9df58046ce0356886f190aad6c9b55216 100644 (file)
@@ -54,6 +54,7 @@ F90Scan = SCons.Scanner.Fortran.FortranScan("F90PATH")
 
 for suffix in F90Suffixes + F90PPSuffixes:
     SCons.Tool.SourceFileScanner.add_scanner(suffix, F90Scan)
+del suffix
 
 #
 fVLG = fortran.VariableListGenerator
index 7adc80b36f9c7be7e70e3154c0eca81e00524641..94786c847f8ca821f36c952d7202d21a884879c6 100644 (file)
@@ -53,6 +53,7 @@ F95Scan = SCons.Scanner.Fortran.FortranScan("F95PATH")
 
 for suffix in F95Suffixes + F95PPSuffixes:
     SCons.Tool.SourceFileScanner.add_scanner(suffix, F95Scan)
+del suffix
 
 #
 fVLG = fortran.VariableListGenerator
index b83e7d3b34f94bf2dd9e842128f30f898755d0e3..8494fd6994f80a8265c7e6bfe046aed48917b3f1 100644 (file)
@@ -63,6 +63,7 @@ FortranScan = SCons.Scanner.Fortran.FortranScan("FORTRANPATH")
 
 for suffix in FortranSuffixes + FortranPPSuffixes:
     SCons.Tool.SourceFileScanner.add_scanner(suffix, FortranScan)
+del suffix
 
 #
 def _fortranEmitter(target, source, env):
index e668bf0cf62c5e92385d18b263733ee52954e484..d95a4bece588d3edb0935601624537ac4cb457d1 100644 (file)
@@ -151,7 +151,7 @@ def get_intel_registry_value(valuename, version=None, abi=None):
         return v  # or v.encode('iso-8859-1', 'replace') to remove unicode?
     except SCons.Util.RegError:
         raise MissingRegistryError, \
-              "%s\\%s was not found in the registry."%(K, value)
+              "%s\\%s was not found in the registry."%(K, valuename)
 
 
 def get_all_compiler_versions():
index ed934127ce098608bf064b92408df493fd3594c0..cb0a8eb631d0f0e77ddad9f0e00c3a99933bf5ad 100644 (file)
@@ -35,11 +35,14 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import SCons.Action
 import SCons.Builder
+import SCons.Subst
 import SCons.Util
 
 def jarSources(target, source, env, for_signature):
     """Only include sources that are not a manifest file."""
     jarchdir = env.subst('$JARCHDIR')
+    if jarchdir:
+        jarchdir = env.fs.Dir(jarchdir)
     result = []
     for src in source:
         contents = src.get_contents()
@@ -47,7 +50,7 @@ def jarSources(target, source, env, for_signature):
             if jarchdir:
                 # If we are changing the dir with -C, then sources should
                 # be relative to that directory.
-                src = src.get_path(src.fs.Dir(jarchdir))
+                src = SCons.Subst.Literal(src.get_path(jarchdir))
                 result.append('-C')
                 result.append(jarchdir)
             result.append(src)
index 0639535cf229f66d30ed8372ded0c62f9c2ba227..cc7f5845b71f16a8505a9e036bd4cd06b2e6114d 100644 (file)
@@ -39,6 +39,7 @@ import string
 
 import SCons.Action
 import SCons.Builder
+import SCons.Defaults
 import SCons.Tool
 import SCons.Util
 
index e35c92abff0e26fee2a6dd0a049409b1645aefc0..b84b277592a9f8913a376c542ae24fcf6e974325 100644 (file)
@@ -205,7 +205,7 @@ class _DSPGenerator:
         if len(buildtarget) == 1:
             bt = buildtarget[0]
             buildtarget = []
-            for v in variants:
+            for _ in variants:
                 buildtarget.append(bt)
 
         if not env.has_key('outdir') or env['outdir'] == None:
@@ -1010,7 +1010,6 @@ class _GenerateV7DSW(_DSWGenerator):
             self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
 
         for name in confkeys:
-            name = name
             variant = self.configs[name].variant
             platform = self.configs[name].platform
             if self.version_num >= 8.0:
@@ -1279,7 +1278,7 @@ def get_visualstudio8_suites():
     try:
         idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
             r'Software\Microsoft\VisualStudio\8.0')
-        id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
+        SCons.Util.RegQueryValueEx(idk, 'InstallDir')
         editions = { 'PRO': r'Setup\VS\Pro' }       # ToDo: add standard and team editions
         edition_name = 'STD'
         for name, key_suffix in editions.items():
@@ -1297,7 +1296,7 @@ def get_visualstudio8_suites():
     try:
         idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
             r'Software\Microsoft\VCExpress\8.0')
-        id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
+        SCons.Util.RegQueryValueEx(idk, 'InstallDir')
         suites.append('EXPRESS')
     except SCons.Util.RegError:
         pass
index a1ede44a7a6f5d34c8f9ef3f4df483065cccd0d1..0d5ce82e6e0fa18b5a301f076fe6dfd44bebbcb6 100644 (file)
@@ -32,11 +32,11 @@ selection method.
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
-import SCons.Util
 import os
 import os.path
 import string
 
+import SCons.Util
 
 def set_vars(env):
     """Set MWCW_VERSION, MWCW_VERSIONS, and some codewarrior environment vars
@@ -155,6 +155,8 @@ CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
 
 def generate(env):
     """Add Builders and construction variables for the mwcc to an Environment."""
+    import SCons.Defaults
+    import SCons.Tool
 
     set_vars(env)
 
index e2b1827ca82ec58cd7846f0256a56c27cf86608b..e73c730a71c06d52aab8ced3780a46ed2b41743f 100644 (file)
@@ -33,7 +33,6 @@ selection method.
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import SCons.Tool
-import SCons.Tool.mwcc
 
 
 def generate(env):
@@ -60,7 +59,8 @@ def generate(env):
 
 
 def exists(env):
-    return mwcc.set_versions(env)
+    import SCons.Tool.mwcc
+    return SCons.Tool.mwcc.set_vars(env)
 
 
 def shlib_generator(target, source, env, for_signature):
index 0f6468b0d37f3e8238a69123a403143d59697ba3..b0cd126f7d4c5e664c74dfa1d4a2317f2e6e21be 100644 (file)
@@ -36,7 +36,7 @@ PDFBuilder = None
 
 def generate(env):
     try:
-        bld = env['BUILDERS']['PDF']
+        env['BUILDERS']['PDF']
     except KeyError:
         global PDFBuilder
         if PDFBuilder is None:
index 4d290c777310c502f85b4125b82cc57243841a6e..105f42e5dcc0b44b00d860294f77b32cceb098da 100644 (file)
@@ -75,7 +75,6 @@ def checkMocIncluded(target, source, env):
             (str(moc), str(cpp)))
 
 def find_file(filename, paths, node_factory):
-    retval = None
     for dir in paths:
         node = node_factory(filename, dir)
         if node.rexists():
@@ -219,7 +218,6 @@ def uicEmitter(target, source, env):
     return target, source
 
 def uicScannerFunc(node, env, path):
-    dir = node.dir
     lookout = []
     lookout.extend(env['CPPPATH'])
     lookout.append(str(node.rfile().dir))
@@ -231,18 +229,17 @@ def uicScannerFunc(node, env, path):
             result.append(dep)
     return result
 
-uicScanner = SCons.Scanner.Scanner(uicScannerFunc,
-                                   name = "UicScanner", 
-                                   node_class = SCons.Node.FS.File,
-                                   node_factory = SCons.Node.FS.File,
-                                   recursive = 0)
+uicScanner = SCons.Scanner.Base(uicScannerFunc,
+                                name = "UicScanner", 
+                                node_class = SCons.Node.FS.File,
+                                node_factory = SCons.Node.FS.File,
+                                recursive = 0)
 
 def generate(env):
     """Add Builders and construction variables for qt to an Environment."""
     CLVar = SCons.Util.CLVar
     Action = SCons.Action.Action
     Builder = SCons.Builder.Builder
-    splitext = SCons.Util.splitext
 
     env.SetDefault(QTDIR  = _detect(env),
                    QT_BINPATH = os.path.join('$QTDIR', 'bin'),
index a8e12a29fcb2c835b758f157633ecc1ed53b698f..04c3b2abb68d703f9ede51b15afd63004a17b183 100644 (file)
@@ -77,7 +77,6 @@ def recurse(path, searchPath):
     return found
 
 def _scanSwig(node, env, path):
-    import sys
     r = recurse(str(node), [os.path.abspath(os.path.dirname(str(node))), os.path.abspath(os.path.join("include", "swig"))])
     return r
 
@@ -85,7 +84,8 @@ def _swigEmitter(target, source, env):
     for src in source:
         src = str(src)
         mname = None
-        if "-python" in SCons.Util.CLVar(env.subst("$SWIGFLAGS")):
+        flags = SCons.Util.CLVar(env.subst("$SWIGFLAGS"))
+        if "-python" in flags and "-noproxy" not in flags:
             f = open(src)
             try:
                 for l in f.readlines():
index 0329667f257acabdee8ede01653b2f1c5fca315a..1defd905e859238e7789134190742e4e9408a146 100644 (file)
@@ -112,7 +112,7 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
 
     # Now decide if latex needs to be run yet again.
     logfilename = basename + '.log'
-    for trial in range(int(env.subst('$LATEXRETRIES'))):
+    for _ in range(int(env.subst('$LATEXRETRIES'))):
         if not os.path.exists(logfilename):
             break
         content = open(logfilename, "rb").read()
index f0d4ed0bd70703ff76ec5613a49af460c8a29bf7..22f63fbb28dc386af1f077048287755bf350bf6f 100644 (file)
@@ -36,6 +36,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import os.path
 
 import SCons.Builder
+import SCons.Defaults
 import SCons.Node.FS
 import SCons.Util
 
index 4bd050a1bd8b2db26195812c3eeae3b92991880a..eb38e44ca7fc69d80b166a9c48055ca8f862cd44 100644 (file)
@@ -37,7 +37,6 @@ import os.path
 import re
 import string
 import sys
-import stat
 import types
 
 from UserDict import UserDict
@@ -234,9 +233,6 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
 
     rname = str(root)
 
-    if visited.has_key(rname):
-        return ""
-
     children = child_func(root)
     retval = ""
     for pipe in margin[:-1]:
@@ -245,6 +241,9 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
         else:
             retval = retval + "  "
 
+    if visited.has_key(rname):
+        return retval + "+-[" + rname + "]\n"
+
     retval = retval + "+-" + rname + "\n"
     if not prune:
         visited = copy.copy(visited)
@@ -278,21 +277,19 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
 
     rname = str(root)
 
-    if visited.has_key(rname):
-        return
-
     if showtags:
 
         if showtags == 2:
-            print ' E        = exists'
-            print '  R       = exists in repository only'
-            print '   b      = implicit builder'
-            print '   B      = explicit builder'
-            print '    S     = side effect'
-            print '     P    = precious'
-            print '      A   = always build'
-            print '       C  = current'
-            print '        N = no clean'
+            print ' E         = exists'
+            print '  R        = exists in repository only'
+            print '   b       = implicit builder'
+            print '   B       = explicit builder'
+            print '    S      = side effect'
+            print '     P     = precious'
+            print '      A    = always build'
+            print '       C   = current'
+            print '        N  = no clean'
+            print '         H = no cache'
             print ''
 
         tags = ['[']
@@ -305,6 +302,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
         tags.append(' A'[IDX(root.always_build)])
         tags.append(' C'[IDX(root.current())])
         tags.append(' N'[IDX(root.noclean)])
+        tags.append(' H'[IDX(root.nocache)])
         tags.append(']')
 
     else:
@@ -314,6 +312,10 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
         return ["  ","| "][m]
     margins = map(MMM, margin[:-1])
 
+    if visited.has_key(rname):
+        print string.join(tags + margins + ['+-[', rname, ']'], '')
+        return
+
     print string.join(tags + margins + ['+-', rname], '')
 
     if prune:
@@ -567,6 +569,7 @@ elif os.name == 'os2':
 else:
 
     def WhereIs(file, path=None, pathext=None, reject=[]):
+        import stat
         if path is None:
             try:
                 path = os.environ['PATH']
@@ -864,9 +867,10 @@ def unique(s):
         for x in s:
             u[x] = 1
     except TypeError:
-        del u  # move on to the next method
+        pass    # move on to the next method
     else:
         return u.keys()
+    del u
 
     # We can't hash all the elements.  Second fastest is to sort,
     # which brings the equal elements together; then duplicates are
@@ -879,7 +883,7 @@ def unique(s):
         t = list(s)
         t.sort()
     except TypeError:
-        del t  # move on to the next method
+        pass    # move on to the next method
     else:
         assert n > 0
         last = t[0]
@@ -890,6 +894,7 @@ def unique(s):
                 lasti = lasti + 1
             i = i + 1
         return t[:lasti]
+    del t
 
     # Brute force is all that's left.
     u = []
@@ -926,3 +931,16 @@ class LogicalLines:
                 break
             result.append(line)
         return result
+
+class Unbuffered:
+    """
+    A proxy class that wraps a file object, flushing after every write,
+    and delegating everything else to the wrapped object.
+    """
+    def __init__(self, file):
+        self.file = file
+    def write(self, arg):
+        self.file.write(arg)
+        self.file.flush()
+    def __getattr__(self, attr):
+        return getattr(self.file, attr)
index e2916621f11e1357df28f374e6e399010c4871dc..db6d9f6ea1b2fb472f8703868f4603bfab84935b 100644 (file)
@@ -56,6 +56,7 @@ class UtilTestCase(unittest.TestCase):
         def __init__(self, name, children=[]):
             self.children = children
             self.name = name
+            self.nocache = None
         def __str__(self):
             return self.name
         def exists(self):
@@ -100,7 +101,7 @@ class UtilTestCase(unittest.TestCase):
 """
 
         lines = string.split(expect, '\n')[:-1]
-        lines = map(lambda l: '[E BSPACN]'+l, lines)
+        lines = map(lambda l: '[E BSPACN ]'+l, lines)
         withtags = string.join(lines, '\n') + '\n'
 
         return foo, expect, withtags
@@ -120,10 +121,11 @@ class UtilTestCase(unittest.TestCase):
     +-blat.h
     | +-stdlib.h
     +-bar.h
+      +-[stdlib.h]
 """
 
         lines = string.split(expect, '\n')[:-1]
-        lines = map(lambda l: '[E BSPACN]'+l, lines)
+        lines = map(lambda l: '[E BSPACN ]'+l, lines)
         withtags = string.join(lines, '\n') + '\n'
 
         return blat_o, expect, withtags
index 1b13c96a0a27bd0c1b13a0f206dafdb5581009fe..b313ee06ee63955acee070c59f71fb350abc65fa 100644 (file)
@@ -35,6 +35,7 @@ class Warning(SCons.Errors.UserError):
     pass
 
 
+# NOTE:  If you add a new warning class, add it to the man page, too!
 
 class CacheWriteErrorWarning(Warning):
     pass
@@ -51,6 +52,9 @@ class DeprecatedWarning(Warning):
 class DuplicateEnvironmentWarning(Warning):
     pass
 
+class MisleadingKeywordsWarning(Warning):
+    pass
+
 class MissingSConscriptWarning(Warning):
     pass
 
@@ -66,9 +70,6 @@ class NoParallelSupportWarning(Warning):
 class ReservedVariableWarning(Warning):
     pass
 
-class MisleadingKeywordsWarning(Warning):
-    pass
-
 _warningAsException = 0
 
 # The below is a list of 2-tuples.  The first element is a class object.
index 20e47344e5d18c536d73e57d6fede40dfa7307eb..b5488419fd23a5f526ed080f82dcb7cc535ab0d7 100644 (file)
@@ -38,5 +38,3 @@ __buildsys__ = "__BUILDSYS__"
 __date__ = "__DATE__"
 
 __developer__ = "__DEVELOPER__"
-
-import SCons.Memoize
index 6112db5606f536458a78d136b09a44d76a3fcad6..7b74ab460aefeee58b8da8ca6da08de6d77d26dc 100644 (file)
@@ -79,6 +79,25 @@ def import_as(module, name):
 
 import builtins
 
+try:
+    set
+except NameError:
+    # Pre-2.4 Python has no native set type
+    try:
+        # Python 2.2 and 2.3 can use the copy of the 2.[45] sets module
+        # that we grabbed.
+        import_as('_sets', 'sets')
+    except (ImportError, SyntaxError):
+        # Python 1.5 (ImportError, no __future_ module) and 2.1
+        # (SyntaxError, no generators in __future__) will blow up
+        # trying to import the 2.[45] sets module, so back off to a
+        # custom sets module that can be discarded easily when we
+        # stop supporting those versions.
+        import_as('_sets15', 'sets')
+    import __builtin__
+    import sets
+    __builtin__.set = sets.Set
+
 try:
     import subprocess
 except ImportError:
diff --git a/src/engine/SCons/compat/_sets.py b/src/engine/SCons/compat/_sets.py
new file mode 100644 (file)
index 0000000..32a0dd6
--- /dev/null
@@ -0,0 +1,577 @@
+"""Classes to represent arbitrary sets (including sets of sets).
+
+This module implements sets using dictionaries whose values are
+ignored.  The usual operations (union, intersection, deletion, etc.)
+are provided as both methods and operators.
+
+Important: sets are not sequences!  While they support 'x in s',
+'len(s)', and 'for x in s', none of those operations are unique for
+sequences; for example, mappings support all three as well.  The
+characteristic operation for sequences is subscripting with small
+integers: s[i], for i in range(len(s)).  Sets don't support
+subscripting at all.  Also, sequences allow multiple occurrences and
+their elements have a definite order; sets on the other hand don't
+record multiple occurrences and don't remember the order of element
+insertion (which is why they don't support s[i]).
+
+The following classes are provided:
+
+BaseSet -- All the operations common to both mutable and immutable
+    sets. This is an abstract class, not meant to be directly
+    instantiated.
+
+Set -- Mutable sets, subclass of BaseSet; not hashable.
+
+ImmutableSet -- Immutable sets, subclass of BaseSet; hashable.
+    An iterable argument is mandatory to create an ImmutableSet.
+
+_TemporarilyImmutableSet -- A wrapper around a Set, hashable,
+    giving the same hash value as the immutable set equivalent
+    would have.  Do not use this class directly.
+
+Only hashable objects can be added to a Set. In particular, you cannot
+really add a Set as an element to another Set; if you try, what is
+actually added is an ImmutableSet built from it (it compares equal to
+the one you tried adding).
+
+When you ask if `x in y' where x is a Set and y is a Set or
+ImmutableSet, x is wrapped into a _TemporarilyImmutableSet z, and
+what's tested is actually `z in y'.
+
+"""
+
+# Code history:
+#
+# - Greg V. Wilson wrote the first version, using a different approach
+#   to the mutable/immutable problem, and inheriting from dict.
+#
+# - Alex Martelli modified Greg's version to implement the current
+#   Set/ImmutableSet approach, and make the data an attribute.
+#
+# - Guido van Rossum rewrote much of the code, made some API changes,
+#   and cleaned up the docstrings.
+#
+# - Raymond Hettinger added a number of speedups and other
+#   improvements.
+
+from __future__ import generators
+try:
+    from itertools import ifilter, ifilterfalse
+except ImportError:
+    # Code to make the module run under Py2.2
+    def ifilter(predicate, iterable):
+        if predicate is None:
+            def predicate(x):
+                return x
+        for x in iterable:
+            if predicate(x):
+                yield x
+    def ifilterfalse(predicate, iterable):
+        if predicate is None:
+            def predicate(x):
+                return x
+        for x in iterable:
+            if not predicate(x):
+                yield x
+    try:
+        True, False
+    except NameError:
+        True, False = (0==0, 0!=0)
+
+__all__ = ['BaseSet', 'Set', 'ImmutableSet']
+
+class BaseSet(object):
+    """Common base class for mutable and immutable sets."""
+
+    __slots__ = ['_data']
+
+    # Constructor
+
+    def __init__(self):
+        """This is an abstract class."""
+        # Don't call this from a concrete subclass!
+        if self.__class__ is BaseSet:
+            raise TypeError, ("BaseSet is an abstract class.  "
+                              "Use Set or ImmutableSet.")
+
+    # Standard protocols: __len__, __repr__, __str__, __iter__
+
+    def __len__(self):
+        """Return the number of elements of a set."""
+        return len(self._data)
+
+    def __repr__(self):
+        """Return string representation of a set.
+
+        This looks like 'Set([<list of elements>])'.
+        """
+        return self._repr()
+
+    # __str__ is the same as __repr__
+    __str__ = __repr__
+
+    def _repr(self, sorted=False):
+        elements = self._data.keys()
+        if sorted:
+            elements.sort()
+        return '%s(%r)' % (self.__class__.__name__, elements)
+
+    def __iter__(self):
+        """Return an iterator over the elements or a set.
+
+        This is the keys iterator for the underlying dict.
+        """
+        return self._data.iterkeys()
+
+    # Three-way comparison is not supported.  However, because __eq__ is
+    # tried before __cmp__, if Set x == Set y, x.__eq__(y) returns True and
+    # then cmp(x, y) returns 0 (Python doesn't actually call __cmp__ in this
+    # case).
+
+    def __cmp__(self, other):
+        raise TypeError, "can't compare sets using cmp()"
+
+    # Equality comparisons using the underlying dicts.  Mixed-type comparisons
+    # are allowed here, where Set == z for non-Set z always returns False,
+    # and Set != z always True.  This allows expressions like "x in y" to
+    # give the expected result when y is a sequence of mixed types, not
+    # raising a pointless TypeError just because y contains a Set, or x is
+    # a Set and y contain's a non-set ("in" invokes only __eq__).
+    # Subtle:  it would be nicer if __eq__ and __ne__ could return
+    # NotImplemented instead of True or False.  Then the other comparand
+    # would get a chance to determine the result, and if the other comparand
+    # also returned NotImplemented then it would fall back to object address
+    # comparison (which would always return False for __eq__ and always
+    # True for __ne__).  However, that doesn't work, because this type
+    # *also* implements __cmp__:  if, e.g., __eq__ returns NotImplemented,
+    # Python tries __cmp__ next, and the __cmp__ here then raises TypeError.
+
+    def __eq__(self, other):
+        if isinstance(other, BaseSet):
+            return self._data == other._data
+        else:
+            return False
+
+    def __ne__(self, other):
+        if isinstance(other, BaseSet):
+            return self._data != other._data
+        else:
+            return True
+
+    # Copying operations
+
+    def copy(self):
+        """Return a shallow copy of a set."""
+        result = self.__class__()
+        result._data.update(self._data)
+        return result
+
+    __copy__ = copy # For the copy module
+
+    def __deepcopy__(self, memo):
+        """Return a deep copy of a set; used by copy module."""
+        # This pre-creates the result and inserts it in the memo
+        # early, in case the deep copy recurses into another reference
+        # to this same set.  A set can't be an element of itself, but
+        # it can certainly contain an object that has a reference to
+        # itself.
+        from copy import deepcopy
+        result = self.__class__()
+        memo[id(self)] = result
+        data = result._data
+        value = True
+        for elt in self:
+            data[deepcopy(elt, memo)] = value
+        return result
+
+    # Standard set operations: union, intersection, both differences.
+    # Each has an operator version (e.g. __or__, invoked with |) and a
+    # method version (e.g. union).
+    # Subtle:  Each pair requires distinct code so that the outcome is
+    # correct when the type of other isn't suitable.  For example, if
+    # we did "union = __or__" instead, then Set().union(3) would return
+    # NotImplemented instead of raising TypeError (albeit that *why* it
+    # raises TypeError as-is is also a bit subtle).
+
+    def __or__(self, other):
+        """Return the union of two sets as a new set.
+
+        (I.e. all elements that are in either set.)
+        """
+        if not isinstance(other, BaseSet):
+            return NotImplemented
+        return self.union(other)
+
+    def union(self, other):
+        """Return the union of two sets as a new set.
+
+        (I.e. all elements that are in either set.)
+        """
+        result = self.__class__(self)
+        result._update(other)
+        return result
+
+    def __and__(self, other):
+        """Return the intersection of two sets as a new set.
+
+        (I.e. all elements that are in both sets.)
+        """
+        if not isinstance(other, BaseSet):
+            return NotImplemented
+        return self.intersection(other)
+
+    def intersection(self, other):
+        """Return the intersection of two sets as a new set.
+
+        (I.e. all elements that are in both sets.)
+        """
+        if not isinstance(other, BaseSet):
+            other = Set(other)
+        if len(self) <= len(other):
+            little, big = self, other
+        else:
+            little, big = other, self
+        common = ifilter(big._data.has_key, little)
+        return self.__class__(common)
+
+    def __xor__(self, other):
+        """Return the symmetric difference of two sets as a new set.
+
+        (I.e. all elements that are in exactly one of the sets.)
+        """
+        if not isinstance(other, BaseSet):
+            return NotImplemented
+        return self.symmetric_difference(other)
+
+    def symmetric_difference(self, other):
+        """Return the symmetric difference of two sets as a new set.
+
+        (I.e. all elements that are in exactly one of the sets.)
+        """
+        result = self.__class__()
+        data = result._data
+        value = True
+        selfdata = self._data
+        try:
+            otherdata = other._data
+        except AttributeError:
+            otherdata = Set(other)._data
+        for elt in ifilterfalse(otherdata.has_key, selfdata):
+            data[elt] = value
+        for elt in ifilterfalse(selfdata.has_key, otherdata):
+            data[elt] = value
+        return result
+
+    def  __sub__(self, other):
+        """Return the difference of two sets as a new Set.
+
+        (I.e. all elements that are in this set and not in the other.)
+        """
+        if not isinstance(other, BaseSet):
+            return NotImplemented
+        return self.difference(other)
+
+    def difference(self, other):
+        """Return the difference of two sets as a new Set.
+
+        (I.e. all elements that are in this set and not in the other.)
+        """
+        result = self.__class__()
+        data = result._data
+        try:
+            otherdata = other._data
+        except AttributeError:
+            otherdata = Set(other)._data
+        value = True
+        for elt in ifilterfalse(otherdata.has_key, self):
+            data[elt] = value
+        return result
+
+    # Membership test
+
+    def __contains__(self, element):
+        """Report whether an element is a member of a set.
+
+        (Called in response to the expression `element in self'.)
+        """
+        try:
+            return element in self._data
+        except TypeError:
+            transform = getattr(element, "__as_temporarily_immutable__", None)
+            if transform is None:
+                raise # re-raise the TypeError exception we caught
+            return transform() in self._data
+
+    # Subset and superset test
+
+    def issubset(self, other):
+        """Report whether another set contains this set."""
+        self._binary_sanity_check(other)
+        if len(self) > len(other):  # Fast check for obvious cases
+            return False
+        for elt in ifilterfalse(other._data.has_key, self):
+            return False
+        return True
+
+    def issuperset(self, other):
+        """Report whether this set contains another set."""
+        self._binary_sanity_check(other)
+        if len(self) < len(other):  # Fast check for obvious cases
+            return False
+        for elt in ifilterfalse(self._data.has_key, other):
+            return False
+        return True
+
+    # Inequality comparisons using the is-subset relation.
+    __le__ = issubset
+    __ge__ = issuperset
+
+    def __lt__(self, other):
+        self._binary_sanity_check(other)
+        return len(self) < len(other) and self.issubset(other)
+
+    def __gt__(self, other):
+        self._binary_sanity_check(other)
+        return len(self) > len(other) and self.issuperset(other)
+
+    # Assorted helpers
+
+    def _binary_sanity_check(self, other):
+        # Check that the other argument to a binary operation is also
+        # a set, raising a TypeError otherwise.
+        if not isinstance(other, BaseSet):
+            raise TypeError, "Binary operation only permitted between sets"
+
+    def _compute_hash(self):
+        # Calculate hash code for a set by xor'ing the hash codes of
+        # the elements.  This ensures that the hash code does not depend
+        # on the order in which elements are added to the set.  This is
+        # not called __hash__ because a BaseSet should not be hashable;
+        # only an ImmutableSet is hashable.
+        result = 0
+        for elt in self:
+            result ^= hash(elt)
+        return result
+
+    def _update(self, iterable):
+        # The main loop for update() and the subclass __init__() methods.
+        data = self._data
+
+        # Use the fast update() method when a dictionary is available.
+        if isinstance(iterable, BaseSet):
+            data.update(iterable._data)
+            return
+
+        value = True
+
+        if type(iterable) in (list, tuple, xrange):
+            # Optimized: we know that __iter__() and next() can't
+            # raise TypeError, so we can move 'try:' out of the loop.
+            it = iter(iterable)
+            while True:
+                try:
+                    for element in it:
+                        data[element] = value
+                    return
+                except TypeError:
+                    transform = getattr(element, "__as_immutable__", None)
+                    if transform is None:
+                        raise # re-raise the TypeError exception we caught
+                    data[transform()] = value
+        else:
+            # Safe: only catch TypeError where intended
+            for element in iterable:
+                try:
+                    data[element] = value
+                except TypeError:
+                    transform = getattr(element, "__as_immutable__", None)
+                    if transform is None:
+                        raise # re-raise the TypeError exception we caught
+                    data[transform()] = value
+
+
+class ImmutableSet(BaseSet):
+    """Immutable set class."""
+
+    __slots__ = ['_hashcode']
+
+    # BaseSet + hashing
+
+    def __init__(self, iterable=None):
+        """Construct an immutable set from an optional iterable."""
+        self._hashcode = None
+        self._data = {}
+        if iterable is not None:
+            self._update(iterable)
+
+    def __hash__(self):
+        if self._hashcode is None:
+            self._hashcode = self._compute_hash()
+        return self._hashcode
+
+    def __getstate__(self):
+        return self._data, self._hashcode
+
+    def __setstate__(self, state):
+        self._data, self._hashcode = state
+
+class Set(BaseSet):
+    """ Mutable set class."""
+
+    __slots__ = []
+
+    # BaseSet + operations requiring mutability; no hashing
+
+    def __init__(self, iterable=None):
+        """Construct a set from an optional iterable."""
+        self._data = {}
+        if iterable is not None:
+            self._update(iterable)
+
+    def __getstate__(self):
+        # getstate's results are ignored if it is not
+        return self._data,
+
+    def __setstate__(self, data):
+        self._data, = data
+
+    def __hash__(self):
+        """A Set cannot be hashed."""
+        # We inherit object.__hash__, so we must deny this explicitly
+        raise TypeError, "Can't hash a Set, only an ImmutableSet."
+
+    # In-place union, intersection, differences.
+    # Subtle:  The xyz_update() functions deliberately return None,
+    # as do all mutating operations on built-in container types.
+    # The __xyz__ spellings have to return self, though.
+
+    def __ior__(self, other):
+        """Update a set with the union of itself and another."""
+        self._binary_sanity_check(other)
+        self._data.update(other._data)
+        return self
+
+    def union_update(self, other):
+        """Update a set with the union of itself and another."""
+        self._update(other)
+
+    def __iand__(self, other):
+        """Update a set with the intersection of itself and another."""
+        self._binary_sanity_check(other)
+        self._data = (self & other)._data
+        return self
+
+    def intersection_update(self, other):
+        """Update a set with the intersection of itself and another."""
+        if isinstance(other, BaseSet):
+            self &= other
+        else:
+            self._data = (self.intersection(other))._data
+
+    def __ixor__(self, other):
+        """Update a set with the symmetric difference of itself and another."""
+        self._binary_sanity_check(other)
+        self.symmetric_difference_update(other)
+        return self
+
+    def symmetric_difference_update(self, other):
+        """Update a set with the symmetric difference of itself and another."""
+        data = self._data
+        value = True
+        if not isinstance(other, BaseSet):
+            other = Set(other)
+        if self is other:
+            self.clear()
+        for elt in other:
+            if elt in data:
+                del data[elt]
+            else:
+                data[elt] = value
+
+    def __isub__(self, other):
+        """Remove all elements of another set from this set."""
+        self._binary_sanity_check(other)
+        self.difference_update(other)
+        return self
+
+    def difference_update(self, other):
+        """Remove all elements of another set from this set."""
+        data = self._data
+        if not isinstance(other, BaseSet):
+            other = Set(other)
+        if self is other:
+            self.clear()
+        for elt in ifilter(data.has_key, other):
+            del data[elt]
+
+    # Python dict-like mass mutations: update, clear
+
+    def update(self, iterable):
+        """Add all values from an iterable (such as a list or file)."""
+        self._update(iterable)
+
+    def clear(self):
+        """Remove all elements from this set."""
+        self._data.clear()
+
+    # Single-element mutations: add, remove, discard
+
+    def add(self, element):
+        """Add an element to a set.
+
+        This has no effect if the element is already present.
+        """
+        try:
+            self._data[element] = True
+        except TypeError:
+            transform = getattr(element, "__as_immutable__", None)
+            if transform is None:
+                raise # re-raise the TypeError exception we caught
+            self._data[transform()] = True
+
+    def remove(self, element):
+        """Remove an element from a set; it must be a member.
+
+        If the element is not a member, raise a KeyError.
+        """
+        try:
+            del self._data[element]
+        except TypeError:
+            transform = getattr(element, "__as_temporarily_immutable__", None)
+            if transform is None:
+                raise # re-raise the TypeError exception we caught
+            del self._data[transform()]
+
+    def discard(self, element):
+        """Remove an element from a set if it is a member.
+
+        If the element is not a member, do nothing.
+        """
+        try:
+            self.remove(element)
+        except KeyError:
+            pass
+
+    def pop(self):
+        """Remove and return an arbitrary set element."""
+        return self._data.popitem()[0]
+
+    def __as_immutable__(self):
+        # Return a copy of self as an immutable set
+        return ImmutableSet(self)
+
+    def __as_temporarily_immutable__(self):
+        # Return self wrapped in a temporarily immutable set
+        return _TemporarilyImmutableSet(self)
+
+
+class _TemporarilyImmutableSet(BaseSet):
+    # Wrap a mutable set as if it was temporarily immutable.
+    # This only supplies hashing and equality comparisons.
+
+    def __init__(self, set):
+        self._set = set
+        self._data = set._data  # Needed by ImmutableSet.__eq__()
+
+    def __hash__(self):
+        return self._set._compute_hash()
diff --git a/src/engine/SCons/compat/_sets15.py b/src/engine/SCons/compat/_sets15.py
new file mode 100644 (file)
index 0000000..b3d0bb3
--- /dev/null
@@ -0,0 +1,159 @@
+#
+# A Set class that works all the way back to Python 1.5.  From:
+#
+#       Python Cookbook:  Yet another Set class for Python
+#       http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/106469
+#       Goncalo Rodriques
+#
+#       This is a pure Pythonic implementation of a set class.  The syntax
+#       and methods implemented are, for the most part, borrowed from
+#       PEP 218 by Greg Wilson.
+#
+# Note that this class violates the formal definition of a set() by adding
+# a __getitem__() method so we can iterate over a set's elements under
+# Python 1.5 and 2.1, which don't support __iter__() and iterator types.
+#
+
+import string
+
+class Set:
+    """The set class. It can contain mutable objects."""
+
+    def __init__(self, seq = None):
+        """The constructor. It can take any object giving an iterator as an optional
+        argument to populate the new set."""
+        self.elems = []
+        if seq:
+            for elem in seq:
+                if elem not in self.elems:
+                    self.elems.append(elem)
+
+    def __str__(self):
+        return "{%s}" % string.join(map(str, self.elems), ", ")
+
+
+    def copy(self):
+        """Shallow copy of a set object."""
+        return Set(self.elems)
+
+    def __contains__(self, elem):
+        return elem in self.elems
+
+    def __len__(self):
+        return len(self.elems)
+
+    def __getitem__(self, index):
+        # Added so that Python 1.5 can iterate over the elements.
+        # The cookbook recipe's author didn't like this because there
+        # really isn't any order in a set object, but this is necessary
+        # to make the class work well enough for our purposes.
+        return self.elems[index]
+
+    def items(self):
+        """Returns a list of the elements in the set."""
+        return self.elems
+
+    def add(self, elem):
+        """Add one element to the set."""
+        if elem not in self.elems:
+            self.elems.append(elem)
+
+    def remove(self, elem):
+        """Remove an element from the set. Return an error if elem is not in the set."""
+        try:
+            self.elems.remove(elem)
+        except ValueError:
+            raise LookupError, "Object %s is not a member of the set." % str(elem)
+
+    def discard(self, elem):
+        """Remove an element from the set. Do nothing if elem is not in the set."""
+        try:
+            self.elems.remove(elem)
+        except ValueError:
+            pass
+
+    def sort(self, func=cmp):
+        self.elems.sort(func)
+
+    #Define an iterator for a set.
+    def __iter__(self):
+        return iter(self.elems)
+
+    #The basic binary operations with sets.
+    def __or__(self, other):
+        """Union of two sets."""
+        ret = self.copy()
+        for elem in other.elems:
+            if elem not in ret:
+                ret.elems.append(elem)
+        return ret
+
+    def __sub__(self, other):
+        """Difference of two sets."""
+        ret = self.copy()
+        for elem in other.elems:
+            ret.discard(elem)
+        return ret
+
+    def __and__(self, other):
+        """Intersection of two sets."""
+        ret = Set()
+        for elem in self.elems:
+            if elem in other.elems:
+                ret.elems.append(elem)
+        return ret
+
+    def __add__(self, other):
+        """Symmetric difference of two sets."""
+        ret = Set()
+        temp = other.copy()
+        for elem in self.elems:
+            if elem in temp.elems:
+                temp.elems.remove(elem)
+            else:
+                ret.elems.append(elem)
+        #Add remaining elements.
+        for elem in temp.elems:
+                ret.elems.append(elem)
+        return ret
+
+    def __mul__(self, other):
+        """Cartesian product of two sets."""
+        ret = Set()
+        for elemself in self.elems:
+            x = map(lambda other, s=elemself: (s, other), other.elems)
+            ret.elems.extend(x)
+        return ret
+
+    #Some of the binary comparisons.
+    def __lt__(self, other):
+        """Returns 1 if the lhs set is contained but not equal to the rhs set."""
+        if len(self.elems) < len(other.elems):
+            temp = other.copy()
+            for elem in self.elems:
+                if elem in temp.elems:
+                    temp.remove(elem)
+                else:
+                    return 0
+            return len(temp.elems) == 0
+        else:
+            return 0
+
+    def __le__(self, other):
+        """Returns 1 if the lhs set is contained in the rhs set."""
+        if len(self.elems) <= len(other.elems):
+            ret = 1
+            for elem in self.elems:
+                if elem not in other.elems:
+                    ret = 0
+                    break
+            return ret
+        else:
+            return 0
+
+    def __eq__(self, other):
+        """Returns 1 if the sets are equal."""
+        if len(self.elems) != len(other.elems):
+            return 0
+        else:
+            return len(self - other) == 0
index aa17caefd8497e4e2d35d467f7e9a228b018f729..fc06347d8186aa5e749b08b1f97b1779d729e661 100644 (file)
@@ -356,6 +356,7 @@ import sys
 mswindows = (sys.platform == "win32")
 
 import os
+import string
 import types
 import traceback
 
@@ -565,7 +566,7 @@ def list2cmdline(seq):
             result.extend(bs_buf)
             result.append('"')
 
-    return ''.join(result)
+    return string.join(result, '')
 
 
 try:
@@ -1048,12 +1049,8 @@ class Popen(object):
 
                     # Close pipe fds.  Make sure we don't close the same
                     # fd more than once, or standard fds.
-                    if p2cread:
-                        os.close(p2cread)
-                    if c2pwrite and c2pwrite not in (p2cread,):
-                        os.close(c2pwrite)
-                    if errwrite and errwrite not in (p2cread, c2pwrite):
-                        os.close(errwrite)
+                    for fd in set((p2cread, c2pwrite, errwrite))-set((0,1,2)):
+                        if fd: os.close(fd)
 
                     # Close all other fds, if asked for
                     if close_fds:
@@ -1079,7 +1076,7 @@ class Popen(object):
                     exc_lines = traceback.format_exception(exc_type,
                                                            exc_value,
                                                            tb)
-                    exc_value.child_traceback = ''.join(exc_lines)
+                    exc_value.child_traceback = string.join(exc_lines, '')
                     os.write(errpipe_write, pickle.dumps(exc_value))
 
                 # This exitcode won't be reported to applications, so it
@@ -1158,6 +1155,7 @@ class Popen(object):
                 read_set.append(self.stderr)
                 stderr = []
 
+            input_offset = 0
             while read_set or write_set:
                 rlist, wlist, xlist = select.select(read_set, write_set, [])
 
@@ -1165,9 +1163,9 @@ class Popen(object):
                     # When select has indicated that the file is writable,
                     # we can write up to PIPE_BUF bytes without risk
                     # blocking.  POSIX defines PIPE_BUF >= 512
-                    bytes_written = os.write(self.stdin.fileno(), input[:512])
-                    input = input[bytes_written:]
-                    if not input:
+                    bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512))
+                    input_offset = input_offset + bytes_written
+                    if input_offset >= len(input):
                         self.stdin.close()
                         write_set.remove(self.stdin)
 
@@ -1187,9 +1185,9 @@ class Popen(object):
 
             # All data exchanged.  Translate lists into strings.
             if stdout is not None:
-                stdout = ''.join(stdout)
+                stdout = string.join(stdout, '')
             if stderr is not None:
-                stderr = ''.join(stderr)
+                stderr = string.join(stderr, '')
 
             # Translate newlines, if requested.  We cannot let the file
             # object do the translation: It is based on stdio, which is
index d96ef235bebbb0ace85b8d69f8c01691ea0a8fc7..8620936f53c6882ce981d198a0bfbe79f06acfa9 100644 (file)
@@ -32,7 +32,6 @@ import SCons.compat
 import os
 import re
 import string
-import sys
 
 #
 # First "subsystem" of regular expressions that we set up:
diff --git a/src/script/scons-post-install.py b/src/script/scons-post-install.py
new file mode 100644 (file)
index 0000000..a622a6a
--- /dev/null
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# scons-post-install - SCons post install script for Windows 
+#
+# A script for configuring "App Paths" registry key so that SCons could
+# be run from any directory the same way Python is. 
+#
+
+#
+# SCons - a Software Constructor
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os.path
+import sys
+
+scons_bat_path = os.path.join(sys.prefix, 'Scripts', 'scons.bat')
+
+app_paths_key = r'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\SCons.bat'
+
+def install():
+    if sys.platform == 'win32':
+        try:
+            import _winreg
+        except ImportError:
+            pass
+        else:
+            print 'Writing "App Paths" registry entry for %s' % scons_bat_path
+            _winreg.SetValue(
+                _winreg.HKEY_LOCAL_MACHINE, 
+                app_paths_key,
+                _winreg.REG_SZ,
+                scons_bat_path)
+            print 'Done.'
+
+
+def remove():
+    if sys.platform == 'win32':
+        try:
+            import _winreg
+        except ImportError:
+            pass
+        else:
+            # print 'Remove "App Paths" registry entry'
+            _winreg.DeleteKey(_winreg.HKEY_LOCAL_MACHINE, app_paths_key)
+
+
+if len(sys.argv) > 1:
+    if sys.argv[1] == '-install':
+        install()
+    elif sys.argv[1] == '-remove':
+        remove()
+
+sys.exit(0)
index 9e45a911113e3c20366a2090d0411e4a077904cb..c0a304d51455a41314dac6d3a57e5506e8137b72 100644 (file)
@@ -7,6 +7,7 @@ python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, '
 @REM no way to set exit status of this script for 9x/Me\r
 goto endscons\r
 :WinNT\r
+set path=%path%;%~dp0\r
 python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %*\r
 if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endscons\r
 if errorlevel 9009 echo you do not have python in your PATH\r
index f04ca1bb7e99d9e03fa320e5167420d0aad64045..4b097ac4fa00ae7d4b3d1cbc8d1a5ff75d00b60c 100644 (file)
@@ -3,3 +3,4 @@ group = Development/Tools
 
 [bdist_wininst]
 title = SCons - a software construction tool
+install-script = scons-post-install.py
index 9ad00694eb6ea659858efe38f3e4ceee30cd9c94..53b19fa6141fc724f2976a063c5a1ea6331cfc5e 100644 (file)
@@ -350,9 +350,35 @@ class install_data(_install_data):
         else:
             self.data_files = []
 
+description = """Open Source next-generation build tool.
+Improved, cross-platform substitute for the classic Make
+utility.  In short, SCons is an easier, more reliable
+and faster way to build software."""
+
+scripts = [
+    'script/scons',
+    'script/sconsign',
+    'script/scons-time',
+
+    # We include scons.bat in the list of scripts, even on UNIX systems,
+    # because we provide an option to allow it be installed explicitly,
+    # for example if you're installing from UNIX on a share that's
+    # accessible to Windows and you want the scons.bat.
+    'script/scons.bat',
+]
+
+if is_win32:
+    scripts = scripts + [
+        'script/scons-post-install.py'
+    ]
+
 arguments = {
     'name'             : "scons",
     'version'          : Version,
+    'description'      : description,
+    'author'           : 'Steven Knight',
+    'author_email'     : 'knight@baldmt.com',
+    'url'              : "http://www.scons.org/",
     'packages'         : ["SCons",
                           "SCons.compat",
                           "SCons.Node",
@@ -365,10 +391,7 @@ arguments = {
                           "SCons.Tool"],
     'package_dir'      : {'' : 'engine'},
     'data_files'       : [('man/man1', man_pages)],
-    'scripts'          : ['script/scons',
-                          'script/sconsign',
-                          'script/scons-time',
-                          'script/scons.bat'],
+    'scripts'          : scripts,
     'cmdclass'         : {'install'         : install,
                           'install_lib'     : install_lib,
                           'install_data'    : install_data,
diff --git a/src/test_pychecker.py b/src/test_pychecker.py
new file mode 100644 (file)
index 0000000..368520f
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Use pychecker to catch various Python coding errors.
+"""
+
+import os
+import os.path
+import string
+import sys
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.skip_test('Not ready for clean pychecker output; skipping test.\n')
+
+try:
+    import pychecker
+except ImportError:
+    pychecker = test.where_is('pychecker')
+    if not pychecker:
+        test.skip_test("Could not find 'pychecker'; skipping test(s).\n")
+    program = pychecker
+    default_arguments = []
+else:
+    pychecker = os.path.join(os.path.split(pychecker.__file__)[0], 'checker.py')
+    program = sys.executable
+    default_arguments = [pychecker]
+
+try:
+    cwd = os.environ['SCONS_CWD']
+except KeyError:
+    src_engine = os.environ['SCONS_LIB_DIR']
+else:
+    src_engine = os.path.join(cwd, 'build', 'scons-src', 'src', 'engine')
+    if not os.path.exists(src_engine):
+        src_engine = os.path.join(cwd, 'src', 'engine')
+
+src_engine_ = os.path.join(src_engine, '')
+
+MANIFEST = os.path.join(src_engine, 'MANIFEST.in')
+files = string.split(open(MANIFEST).read())
+
+files = filter(lambda f: f[-3:] == '.py', files)
+
+ignore = [
+    'SCons/compat/__init__.py',
+    'SCons/compat/builtins.py',
+    'SCons/compat/_subprocess.py',
+    'SCons/Optik/__init__.py',
+    'SCons/Optik/errors.py',
+    'SCons/Optik/option.py',
+    'SCons/Optik/option_parser.py',
+]
+
+u = {}
+for file in files:
+    u[file] = 1
+for file in ignore:
+    try:
+        del u[file]
+    except KeyError:
+        pass
+
+files = u.keys()
+
+files.sort()
+
+mismatches = []
+
+default_arguments.extend([
+    '--quiet',
+    '--limit=1000',
+])
+
+if sys.platform == 'win32':
+    default_arguments.extend([
+        '--blacklist', '"pywintypes,pywintypes.error"',
+    ])
+
+per_file_arguments = {
+    'SCons/__init__.py' : [
+        '--varlist', '"__revision__,__version__,__build__,__buildsys__,__date__,__developer__"',
+    ],
+}
+
+pywintypes_warning = "warning: couldn't find real module for class pywintypes.error (module name: pywintypes)\n"
+
+os.environ['PYTHONPATH'] = src_engine
+
+for file in files:
+
+    file = os.path.join(src_engine, file)
+    args = default_arguments + per_file_arguments.get(file, []) + [file]
+
+    test.run(program=program, arguments=args, status=None, stderr=None)
+
+    stdout = test.stdout()
+    stdout = string.replace(stdout, src_engine_, '')
+
+    stderr = test.stderr()
+    stderr = string.replace(stderr, src_engine_, '')
+    stderr = string.replace(stderr, pywintypes_warning, '')
+
+    if test.status or stdout or stderr:
+        mismatches.append('\n')
+        mismatches.append(string.join([program] + args) + '\n')
+
+        mismatches.append('STDOUT =====================================\n')
+        mismatches.append(stdout)
+
+        if stderr:
+            mismatches.append('STDERR =====================================\n')
+            mismatches.append(stderr)
+
+if mismatches:
+    print string.join(mismatches[1:], '')
+    test.fail_test()
+
+test.pass_test()
index 92202315ea2f3e2f75dcfee9e603d66ce2af4abf..b609f595d6ba37a309f96cea381573be3462d846 100644 (file)
@@ -114,6 +114,8 @@ check_list = [
         'src',
         search_list = [ '*.py' ],
         remove_list = [
+            'engine/SCons/compat/_sets.py',
+            'engine/SCons/compat/_sets15.py',
             'engine/SCons/compat/_subprocess.py',
             'engine/SCons/Conftest.py',
             'engine/SCons/dblite.py',
@@ -134,6 +136,9 @@ check_list = [
             'configure-stamp',
             'debian',
             'dist',
+            'gentoo',
+            'engine/SCons/compat/_sets.py',
+            'engine/SCons/compat/_sets15.py',
             'engine/SCons/compat/_subprocess.py',
             'engine/SCons/Conftest.py',
             'engine/SCons/dblite.py',
@@ -147,6 +152,8 @@ check_list = [
     CheckExpandedCopyright(
         build_local,
         remove_list = [
+            'SCons/compat/_sets.py',
+            'SCons/compat/_sets15.py',
             'SCons/compat/_subprocess.py',
             'SCons/Conftest.py',
             'SCons/dblite.py',
@@ -160,10 +167,12 @@ check_list = [
             'bin',
             'config',
             'debian',
+            'gentoo',
             'doc/design',
             'doc/MANIFEST',
             'doc/python10',
             'doc/reference',
+            'doc/developer/MANIFEST',
             'doc/man/MANIFEST',
             'doc/user/cons.pl',
             'doc/user/MANIFEST',
@@ -183,6 +192,8 @@ check_list = [
             'src/engine/MANIFEST.in',
             'src/engine/MANIFEST-xml.in',
             'src/engine/setup.cfg',
+            'src/engine/SCons/compat/_sets.py',
+            'src/engine/SCons/compat/_sets15.py',
             'src/engine/SCons/compat/_subprocess.py',
             'src/engine/SCons/Conftest.py',
             'src/engine/SCons/dblite.py',
diff --git a/test/CXX/CC-variables.py b/test/CXX/CC-variables.py
new file mode 100644 (file)
index 0000000..93aa315
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that initializing a construction environment with just the
+g++ tool uses the CCFLAGS.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env = Environment(tools = ['g++'])
+env.Object(target = 'test.obj', source = 'test.cxx')
+env.MergeFlags('+for_CCFLAGS -Wp,-for_CPPFLAGS')
+""")
+
+test.write('test.cxx', "test.cxx\n")
+
+expect = """\
+g++ -o test.obj -c +for_CCFLAGS -Wp,-for_CPPFLAGS test.cxx
+"""
+
+test.run(arguments = '-Q -n test.obj', stdout=expect)
+
+test.pass_test()
diff --git a/test/CacheDir/NoCache.py b/test/CacheDir/NoCache.py
new file mode 100644 (file)
index 0000000..44e51a0
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the NoCache environment method works.
+"""
+
+import TestSCons, os.path
+
+test = TestSCons.TestSCons()
+
+test.subdir('cache', 'alpha', 'beta')
+
+sconstruct = """
+import os
+CacheDir(r'%s')
+
+
+# This is bad form, but the easiest way to produce a test case.
+# Obviously, this could be cached if the inputs were passed in a
+# reasonable fashion.
+g = '%s'
+
+def ActionWithUndeclaredInputs(target,source,env):
+    open(target[0].abspath,'w').write(g)
+
+Command('foo_cached', [], ActionWithUndeclaredInputs)
+NoCache(Command('foo_notcached', [], ActionWithUndeclaredInputs))
+Command('bar_cached', [], ActionWithUndeclaredInputs)
+Command('bar_notcached', [], ActionWithUndeclaredInputs)
+NoCache('bar_notcached')
+
+# Make sure NoCache doesn't vomit when applied to a Dir
+NoCache(Command(Dir('aoeu'), [], Mkdir('$TARGET')))
+"""
+
+test.write('alpha/SConstruct', sconstruct % (test.workpath('cache'), 'alpha'))
+
+test.write('beta/SConstruct', sconstruct % (test.workpath('cache'), 'beta'))
+
+# First build, would populate the cache without NoCache
+test.run(chdir = 'alpha', arguments = '.')
+
+# Second build, without NoCache there would be a cache hit
+test.run(chdir = 'beta', arguments = '.')
+
+test.must_match(['beta','foo_cached'],      'alpha')
+test.must_match(['beta','foo_notcached'],   'beta')
+test.must_match(['beta','bar_cached'],      'alpha')
+test.must_match(['beta','bar_notcached'],   'beta')
+
+test.pass_test()
diff --git a/test/Install/no-top-relative.py b/test/Install/no-top-relative.py
new file mode 100644 (file)
index 0000000..51538ea
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that we can install a file if its file name portion begins
+with a '#'.  (A previous bug re-interpreted that as relative to
+the top-level SConstruct directory.)
+
+Thanks to Dave Weber for the test case.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir(['test'])
+
+test.write(['SConstruct'], """\
+env = Environment()
+i = env.Install("#/install", "#/test/#testfile.txt#");
+env.Default(i);
+""")
+
+test.write(['test', '#testfile.txt#'], "test/#testfile.txt#\n")
+
+test.run()
+
+test.must_match(['install', '#testfile.txt#'], "test/#testfile.txt#\n")
+
+test.pass_test()
index 3ee3deed06abd14c544f8dd3fe57dccb82905bc3..9250843a874cc54b06fc7b09315509e87945d183 100644 (file)
@@ -58,7 +58,13 @@ env = Environment(tools    = ['javac', 'jar'],
                   JARCHDIR = dir)
 bin = env.Java(dir, Dir('./'))
 jar = env.Jar(File('c.jar', dir), bin)
-Default(bin, jar)
+
+# Make sure we handle class files with $ in them, such as typically
+# created for inner classes.
+env = env.Clone(JARCHDIR = '.')
+inner = env.Jar('inner.jar', 'Inner$$Class.class')
+
+Default(bin, jar, inner)
 """ % locals())
 
 test.write('a.java', """\
@@ -71,6 +77,8 @@ package foo.bar;
 public class b {}
 """)
 
+test.write('Inner$Class.class', "Inner$Class.class\n")
+
 test.run(arguments = '.')
 
 test.pass_test()
index 7af9bfd4120e721345678008e88639aadced56a7..aab2b205d38f84f5aa0d0680ebc18ae4025689bb 100644 (file)
@@ -31,6 +31,12 @@ Test the BoolOption canned Option type.
 import os.path
 import string
 
+try:
+    True, False
+except NameError:
+    True = (0 == 0)
+    False = (0 != 0)
+
 import TestSCons
 
 test = TestSCons.TestSCons()
@@ -64,10 +70,10 @@ Default(env.Alias('dummy', None))
 
 
 test.run()
-check(['1', '0'])
+check([str(True), str(False)])
 
 test.run(arguments='warnings=0 profile=no profile=true')
-check(['0', '1'])
+check([str(False), str(True)])
 
 expect_stderr = """
 scons: *** Error converting option: warnings
index 81f70032b19c14d3c5d3c8ef7c6e47ac62be8fac..d285338e07817b94f2e7d9c0e0035601f401646e 100644 (file)
@@ -31,6 +31,12 @@ Test the PackageOption canned Option type.
 import os.path
 import string
 
+try:
+    True, False
+except NameError:
+    True = (0 == 0)
+    False = (0 != 0)
+
 import TestSCons
 
 test = TestSCons.TestSCons()
@@ -61,10 +67,16 @@ Default(env.Alias('dummy', None))
 """)
 
 test.run()
-check(['1'])
-test.run(arguments='x11=no'); check(['0'])
-test.run(arguments='x11=0'); check(['0'])
-test.run(arguments=['x11=%s' % test.workpath()]); check([test.workpath()])
+check([str(True)])
+
+test.run(arguments='x11=no')
+check([str(False)])
+
+test.run(arguments='x11=0')
+check([str(False)])
+
+test.run(arguments=['x11=%s' % test.workpath()])
+check([test.workpath()])
 
 expect_stderr = """
 scons: *** Path does not exist for option x11: /non/existing/path/
index 5ef5622463a337afd424e0d906353b0e2c1640fe..d3fa9ad0ba36a13b907cc970c45788d595b055b7 100644 (file)
@@ -31,6 +31,15 @@ Test the Options help messages.
 import os.path
 import string
 
+try:
+    True, False
+except NameError:
+    True = (0 == 0)
+    False = (0 != 0)
+
+str_True = str(True)
+str_False = str(False)
+
 import TestSCons
 
 test = TestSCons.TestSCons()
@@ -50,7 +59,7 @@ from SCons.Options import BoolOption, EnumOption, ListOption, \
    PackageOption, PathOption
 
 list_of_libs = Split('x11 gl qt ical')
-qtdir = r'%(qtdir)s'
+qtdir = r'%(qtpath)s'
 
 opts = Options(args=ARGUMENTS)
 opts.AddOptions(
@@ -85,23 +94,23 @@ print env['warnings']
 print env['profile']
 
 Default(env.Alias('dummy', None))
-""" % {'qtdir': qtpath, 'libdirvar': libdirvar, 'libdir': libpath})
+""" % locals())
 
 
 test.run(arguments='-h',
          stdout = """\
 scons: Reading SConscript files ...
-1
-0
+%(str_True)s
+%(str_False)s
 scons: done reading SConscript files.
 
 warnings: compilation with -Wall and similiar (yes|no)
     default: 1
-    actual: 1
+    actual: %(str_True)s
 
 profile: create profiling informations (yes|no)
     default: 0
-    actual: 0
+    actual: %(str_False)s
 
 debug: debug output and symbols (yes|no|full)
     default: no
@@ -124,19 +133,18 @@ shared: libraries to build as shared libraries
 x11: use X11 installed here (yes = search some places)
     ( yes | no | /path/to/x11 )
     default: yes
-    actual: 1
+    actual: %(str_True)s
 
 qtdir: where the root of Qt is installed ( /path/to/qtdir )
-    default: %(qtdir)s
-    actual: %(qtdir)s
+    default: %(qtpath)s
+    actual: %(qtpath)s
 
 qt_libraries: where the Qt library is installed ( /path/to/qt_libraries )
-    default: %(qtdir_lib)s
-    actual: %(libdir)s
+    default: %(libdirvar)s
+    actual: %(libpath)s
 
 Use scons -H for help about command-line options.
-""" % {'qtdir': qtpath, 'qtdir_lib' : os.path.join('$qtdir', 'lib'),
-       'libdirvar': libdirvar, 'libdir': libpath})
+""" % locals())
 
 
 
index f14278341ca265e16c127c463ceba473262c62b1..ed2227649971dc35867d0b865d92fe8cefa72d88 100644 (file)
@@ -55,8 +55,9 @@ test.write(test_config3, """\
 print "-L foo -L lib_dir -isysroot /tmp -arch ppc -arch i386"
 """)
 
-test.write('SConstruct', """
-env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '')
+test.write('SConstruct1', """
+env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
+                  CCFLAGS = '-pipe -Wall')
 env.ParseConfig([r'%(_python_)s', r"%(test_config1)s", "--libs --cflags"])
 env.ParseConfig([r'%(_python_)s', r"%(test_config2)s", "--libs --cflags"])
 print env['CPPPATH']
@@ -66,7 +67,8 @@ print env['CCFLAGS']
 """ % locals())
 
 test.write('SConstruct2', """
-env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '',
+env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
+                  CCFLAGS = '-pipe -Wall',
                   PYTHON = r'%(_python_)s')
 env.ParseConfig(r"$PYTHON %(test_config1)s --libs --cflags")
 env.ParseConfig(r"$PYTHON %(test_config2)s --libs --cflags")
@@ -77,7 +79,8 @@ print env['CCFLAGS']
 """ % locals())
 
 test.write('SConstruct3', """
-env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [], CCFLAGS = '',
+env = Environment(CPPPATH = [], LIBPATH = [], LIBS = [],
+                  CCFLAGS = '-pipe -Wall',
                   PYTHON = r'%(_python_)s')
 env.ParseConfig(r"$PYTHON %(test_config3)s --libs --cflags")
 print env['CPPPATH']
@@ -86,24 +89,24 @@ print map(lambda x: str(x), env['LIBS'])
 print env['CCFLAGS']
 """ % locals())
 
-good_stdout = test.wrap_stdout(read_str = """\
+good_stdout = """\
 ['/usr/include/fum', 'bar']
 ['/usr/fax', 'foo', 'lib_dir']
 ['xxx', 'abc']
-['-X', ('-arch', 'i386')]
-""", build_str = "scons: `.' is up to date.\n")
+['-pipe', '-Wall', '-X', ('-arch', 'i386')]
+"""
 
-stdout3 = test.wrap_stdout(read_str = """\
+stdout3 = """\
 []
 ['foo', 'lib_dir']
 []
-[('-isysroot', '/tmp'), ('-arch', 'ppc'), ('-arch', 'i386')]
-""", build_str = "scons: `.' is up to date.\n")
+['-pipe', '-Wall', ('-isysroot', '/tmp'), ('-arch', 'ppc'), ('-arch', 'i386')]
+"""
 
-test.run(arguments = ".", stdout = good_stdout)
+test.run(arguments = "-q -Q -f SConstruct1 .", stdout = good_stdout)
 
-test.run(arguments = "-f SConstruct2 .", stdout = good_stdout)
+test.run(arguments = "-q -Q -f SConstruct2 .", stdout = good_stdout)
 
-test.run(arguments = "-f SConstruct3 .", stdout = stdout3)
+test.run(arguments = "-q -Q -f SConstruct3 .", stdout = stdout3)
 
 test.pass_test()
index f73ab112010886cd70442c0bcb7ba9cea77320c7..2a3632eb5e227d8e862e2f166033118792a702cf 100644 (file)
@@ -46,21 +46,42 @@ test.write('SConstruct', """
 import os
 import string
 import sys
-def my_spawn(sh, escape, cmd, args, env):
-    s = string.join(args + ['extra.txt'])
+def my_spawn1(sh, escape, cmd, args, env):
+    s = string.join(args + ['extra1.txt'])
     if sys.platform in ['win32']:
         s = '"' + s + '"'
     os.system(s)
-env = Environment(SPAWN = my_spawn)
-env.Command('file.out', 'file.in', '%(_python_)s cat.py $TARGET $SOURCES')
-env = Environment()
+def my_spawn2(sh, escape, cmd, args, env):
+    s = string.join(args + ['extra2.txt'])
+    if sys.platform in ['win32']:
+        s = '"' + s + '"'
+    os.system(s)
+env = Environment(MY_SPAWN1 = my_spawn1,
+                  MY_SPAWN2 = my_spawn2,
+                  COMMAND = r'%(_python_)s cat.py $TARGET $SOURCES')
+env1 = env.Clone(SPAWN = my_spawn1)
+env1.Command('file1.out', 'file1.in', '$COMMAND')
+
+env2 = env.Clone(SPAWN = '$MY_SPAWN2')
+env2.Command('file2.out', 'file2.in', '$COMMAND')
+
+env3 = env.Clone(SPAWN = '${USE_TWO and MY_SPAWN2 or MY_SPAWN1}')
+env3.Command('file3.out', 'file3.in', '$COMMAND', USE_TWO=0)
+env3.Command('file4.out', 'file4.in', '$COMMAND', USE_TWO=1)
 """ % locals())
 
-test.write('file.in', "file.in\n")
-test.write('extra.txt', "extra.txt\n")
+test.write('file1.in', "file1.in\n")
+test.write('file2.in', "file2.in\n")
+test.write('file3.in', "file3.in\n")
+test.write('file4.in', "file4.in\n")
+test.write('extra1.txt', "extra1.txt\n")
+test.write('extra2.txt', "extra2.txt\n")
 
 test.run(arguments = '.')
 
-test.must_match('file.out', "file.in\nextra.txt\n")
+test.must_match('file1.out', "file1.in\nextra1.txt\n")
+test.must_match('file2.out', "file2.in\nextra2.txt\n")
+test.must_match('file3.out', "file3.in\nextra1.txt\n")
+test.must_match('file4.out', "file4.in\nextra2.txt\n")
 
 test.pass_test()
index 791d0e0dc97031b80090f4174061a3980346132c..dfee5ef2255429d0c8bab7f922fefdf45ecf2852 100644 (file)
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+"""
+Verify that the swig tool generates file names that we expect.
+"""
+
 import os
 import string
 import sys
@@ -37,19 +41,11 @@ if sys.platform =='darwin':
     python = "/System/Library/Frameworks/Python.framework/Versions/Current/bin/python"
     _python_ = '"' + python + '"'
 else:
-    python = TestSCons.python
     _python_ = TestSCons._python_
     
 _exe   = TestSCons._exe
 _obj   = TestSCons._obj
 
-# swig-python expects specific filenames.
-# the platform specific suffix won't necessarily work.
-if sys.platform == 'win32':
-    _dll = '.dll'
-else:
-    _dll   = '.so' 
-
 test = TestSCons.TestSCons()
 
 
@@ -105,168 +101,13 @@ swig
 test.run(arguments = '.', stderr = None)
 
 test.run(program = test.workpath('test1' + _exe), stdout = "test1.i\n")
-test.fail_test(not os.path.exists(test.workpath('test1_wrap.c')))
-test.fail_test(not os.path.exists(test.workpath('test1_wrap' + _obj)))
+test.must_exist(test.workpath('test1_wrap.c'))
+test.must_exist(test.workpath('test1_wrap' + _obj))
 
-test.fail_test(test.read('test2_wrap.c') != "test2.i\n")
+test.must_match('test2_wrap.c', "test2.i\n")
 
 test.run(program = test.workpath('test3' + _exe), stdout = "test3.i\n")
-test.fail_test(not os.path.exists(test.workpath('test3_wrap.cc')))
-test.fail_test(not os.path.exists(test.workpath('test3_wrap' + _obj)))
-
-
-
-swig = test.where_is('swig')
-
-if swig:
-
-    version = sys.version[:3] # see also sys.prefix documentation
-
-    # handle testing on other platforms:
-    ldmodule_prefix = '_'
-
-    frameworks = ''
-    platform_sys_prefix = sys.prefix
-    if sys.platform == 'darwin':
-        # OS X has a built-in Python but no static libpython
-        # so you should link to it using apple's 'framework' scheme.
-        # (see top of file for further explanation)
-        frameworks = '-framework Python'
-        platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
-    
-    test.write("wrapper.py",
-"""import os
-import string
-import sys
-open('%s', 'wb').write("wrapper.py\\n")
-os.system(string.join(sys.argv[1:], " "))
-""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
-
-    test.write('SConstruct', """
-foo = Environment(SWIGFLAGS='-python',
-                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
-                  LDMODULEPREFIX='%(ldmodule_prefix)s',
-                  LDMODULESUFFIX='%(_dll)s',
-                  FRAMEWORKSFLAGS='%(frameworks)s',
-                  )
-
-swig = foo.Dictionary('SWIG')
-bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig)
-foo.LoadableModule(target = 'foo', source = ['foo.c', 'foo.i'])
-bar.LoadableModule(target = 'bar', source = ['bar.c', 'bar.i'])
-""" % locals())
-
-    test.write("foo.c", """\
-char *
-foo_string()
-{
-    return "This is foo.c!";
-}
-""")
-
-    test.write("foo.i", """\
-%module foo
-%{
-/* Put header files here (optional) */
-%}
-
-extern char *foo_string();
-""")
-
-    test.write("bar.c", """\
-char *
-bar_string()
-{
-    return "This is bar.c!";
-}
-""")
-
-    test.write("bar.i", """\
-%module \t bar
-%{
-/* Put header files here (optional) */
-%}
-
-extern char *bar_string();
-""")
-
-    test.run(arguments = ldmodule_prefix+'foo' + _dll)
-
-    test.must_not_exist(test.workpath('wrapper.out'))
-
-    test.run(program = python, stdin = """\
-import foo
-print foo.foo_string()
-""", stdout="""\
-This is foo.c!
-""")
-
-    test.up_to_date(arguments = ldmodule_prefix+'foo' + _dll)
-
-    test.run(arguments = ldmodule_prefix+'bar' + _dll)
-
-    test.must_match('wrapper.out', "wrapper.py\n")
-
-    test.run(program = python, stdin = """\
-import foo
-import bar
-print foo.foo_string()
-print bar.bar_string()
-""", stdout="""\
-This is foo.c!
-This is bar.c!
-""")
-
-    test.up_to_date(arguments = '.')
-
-    # Test that swig-generated modules are removed
-    # The %module directive specifies the module name
-    test.write("module.i", """\
-%module modulename
-""")
-    test.write('SConstruct', """
-foo = Environment(SWIGFLAGS='-python',
-                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
-                  LDMODULEPREFIX='%(ldmodule_prefix)s',
-                  LDMODULESUFFIX='%(_dll)s',
-                  FRAMEWORKSFLAGS='%(frameworks)s',
-                  )
-
-foo.LoadableModule(target = 'modulename', source = ['module.i'])
-""" % locals())
-    test.run()
-    test.must_exist(test.workpath("modulename.py"))
-    test.run(arguments = "-c")
-    test.must_not_exist(test.workpath("modulename.py"))
-
-    # Test that implicit dependencies are caught
-
-    test.write("dependency.i", """\
-%module dependency
-""")
-    test.write("dependent.i", """\
-%module dependent
-
-%include dependency.i
-""")
-    test.write('SConstruct', """
-foo = Environment(SWIGFLAGS='-python',
-                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
-                  LDMODULEPREFIX='%(ldmodule_prefix)s',
-                  LDMODULESUFFIX='%(_dll)s',
-                  FRAMEWORKSFLAGS='%(frameworks)s',
-                  )
-
-swig = foo.Dictionary('SWIG')
-bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig)
-foo.CFile(target = 'dependent', source = ['dependent.i'])
-""" % locals())
-
-    test.run()
-    test.write("dependency.i", """%module dependency
-
-extern char *dependency_string();
-""")
-    test.not_up_to_date(arguments = "dependent_wrap.c")
+test.must_exist(test.workpath('test3_wrap.cc'))
+test.must_exist(test.workpath('test3_wrap' + _obj))
 
 test.pass_test()
diff --git a/test/SWIG/implicit-dependencies.py b/test/SWIG/implicit-dependencies.py
new file mode 100644 (file)
index 0000000..55645a4
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that SWIG implicit dependencies are caught.
+"""
+
+import sys
+
+import TestSCons
+
+if sys.platform =='darwin':
+    # change to make it work with stock OS X python framework
+    # we can't link to static libpython because there isn't one on OS X
+    # so we link to a framework version. However, testing must also
+    # use the same version, or else you get interpreter errors.
+    python = "/System/Library/Frameworks/Python.framework/Versions/Current/bin/python"
+    _python_ = '"' + python + '"'
+else:
+    python = TestSCons.python
+    _python_ = TestSCons._python_
+
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+    _dll = '.dll'
+else:
+    _dll   = '.so' 
+
+test = TestSCons.TestSCons()
+
+swig = test.where_is('swig')
+
+if not swig:
+    test.skip_test('Can not find installed "swig", skipping test.\n')
+
+
+
+version = sys.version[:3] # see also sys.prefix documentation
+
+# handle testing on other platforms:
+ldmodule_prefix = '_'
+
+frameworks = ''
+platform_sys_prefix = sys.prefix
+if sys.platform == 'darwin':
+    # OS X has a built-in Python but no static libpython
+    # so you should link to it using apple's 'framework' scheme.
+    # (see top of file for further explanation)
+    frameworks = '-framework Python'
+    platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
+
+test.write("dependency.i", """\
+%module dependency
+""")
+
+test.write("dependent.i", """\
+%module dependent
+
+%include dependency.i
+""")
+
+test.write('SConstruct', """
+foo = Environment(SWIGFLAGS='-python',
+                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
+                  LDMODULEPREFIX='%(ldmodule_prefix)s',
+                  LDMODULESUFFIX='%(_dll)s',
+                  FRAMEWORKSFLAGS='%(frameworks)s',
+                  )
+
+swig = foo.Dictionary('SWIG')
+bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig)
+foo.CFile(target = 'dependent', source = ['dependent.i'])
+""" % locals())
+
+test.run()
+
+test.write("dependency.i", """%module dependency
+
+extern char *dependency_string();
+""")
+
+test.not_up_to_date(arguments = "dependent_wrap.c")
+
+
+
+test.pass_test()
diff --git a/test/SWIG/live.py b/test/SWIG/live.py
new file mode 100644 (file)
index 0000000..c6b45d2
--- /dev/null
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test SWIG behavior with a live, installed SWIG.
+"""
+
+import string
+import sys
+
+import TestSCons
+
+if sys.platform =='darwin':
+    # change to make it work with stock OS X python framework
+    # we can't link to static libpython because there isn't one on OS X
+    # so we link to a framework version. However, testing must also
+    # use the same version, or else you get interpreter errors.
+    python = "/System/Library/Frameworks/Python.framework/Versions/Current/bin/python"
+    _python_ = '"' + python + '"'
+else:
+    python = TestSCons.python
+    _python_ = TestSCons._python_
+
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+    _dll = '.dll'
+else:
+    _dll   = '.so' 
+
+test = TestSCons.TestSCons()
+
+swig = test.where_is('swig')
+
+if not swig:
+    test.skip_test('Can not find installed "swig", skipping test.\n')
+
+
+
+version = sys.version[:3] # see also sys.prefix documentation
+
+# handle testing on other platforms:
+ldmodule_prefix = '_'
+
+frameworks = ''
+platform_sys_prefix = sys.prefix
+if sys.platform == 'darwin':
+    # OS X has a built-in Python but no static libpython
+    # so you should link to it using apple's 'framework' scheme.
+    # (see top of file for further explanation)
+    frameworks = '-framework Python'
+    platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
+    
+test.write("wrapper.py",
+"""import os
+import string
+import sys
+open('%s', 'wb').write("wrapper.py\\n")
+os.system(string.join(sys.argv[1:], " "))
+""" % string.replace(test.workpath('wrapper.out'), '\\', '\\\\'))
+
+test.write('SConstruct', """
+foo = Environment(SWIGFLAGS='-python',
+                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
+                  LDMODULEPREFIX='%(ldmodule_prefix)s',
+                  LDMODULESUFFIX='%(_dll)s',
+                  FRAMEWORKSFLAGS='%(frameworks)s',
+                  )
+
+swig = foo.Dictionary('SWIG')
+bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig)
+foo.LoadableModule(target = 'foo', source = ['foo.c', 'foo.i'])
+bar.LoadableModule(target = 'bar', source = ['bar.c', 'bar.i'])
+""" % locals())
+
+test.write("foo.c", """\
+char *
+foo_string()
+{
+    return "This is foo.c!";
+}
+""")
+
+test.write("foo.i", """\
+%module foo
+%{
+/* Put header files here (optional) */
+%}
+
+extern char *foo_string();
+""")
+
+test.write("bar.c", """\
+char *
+bar_string()
+{
+    return "This is bar.c!";
+}
+""")
+
+test.write("bar.i", """\
+%module \t bar
+%{
+/* Put header files here (optional) */
+%}
+
+extern char *bar_string();
+""")
+
+test.run(arguments = ldmodule_prefix+'foo' + _dll)
+
+test.must_not_exist(test.workpath('wrapper.out'))
+
+test.run(program = python, stdin = """\
+import foo
+print foo.foo_string()
+""", stdout="""\
+This is foo.c!
+""")
+
+test.up_to_date(arguments = ldmodule_prefix+'foo' + _dll)
+
+test.run(arguments = ldmodule_prefix+'bar' + _dll)
+
+test.must_match('wrapper.out', "wrapper.py\n")
+
+test.run(program = python, stdin = """\
+import foo
+import bar
+print foo.foo_string()
+print bar.bar_string()
+""", stdout="""\
+This is foo.c!
+This is bar.c!
+""")
+
+test.up_to_date(arguments = '.')
+
+
+
+test.pass_test()
diff --git a/test/SWIG/noproxy.py b/test/SWIG/noproxy.py
new file mode 100644 (file)
index 0000000..c0f6da6
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that SCons realizes the -noproxy option means no .py file will
+be created.
+"""
+
+import sys
+
+import TestSCons
+
+if sys.platform =='darwin':
+    # change to make it work with stock OS X python framework
+    # we can't link to static libpython because there isn't one on OS X
+    # so we link to a framework version. However, testing must also
+    # use the same version, or else you get interpreter errors.
+    python = "/System/Library/Frameworks/Python.framework/Versions/Current/bin/python"
+    _python_ = '"' + python + '"'
+else:
+    python = TestSCons.python
+    _python_ = TestSCons._python_
+
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+    _dll = '.dll'
+else:
+    _dll   = '.so' 
+
+test = TestSCons.TestSCons()
+
+swig = test.where_is('swig')
+
+if not swig:
+    test.skip_test('Can not find installed "swig", skipping test.\n')
+
+
+
+version = sys.version[:3] # see also sys.prefix documentation
+
+# handle testing on other platforms:
+ldmodule_prefix = '_'
+
+frameworks = ''
+platform_sys_prefix = sys.prefix
+if sys.platform == 'darwin':
+    # OS X has a built-in Python but no static libpython
+    # so you should link to it using apple's 'framework' scheme.
+    # (see top of file for further explanation)
+    frameworks = '-framework Python'
+    platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
+
+test.write("dependency.i", """\
+%module dependency
+""")
+
+test.write("dependent.i", """\
+%module dependent
+
+%include dependency.i
+""")
+
+test.write('SConstruct', """
+foo = Environment(SWIGFLAGS=['-python', '-noproxy'],
+                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
+                  LDMODULEPREFIX='%(ldmodule_prefix)s',
+                  LDMODULESUFFIX='%(_dll)s',
+                  FRAMEWORKSFLAGS='%(frameworks)s',
+                  )
+
+swig = foo.Dictionary('SWIG')
+bar = foo.Clone(SWIG = r'%(_python_)s wrapper.py ' + swig)
+foo.CFile(target = 'dependent', source = ['dependent.i'])
+""" % locals())
+
+test.run(arguments = '.')
+
+# If we mistakenly depend on the .py file that SWIG didn't create
+# (suppressed by the -noproxy option) then the build won't be up-to-date.
+test.up_to_date(arguments = '.')
+
+
+
+test.pass_test()
diff --git a/test/SWIG/remove-modules.py b/test/SWIG/remove-modules.py
new file mode 100644 (file)
index 0000000..cac9677
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that swig-generated modules are removed.
+The %module directive specifies the module name.
+"""
+
+import sys
+
+import TestSCons
+
+# swig-python expects specific filenames.
+# the platform specific suffix won't necessarily work.
+if sys.platform == 'win32':
+    _dll = '.dll'
+else:
+    _dll   = '.so' 
+
+test = TestSCons.TestSCons()
+
+swig = test.where_is('swig')
+
+if not swig:
+    test.skip_test('Can not find installed "swig", skipping test.\n')
+
+
+
+version = sys.version[:3] # see also sys.prefix documentation
+
+# handle testing on other platforms:
+ldmodule_prefix = '_'
+
+frameworks = ''
+platform_sys_prefix = sys.prefix
+if sys.platform == 'darwin':
+    # OS X has a built-in Python but no static libpython
+    # so you should link to it using apple's 'framework' scheme.
+    # (see top of file for further explanation)
+    frameworks = '-framework Python'
+    platform_sys_prefix = '/System/Library/Frameworks/Python.framework/Versions/%s/' % version
+    
+
+test.write("module.i", """\
+%module modulename
+""")
+
+test.write('SConstruct', """
+foo = Environment(SWIGFLAGS='-python',
+                  CPPPATH='%(platform_sys_prefix)s/include/python%(version)s/',
+                  LDMODULEPREFIX='%(ldmodule_prefix)s',
+                  LDMODULESUFFIX='%(_dll)s',
+                  FRAMEWORKSFLAGS='%(frameworks)s',
+                  )
+
+foo.LoadableModule(target = 'modulename', source = ['module.i'])
+""" % locals())
+
+test.run()
+
+test.must_exist(test.workpath("modulename.py"))
+
+test.run(arguments = "-c")
+
+test.must_not_exist(test.workpath("modulename.py"))
+
+
+
+test.pass_test()
diff --git a/test/Scanner/dictionary.py b/test/Scanner/dictionary.py
new file mode 100644 (file)
index 0000000..62fda9b
--- /dev/null
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify
+"""
+
+import TestSCons
+
+_python_ = TestSCons._python_
+
+test = TestSCons.TestSCons()
+
+test.write('build.py', r"""
+import sys
+input = open(sys.argv[1], 'rb')
+output = open(sys.argv[2], 'wb')
+
+include_prefix = 'include%s ' % sys.argv[1][-1]
+
+def process(infp, outfp):
+    for line in infp.readlines():
+        if line[:len(include_prefix)] == include_prefix:
+            file = line[len(include_prefix):-1]
+            process(open(file, 'rb'), outfp)
+        else:
+            outfp.write(line)
+
+process(input, output)
+
+sys.exit(0)
+""")
+
+# Execute a subsidiary SConscript just to make sure we can
+# get at the Scanner keyword from there.
+
+test.write('SConstruct', """
+SConscript('SConscript')
+""")
+
+test.write('SConscript', """
+import re
+
+include1_re = re.compile(r'^include1\s+(\S+)$', re.M)
+include2_re = re.compile(r'^include2\s+(\S+)$', re.M)
+include3_re = re.compile(r'^include3\s+(\S+)$', re.M)
+
+def kfile_scan1(node, env, scanpaths, arg=None):
+    contents = node.get_contents()
+    includes = include1_re.findall(contents)
+    return includes
+
+def kfile_scan2(node, env, scanpaths, arg=None):
+    contents = node.get_contents()
+    includes = include2_re.findall(contents)
+    return includes
+
+def kfile_scan3(node, env, scanpaths, arg=None):
+    contents = node.get_contents()
+    includes = include3_re.findall(contents)
+    return includes
+
+scan1 = Scanner(kfile_scan1)
+
+scan2 = Scanner(kfile_scan2)
+
+scan3 = Scanner(kfile_scan3)
+
+kscanner = Scanner({'.k1' : scan1, '.k2': scan2})
+
+env = Environment(SCANNERS = [kscanner])
+
+kscanner.add_scanner('.k3', scan3)
+
+env.Command('aaa', 'aaa.k1', r'%(_python_)s build.py $SOURCES $TARGET')
+env.Command('bbb', 'bbb.k2', r'%(_python_)s build.py $SOURCES $TARGET')
+env.Command('ccc', 'ccc.k3', r'%(_python_)s build.py $SOURCES $TARGET')
+""" % locals())
+
+test.write('aaa.k1', 
+"""aaa.k1 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('bbb.k2', 
+"""bbb.k2 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('ccc.k3', 
+"""ccc.k3 1
+line 2
+include1 xxx
+include2 yyy
+include3 zzz
+line 6
+""")
+
+test.write('xxx', "xxx 1\n")
+test.write('yyy', "yyy 1\n")
+test.write('zzz', "zzz 1\n")
+
+
+
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py aaa.k1 aaa
+%(_python_)s build.py bbb.k2 bbb
+%(_python_)s build.py ccc.k3 ccc
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_aaa = 'aaa.k1 1\nline 2\nxxx 1\ninclude2 yyy\ninclude3 zzz\nline 6\n'
+expect_bbb = 'bbb.k2 1\nline 2\ninclude1 xxx\nyyy 1\ninclude3 zzz\nline 6\n'
+expect_ccc = 'ccc.k3 1\nline 2\ninclude1 xxx\ninclude2 yyy\nzzz 1\nline 6\n'
+
+test.must_match('aaa', expect_aaa)
+test.must_match('bbb', expect_bbb)
+test.must_match('ccc', expect_ccc)
+
+test.up_to_date(arguments = '.')
+
+
+
+test.write('zzz', "zzz 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py ccc.k3 ccc
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_ccc = 'ccc.k3 1\nline 2\ninclude1 xxx\ninclude2 yyy\nzzz 2\nline 6\n'
+
+test.must_match('bbb', expect_bbb)
+
+
+
+test.write('yyy', "yyy 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py bbb.k2 bbb
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_bbb = 'bbb.k2 1\nline 2\ninclude1 xxx\nyyy 2\ninclude3 zzz\nline 6\n'
+
+test.must_match('bbb', expect_bbb)
+
+
+
+test.write('xxx', "xxx 2\n")
+
+expect = test.wrap_stdout("""\
+%(_python_)s build.py aaa.k1 aaa
+""" % locals())
+
+test.run(stdout=expect)
+
+expect_aaa = 'aaa.k1 1\nline 2\nxxx 2\ninclude2 yyy\ninclude3 zzz\nline 6\n'
+
+test.must_match('bbb', expect_bbb)
+
+
+
+test.pass_test()
index 4dd8d914e7eab43dd0f1470c506fda8998fe5491..544960bba95eecc1734705388f6661972a6e1b4d 100644 (file)
@@ -65,12 +65,12 @@ SCons.Script.OptParser
 SCons.Script.SConscriptSettableOptions
 
 SCons.Script.keep_going_on_error
-SCons.Script.print_dtree
+#SCons.Script.print_dtree
 SCons.Script.print_explanations
 SCons.Script.print_includes
 SCons.Script.print_objects
 SCons.Script.print_time
-SCons.Script.print_tree
+#SCons.Script.print_tree
 SCons.Script.memory_stats
 SCons.Script.ignore_errors
 #SCons.Script.sconscript_time
index 8ffadc6d46e09067a3cd12432f9ac8e3349f691b..21ca38661df9394818614145de5e01629a36f49e 100644 (file)
@@ -73,40 +73,41 @@ test.write('bar.h', """
 """)
 
 stree = """
-[E B   C ]+-foo.xxx
-[E B   C ]  +-foo.ooo
-[E       ]  | +-foo.c
-[E       ]  | +-foo.h
-[E       ]  | +-bar.h
-[E B   C ]  +-bar.ooo
-[E       ]    +-bar.c
-[E       ]    +-bar.h
-[E       ]    +-foo.h
+[E B   C  ]+-foo.xxx
+[E B   C  ]  +-foo.ooo
+[E        ]  | +-foo.c
+[E        ]  | +-foo.h
+[E        ]  | +-bar.h
+[E B   C  ]  +-bar.ooo
+[E        ]    +-bar.c
+[E        ]    +-bar.h
+[E        ]    +-foo.h
 """
 
 test.run(arguments = "--debug=stree foo.xxx")
 test.fail_test(string.find(test.stdout(), stree) == -1)
 
 stree2 = """
- E        = exists
-  R       = exists in repository only
-   b      = implicit builder
-   B      = explicit builder
-    S     = side effect
-     P    = precious
-      A   = always build
-       C  = current
-        N = no clean
-
-[  B     ]+-foo.xxx
-[  B     ]  +-foo.ooo
-[E       ]  | +-foo.c
-[E       ]  | +-foo.h
-[E       ]  | +-bar.h
-[  B     ]  +-bar.ooo
-[E       ]    +-bar.c
-[E       ]    +-bar.h
-[E       ]    +-foo.h
+ E         = exists
+  R        = exists in repository only
+   b       = implicit builder
+   B       = explicit builder
+    S      = side effect
+     P     = precious
+      A    = always build
+       C   = current
+        N  = no clean
+         H = no cache
+
+[  B      ]+-foo.xxx
+[  B      ]  +-foo.ooo
+[E        ]  | +-foo.c
+[E        ]  | +-foo.h
+[E        ]  | +-bar.h
+[  B      ]  +-bar.ooo
+[E        ]    +-bar.c
+[E        ]    +-bar.h
+[E        ]    +-foo.h
 """
 
 test.run(arguments = '-c foo.xxx')
diff --git a/test/option/repository.py b/test/option/repository.py
new file mode 100644 (file)
index 0000000..d30cbec
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the --srcdir option works to fetch things from a repository.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('repository', 'work1')
+
+repository = test.workpath('repository')
+
+test.write(['repository', 'SConstruct'], """\
+env = Environment()
+env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write(['repository', 'file.in'], "repository/file.in\n")
+
+opts = '--repository ' + repository
+
+# Make the entire repository non-writable, so we'll detect
+# if we try to write into it accidentally.
+test.writable('repository', 0)
+
+test.run(chdir = 'work1', options = opts, arguments = '.')
+
+test.must_match(['work1', 'file.out'], "repository/file.in\n")
+
+test.up_to_date(chdir = 'work1', options = opts, arguments = '.')
+
+
+
+#
+test.pass_test()
diff --git a/test/option/srcdir.py b/test/option/srcdir.py
new file mode 100644 (file)
index 0000000..b6bcc59
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that the --srcdir option works to fetch things from a repository.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('repository', 'work1')
+
+repository = test.workpath('repository')
+
+test.write(['repository', 'SConstruct'], r"""
+env = Environment()
+env.Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write(['repository', 'file.in'], "repository/file.in\n")
+
+opts = '--srcdir ' + repository
+
+# Make the entire repository non-writable, so we'll detect
+# if we try to write into it accidentally.
+test.writable('repository', 0)
+
+test.run(chdir = 'work1', options = opts, arguments = '.')
+
+test.must_match(['work1', 'file.out'], "repository/file.in\n")
+
+test.up_to_date(chdir = 'work1', options = opts, arguments = '.')
+
+
+
+#
+test.pass_test()
diff --git a/test/option/tree-all.py b/test/option/tree-all.py
new file mode 100644 (file)
index 0000000..92b9065
--- /dev/null
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that the --tree=all option prints a tree representation of the
+complete dependencies of a target.
+"""
+
+import TestSCons
+import sys
+import string
+import re
+import time
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx')
+env.Program('Foo', Split('Foo.c Bar.c'))
+""")
+
+# N.B.:  We use upper-case file names (Foo* and Bar*) so that the sorting
+# order with our upper-case SConstruct file is the same on case-sensitive
+# (UNIX/Linux) and case-insensitive (Windows) systems.
+
+test.write('Foo.c', r"""
+#include <stdio.h>
+#include <stdlib.h>
+#include "Foo.h"
+int main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf("f1.c\n");
+        exit (0);
+}
+""")
+
+test.write('Bar.c', """
+#include "Bar.h"
+""")
+
+test.write('Foo.h', """
+#ifndef FOO_H
+#define FOO_H
+#include "Bar.h"
+#endif
+""")
+
+test.write('Bar.h', """
+#ifndef BAR_H
+#define BAR_H
+#include "Foo.h"
+#endif
+""")
+
+tree1 = """
++-Foo.xxx
+  +-Foo.ooo
+  | +-Foo.c
+  | +-Foo.h
+  | +-Bar.h
+  +-Bar.ooo
+    +-Bar.c
+    +-Bar.h
+    +-Foo.h
+"""
+
+test.run(arguments = "--tree=all Foo.xxx")
+test.fail_test(string.find(test.stdout(), tree1) == -1)
+
+tree2 = """
++-.
+  +-Bar.c
+  +-Bar.ooo
+  | +-Bar.c
+  | +-Bar.h
+  | +-Foo.h
+  +-Foo.c
+  +-Foo.ooo
+  | +-Foo.c
+  | +-Foo.h
+  | +-Bar.h
+  +-Foo.xxx
+  | +-Foo.ooo
+  | | +-Foo.c
+  | | +-Foo.h
+  | | +-Bar.h
+  | +-Bar.ooo
+  |   +-Bar.c
+  |   +-Bar.h
+  |   +-Foo.h
+  +-SConstruct
+"""
+
+test.run(arguments = "--tree=all .")
+test.fail_test(string.find(test.stdout(), tree2) == -1)
+
+tree3 = """
++-.
+  +-Bar.c
+  +-Bar.ooo
+  | +-[Bar.c]
+  | +-Bar.h
+  | +-Foo.h
+  +-Foo.c
+  +-Foo.ooo
+  | +-[Foo.c]
+  | +-[Foo.h]
+  | +-[Bar.h]
+  +-Foo.xxx
+  | +-[Foo.ooo]
+  | +-[Bar.ooo]
+  +-SConstruct
+"""
+
+test.run(arguments = "--tree=all,prune .")
+test.fail_test(string.find(test.stdout(), tree3) == -1)
+
+test.run(arguments = "--tree=prune .")
+test.fail_test(string.find(test.stdout(), tree3) == -1)
+
+tree4 = """
+ E         = exists
+  R        = exists in repository only
+   b       = implicit builder
+   B       = explicit builder
+    S      = side effect
+     P     = precious
+      A    = always build
+       C   = current
+        N  = no clean
+         H = no cache
+
+[  B      ]+-Foo.xxx
+[  B      ]  +-Foo.ooo
+[E        ]  | +-Foo.c
+[E        ]  | +-Foo.h
+[E        ]  | +-Bar.h
+[  B      ]  +-Bar.ooo
+[E        ]    +-Bar.c
+[E        ]    +-Bar.h
+[E        ]    +-Foo.h
+"""
+
+test.run(arguments = '-c Foo.xxx')
+
+test.run(arguments = "--no-exec --tree=all,status Foo.xxx")
+test.fail_test(string.find(test.stdout(), tree4) == -1)
+
+test.run(arguments = "--no-exec --tree=status Foo.xxx")
+test.fail_test(string.find(test.stdout(), tree4) == -1)
+
+# Make sure we print the debug stuff even if there's a build failure.
+test.write('Bar.h', """
+#ifndef BAR_H
+#define BAR_H
+#include "Foo.h"
+#endif
+THIS SHOULD CAUSE A BUILD FAILURE
+""")
+
+test.run(arguments = "--tree=all Foo.xxx",
+         status = 2,
+         stderr = None)
+test.fail_test(string.find(test.stdout(), tree1) == -1)
+
+test.pass_test()
diff --git a/test/option/tree-derived.py b/test/option/tree-derived.py
new file mode 100644 (file)
index 0000000..a10faa2
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Test that the --debug=dtree option correctly prints just the explicit
+dependencies (sources or Depends()) of a target.
+"""
+
+import TestSCons
+import sys
+import string
+import re
+import time
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env = Environment(OBJSUFFIX = '.ooo', PROGSUFFIX = '.xxx')
+env.Program('foo', Split('foo.c bar.c'))
+""")
+
+test.write('foo.c', r"""
+#include <stdio.h>
+#include <stdlib.h>
+#include "foo.h"
+int main(int argc, char *argv[])
+{
+        argv[argc++] = "--";
+        printf("f1.c\n");
+        exit (0);
+}
+""")
+
+test.write('bar.c', """
+#include "bar.h"
+""")
+
+test.write('foo.h', """
+#ifndef FOO_H
+#define FOO_H
+#include "bar.h"
+#endif
+""")
+
+test.write('bar.h', """
+#ifndef BAR_H
+#define BAR_H
+#include "foo.h"
+#endif
+""")
+
+dtree1 = """
++-foo.xxx
+  +-foo.ooo
+  +-bar.ooo
+"""
+
+test.run(arguments = "--tree=derived foo.xxx")
+test.fail_test(string.find(test.stdout(), dtree1) == -1)
+
+dtree2 = """
++-.
+  +-bar.ooo
+  +-foo.ooo
+  +-foo.xxx
+    +-foo.ooo
+    +-bar.ooo
+"""
+
+test.run(arguments = "--tree=derived .")
+test.fail_test(string.find(test.stdout(), dtree2) == -1)
+
+dtree3 = """
++-.
+  +-bar.ooo
+  +-foo.ooo
+  +-foo.xxx
+    +-[foo.ooo]
+    +-[bar.ooo]
+"""
+
+test.run(arguments = "--tree=derived,prune .")
+test.fail_test(string.find(test.stdout(), dtree3) == -1)
+
+dtree4 = """
+ E         = exists
+  R        = exists in repository only
+   b       = implicit builder
+   B       = explicit builder
+    S      = side effect
+     P     = precious
+      A    = always build
+       C   = current
+        N  = no clean
+         H = no cache
+
+[  B      ]+-foo.xxx
+[  B      ]  +-foo.ooo
+[  B      ]  +-bar.ooo
+"""
+
+test.run(arguments = '-c foo.xxx')
+
+test.run(arguments = "--no-exec --tree=derived,status foo.xxx")
+test.fail_test(string.find(test.stdout(), dtree4) == -1)
+
+# Make sure we print the debug stuff even if there's a build failure.
+test.write('bar.h', """
+#ifndef BAR_H
+#define BAR_H
+#include "foo.h"
+#endif
+THIS SHOULD CAUSE A BUILD FAILURE
+""")
+
+test.run(arguments = "--tree=derived foo.xxx",
+         status = 2,
+         stderr = None)
+test.fail_test(string.find(test.stdout(), dtree1) == -1)
+
+test.pass_test()
diff --git a/test/site_scons/basic.py b/test/site_scons/basic.py
new file mode 100644 (file)
index 0000000..ed2e1d5
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+
+"""
+Verify basic functionality of the site_scons dir and
+site_scons/site_init.py file:
+Make sure the site_scons/site_init.py file gets loaded,
+and make sure a tool can be loaded from the site_scons/site_tools subdir,
+even when executing out of a subdirectory.
+"""
+
+test = TestSCons.TestSCons()
+
+test.subdir('site_scons', ['site_scons', 'site_tools'])
+
+test.write(['site_scons', 'site_init.py'], """
+from SCons.Script import *
+print "Hi there, I am in site_scons/site_init.py!"
+""")
+
+test.write(['site_scons', 'site_tools', 'mytool.py'], """
+import SCons.Tool
+def generate(env):
+    env['MYTOOL']='mytool'
+def exists(env):
+    return 1
+""")
+
+
+test.write('SConstruct', """
+e=Environment(tools=['default', 'mytool'])
+print e.subst('My site tool is $MYTOOL')
+""")
+
+test.run(arguments = '-Q .',
+         stdout = """Hi there, I am in site_scons/site_init.py!
+My site tool is mytool
+scons: `.' is up to date.\n""")
+
+
+
+test.pass_test()
+
+# end of file
diff --git a/test/site_scons/no-site-dir.py b/test/site_scons/no-site-dir.py
new file mode 100644 (file)
index 0000000..6f2f26e
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify use of the --no-site-dir option:
+the site_scons/site_init.py script should NOT be loaded.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('site_scons', ['site_scons', 'site_tools'])
+
+test.write(['site_scons', 'site_init.py'], """
+from SCons.Script import *
+print "Hi there, I am in site_scons/site_init.py!"
+""")
+
+test.write(['site_scons', 'site_tools', 'mytool.py'], """
+import SCons.Tool
+def generate(env):
+    env['MYTOOL']='mytool'
+def exists(env):
+    return 1
+""")
+
+test.write(['site_scons', 'site_tools', 'm4.py'], """
+import SCons.Tool
+def generate(env):
+    env['M4']='my_m4'
+    env['M4_MINE']=1
+def exists(env):
+    return 1
+""")
+
+test.write('SConstruct', """
+e=Environment()
+""")
+
+test.run(arguments = '-Q --no-site-dir .',
+         stdout = "scons: `.' is up to date.\n")
+
+# With --no-site-dir, shouldn't override default m4 tool
+
+test.write('SConstruct', """
+e=Environment()
+print e.subst('no site: M4 is $M4, M4_MINE is $M4_MINE')
+""")
+
+test.run(arguments = '-Q --no-site-dir .',
+stdout = """no site: M4 is m4, M4_MINE is
+scons: `.' is up to date.\n""")
+
+
+
+test.pass_test()
+
+# end of file
diff --git a/test/site_scons/nonexistent.py b/test/site_scons/nonexistent.py
new file mode 100644 (file)
index 0000000..2185304
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that specifying --site-dir= with a nonexistent directory
+gives an error and nonzero status.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', "\n")
+
+test.run(arguments = '-Q --site-dir=whatever .',
+         stderr = r".*site dir .*whatever not found.*",
+         status = 2, 
+         match = TestSCons.match_re_dotall)
+
+
+
+test.pass_test()
+
+# end of file
diff --git a/test/site_scons/override.py b/test/site_scons/override.py
new file mode 100644 (file)
index 0000000..ebe56a6
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+
+"""
+Verify that a that a tool module in site_tools overrides base tool.
+
+Use 'm4' as test tool since it's likely to be found,
+and not commonly overridden by platform-specific stuff the way cc is.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('site_scons', ['site_scons', 'site_tools'])
+
+test.write(['site_scons', 'site_tools', 'm4.py'], """
+import SCons.Tool
+def generate(env):
+    env['M4']='my_m4'
+    env['M4_MINE']=1
+def exists(env):
+    return 1
+""")
+
+test.write('SConstruct', """
+e=Environment()
+print e.subst('M4 is $M4, M4_MINE is $M4_MINE')
+""")
+test.run(arguments = '-Q .',
+         stdout = """M4 is my_m4, M4_MINE is 1
+scons: `.' is up to date.\n""")
+
+
+
+test.pass_test()
+
+# end of file
diff --git a/test/site_scons/site-dir.py b/test/site_scons/site-dir.py
new file mode 100644 (file)
index 0000000..a05817e
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that --site-dir=otherdir loads the site_init.py script
+from the other dir;
+the usual site_scons/site_init.py should NOT be loaded.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('site_scons', ['site_scons', 'site_tools'])
+
+test.write(['site_scons', 'site_init.py'], """
+from SCons.Script import *
+print "Hi there, I am in site_scons/site_init.py!"
+""")
+
+test.write(['site_scons', 'site_tools', 'mytool.py'], """
+import SCons.Tool
+def generate(env):
+    env['MYTOOL']='mytool'
+def exists(env):
+    return 1
+""")
+
+
+
+test.subdir('alt_site', ['alt_site', 'site_tools'])
+
+test.write(['alt_site', 'site_init.py'], """
+from SCons.Script import *
+print "Hi there, I am in alt_site/site_init.py!"
+""")
+
+test.write('SConstruct', """
+e=Environment()
+""")
+
+test.run(arguments = '-Q --site-dir=alt_site .',
+         stdout = """Hi there, I am in alt_site/site_init.py!
+scons: `.' is up to date.\n""")
+
+
+
+test.pass_test()
+
+# end of file
diff --git a/test/toolpath/BuildDir.py b/test/toolpath/BuildDir.py
new file mode 100644 (file)
index 0000000..a8b8b8a
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+"""
+Verify that toolpath works with BuildDir() for an SConscript.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('subdir', ['subdir', 'src'], ['subdir', 'src', 'tools'])
+
+test.write('SConstruct', """\
+BuildDir('build', 'subdir', duplicate=0)
+SConscript('build/SConscript')
+""")
+
+test.write(['subdir', 'SConscript'], """\
+env = Environment(tools = ['MyBuilder'], toolpath = ['src/tools'])
+env.MyCopy('src/file.out', 'src/file.in')
+""")
+
+test.write(['subdir', 'src', 'file.in'], "subdir/src/file.in\n")
+
+test.write(['subdir', 'src', 'tools', 'MyBuilder.py'], """\
+from SCons.Script import Builder
+def generate(env):
+    def my_copy(target, source, env):
+        content = open(str(source[0]), 'rb').read()
+        open(str(target[0]), 'wb').write(content)
+    env['BUILDERS']['MyCopy'] = Builder(action = my_copy)
+
+def exists(env):
+    return 1
+""")
+
+test.run()
+
+test.must_match(['build', 'src', 'file.out'], "subdir/src/file.in\n")
+
+# We should look for the underlying tool in both the build/src/tools
+# (which doesn't exist) and subdir/src/tools (which still does).  If we
+# don't, the following would fail because the execution directory is
+# now relative to the created BuildDir.
+test.run()
+
+test.pass_test()
similarity index 100%
rename from test/toolpath.py
rename to test/toolpath/basic.py