From ba4425ab5227fd9597fccd368bffff6bf1032149 Mon Sep 17 00:00:00 2001 From: Luca Falavigna Date: Sat, 10 Sep 2011 11:25:53 +0200 Subject: Imported Upstream version 2.1.0 --- LICENSE | 2 +- SConstruct | 22 +- bin/calibrate.py | 6 +- bin/docdiff | 16 - bin/docrun | 16 - bin/docupdate | 16 - bin/import-test.py | 4 +- bin/linecount.py | 4 +- bin/restore.sh | 28 +- bin/scons-doc.py | 95 +- bin/scons-proc.py | 174 +- bin/sconsexamples.py | 505 --- bin/scp-sourceforge | 38 + bin/update-release-info.py | 18 +- bin/xmlagenda.py | 18 +- doc/SConscript | 145 +- doc/design/scons.mod | 2 +- doc/developer/architecture.xml | 2 +- doc/developer/branches.xml | 2 +- doc/developer/copyright.xml | 2 +- doc/developer/cycle.xml | 2 +- doc/developer/main.xml | 2 +- doc/developer/packaging.xml | 2 +- doc/developer/preface.xml | 2 +- doc/developer/sourcetree.xml | 2 +- doc/developer/testing.xml | 2 +- doc/man/scons-time.1 | 6 +- doc/man/scons.1 | 4466 ++------------------ doc/man/sconsign.1 | 6 +- doc/python10/scons.mod | 2 +- doc/scons.mod | 4 +- doc/user/MANIFEST | 1 + doc/user/README | 2 +- doc/user/actions.in | 2 +- doc/user/actions.xml | 2 +- doc/user/add-method.in | 2 +- doc/user/add-method.xml | 3 +- doc/user/alias.in | 2 +- doc/user/alias.xml | 2 +- doc/user/ant.in | 2 +- doc/user/ant.xml | 2 +- doc/user/build-install.in | 25 +- doc/user/build-install.xml | 25 +- doc/user/builders-built-in.in | 2 +- doc/user/builders-built-in.xml | 3 +- doc/user/builders-commands.in | 4 +- doc/user/builders-commands.xml | 2 +- doc/user/builders-writing.in | 63 +- doc/user/builders-writing.xml | 59 +- doc/user/builders.in | 2 +- doc/user/builders.xml | 2 +- doc/user/caching.in | 2 +- doc/user/caching.xml | 2 +- doc/user/command-line.in | 6 +- doc/user/command-line.xml | 17 +- doc/user/copyright.in | 2 +- doc/user/copyright.xml | 2 +- doc/user/depends.in | 61 +- doc/user/depends.xml | 60 +- doc/user/environments.in | 22 +- doc/user/environments.xml | 10 +- doc/user/errors.in | 2 +- doc/user/errors.xml | 2 +- doc/user/example.in | 2 +- doc/user/example.xml | 2 +- doc/user/factories.in | 4 +- doc/user/factories.xml | 2 +- doc/user/file-removal.in | 2 +- doc/user/file-removal.xml | 2 +- doc/user/functions.in | 38 + doc/user/functions.xml | 38 + doc/user/hierarchy.in | 6 +- doc/user/hierarchy.xml | 4 +- doc/user/install.in | 2 +- doc/user/install.xml | 2 +- doc/user/java.in | 6 +- doc/user/java.xml | 2 +- doc/user/less-simple.in | 2 +- doc/user/less-simple.xml | 4 +- doc/user/libraries.in | 2 +- doc/user/libraries.xml | 5 +- doc/user/main.in | 53 +- doc/user/main.xml | 53 +- doc/user/make.in | 2 +- doc/user/make.xml | 2 +- doc/user/mergeflags.in | 2 +- doc/user/mergeflags.xml | 2 +- doc/user/misc.in | 12 +- doc/user/misc.xml | 6 +- doc/user/nodes.in | 2 +- doc/user/nodes.xml | 4 +- doc/user/output.in | 4 +- doc/user/output.xml | 2 +- doc/user/parseconfig.in | 2 +- doc/user/parseconfig.xml | 2 +- doc/user/parseflags.in | 2 +- doc/user/parseflags.xml | 3 +- doc/user/preface.in | 6 +- doc/user/preface.xml | 2 +- doc/user/python.in | 2 +- doc/user/python.xml | 2 +- doc/user/repositories.in | 6 +- doc/user/repositories.xml | 6 +- doc/user/run.in | 2 +- doc/user/run.xml | 2 +- doc/user/scanners.in | 17 +- doc/user/scanners.xml | 17 +- doc/user/sconf.in | 6 +- doc/user/sconf.xml | 4 +- doc/user/separate.in | 2 +- doc/user/separate.xml | 2 +- doc/user/sideeffect.in | 2 +- doc/user/sideeffect.xml | 2 +- doc/user/simple.in | 10 +- doc/user/simple.xml | 10 +- doc/user/sourcecode.in | 2 +- doc/user/sourcecode.xml | 2 +- doc/user/tasks.in | 6 +- doc/user/tasks.xml | 2 +- doc/user/tools.in | 2 +- doc/user/tools.xml | 2 +- doc/user/troubleshoot.in | 49 +- doc/user/troubleshoot.xml | 57 +- doc/user/variables.in | 2 +- doc/user/variables.xml | 2 +- doc/user/variants.in | 2 +- doc/user/variants.xml | 3 +- src/Announce.txt | 19 +- src/CHANGES.txt | 255 +- src/LICENSE.txt | 2 +- src/README.txt | 18 +- src/RELEASE.txt | 152 +- src/engine/MANIFEST-xml.in | 4 + src/engine/MANIFEST.in | 1 + src/engine/README.txt | 167 - src/engine/SCons/Action.py | 28 +- src/engine/SCons/Action.xml | 2 +- src/engine/SCons/ActionTests.py | 19 +- src/engine/SCons/Builder.py | 4 +- src/engine/SCons/BuilderTests.py | 4 +- src/engine/SCons/CacheDir.py | 4 +- src/engine/SCons/CacheDirTests.py | 4 +- src/engine/SCons/Debug.py | 4 +- src/engine/SCons/Defaults.py | 34 +- src/engine/SCons/Defaults.xml | 15 +- src/engine/SCons/DefaultsTests.py | 4 +- src/engine/SCons/Environment.py | 137 +- src/engine/SCons/Environment.xml | 2973 ++++++++++++- src/engine/SCons/EnvironmentTests.py | 19 +- src/engine/SCons/Errors.py | 4 +- src/engine/SCons/ErrorsTests.py | 4 +- src/engine/SCons/Executor.py | 4 +- src/engine/SCons/ExecutorTests.py | 4 +- src/engine/SCons/Job.py | 4 +- src/engine/SCons/JobTests.py | 4 +- src/engine/SCons/Memoize.py | 4 +- src/engine/SCons/MemoizeTests.py | 4 +- src/engine/SCons/Node/Alias.py | 4 +- src/engine/SCons/Node/AliasTests.py | 4 +- src/engine/SCons/Node/FS.py | 402 +- src/engine/SCons/Node/FSTests.py | 299 +- src/engine/SCons/Node/NodeTests.py | 4 +- src/engine/SCons/Node/Python.py | 4 +- src/engine/SCons/Node/PythonTests.py | 4 +- src/engine/SCons/Node/__init__.py | 11 +- src/engine/SCons/Options/BoolOption.py | 4 +- src/engine/SCons/Options/EnumOption.py | 4 +- src/engine/SCons/Options/ListOption.py | 4 +- src/engine/SCons/Options/PackageOption.py | 4 +- src/engine/SCons/Options/PathOption.py | 4 +- src/engine/SCons/Options/__init__.py | 4 +- src/engine/SCons/PathList.py | 4 +- src/engine/SCons/PathListTests.py | 4 +- src/engine/SCons/Platform/PlatformTests.py | 4 +- src/engine/SCons/Platform/__init__.py | 4 +- src/engine/SCons/Platform/__init__.xml | 2 +- src/engine/SCons/Platform/aix.py | 4 +- src/engine/SCons/Platform/cygwin.py | 4 +- src/engine/SCons/Platform/darwin.py | 30 +- src/engine/SCons/Platform/hpux.py | 4 +- src/engine/SCons/Platform/irix.py | 4 +- src/engine/SCons/Platform/os2.py | 4 +- src/engine/SCons/Platform/posix.py | 4 +- src/engine/SCons/Platform/posix.xml | 2 +- src/engine/SCons/Platform/sunos.py | 4 +- src/engine/SCons/Platform/sunos.xml | 2 +- src/engine/SCons/Platform/win32.py | 4 +- src/engine/SCons/Platform/win32.xml | 2 +- src/engine/SCons/SConf.py | 4 +- src/engine/SCons/SConfTests.py | 4 +- src/engine/SCons/SConsign.py | 12 +- src/engine/SCons/SConsignTests.py | 4 +- src/engine/SCons/Scanner/C.py | 4 +- src/engine/SCons/Scanner/CTests.py | 4 +- src/engine/SCons/Scanner/D.py | 4 +- src/engine/SCons/Scanner/Dir.py | 4 +- src/engine/SCons/Scanner/DirTests.py | 4 +- src/engine/SCons/Scanner/Fortran.py | 4 +- src/engine/SCons/Scanner/FortranTests.py | 4 +- src/engine/SCons/Scanner/IDL.py | 4 +- src/engine/SCons/Scanner/IDLTests.py | 4 +- src/engine/SCons/Scanner/LaTeX.py | 7 +- src/engine/SCons/Scanner/LaTeXTests.py | 4 +- src/engine/SCons/Scanner/Prog.py | 4 +- src/engine/SCons/Scanner/ProgTests.py | 4 +- src/engine/SCons/Scanner/RC.py | 6 +- src/engine/SCons/Scanner/RCTests.py | 15 +- src/engine/SCons/Scanner/ScannerTests.py | 4 +- src/engine/SCons/Scanner/__init__.py | 4 +- src/engine/SCons/Scanner/__init__.xml | 64 + src/engine/SCons/Script/Interactive.py | 4 +- src/engine/SCons/Script/Main.py | 93 +- src/engine/SCons/Script/Main.xml | 710 ++++ src/engine/SCons/Script/MainTests.py | 4 +- src/engine/SCons/Script/SConsOptions.py | 10 +- src/engine/SCons/Script/SConscript.py | 4 +- src/engine/SCons/Script/SConscript.xml | 509 +++ src/engine/SCons/Script/SConscriptTests.py | 4 +- src/engine/SCons/Script/__init__.py | 4 +- src/engine/SCons/Sig.py | 4 +- src/engine/SCons/Subst.py | 4 +- src/engine/SCons/Subst.xml | 46 + src/engine/SCons/SubstTests.py | 8 +- src/engine/SCons/Taskmaster.py | 12 +- src/engine/SCons/TaskmasterTests.py | 4 +- src/engine/SCons/Tool/386asm.py | 4 +- src/engine/SCons/Tool/386asm.xml | 2 +- src/engine/SCons/Tool/BitKeeper.py | 4 +- src/engine/SCons/Tool/BitKeeper.xml | 28 +- src/engine/SCons/Tool/CVS.py | 4 +- src/engine/SCons/Tool/CVS.xml | 52 +- src/engine/SCons/Tool/FortranCommon.py | 21 +- src/engine/SCons/Tool/JavaCommon.py | 4 +- src/engine/SCons/Tool/JavaCommonTests.py | 4 +- src/engine/SCons/Tool/MSCommon/__init__.py | 4 +- src/engine/SCons/Tool/MSCommon/arch.py | 4 +- src/engine/SCons/Tool/MSCommon/common.py | 4 +- src/engine/SCons/Tool/MSCommon/netframework.py | 4 +- src/engine/SCons/Tool/MSCommon/sdk.py | 4 +- src/engine/SCons/Tool/MSCommon/vc.py | 15 +- src/engine/SCons/Tool/MSCommon/vs.py | 31 +- src/engine/SCons/Tool/Perforce.py | 4 +- src/engine/SCons/Tool/Perforce.xml | 45 +- src/engine/SCons/Tool/PharLapCommon.py | 4 +- src/engine/SCons/Tool/PharLapCommonTests.py | 4 +- src/engine/SCons/Tool/RCS.py | 4 +- src/engine/SCons/Tool/RCS.xml | 42 +- src/engine/SCons/Tool/SCCS.py | 4 +- src/engine/SCons/Tool/SCCS.xml | 38 +- src/engine/SCons/Tool/Subversion.py | 4 +- src/engine/SCons/Tool/Subversion.xml | 53 +- src/engine/SCons/Tool/ToolTests.py | 4 +- src/engine/SCons/Tool/__init__.py | 6 +- src/engine/SCons/Tool/__init__.xml | 20 +- src/engine/SCons/Tool/aixc++.py | 4 +- src/engine/SCons/Tool/aixc++.xml | 2 +- src/engine/SCons/Tool/aixcc.py | 4 +- src/engine/SCons/Tool/aixcc.xml | 2 +- src/engine/SCons/Tool/aixf77.py | 4 +- src/engine/SCons/Tool/aixf77.xml | 2 +- src/engine/SCons/Tool/aixlink.py | 4 +- src/engine/SCons/Tool/aixlink.xml | 2 +- src/engine/SCons/Tool/applelink.py | 4 +- src/engine/SCons/Tool/applelink.xml | 2 +- src/engine/SCons/Tool/ar.py | 4 +- src/engine/SCons/Tool/ar.xml | 2 +- src/engine/SCons/Tool/as.py | 4 +- src/engine/SCons/Tool/as.xml | 2 +- src/engine/SCons/Tool/bcc32.py | 4 +- src/engine/SCons/Tool/bcc32.xml | 2 +- src/engine/SCons/Tool/c++.py | 4 +- src/engine/SCons/Tool/c++.xml | 2 +- src/engine/SCons/Tool/cc.py | 4 +- src/engine/SCons/Tool/cc.xml | 2 +- src/engine/SCons/Tool/cvf.py | 4 +- src/engine/SCons/Tool/cvf.xml | 2 +- src/engine/SCons/Tool/default.py | 4 +- src/engine/SCons/Tool/default.xml | 2 +- src/engine/SCons/Tool/dmd.py | 31 +- src/engine/SCons/Tool/dmd.xml | 2 +- src/engine/SCons/Tool/dvi.py | 4 +- src/engine/SCons/Tool/dvi.xml | 2 +- src/engine/SCons/Tool/dvipdf.py | 5 +- src/engine/SCons/Tool/dvipdf.xml | 2 +- src/engine/SCons/Tool/dvips.py | 5 +- src/engine/SCons/Tool/dvips.xml | 2 +- src/engine/SCons/Tool/f03.py | 63 + src/engine/SCons/Tool/f03.xml | 252 ++ src/engine/SCons/Tool/f77.py | 4 +- src/engine/SCons/Tool/f77.xml | 2 +- src/engine/SCons/Tool/f90.py | 4 +- src/engine/SCons/Tool/f90.xml | 2 +- src/engine/SCons/Tool/f95.py | 4 +- src/engine/SCons/Tool/f95.xml | 2 +- src/engine/SCons/Tool/filesystem.py | 4 +- src/engine/SCons/Tool/fortran.py | 4 +- src/engine/SCons/Tool/fortran.xml | 2 +- src/engine/SCons/Tool/g++.py | 4 +- src/engine/SCons/Tool/g++.xml | 2 +- src/engine/SCons/Tool/g77.py | 4 +- src/engine/SCons/Tool/g77.xml | 2 +- src/engine/SCons/Tool/gas.py | 4 +- src/engine/SCons/Tool/gas.xml | 2 +- src/engine/SCons/Tool/gcc.py | 4 +- src/engine/SCons/Tool/gcc.xml | 2 +- src/engine/SCons/Tool/gfortran.py | 6 +- src/engine/SCons/Tool/gfortran.xml | 2 +- src/engine/SCons/Tool/gnulink.py | 5 +- src/engine/SCons/Tool/gnulink.xml | 2 +- src/engine/SCons/Tool/gs.py | 4 +- src/engine/SCons/Tool/gs.xml | 2 +- src/engine/SCons/Tool/hpc++.py | 4 +- src/engine/SCons/Tool/hpc++.xml | 2 +- src/engine/SCons/Tool/hpcc.py | 4 +- src/engine/SCons/Tool/hpcc.xml | 2 +- src/engine/SCons/Tool/hplink.py | 4 +- src/engine/SCons/Tool/hplink.xml | 2 +- src/engine/SCons/Tool/icc.py | 4 +- src/engine/SCons/Tool/icc.xml | 2 +- src/engine/SCons/Tool/icl.py | 4 +- src/engine/SCons/Tool/icl.xml | 2 +- src/engine/SCons/Tool/ifl.py | 4 +- src/engine/SCons/Tool/ifl.xml | 2 +- src/engine/SCons/Tool/ifort.py | 4 +- src/engine/SCons/Tool/ifort.xml | 2 +- src/engine/SCons/Tool/ilink.py | 4 +- src/engine/SCons/Tool/ilink.xml | 2 +- src/engine/SCons/Tool/ilink32.py | 4 +- src/engine/SCons/Tool/ilink32.xml | 2 +- src/engine/SCons/Tool/install.py | 60 +- src/engine/SCons/Tool/install.xml | 2 +- src/engine/SCons/Tool/intelc.py | 90 +- src/engine/SCons/Tool/intelc.xml | 2 +- src/engine/SCons/Tool/ipkg.py | 4 +- src/engine/SCons/Tool/jar.py | 12 +- src/engine/SCons/Tool/jar.xml | 2 +- src/engine/SCons/Tool/javac.py | 4 +- src/engine/SCons/Tool/javac.xml | 2 +- src/engine/SCons/Tool/javah.py | 4 +- src/engine/SCons/Tool/javah.xml | 2 +- src/engine/SCons/Tool/latex.py | 5 +- src/engine/SCons/Tool/latex.xml | 2 +- src/engine/SCons/Tool/lex.py | 4 +- src/engine/SCons/Tool/lex.xml | 2 +- src/engine/SCons/Tool/link.py | 11 +- src/engine/SCons/Tool/link.xml | 2 +- src/engine/SCons/Tool/linkloc.py | 4 +- src/engine/SCons/Tool/linkloc.xml | 2 +- src/engine/SCons/Tool/m4.py | 4 +- src/engine/SCons/Tool/m4.xml | 2 +- src/engine/SCons/Tool/masm.py | 4 +- src/engine/SCons/Tool/masm.xml | 2 +- src/engine/SCons/Tool/midl.py | 4 +- src/engine/SCons/Tool/midl.xml | 2 +- src/engine/SCons/Tool/mingw.py | 41 +- src/engine/SCons/Tool/mingw.xml | 2 +- src/engine/SCons/Tool/mslib.py | 4 +- src/engine/SCons/Tool/mslib.xml | 2 +- src/engine/SCons/Tool/mslink.py | 70 +- src/engine/SCons/Tool/mslink.xml | 41 +- src/engine/SCons/Tool/mssdk.py | 4 +- src/engine/SCons/Tool/mssdk.xml | 2 +- src/engine/SCons/Tool/msvc.py | 32 +- src/engine/SCons/Tool/msvc.xml | 2 +- src/engine/SCons/Tool/msvs.py | 536 ++- src/engine/SCons/Tool/msvs.xml | 73 +- src/engine/SCons/Tool/msvsTests.py | 24 +- src/engine/SCons/Tool/mwcc.py | 4 +- src/engine/SCons/Tool/mwcc.xml | 2 +- src/engine/SCons/Tool/mwld.py | 4 +- src/engine/SCons/Tool/mwld.xml | 2 +- src/engine/SCons/Tool/nasm.py | 4 +- src/engine/SCons/Tool/nasm.xml | 2 +- src/engine/SCons/Tool/packaging.xml | 2 +- src/engine/SCons/Tool/packaging/__init__.py | 4 +- src/engine/SCons/Tool/packaging/__init__.xml | 25 +- src/engine/SCons/Tool/packaging/ipk.py | 4 +- src/engine/SCons/Tool/packaging/msi.py | 4 +- src/engine/SCons/Tool/packaging/rpm.py | 4 +- src/engine/SCons/Tool/packaging/src_tarbz2.py | 4 +- src/engine/SCons/Tool/packaging/src_targz.py | 4 +- src/engine/SCons/Tool/packaging/src_zip.py | 4 +- src/engine/SCons/Tool/packaging/tarbz2.py | 4 +- src/engine/SCons/Tool/packaging/targz.py | 4 +- src/engine/SCons/Tool/packaging/zip.py | 4 +- src/engine/SCons/Tool/pdf.py | 4 +- src/engine/SCons/Tool/pdf.xml | 2 +- src/engine/SCons/Tool/pdflatex.py | 5 +- src/engine/SCons/Tool/pdflatex.xml | 2 +- src/engine/SCons/Tool/pdftex.py | 5 +- src/engine/SCons/Tool/pdftex.xml | 2 +- src/engine/SCons/Tool/qt.py | 4 +- src/engine/SCons/Tool/qt.xml | 9 +- src/engine/SCons/Tool/rmic.py | 12 +- src/engine/SCons/Tool/rmic.xml | 2 +- src/engine/SCons/Tool/rpcgen.py | 4 +- src/engine/SCons/Tool/rpcgen.xml | 2 +- src/engine/SCons/Tool/rpm.py | 4 +- src/engine/SCons/Tool/sgiar.py | 4 +- src/engine/SCons/Tool/sgiar.xml | 2 +- src/engine/SCons/Tool/sgic++.py | 4 +- src/engine/SCons/Tool/sgic++.xml | 2 +- src/engine/SCons/Tool/sgicc.py | 4 +- src/engine/SCons/Tool/sgicc.xml | 2 +- src/engine/SCons/Tool/sgilink.py | 5 +- src/engine/SCons/Tool/sgilink.xml | 2 +- src/engine/SCons/Tool/sunar.py | 4 +- src/engine/SCons/Tool/sunar.xml | 2 +- src/engine/SCons/Tool/sunc++.py | 4 +- src/engine/SCons/Tool/sunc++.xml | 2 +- src/engine/SCons/Tool/suncc.py | 4 +- src/engine/SCons/Tool/suncc.xml | 2 +- src/engine/SCons/Tool/sunf77.py | 4 +- src/engine/SCons/Tool/sunf77.xml | 2 +- src/engine/SCons/Tool/sunf90.py | 4 +- src/engine/SCons/Tool/sunf90.xml | 2 +- src/engine/SCons/Tool/sunf95.py | 4 +- src/engine/SCons/Tool/sunf95.xml | 2 +- src/engine/SCons/Tool/sunlink.py | 5 +- src/engine/SCons/Tool/sunlink.xml | 2 +- src/engine/SCons/Tool/swig.py | 11 +- src/engine/SCons/Tool/swig.xml | 2 +- src/engine/SCons/Tool/tar.py | 4 +- src/engine/SCons/Tool/tar.xml | 2 +- src/engine/SCons/Tool/tex.py | 139 +- src/engine/SCons/Tool/tex.xml | 2 +- src/engine/SCons/Tool/textfile.py | 4 +- src/engine/SCons/Tool/textfile.xml | 2 +- src/engine/SCons/Tool/tlib.py | 4 +- src/engine/SCons/Tool/tlib.xml | 2 +- src/engine/SCons/Tool/wix.py | 4 +- src/engine/SCons/Tool/yacc.py | 14 +- src/engine/SCons/Tool/yacc.xml | 2 +- src/engine/SCons/Tool/zip.py | 4 +- src/engine/SCons/Tool/zip.xml | 2 +- src/engine/SCons/Util.py | 6 +- src/engine/SCons/UtilTests.py | 13 +- src/engine/SCons/Variables/BoolVariable.py | 4 +- src/engine/SCons/Variables/BoolVariableTests.py | 4 +- src/engine/SCons/Variables/EnumVariable.py | 6 +- src/engine/SCons/Variables/EnumVariableTests.py | 4 +- src/engine/SCons/Variables/ListVariable.py | 4 +- src/engine/SCons/Variables/ListVariableTests.py | 4 +- src/engine/SCons/Variables/PackageVariable.py | 4 +- src/engine/SCons/Variables/PackageVariableTests.py | 4 +- src/engine/SCons/Variables/PathVariable.py | 4 +- src/engine/SCons/Variables/PathVariableTests.py | 4 +- src/engine/SCons/Variables/VariablesTests.py | 4 +- src/engine/SCons/Variables/__init__.py | 4 +- src/engine/SCons/Warnings.py | 4 +- src/engine/SCons/WarningsTests.py | 4 +- src/engine/SCons/__init__.py | 12 +- src/engine/SCons/compat/__init__.py | 4 +- src/engine/SCons/compat/_scons_builtins.py | 4 +- src/engine/SCons/compat/_scons_collections.py | 4 +- src/engine/SCons/compat/_scons_dbm.py | 4 +- src/engine/SCons/compat/_scons_hashlib.py | 4 +- src/engine/SCons/compat/_scons_io.py | 4 +- src/engine/SCons/cpp.py | 4 +- src/engine/SCons/cppTests.py | 4 +- src/engine/SCons/dblite.py | 5 +- src/engine/SCons/exitfuncs.py | 4 +- src/engine/setup.cfg | 2 - src/engine/setup.py | 74 - src/script/README.txt | 169 - src/script/scons-post-install.py | 91 - src/script/scons-time.py | 4 +- src/script/scons.bat | 11 +- src/script/scons.py | 44 +- src/script/sconsign.py | 41 +- src/script/setup.cfg | 2 - src/script/setup.py | 55 - src/setup.cfg | 1 - src/setup.py | 78 +- src/test_aegistests.py | 4 +- src/test_files.py | 4 +- src/test_interrupts.py | 4 +- src/test_pychecker.py | 4 +- src/test_setup.py | 4 +- src/test_strings.py | 10 +- 480 files changed, 9148 insertions(+), 6897 deletions(-) delete mode 100644 bin/docdiff delete mode 100644 bin/docrun delete mode 100644 bin/docupdate delete mode 100644 bin/sconsexamples.py create mode 100755 bin/scp-sourceforge create mode 100644 doc/user/functions.in create mode 100644 doc/user/functions.xml delete mode 100644 src/engine/README.txt create mode 100644 src/engine/SCons/Scanner/__init__.xml create mode 100644 src/engine/SCons/Script/Main.xml create mode 100644 src/engine/SCons/Script/SConscript.xml create mode 100644 src/engine/SCons/Subst.xml create mode 100644 src/engine/SCons/Tool/f03.py create mode 100644 src/engine/SCons/Tool/f03.xml delete mode 100644 src/engine/setup.cfg delete mode 100644 src/engine/setup.py delete mode 100644 src/script/README.txt delete mode 100644 src/script/scons-post-install.py delete mode 100644 src/script/setup.cfg delete mode 100644 src/script/setup.py diff --git a/LICENSE b/LICENSE index 77421fa..c0de36f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/SConstruct b/SConstruct index 4f73381..ab6e2d5 100644 --- a/SConstruct +++ b/SConstruct @@ -5,13 +5,13 @@ # When this gets changed, you must also change the copyright_years string # in QMTest/TestSCons.py so the test scripts look for the right string. -copyright_years = '2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010' +copyright_years = '2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011' # This gets inserted into the man pages to reflect the month of release. -month_year = 'August 2010' +month_year = 'September 2011' # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -43,7 +43,7 @@ import sys import tempfile project = 'scons' -default_version = '2.0.1' +default_version = '2.1.0' copyright = "Copyright (c) %s The SCons Foundation" % copyright_years platform = distutils.util.get_platform() @@ -794,7 +794,7 @@ for p in [ scons ]: # # Now run everything in src_file through the sed command we - # concocted to expand SConstruct, 2.0.1, etc. + # concocted to expand SConstruct, 2.1.0, etc. # for b in src_files: s = p['filemap'].get(b, b) @@ -1093,7 +1093,9 @@ for p in [ scons ]: ] for script in scripts: - #commands.append("mv %s/%s %s/%s.py" % (local, script, local, script)) + # add .py extension for scons-local scripts on non-windows platforms + if platform == "win32": + break local_script = os.path.join(build_dir_local, script) commands.append(Move(local_script + '.py', local_script)) @@ -1116,9 +1118,14 @@ for p in [ scons ]: Local(l) if gzip: + if platform == "win32": + # avoid problem with tar interpreting c:/ as a remote machine + tar_cargs = '-cz --force-local -f' + else: + tar_cargs = '-czf' env.Command(dist_local_tar_gz, local_targets, - "cd %s && tar czf $( ${TARGET.abspath} $) *" % build_dir_local) + "cd %s && tar %s $( ${TARGET.abspath} $) *" % (build_dir_local, tar_cargs)) unpack_targets = [os.path.join(test_local_tar_gz_dir, x) for x in rf] commands = [Delete(test_local_tar_gz_dir), @@ -1198,7 +1205,6 @@ if sfiles: '.hgt/*', '.svnt/*', '*.aeignore', - '*.cvsignore', '*.hgignore', 'www/*', ] diff --git a/bin/calibrate.py b/bin/calibrate.py index f377869..72a6ac7 100644 --- a/bin/calibrate.py +++ b/bin/calibrate.py @@ -64,7 +64,11 @@ def main(argv=None): output = p.communicate()[0] vm = variable_re.search(output) em = elapsed_re.search(output) - elapsed = float(em.group(1)) + try: + elapsed = float(em.group(1)) + except AttributeError: + print output + raise print "run %3d: %7.3f: %s" % (run, elapsed, ' '.join(vm.groups())) if opts.min < elapsed and elapsed < opts.max: good += 1 diff --git a/bin/docdiff b/bin/docdiff deleted file mode 100644 index c7adb05..0000000 --- a/bin/docdiff +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -if test $# -eq 0; then - for f in doc/user/*.in; do - xml=doc/user/`basename $f .in`.xml - echo $f: - python bin/scons-doc.py $f | diff $DIFFFLAGS $xml - - done -else - for a in $*; do - f=doc/user/$a.in - xml=doc/user/$a.xml - echo $f: - python bin/scons-doc.py $f | diff $DIFFFLAGS $xml - - done -fi diff --git a/bin/docrun b/bin/docrun deleted file mode 100644 index ad8ea9f..0000000 --- a/bin/docrun +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -if test $# -eq 0; then - for f in doc/user/*.in; do - xml=doc/user/`basename $f .in`.xml - echo $f: - python bin/scons-doc.py $f - done -else - for a in $*; do - f=doc/user/$a.in - xml=doc/user/$a.xml - echo $f: - python bin/scons-doc.py $f - done -fi diff --git a/bin/docupdate b/bin/docupdate deleted file mode 100644 index cd9b532..0000000 --- a/bin/docupdate +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -if test $# -eq 0; then - for f in doc/user/*.in; do - xml=doc/user/`basename $f .in`.xml - echo $f: - python bin/scons-doc.py $f > $xml - done -else - for a in $*; do - f=doc/user/$a.in - xml=doc/user/$a.xml - echo $f: - python bin/scons-doc.py $f > $xml - done -fi diff --git a/bin/import-test.py b/bin/import-test.py index 4991aee..cb95ff2 100644 --- a/bin/import-test.py +++ b/bin/import-test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # tree2test.py - turn a directory tree into TestSCons code # @@ -25,7 +25,7 @@ # """ triple-quotes will need to have their contents edited by hand. # -__revision__ = "bin/import-test.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "bin/import-test.py 5357 2011/09/09 21:31:03 bdeegan" import os.path import sys diff --git a/bin/linecount.py b/bin/linecount.py index 9d0be94..7121ebd 100644 --- a/bin/linecount.py +++ b/bin/linecount.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Count statistics about SCons test and source files. This must be run # against a fully-populated tree (for example, one that's been freshly @@ -23,7 +23,7 @@ # interesting one for most purposes. from __future__ import division -__revision__ = "bin/linecount.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "bin/linecount.py 5357 2011/09/09 21:31:03 bdeegan" import os.path diff --git a/bin/restore.sh b/bin/restore.sh index 6db56f1..3aab7ae 100644 --- a/bin/restore.sh +++ b/bin/restore.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh # -# Simple hack script to restore __revision__, __COPYRIGHT_, 2.0.1 +# Simple hack script to restore __revision__, __COPYRIGHT_, 2.1.0 # and other similar variables to what gets checked in to source. This # comes in handy when people send in diffs based on the released source. # @@ -22,9 +22,9 @@ header() { for i in `find $DIRS -name '*.py'`; do header $i ed $i <\n' % (v.prefix, v.idfunc())) - for term in v.termfunc(): - f.write('<%s>%s\n' % - (v.tag, term, v.tag)) + f.write('%s\n' % v.xml_term()) f.write('\n') for chunk in v.summary.body: f.write(str(chunk)) @@ -212,23 +211,41 @@ class SCons_XML_to_XML(SCons_XML): class SCons_XML_to_man(SCons_XML): def write(self, filename): + """ + Converts the contents of the specified filename from DocBook XML + to man page macros. + + This does not do an intelligent job. In particular, it doesn't + actually use the structured nature of XML to handle arbitrary + input. Instead, we're using text replacement and regular + expression substitutions to convert observed patterns into the + macros we want. To the extent that we're relatively consistent + with our input .xml, this works, but could easily break if handed + input that doesn't match these specific expectations. + """ if not filename: return f = self.fopen(filename) chunks = [] for v in self.values: - chunks.extend(v.mansep()) - chunks.extend(v.initial_chunks()) + chunks.extend(v.man_separator()) + chunks.extend(v.initial_man_chunks()) chunks.extend(list(map(str, v.summary.body))) body = ''.join(chunks) + + # Simple transformation of examples into our defined macros for those. body = body.replace('', '.ES') body = body.replace('', '.EE') + + # Replace groupings of tags and surrounding newlines + # with single blank lines. body = body.replace('\n\n\n', '\n\n') body = body.replace('\n', '') body = body.replace('', '\n') body = body.replace('\n', '') + # Convert and its child tags. body = body.replace('\n', '.RS 10\n') # Handling needs to be rationalized and made # consistent. Right now, the values map to arbitrary, @@ -240,35 +257,54 @@ class SCons_XML_to_man(SCons_XML): body = body.replace('\n', '') body = body.replace('\n', '.RE\n') + # Get rid of unnecessary .IP macros, and unnecessary blank lines + # in front of .IP macros. body = re.sub(r'\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body) + body = body.replace('\n.EE\n.IP\n.ES\n', '\n.EE\n\n.ES\n') body = body.replace('\n.IP\n\'\\"', '\n\n\'\\"') - body = re.sub('&(scons|SConstruct|SConscript|jar|Make|lambda);', r'\\fB\1\\fP', body) + + # Convert various named entities and tagged names to nroff + # in-line font conversions (\fB, \fI, \fP). + body = re.sub('&(scons|SConstruct|SConscript|Dir|jar|Make|lambda);', + r'\\fB\1\\fP', body) body = re.sub('&(TARGET|TARGETS|SOURCE|SOURCES);', r'\\fB$\1\\fP', body) - body = body.replace('&Dir;', r'\fBDir\fP') - body = body.replace('⌖', r'\fItarget\fP') - body = body.replace('&source;', r'\fIsource\fP') + body = re.sub('&(target|source);', r'\\fI\1\\fP', body) body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body) - body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body) + body = re.sub('&cv(-link)?-([^;]*);', r'\\fB$\2\\fP', body) body = re.sub('&f(-link)?-env-([^;]*);', r'\\fBenv.\2\\fP()', body) body = re.sub('&f(-link)?-([^;]*);', r'\\fB\2\\fP()', body) body = re.sub(r'<(application|command|envar|filename|function|literal|option)>([^<]*)', r'\\fB\2\\fP', body) body = re.sub(r'<(classname|emphasis|varname)>([^<]*)', r'\\fI\2\\fP', body) + + # Convert groupings of font conversions (\fB, \fI, \fP) to + # man page .B, .BR, .I, .IR, .R, .RB and .RI macros. body = re.compile(r'^\\f([BI])([^\\]* [^\\]*)\\fP\s*$', re.M).sub(r'.\1 "\2"', body) body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body) body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)$', re.M).sub(r'.\1R \2 \3', body) + body = re.compile(r'^(\.B)( .*)\\fP(.*)\\fB(.*)$', re.M).sub(r'\1R\2 \3 \4', body) + body = re.compile(r'^(\.B)R?( .*)\\fP(.*)\\fI(.*)$', re.M).sub(r'\1I\2\3 \4', body) + body = re.compile(r'^(\.I)( .*)\\fP\\fB(.*)\\fP\\fI(.*)$', re.M).sub(r'\1R\2 \3 \4', body) body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP$', re.M).sub(r'.R\2 \1 \3', body) body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP([^\s\\]+)$', re.M).sub(r'.R\2 \1 \3 \4', body) body = re.compile(r'^(\.R[BI].*[\S])\s+$;', re.M).sub(r'\1', body) + + # Convert < and > entities to literal < and > characters. body = body.replace('<', '<') body = body.replace('>', '>') - body = re.sub(r'\\([^f])', r'\\\\\1', body) + + # Backslashes. Oh joy. + body = re.sub(r'\\(?=[^f])', r'\\\\', body) body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body) + body = re.compile(r'^\.([BI]R?) ([^"]\S*\\\\\S+[^"])$', re.M).sub(r'.\1 "\2"', body) + + # Put backslashes in front of various hyphens that need + # to be long em-dashes. body = re.compile(r'^\.([BI]R?) --', re.M).sub(r'.\1 \-\-', body) body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body) - body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)$', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body) body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body) + f.write(body) class Proxy(object): @@ -290,34 +326,91 @@ class Proxy(object): return cmp(self.__subject, other) return cmp(self.__dict__, other.__dict__) -class Builder(Proxy): +class SConsThing(Proxy): + def idfunc(self): + return self.name + def xml_term(self): + return '%s' % self.name + +class Builder(SConsThing): description = 'builder' prefix = 'b-' tag = 'function' - def idfunc(self): - return self.name - def termfunc(self): - return ['%s()' % self.name, 'env.%s()' % self.name] + def xml_term(self): + return ('<%s>%s()\n<%s>env.%s()' % + (self.tag, self.name, self.tag, self.tag, self.name, self.tag)) def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n', "'\\" + '"'*69 + '\n'] - def initial_chunks(self): - return [ '.IP %s\n' % t for t in self.termfunc() ] + def initial_man_chunks(self): + return [ '.IP %s()\n.IP env.%s()\n' % (self.name, self.name) ] -class Function(Proxy): +class Function(SConsThing): description = 'function' prefix = 'f-' tag = 'function' - def idfunc(self): - return self.name - def termfunc(self): - return ['%s()' % self.name, 'env.%s()' % self.name] + def args_to_xml(self, arg): + s = ''.join(arg.body).strip() + result = [] + for m in re.findall('([a-zA-Z/_]+=?|[^a-zA-Z/_]+)', s): + if m[0] in string.letters: + if m[-1] == '=': + result.append('%s=' % m[:-1]) + else: + result.append('%s' % m) + else: + result.append(m) + return ''.join(result) + def xml_term(self): + try: + arguments = self.arguments + except AttributeError: + arguments = ['()'] + result = [''] + for arg in arguments: + try: + signature = arg.signature + except AttributeError: + signature = "both" + s = self.args_to_xml(arg) + if signature in ('both', 'global'): + result.append('%s%s\n' % (self.name, s)) #
+ if signature in ('both', 'env'): + result.append('env.%s%s' % (self.name, s)) + result.append('
') + return ''.join(result) def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n', "'\\" + '"'*69 + '\n'] - def initial_chunks(self): + def args_to_man(self, arg): + """Converts the contents of an tag, which + specifies a function's calling signature, into a series + of tokens that alternate between literal tokens + (to be displayed in roman or bold face) and variable + names (to be displayed in italics). + + This is complicated by the presence of Python "keyword=var" + arguments, where "keyword=" should be displayed literally, + and "var" should be displayed in italics. We do this by + detecting the keyword= var portion and appending it to the + previous string, if any. + """ + s = ''.join(arg.body).strip() + result = [] + for m in re.findall('([a-zA-Z/_]+=?|[^a-zA-Z/_]+)', s): + if m[-1] == '=' and result: + if result[-1][-1] == '"': + result[-1] = result[-1][:-1] + m + '"' + else: + result[-1] += m + else: + if ' ' in m: + m = '"%s"' % m + result.append(m) + return ' '.join(result) + def initial_man_chunks(self): try: arguments = self.arguments except AttributeError: @@ -328,40 +421,35 @@ class Function(Proxy): signature = arg.signature except AttributeError: signature = "both" + s = self.args_to_man(arg) if signature in ('both', 'global'): - result.append('.TP\n.RI %s%s\n' % (self.name, arg)) + result.append('.TP\n.RI %s%s\n' % (self.name, s)) if signature in ('both', 'env'): - result.append('.TP\n.IR env .%s%s\n' % (self.name, arg)) + result.append('.TP\n.IR env .%s%s\n' % (self.name, s)) return result -class Tool(Proxy): +class Tool(SConsThing): description = 'tool' prefix = 't-' tag = 'literal' def idfunc(self): return self.name.replace('+', 'X') - def termfunc(self): - return [self.name] def entityfunc(self): return self.name - def mansep(self): + def man_separator(self): return ['\n'] - def initial_chunks(self): + def initial_man_chunks(self): return ['.IP %s\n' % self.name] -class Variable(Proxy): +class Variable(SConsThing): description = 'construction variable' prefix = 'cv-' tag = 'envar' - def idfunc(self): - return self.name - def termfunc(self): - return [self.name] def entityfunc(self): return '$' + self.name - def mansep(self): + def man_separator(self): return ['\n'] - def initial_chunks(self): + def initial_man_chunks(self): return ['.IP %s\n' % self.name] if output_type == '--man': diff --git a/bin/sconsexamples.py b/bin/sconsexamples.py deleted file mode 100644 index 6d3b2de..0000000 --- a/bin/sconsexamples.py +++ /dev/null @@ -1,505 +0,0 @@ -#!/usr/bin/env python2 -# -# scons_examples.py - an SGML preprocessor for capturing SCons output -# and inserting into examples in our DocBook -# documentation -# - -# This script looks for some SGML tags that describe SCons example -# configurations and commands to execute in those configurations, and -# uses TestCmd.py to execute the commands and insert the output into -# the output SGML. This way, we can run a script and update all of -# our example output without having to do a lot of laborious by-hand -# checking. -# -# An "SCons example" looks like this, and essentially describes a set of -# input files (program source files as well as SConscript files): -# -# -# -# env = Environment() -# env.Program('foo') -# -# -# int main() { printf("foo.c\n"); } -# -# -# -# The contents within the tag will get written -# into a temporary directory whenever example output needs to be -# generated. By default, the contents are not inserted into text -# directly, unless you set the "printme" attribute on one or more files, -# in which case they will get inserted within a tag. -# This makes it easy to define the example at the appropriate -# point in the text where you intend to show the SConstruct file. -# -# Note that you should usually give the a "name" -# attribute so that you can refer to the example configuration later to -# run SCons and generate output. -# -# If you just want to show a file's contents without worry about running -# SCons, there's a shorter tag: -# -# -# env = Environment() -# env.Program('foo') -# -# -# This is essentially equivalent to , -# but it's more straightforward. -# -# SCons output is generated from the following sort of tag: -# -# -# scons -Q foo -# scons -Q foo -# -# -# You tell it which example to use with the "example" attribute, and -# then give it a list of tags to execute. You can also supply -# an "os" tag, which specifies the type of operating system this example -# is intended to show; if you omit this, default value is "posix". -# -# The generated SGML will show the command line (with the appropriate -# command-line prompt for the operating system), execute the command in -# a temporary directory with the example files, capture the standard -# output from SCons, and insert it into the text as appropriate. -# Error output gets passed through to your error output so you -# can see if there are any problems executing the command. - -import os -import os.path -import re -import sgmllib -import sys - -sys.path.append(os.path.join(os.getcwd(), 'etc')) -sys.path.append(os.path.join(os.getcwd(), 'build', 'etc')) - -scons_py = os.path.join('bootstrap', 'src', 'script', 'scons.py') -if not os.path.exists(scons_py): - scons_py = os.path.join('src', 'script', 'scons.py') - -scons_lib_dir = os.path.join(os.getcwd(), 'bootstrap', 'src', 'engine') -if not os.path.exists(scons_lib_dir): - scons_lib_dir = os.path.join(os.getcwd(), 'src', 'engine') - -import TestCmd - -# The regular expression that identifies entity references in the -# standard sgmllib omits the underscore from the legal characters. -# Override it with our own regular expression that adds underscore. -sgmllib.entityref = re.compile('&([a-zA-Z][-_.a-zA-Z0-9]*)[^-_a-zA-Z0-9]') - -class DataCollector(object): - """Generic class for collecting data between a start tag and end - tag. We subclass for various types of tags we care about.""" - def __init__(self): - self.data = "" - def afunc(self, data): - self.data = self.data + data - -class Example(DataCollector): - """An SCons example. This is essentially a list of files that - will get written to a temporary directory to collect output - from one or more SCons runs.""" - def __init__(self): - DataCollector.__init__(self) - self.files = [] - self.dirs = [] - -class File(DataCollector): - """A file, that will get written out to a temporary directory - for one or more SCons runs.""" - def __init__(self, name): - DataCollector.__init__(self) - self.name = name - -class Directory(DataCollector): - """A directory, that will get created in a temporary directory - for one or more SCons runs.""" - def __init__(self, name): - DataCollector.__init__(self) - self.name = name - -class Output(DataCollector): - """Where the command output goes. This is essentially - a list of commands that will get executed.""" - def __init__(self): - DataCollector.__init__(self) - self.commandlist = [] - -class Command(DataCollector): - """A tag for where the command output goes. This is essentially - a list of commands that will get executed.""" - pass - -Prompt = { - 'posix' : '% ', - 'win32' : 'C:\\>' -} - -# Magick SCons hackery. -# -# So that our examples can still use the default SConstruct file, we -# actually feed the following into SCons via stdin and then have it -# SConscript() the SConstruct file. This stdin wrapper creates a set -# of ToolSurrogates for the tools for the appropriate platform. These -# Surrogates print output like the real tools and behave like them -# without actually having to be on the right platform or have the right -# tool installed. -# -# The upshot: We transparently change the world out from under the -# top-level SConstruct file in an example just so we can get the -# command output. - -Stdin = """\ -import SCons.Defaults - -platform = '%s' - -class Curry(object): - def __init__(self, fun, *args, **kwargs): - self.fun = fun - self.pending = args[:] - self.kwargs = kwargs.copy() - - def __call__(self, *args, **kwargs): - if kwargs and self.kwargs: - kw = self.kwargs.copy() - kw.update(kwargs) - else: - kw = kwargs or self.kwargs - - return self.fun(*self.pending + args, **kw) - -def Str(target, source, env, cmd=""): - result = [] - for cmd in env.subst_list(cmd, target=target, source=source): - result.append(" ".join(map(str, cmd))) - return '\\n'.join(result) - -class ToolSurrogate(object): - def __init__(self, tool, variable, func): - self.tool = tool - self.variable = variable - self.func = func - def __call__(self, env): - t = Tool(self.tool) - t.generate(env) - orig = env[self.variable] - env[self.variable] = Action(self.func, strfunction=Curry(Str, cmd=orig)) - -def Null(target, source, env): - pass - -def Cat(target, source, env): - target = str(target[0]) - f = open(target, "wb") - for src in map(str, source): - f.write(open(src, "rb").read()) - f.close() - -ToolList = { - 'posix' : [('cc', 'CCCOM', Cat), - ('link', 'LINKCOM', Cat), - ('tar', 'TARCOM', Null), - ('zip', 'ZIPCOM', Null)], - 'win32' : [('msvc', 'CCCOM', Cat), - ('mslink', 'LINKCOM', Cat)] -} - -tools = map(lambda t: ToolSurrogate(*t), ToolList[platform]) - -SCons.Defaults.ConstructionEnvironment.update({ - 'PLATFORM' : platform, - 'TOOLS' : tools, -}) - -SConscript('SConstruct') -""" - -class MySGML(sgmllib.SGMLParser): - """A subclass of the standard Python sgmllib SGML parser. - """ - def __init__(self): - sgmllib.SGMLParser.__init__(self) - self.examples = {} - self.afunclist = [] - - def handle_data(self, data): - try: - f = self.afunclist[-1] - except IndexError: - sys.stdout.write(data) - else: - f(data) - - def handle_comment(self, data): - sys.stdout.write('') - - def handle_decl(self, data): - sys.stdout.write('') - - def unknown_starttag(self, tag, attrs): - try: - f = self.example.afunc - except AttributeError: - f = sys.stdout.write - if not attrs: - f('<' + tag + '>') - else: - f('<' + tag) - for name, value in attrs: - f(' ' + name + '=' + '"' + value + '"') - f('>') - - def unknown_endtag(self, tag): - sys.stdout.write('') - - def unknown_entityref(self, ref): - sys.stdout.write('&' + ref + ';') - - def unknown_charref(self, ref): - sys.stdout.write('&#' + ref + ';') - - def start_scons_example(self, attrs): - t = [t for t in attrs if t[0] == 'name'] - if t: - name = t[0][1] - try: - e = self.examples[name] - except KeyError: - e = self.examples[name] = Example() - else: - e = Example() - for name, value in attrs: - setattr(e, name, value) - self.e = e - self.afunclist.append(e.afunc) - - def end_scons_example(self): - e = self.e - files = [f for f in e.files if f.printme] - if files: - sys.stdout.write('') - for f in files: - if f.printme: - i = len(f.data) - 1 - while f.data[i] == ' ': - i = i - 1 - output = f.data[:i+1].replace('__ROOT__', '') - sys.stdout.write(output) - if e.data and e.data[0] == '\n': - e.data = e.data[1:] - sys.stdout.write(e.data + '') - delattr(self, 'e') - self.afunclist = self.afunclist[:-1] - - def start_file(self, attrs): - try: - e = self.e - except AttributeError: - self.error(" tag outside of ") - t = [t for t in attrs if t[0] == 'name'] - if not t: - self.error("no name attribute found") - try: - e.prefix - except AttributeError: - e.prefix = e.data - e.data = "" - f = File(t[0][1]) - f.printme = None - for name, value in attrs: - setattr(f, name, value) - e.files.append(f) - self.afunclist.append(f.afunc) - - def end_file(self): - self.e.data = "" - self.afunclist = self.afunclist[:-1] - - def start_directory(self, attrs): - try: - e = self.e - except AttributeError: - self.error(" tag outside of ") - t = [t for t in attrs if t[0] == 'name'] - if not t: - self.error("no name attribute found") - try: - e.prefix - except AttributeError: - e.prefix = e.data - e.data = "" - d = Directory(t[0][1]) - for name, value in attrs: - setattr(d, name, value) - e.dirs.append(d) - self.afunclist.append(d.afunc) - - def end_directory(self): - self.e.data = "" - self.afunclist = self.afunclist[:-1] - - def start_scons_example_file(self, attrs): - t = [t for t in attrs if t[0] == 'example'] - if not t: - self.error("no example attribute found") - exname = t[0][1] - try: - e = self.examples[exname] - except KeyError: - self.error("unknown example name '%s'" % exname) - fattrs = [t for t in attrs if t[0] == 'name'] - if not fattrs: - self.error("no name attribute found") - fname = fattrs[0][1] - f = [f for f in e.files if f.name == fname] - if not f: - self.error("example '%s' does not have a file named '%s'" % (exname, fname)) - self.f = f[0] - - def end_scons_example_file(self): - f = self.f - sys.stdout.write('') - i = len(f.data) - 1 - while f.data[i] == ' ': - i = i - 1 - sys.stdout.write(f.data[:i+1] + '') - delattr(self, 'f') - - def start_scons_output(self, attrs): - t = [t for t in attrs if t[0] == 'example'] - if not t: - self.error("no example attribute found") - exname = t[0][1] - try: - e = self.examples[exname] - except KeyError: - self.error("unknown example name '%s'" % exname) - # Default values for an example. - o = Output() - o.os = 'posix' - o.e = e - # Locally-set. - for name, value in attrs: - setattr(o, name, value) - self.o = o - self.afunclist.append(o.afunc) - - def end_scons_output(self): - o = self.o - e = o.e - t = TestCmd.TestCmd(workdir='', combine=1) - t.subdir('ROOT', 'WORK') - for d in e.dirs: - dir = t.workpath('WORK', d.name) - if not os.path.exists(dir): - os.makedirs(dir) - for f in e.files: - i = 0 - while f.data[i] == '\n': - i = i + 1 - lines = f.data[i:].split('\n') - i = 0 - while lines[0][i] == ' ': - i = i + 1 - lines = [l[i:] for l in lines] - path = f.name.replace('__ROOT__', t.workpath('ROOT')) - dir, name = os.path.split(f.name) - if dir: - dir = t.workpath('WORK', dir) - if not os.path.exists(dir): - os.makedirs(dir) - content = '\n'.join(lines) - content = content.replace('__ROOT__', - t.workpath('ROOT')) - t.write(t.workpath('WORK', f.name), content) - i = len(o.prefix) - while o.prefix[i-1] != '\n': - i = i - 1 - sys.stdout.write('' + o.prefix[:i]) - p = o.prefix[i:] - for c in o.commandlist: - sys.stdout.write(p + Prompt[o.os]) - d = c.data.replace('__ROOT__', '') - sys.stdout.write('' + d + '\n') - e = c.data.replace('__ROOT__', t.workpath('ROOT')) - args = e.split()[1:] - os.environ['SCONS_LIB_DIR'] = scons_lib_dir - t.run(interpreter = sys.executable, - program = scons_py, - arguments = '-f - ' + ' '.join(args), - chdir = t.workpath('WORK'), - stdin = Stdin % o.os) - out = t.stdout().replace(t.workpath('ROOT'), '') - if out: - lines = out.split('\n') - if lines: - while lines[-1] == '': - lines = lines[:-1] - for l in lines: - sys.stdout.write(p + l + '\n') - #err = t.stderr() - #if err: - # sys.stderr.write(err) - if o.data[0] == '\n': - o.data = o.data[1:] - sys.stdout.write(o.data + '') - delattr(self, 'o') - self.afunclist = self.afunclist[:-1] - - def start_command(self, attrs): - try: - o = self.o - except AttributeError: - self.error(" tag outside of ") - try: - o.prefix - except AttributeError: - o.prefix = o.data - o.data = "" - c = Command() - o.commandlist.append(c) - self.afunclist.append(c.afunc) - - def end_command(self): - self.o.data = "" - self.afunclist = self.afunclist[:-1] - - def start_sconstruct(self, attrs): - sys.stdout.write('') - - def end_sconstruct(self): - sys.stdout.write('') - -try: - file = sys.argv[1] -except IndexError: - file = '-' - -if file == '-': - f = sys.stdin -else: - try: - f = open(file, 'r') - except IOError, msg: - print file, ":", msg - sys.exit(1) - -data = f.read() -if f is not sys.stdin: - f.close() - -x = MySGML() -for c in data: - x.feed(c) -x.close() - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/bin/scp-sourceforge b/bin/scp-sourceforge new file mode 100755 index 0000000..ad761d1 --- /dev/null +++ b/bin/scp-sourceforge @@ -0,0 +1,38 @@ +#!/bin/bash +set -x +set -e + +if [ -z "$1" ]; then + echo usage: $0 SourceForgeUserName + exit +fi + +SF_USER=$1 + +rm -rf sf +for p in scons scons-src scons-local +do + mkdir -p sf/$p/$VERSION + cp -p src/Announce.txt \ + build/scons/CHANGES.txt \ + build/scons/RELEASE.txt \ + sf/$p/$VERSION +done + +cp -p build/dist/scons-$VERSION-1.noarch.rpm \ + build/dist/scons-$VERSION-1.src.rpm \ + build/dist/scons-$VERSION.tar.gz \ + build/dist/scons-$VERSION.win32.exe \ + build/dist/scons-$VERSION.zip \ + sf/scons/$VERSION +cp -p build/dist/scons-local-$VERSION.tar.gz \ + build/dist/scons-local-$VERSION.zip \ + sf/scons-src/$VERSION +cp -p build/dist/scons-src-$VERSION.tar.gz \ + build/dist/scons-src-$VERSION.zip \ + sf/scons-local/$VERSION + +# Transmit them in this order, since the most-recent is displayed at the top +scp -r sf/scons-local/ sf/scons-src/ sf/scons/ \ + $SF_USER,scons@frs.sourceforge.net:/home/pfs/project/s/sc/scons +rm -rf sf diff --git a/bin/update-release-info.py b/bin/update-release-info.py index 7e11c4b..1c84466 100644 --- a/bin/update-release-info.py +++ b/bin/update-release-info.py @@ -36,7 +36,7 @@ In 'post' mode, files are prepared for the next release cycle: src/Announce.txt. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -57,7 +57,7 @@ In 'post' mode, files are prepared for the next release cycle: # 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__ = "bin/update-release-info.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "bin/update-release-info.py 5357 2011/09/09 21:31:03 bdeegan" import os import sys @@ -114,12 +114,18 @@ if version_tuple[3] != 'final': else: yyyy,mm,dd,_,_,_ = release_date version_tuple = version_tuple[:4] + ((yyyy*100 + mm)*100 + dd,) - version_string = '.'.join(map(str, version_tuple)) + +import pdb +pdb.set_trace() + +if mode == 'final' or mode == 'release': + version_string = '.'.join(map(str, version_tuple[0:3])) else: - # Final release doesn't have type or builddate in version string - version_string = '.'.join(map(str, version_tuple[:3])) + version_string = '.'.join(map(str, version_tuple)) version_type = version_tuple[3] + + if DEBUG: print 'version string', version_string if version_type not in ['alpha', 'beta', 'candidate', 'final']: @@ -188,7 +194,9 @@ class UpdateFile(object): ''' XXX ''' + if DEBUG: print "content before:%s"%self.content self.content = self.match_rel.sub(replacement, self.content, count) + if DEBUG: print "content after :%s"%self.content # Determine the release date and the pattern to match a date # Mon, 05 Jun 2010 21:17:15 -0700 diff --git a/bin/xmlagenda.py b/bin/xmlagenda.py index 7937331..b3cd520 100755 --- a/bin/xmlagenda.py +++ b/bin/xmlagenda.py @@ -1,11 +1,15 @@ #!/usr/bin/env python -# Download the issues from Issuzilla as XML; this creates a file named -# 'issues.xml'. Run this script to translate 'issues.xml' into a CSV -# file named 'editlist.csv'. Upload the CSV into a Google spreadsheet. +# Query the scons.tigris.org database for the issues of interest. +# The typical triage query is found on http://www.scons.org/wiki/BugParty -# In the spreadsheet, select the last column and pick "delete-->column" (it -# was added by the upload to allow for expansion and we don't need it). +# Download the issues from Issuezilla as XML; this creates a file +# named 'issues.xml'. Run this script in the dir containing +# issues.xml (or pass full path as arg to this script) to translate +# 'issues.xml' into a CSV file named 'editlist.csv'. Upload the CSV +# into a Google spreadsheet. + +# In the spreadsheet: # Select all the columns and pick "align-->top" # Select the ID and votes columns and pick "align-->right" # Select the priority column and pick "align-->center" @@ -17,7 +21,7 @@ # The team members # FIXME: These names really should be external to this script -team = sorted('Steven Gary Greg Ken Jim David Bill Sergey Jason'.split()) +team = sorted('Steven Gary Greg Ken Jim Bill Jason Dirk Anatoly'.split()) # The elements to be picked out of the issue PickList = [ @@ -85,6 +89,8 @@ for issue in issues: writer.writerow(['','','','','','','']) for member in team: writer.writerow(['','',member,'','','','']) +print "Exported %d issues to editlist.csv. Ready to upload to Google."%len(issues) + # Local Variables: # tab-width:4 # indent-tabs-mode:nil diff --git a/doc/SConscript b/doc/SConscript index e0b3f71..54b620e 100644 --- a/doc/SConscript +++ b/doc/SConscript @@ -3,7 +3,7 @@ # # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -43,7 +43,7 @@ dist_doc_tar_gz = '$DISTDIR/scons-doc-${VERSION}.tar.gz' # if lynx is available to do the dump. # fig2dev = whereis('fig2dev') -epydoc = whereis('epydoc') +epydoc_cli = whereis('epydoc') groff = whereis('groff') lynx = whereis('lynx') man2html = whereis('man2html') @@ -121,7 +121,7 @@ scons_doc_files = list(map(chop, open(manifest_xml_in).readlines())) scons_doc_files = [File('#src/engine/'+x).rstr() for x in scons_doc_files] if not jw: - print "jw not found, skipping building User Guide." + print "doc: jw not found, skipping building User Guide." else: # # Always create a version.xml file containing the version information @@ -151,6 +151,8 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT. builders_gen = os.path.join(build, 'user', 'builders.gen') builders_mod = os.path.join(build, 'user', 'builders.mod') + functions_gen = os.path.join(build, 'user', 'functions.gen') + functions_mod = os.path.join(build, 'user', 'functions.mod') tools_gen = os.path.join(build, 'user', 'tools.gen') tools_mod = os.path.join(build, 'user', 'tools.mod') variables_gen = os.path.join(build, 'user', 'variables.gen') @@ -163,11 +165,12 @@ THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT. # vs. the other. The *.gen and *.mod targets will still be dependent # on the list of the files themselves. doc_output_files = [builders_gen, builders_mod, + functions_gen, functions_mod, tools_gen, tools_mod, variables_gen, variables_mod] b = env.Command(doc_output_files, scons_doc_files, - "$PYTHON $SCONS_PROC_PY --xml -b ${TARGETS[0]},${TARGETS[1]} -t ${TARGETS[2]},${TARGETS[3]} -v ${TARGETS[4]},${TARGETS[5]} $( $SOURCES $)") + "$PYTHON $SCONS_PROC_PY --xml -b ${TARGETS[0]},${TARGETS[1]} -f ${TARGETS[2]},${TARGETS[3]} -t ${TARGETS[4]},${TARGETS[5]} -v ${TARGETS[6]},${TARGETS[7]} $( $SOURCES $)") env.Depends(b, "$SCONS_PROC_PY") env.Local(b) @@ -403,11 +406,11 @@ for m in man_page_list: 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'] +man_i_files = ['builders.man', 'functions.man', 'tools.man', 'variables.man'] man_intermediate_files = [os.path.join(build, 'man', x) for x in man_i_files] -cmd = "$PYTHON $SCONS_PROC_PY --man -b ${TARGETS[0]} -t ${TARGETS[1]} -v ${TARGETS[2]} $( $SOURCES $)" +cmd = "$PYTHON $SCONS_PROC_PY --man -b ${TARGETS[0]} -f ${TARGETS[1]} -t ${TARGETS[2]} -v ${TARGETS[3]} $( $SOURCES $)" man_intermediate_files = env.Command(man_intermediate_files, scons_doc_files, cmd) @@ -458,8 +461,79 @@ for man_1 in man_page_list: tar_deps.append(html) tar_list.append(html) -if not epydoc: - print "epydoc not found, skipping building API documentation." +if not epydoc_cli: + try: + import epydoc + except ImportError: + epydoc = None + else: + # adding Epydoc builder using imported module + def epydoc_builder_action(target, source, env): + """ + Take a list of `source` files and build docs for them in + `target` dir. + + `target` and `source` are lists. + + Uses OUTDIR and EPYDOCFLAGS environment variables. + + http://www.scons.org/doc/2.0.1/HTML/scons-user/x3594.html + """ + + # the epydoc build process is the following: + # 1. build documentation index + # 2. feed doc index to writer for docs + + from epydoc.docbuilder import build_doc_index + from epydoc.docwriter.html import HTMLWriter + from epydoc.docwriter.latex import LatexWriter + + # first arg is a list where can be names of python package dirs, + # python files, object names or objects itself + docindex = build_doc_index([str(src) for src in source]) + if docindex == None: + return -1 + + if env['EPYDOCFLAGS'] == '--html': + html_writer = HTMLWriter(docindex, + docformat='restructuredText', + prj_name='SCons', + prj_url='http://www.scons.org/') + try: + html_writer.write(env['OUTDIR']) + except OSError: # If directory cannot be created or any file cannot + # be created or written to. + return -2 + + """ + # PDF support requires external Linux utilites, so it's not crossplatform. + # Leaving for now. + # http://epydoc.svn.sourceforge.net/viewvc/epydoc/trunk/epydoc/src/epydoc/cli.py + + elif env['EPYDOCFLAGS'] == '--pdf': + pdf_writer = LatexWriter(docindex, + docformat='restructuredText', + prj_name='SCons', + prj_url='http://www.scons.org/') + """ + return 0 + + epydoc_commands = [ + Delete('$OUTDIR'), + epydoc_builder_action, + Touch('$TARGET'), + ] + +else: # epydoc_cli is found + epydoc_commands = [ + Delete('$OUTDIR'), + '$EPYDOC $EPYDOCFLAGS --debug --output $OUTDIR --docformat=restructuredText --name SCons --url http://www.scons.org/ $SOURCES', + Touch('$TARGET'), + ] + + +if not epydoc_cli and not epydoc: + print "doc: epydoc not found, skipping building API documentation." else: # XXX Should be in common with reading the same thing in # the SConstruct file. @@ -475,40 +549,37 @@ else: e = os.path.join(build, '..', 'scons', 'engine') sources = [os.path.join(e, x) for x in sources] - epydoc_commands = [ - Delete('$OUTDIR'), - '$EPYDOC $EPYDOCFLAGS --debug --output $OUTDIR --docformat=restructuredText --name SCons --url http://www.scons.org/ $SOURCES', - Touch('$TARGET'), - ] - htmldir = os.path.join(build, 'HTML', 'scons-api') env.Command('${OUTDIR}/index.html', sources, epydoc_commands, - EPYDOC=epydoc, EPYDOCFLAGS='--html', OUTDIR=htmldir) + EPYDOC=epydoc_cli, EPYDOCFLAGS='--html', OUTDIR=htmldir) tar_deps.append(htmldir) tar_list.append(htmldir) - # PDF and PostScript and TeX are built from the - # same invocation. - api_dir = os.path.join(build, 'scons-api') - api_pdf = os.path.join(api_dir, 'api.pdf') - api_ps = os.path.join(api_dir, 'api.ps') - api_tex = os.path.join(api_dir, 'api.tex') - api_targets = [api_pdf, api_ps, api_tex] - env.Command(api_targets, sources, epydoc_commands, - EPYDOC=epydoc, EPYDOCFLAGS='--pdf', OUTDIR=api_dir) - Local(api_targets) - - pdf_install = os.path.join(build, 'PDF', 'scons-api.pdf') - env.InstallAs(pdf_install, api_pdf) - tar_deps.append(pdf_install) - tar_list.append(pdf_install) - Local(pdf_install) - - ps_install = os.path.join(build, 'PS', 'scons-api.ps') - env.InstallAs(ps_install, api_ps) - tar_deps.append(ps_install) - tar_list.append(ps_install) - Local(ps_install) + if not epydoc_cli: + print "doc: command line epydoc is not found, skipping PDF/PS/Tex output" + else: + # PDF and PostScript and TeX are built from the + # same invocation. + api_dir = os.path.join(build, 'scons-api') + api_pdf = os.path.join(api_dir, 'api.pdf') + api_ps = os.path.join(api_dir, 'api.ps') + api_tex = os.path.join(api_dir, 'api.tex') + api_targets = [api_pdf, api_ps, api_tex] + env.Command(api_targets, sources, epydoc_commands, + EPYDOC=epydoc_cli, EPYDOCFLAGS='--pdf', OUTDIR=api_dir) + Local(api_targets) + + pdf_install = os.path.join(build, 'PDF', 'scons-api.pdf') + env.InstallAs(pdf_install, api_pdf) + tar_deps.append(pdf_install) + tar_list.append(pdf_install) + Local(pdf_install) + + ps_install = os.path.join(build, 'PS', 'scons-api.ps') + env.InstallAs(ps_install, api_ps) + tar_deps.append(ps_install) + tar_list.append(ps_install) + Local(ps_install) # # Now actually create the tar file of the documentation, diff --git a/doc/design/scons.mod b/doc/design/scons.mod index 012bc3e..33538fb 100644 --- a/doc/design/scons.mod +++ b/doc/design/scons.mod @@ -1,6 +1,6 @@ - Similarly, a more full-fledged tool with + A more full-fledged tool with exists() and generate() - methods can be installed in - site_scons/site_tools/toolname.py. Since - site_scons/site_tools is automatically added - to the head of the tool search path, any tool found there will be - available to all environments. Furthermore, a tool found there - will override a built-in tool of the same name, so if you need to - change the behavior of a built-in tool, site_scons gives you the - hook you need. + methods can be installed either as a module in the file + site_scons/site_tools/toolname.py or as a + package in the + directory site_scons/site_tools/toolname. In + the case of using a package, the exists() + and generate() are in the + file site_scons/site_tools/toolname/__init__.py. + (In all the above case toolname is replaced + by the name of the tool.) + Since site_scons/site_tools is automatically + added to the head of the tool search path, any tool found there + will be available to all environments. Furthermore, a tool found + there will override a built-in tool of the same name, so if you + need to change the behavior of a built-in + tool, site_scons gives you the hook you need. @@ -998,7 +1013,7 @@ This functionality could be invoked as in the following example: - + from SCons.Script import * # for Execute and Mkdir def build_id(): """Return a build ID (stub version)""" @@ -1047,13 +1062,15 @@ This functionality could be invoked as in the following example: - If you have a machine-wide site dir you'd like to use instead of - ./site_scons, use the - --site-dir option to point to your dir. + You can use any of the user- or machine-wide site dirs such as + ~/.scons/site_scons instead of + ./site_scons, or use the + --site-dir option to point to your own dir. site_init.py and site_tools will be located under that dir. - To avoid using a site_scons dir at all, even - if it exists, use the --no-site-dir option. + To avoid using a site_scons dir at all, + even if it exists, use the --no-site-dir + option. diff --git a/doc/user/builders-writing.xml b/doc/user/builders-writing.xml index f364e27..d9bda79 100644 --- a/doc/user/builders-writing.xml +++ b/doc/user/builders-writing.xml @@ -1,6 +1,6 @@ - Similarly, a more full-fledged tool with + A more full-fledged tool with exists() and generate() - methods can be installed in - site_scons/site_tools/toolname.py. Since - site_scons/site_tools is automatically added - to the head of the tool search path, any tool found there will be - available to all environments. Furthermore, a tool found there - will override a built-in tool of the same name, so if you need to - change the behavior of a built-in tool, site_scons gives you the - hook you need. + methods can be installed either as a module in the file + site_scons/site_tools/toolname.py or as a + package in the + directory site_scons/site_tools/toolname. In + the case of using a package, the exists() + and generate() are in the + file site_scons/site_tools/toolname/__init__.py. + (In all the above case toolname is replaced + by the name of the tool.) + Since site_scons/site_tools is automatically + added to the head of the tool search path, any tool found there + will be available to all environments. Furthermore, a tool found + there will override a built-in tool of the same name, so if you + need to change the behavior of a built-in + tool, site_scons gives you the hook you need. @@ -913,13 +928,15 @@ This functionality could be invoked as in the following example: - If you have a machine-wide site dir you'd like to use instead of - ./site_scons, use the - --site-dir option to point to your dir. + You can use any of the user- or machine-wide site dirs such as + ~/.scons/site_scons instead of + ./site_scons, or use the + --site-dir option to point to your own dir. site_init.py and site_tools will be located under that dir. - To avoid using a site_scons dir at all, even - if it exists, use the --no-site-dir option. + To avoid using a site_scons dir at all, + even if it exists, use the --no-site-dir + option. diff --git a/doc/user/builders.in b/doc/user/builders.in index 9e9b647..f2bf36d 100644 --- a/doc/user/builders.in +++ b/doc/user/builders.in @@ -1,6 +1,6 @@ + + + +This appendix contains descriptions of all of the +function and construction environment methods +in this version of &SCons; + + + + + +&functions-gen; + + diff --git a/doc/user/functions.xml b/doc/user/functions.xml new file mode 100644 index 0000000..7c96c54 --- /dev/null +++ b/doc/user/functions.xml @@ -0,0 +1,38 @@ + + + + +This appendix contains descriptions of all of the +function and construction environment methods +in this version of &SCons; + + + + + +&functions-gen; + + diff --git a/doc/user/hierarchy.in b/doc/user/hierarchy.in index 16d9389..950bc8a 100644 --- a/doc/user/hierarchy.in +++ b/doc/user/hierarchy.in @@ -1,6 +1,6 @@ diff --git a/doc/user/main.in b/doc/user/main.in index fbc28df..feb8c25 100644 --- a/doc/user/main.in +++ b/doc/user/main.in @@ -1,7 +1,7 @@ - - Merging Options into the Environment: the &MergeFlags; Function - &mergeflags; - - - Separating Compile Arguments into their Variables: the &ParseFlags; Function - &parseflags; - - - Finding Installed Library Information: the &ParseConfig; Function - &parseconfig; + + Automatically Putting Command-line Options into their Construction Variables + + + This chapter describes the &MergeFlags;, &ParseFlags;, and &ParseConfig; methods of a &consenv;. + +
+ Merging Options into the Environment: the &MergeFlags; Function + &mergeflags; +
+
+ Separating Compile Arguments into their Variables: the &ParseFlags; Function + &parseflags; +
+
+ Finding Installed Library Information: the &ParseConfig; Function + &parseconfig; +
+
@@ -341,6 +363,11 @@ &tools; + + Functions and Environment Methods + &functions; + + Handling Common Tasks &tasks; diff --git a/doc/user/main.xml b/doc/user/main.xml index fbc28df..feb8c25 100644 --- a/doc/user/main.xml +++ b/doc/user/main.xml @@ -1,7 +1,7 @@ - - Merging Options into the Environment: the &MergeFlags; Function - &mergeflags; - - - Separating Compile Arguments into their Variables: the &ParseFlags; Function - &parseflags; - - - Finding Installed Library Information: the &ParseConfig; Function - &parseconfig; + + Automatically Putting Command-line Options into their Construction Variables + + + This chapter describes the &MergeFlags;, &ParseFlags;, and &ParseConfig; methods of a &consenv;. + +
+ Merging Options into the Environment: the &MergeFlags; Function + &mergeflags; +
+
+ Separating Compile Arguments into their Variables: the &ParseFlags; Function + &parseflags; +
+
+ Finding Installed Library Information: the &ParseConfig; Function + &parseconfig; +
+
@@ -341,6 +363,11 @@ &tools;
+ + Functions and Environment Methods + &functions; + + Handling Common Tasks &tasks; diff --git a/doc/user/make.in b/doc/user/make.in index c17b047..7102557 100644 --- a/doc/user/make.in +++ b/doc/user/make.in @@ -1,6 +1,6 @@ + + + A dictionary mapping the names of the builders @@ -185,3 +188,2971 @@ A list of the names of the Tool specifications that are part of this construction environment. + + + + + +(action, [cmd/str/fun, [var, ...]] [option=value, ...]) + + +Creates an Action object for +the specified +action. +See the section "Action Objects," +below, for a complete explanation of the arguments and behavior. + +Note that the +env.Action() +form of the invocation will expand +construction variables in any argument strings, +including the +action +argument, at the time it is called +using the construction variables in the +env +construction environment through which +env.Action() +was called. +The +Action() +form delays all variable expansion +until the Action object is actually used. + + + + + +(object, function, [name]) + + +(function, [name]) + + +When called with the +AddMethod() +form, +adds the specified +function +to the specified +object +as the specified method +name. +When called with the +env.AddMethod() +form, +adds the specified +function +to the construction environment +env +as the specified method +name. +In both cases, if +name +is omitted or +None, +the name of the +specified +function +itself is used for the method name. + +Examples: + + +# Note that the first argument to the function to +# be attached as a method must be the object through +# which the method will be called; the Python +# convention is to call it 'self'. +def my_method(self, arg): + print "my_method() got", arg + +# Use the global AddMethod() function to add a method +# to the Environment class. This +AddMethod(Environment, my_method) +env = Environment() +env.my_method('arg') + +# Add the function as a method, using the function +# name for the method call. +env = Environment() +env.AddMethod(my_method, 'other_method_name') +env.other_method_name('another arg') + + + + + + +(target, action) + + +Arranges for the specified +action +to be performed +after the specified +target +has been built. +The specified action(s) may be +an Action object, or anything that +can be converted into an Action object +(see below). + +When multiple targets are supplied, +the action may be called multiple times, +once after each action that generates +one or more targets in the list. + + + + + +(target, action) + + +Arranges for the specified +action +to be performed +before the specified +target +is built. +The specified action(s) may be +an Action object, or anything that +can be converted into an Action object +(see below). + +When multiple targets are specified, +the action(s) may be called multiple times, +once before each action that generates +one or more targets in the list. + +Note that if any of the targets are built in multiple steps, +the action will be invoked just +before the "final" action that specifically +generates the specified target(s). +For example, when building an executable program +from a specified source +.c +file via an intermediate object file: + + +foo = Program('foo.c') +AddPreAction(foo, 'pre_action') + + +The specified +pre_action +would be executed before +&scons; +calls the link command that actually +generates the executable program binary +foo, +not before compiling the +foo.c +file into an object file. + + + + + +(alias, [targets, [action]]) + + +Creates one or more phony targets that +expand to one or more other targets. +An optional +action +(command) +or list of actions +can be specified that will be executed +whenever the any of the alias targets are out-of-date. +Returns the Node object representing the alias, +which exists outside of any file system. +This Node object, or the alias name, +may be used as a dependency of any other target, +including another alias. +&f-Alias; +can be called multiple times for the same +alias to add additional targets to the alias, +or additional actions to the list for this alias. + +Examples: + + +Alias('install') +Alias('install', '/usr/bin') +Alias(['install', 'install-lib'], '/usr/local/lib') + +env.Alias('install', ['/usr/local/bin', '/usr/local/lib']) +env.Alias('install', ['/usr/local/man']) + +env.Alias('update', ['file1', 'file2'], "update_database $SOURCES") + + + + + + +(target, ...) + + +Marks each given +target +so that it is always assumed to be out of date, +and will always be rebuilt if needed. +Note, however, that +&f-AlwaysBuild; +does not add its target(s) to the default target list, +so the targets will only be built +if they are specified on the command line, +or are a dependent of a target specified on the command line--but +they will +always +be built if so specified. +Multiple targets can be passed in to a single call to +&f-AlwaysBuild;. + + + + + +(key=val, [...]) + + +Appends the specified keyword arguments +to the end of construction variables in the environment. +If the Environment does not have +the specified construction variable, +it is simply added to the environment. +If the values of the construction variable +and the keyword argument are the same type, +then the two values will be simply added together. +Otherwise, the construction variable +and the value of the keyword argument +are both coerced to lists, +and the lists are added together. +(See also the Prepend method, below.) + +Example: + + +env.Append(CCFLAGS = ' -g', FOO = ['foo.yyy']) + + + + + + +(name, newpath, [envname, sep, delete_existing]) + + +This appends new path elements to the given path in the +specified external environment +(ENV +by default). +This will only add +any particular path once (leaving the last one it encounters and +ignoring the rest, to preserve path order), +and to help assure this, +will normalize all paths (using +os.path.normpath +and +os.path.normcase). +This can also handle the +case where the given old path variable is a list instead of a +string, in which case a list will be returned instead of a string. + +If +delete_existing +is 0, then adding a path that already exists +will not move it to the end; it will stay where it is in the list. + +Example: + + +print 'before:',env['ENV']['INCLUDE'] +include_path = '/foo/bar:/foo' +env.AppendENVPath('INCLUDE', include_path) +print 'after:',env['ENV']['INCLUDE'] + +yields: +before: /foo:/biz +after: /biz:/foo/bar:/foo + + + + + + +(key=val, [...], delete_existing=0) + + +Appends the specified keyword arguments +to the end of construction variables in the environment. +If the Environment does not have +the specified construction variable, +it is simply added to the environment. +If the construction variable being appended to is a list, +then any value(s) that already exist in the +construction variable will +not +be added again to the list. +However, if delete_existing is 1, +existing matching values are removed first, so +existing values in the arg list move to the end of the list. + +Example: + + +env.AppendUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) + + + + + + +(build_dir, src_dir, [duplicate]) + + +Deprecated synonyms for +&f-VariantDir; +and +env.VariantDir(). +The +build_dir +argument becomes the +variant_dir +argument of +&f-VariantDir; +or +env.VariantDir(). + + + + + +(action, [arguments]) + + +Creates a Builder object for +the specified +action. +See the section "Builder Objects," +below, for a complete explanation of the arguments and behavior. + +Note that the +env.Builder() +form of the invocation will expand +construction variables in any arguments strings, +including the +action +argument, +at the time it is called +using the construction variables in the +env +construction environment through which +env.Builder() +was called. +The +&f-Builder; +form delays all variable expansion +until after the Builder object is actually called. + + + + + +(cache_dir) + + +Specifies that +&scons; +will maintain a cache of derived files in +cache_dir. +The derived files in the cache will be shared +among all the builds using the same +&f-CacheDir; +call. +Specifying a +cache_dir +of +None +disables derived file caching. + +Calling +env.CacheDir() +will only affect targets built +through the specified construction environment. +Calling +&f-CacheDir; +sets a global default +that will be used by all targets built +through construction environments +that do +not +have an +env.CacheDir() +specified. + +When a +CacheDir() +is being used and +&scons; +finds a derived file that needs to be rebuilt, +it will first look in the cache to see if a +derived file has already been built +from identical input files and an identical build action +(as incorporated into the MD5 build signature). +If so, +&scons; +will retrieve the file from the cache. +If the derived file is not present in the cache, +&scons; +will rebuild it and +then place a copy of the built file in the cache +(identified by its MD5 build signature), +so that it may be retrieved by other +builds that need to build the same derived file +from identical inputs. + +Use of a specified +&f-CacheDir; +may be disabled for any invocation +by using the + +option. + +If the + +option is used, +&scons; +will place a copy of +all +derived files in the cache, +even if they already existed +and were not built by this invocation. +This is useful to populate a cache +the first time +&f-CacheDir; +is added to a build, +or after using the + +option. + +When using +&f-CacheDir;, +&scons; +will report, +"Retrieved `file' from cache," +unless the + +option is being used. +When the + +option is used, +&scons; +will print the action that +would +have been used to build the file, +without any indication that +the file was actually retrieved from the cache. +This is useful to generate build logs +that are equivalent regardless of whether +a given derived file has been built in-place +or retrieved from the cache. + +The +&f-link-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. + + + + + +(targets, files_or_dirs) + + +This specifies a list of files or directories which should be removed +whenever the targets are specified with the + +command line option. +The specified targets may be a list +or an individual target. +Multiple calls to +&f-Clean; +are legal, +and create new targets or add files and directories to the +clean list for the specified targets. + +Multiple files or directories should be specified +either as separate arguments to the +&f-Clean; +method, or as a list. +&f-Clean; +will also accept the return value of any of the construction environment +Builder methods. +Examples: + +The related +&f-link-NoClean; +function overrides calling +&f-Clean; +for the same target, +and any targets passed to both functions will +not +be removed by the + +option. + +Examples: + + +Clean('foo', ['bar', 'baz']) +Clean('dist', env.Program('hello', 'hello.c')) +Clean(['foo', 'bar'], 'something_else_to_clean') + + +In this example, +installing the project creates a subdirectory for the documentation. +This statement causes the subdirectory to be removed +if the project is deinstalled. + +Clean(docdir, os.path.join(docdir, projectname)) + + + + + + +([key=val, ...]) + + +Returns a separate copy of a construction environment. +If there are any keyword arguments specified, +they are added to the returned copy, +overwriting any existing values +for the keywords. + +Example: + + +env2 = env.Clone() +env3 = env.Clone(CCFLAGS = '-g') + + +Additionally, a list of tools and a toolpath may be specified, as in +the Environment constructor: + + +def MyTool(env): env['FOO'] = 'bar' +env4 = env.Clone(tools = ['msvc', MyTool]) + + +The +parse_flags +keyword argument is also recognized: + + +# create an environment for compiling programs that use wxWidgets +wx_env = env.Clone(parse_flags = '!wx-config --cflags --cxxflags') + + + + + + +The &b-Command; "Builder" is actually implemented +as a function that looks like a Builder, +but actually takes an additional argument of the action +from which the Builder should be made. +See the &f-link-Command; function description +for the calling syntax and details. + + + + + +(target, source, action, [key=val, ...]) + + +Executes a specific action +(or list of actions) +to build a target file or files. +This is more convenient +than defining a separate Builder object +for a single special-case build. + +As a special case, the +source_scanner +keyword argument can +be used to specify +a Scanner object +that will be used to scan the sources. +(The global +DirScanner +object can be used +if any of the sources will be directories +that must be scanned on-disk for +changes to files that aren't +already specified in other Builder of function calls.) + +Any other keyword arguments specified override any +same-named existing construction variables. + +An action can be an external command, +specified as a string, +or a callable Python object; +see "Action Objects," below, +for more complete information. +Also note that a string specifying an external command +may be preceded by an +@ +(at-sign) +to suppress printing the command in question, +or by a +- +(hyphen) +to ignore the exit status of the external command. + +Examples: + + +env.Command('foo.out', 'foo.in', + "$FOO_BUILD < $SOURCES > $TARGET") + +env.Command('bar.out', 'bar.in', + ["rm -f $TARGET", + "$BAR_BUILD < $SOURCES > $TARGET"], + ENV = {'PATH' : '/usr/local/bin/'}) + +def rename(env, target, source): + import os + os.rename('.tmp', str(target[0])) + +env.Command('baz.out', 'baz.in', + ["$BAZ_BUILD < $SOURCES > .tmp", + rename ]) + + +Note that the +&f-Command; +function will usually assume, by default, +that the specified targets and/or sources are Files, +if no other part of the configuration +identifies what type of entry it is. +If necessary, you can explicitly specify +that targets or source nodes should +be treated as directoriese +by using the +&f-link-Dir; +or +env.Dir() +functions. + +Examples: + + +env.Command('ddd.list', Dir('ddd'), 'ls -l $SOURCE > $TARGET') + +env['DISTDIR'] = 'destination/directory' +env.Command(env.Dir('$DISTDIR')), None, make_distdir) + + +(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.) + + + + + +(env, [custom_tests, conf_dir, log_file, config_h]) + + +([custom_tests, conf_dir, log_file, config_h]) + + +Creates a Configure object for integrated +functionality similar to GNU autoconf. +See the section "Configure Contexts," +below, for a complete explanation of the arguments and behavior. + + + + + +([key=val, ...]) + + +A now-deprecated synonym for +env.Clone(). + + + + + +(function) + + +Specifies that all up-to-date decisions for +targets built through this construction environment +will be handled by the specified +function. +The +function +can be one of the following strings +that specify the type of decision function +to be performed: + + + +timestamp-newer + + +Specifies that a target shall be considered out of date and rebuilt +if the dependency's timestamp is newer than the target file's timestamp. +This is the behavior of the classic Make utility, +and +make +can be used a synonym for +timestamp-newer. + + + + +timestamp-match + + +Specifies that a target shall be considered out of date and rebuilt +if the dependency's timestamp is different than the +timestamp recorded the last time the target was built. +This provides behavior very similar to the classic Make utility +(in particular, files are not opened up so that their +contents can be checksummed) +except that the target will also be rebuilt if a +dependency file has been restored to a version with an +earlier +timestamp, such as can happen when restoring files from backup archives. + + + + +MD5 + + +Specifies that a target shall be considered out of date and rebuilt +if the dependency's content has changed sine the last time +the target was built, +as determined be performing an MD5 checksum +on the dependency's contents +and comparing it to the checksum recorded the +last time the target was built. +content +can be used as a synonym for +MD5. + + + + +MD5-timestamp + + +Specifies that a target shall be considered out of date and rebuilt +if the dependency's content has changed sine the last time +the target was built, +except that dependencies with a timestamp that matches +the last time the target was rebuilt will be +assumed to be up-to-date and +not +rebuilt. +This provides behavior very similar +to the +MD5 +behavior of always checksumming file contents, +with an optimization of not checking +the contents of files whose timestamps haven't changed. +The drawback is that SCons will +not +detect if a file's content has changed +but its timestamp is the same, +as might happen in an automated script +that runs a build, +updates a file, +and runs the build again, +all within a single second. + + + + + +Examples: + + +# Use exact timestamp matches by default. +Decider('timestamp-match') + +# Use MD5 content signatures for any targets built +# with the attached construction environment. +env.Decider('content') + + +In addition to the above already-available functions, +the +function +argument may be an actual Python function +that takes the following three arguments: + + + +dependency + + +The Node (file) which +should cause the +target +to be rebuilt +if it has "changed" since the last tme +target +was built. + + + + +target + + +The Node (file) being built. +In the normal case, +this is what should get rebuilt +if the +dependency +has "changed." + + + + +prev_ni + + +Stored information about the state of the +dependency +the last time the +target +was built. +This can be consulted to match various +file characteristics +such as the timestamp, +size, or content signature. + + + + + +The +function +should return a +True +(non-zero) +value if the +dependency +has "changed" since the last time +the +target +was built +(indicating that the target +should +be rebuilt), +and +False +(zero) +otherwise +(indicating that the target should +not +be rebuilt). +Note that the decision can be made +using whatever criteria are appopriate. +Ignoring some or all of the function arguments +is perfectly normal. + +Example: + + +def my_decider(dependency, target, prev_ni): + return not os.path.exists(str(target)) + +env.Decider(my_decider) + + + + + + +(target, dependency) + + +Specifies an explicit dependency; +the +target +will be rebuilt +whenever the +dependency +has changed. +Both the specified +target +and +dependency +can be a string +(usually the path name of a file or directory) +or Node objects, +or a list of strings or Node objects +(such as returned by a Builder call). +This should only be necessary +for cases where the dependency +is not caught by a Scanner +for the file. + +Example: + + +env.Depends('foo', 'other-input-file-for-foo') + +mylib = env.Library('mylib.c') +installed_lib = env.Install('lib', mylib) +bar = env.Program('bar.c') + +# Arrange for the library to be copied into the installation +# directory before trying to build the "bar" program. +# (Note that this is for example only. A "real" library +# dependency would normally be configured through the $LIBS +# and $LIBPATH variables, not using an env.Depends() call.) + +env.Depends(bar, installed_lib) + + + + + + +([vars]) + + +Returns a dictionary object +containing copies of all of the +construction variables in the environment. +If there are any variable names specified, +only the specified construction +variables are returned in the dictionary. + +Example: + + +dict = env.Dictionary() +cc_dict = env.Dictionary('CC', 'CCFLAGS', 'CCCOM') + + + + + + +(name, [directory]) + + +This returns a Directory Node, +an object that represents the specified directory +name. +name +can be a relative or absolute path. +directory +is an optional directory that will be used as the parent directory. +If no +directory +is specified, the current script's directory is used as the parent. + +If +name +is a list, SCons returns a list of Dir nodes. +Construction variables are expanded in +name. + +Directory Nodes can be used anywhere you +would supply a string as a directory name +to a Builder method or function. +Directory Nodes have attributes and methods +that are useful in many situations; +see "File and Directory Nodes," below. + + + + + +([key]) + + +Returns a pretty printable representation of the environment. +key, +if not +None, +should be a string containing the name of the variable of interest. + +This SConstruct: + + +env=Environment() +print env.Dump('CCCOM') + + +will print: + + +'$CC -c -o $TARGET $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES' + + +While this SConstruct: + + +env=Environment() +print env.Dump() + + +will print: + +{ 'AR': 'ar', + 'ARCOM': '$AR $ARFLAGS $TARGET $SOURCES\n$RANLIB $RANLIBFLAGS $TARGET', + 'ARFLAGS': ['r'], + 'AS': 'as', + 'ASCOM': '$AS $ASFLAGS -o $TARGET $SOURCES', + 'ASFLAGS': [], + ... + + + + + + +([key=value, ...]) + + +Return a new construction environment +initialized with the specified +key=value +pairs. + + + + + +(action, [strfunction, varlist]) + + +Executes an Action object. +The specified +action +may be an Action object +(see the section "Action Objects," +below, for a complete explanation of the arguments and behavior), +or it may be a command-line string, +list of commands, +or executable Python function, +each of which will be converted +into an Action object +and then executed. +The exit value of the command +or return value of the Python function +will be returned. + +Note that +&scons; +will print an error message if the executed +action +fails--that is, +exits with or returns a non-zero value. +&scons; +will +not, +however, +automatically terminate the build +if the specified +action +fails. +If you want the build to stop in response to a failed +&f-Execute; +call, +you must explicitly check for a non-zero return value: + + +Execute(Copy('file.out', 'file.in')) + +if Execute("mkdir sub/dir/ectory"): + # The mkdir failed, don't try to build. + Exit(1) + + + + + + +(name, [directory]) + + +This returns a +File Node, +an object that represents the specified file +name. +name +can be a relative or absolute path. +directory +is an optional directory that will be used as the parent directory. + +If +name +is a list, SCons returns a list of File nodes. +Construction variables are expanded in +name. + +File Nodes can be used anywhere you +would supply a string as a file name +to a Builder method or function. +File Nodes have attributes and methods +that are useful in many situations; +see "File and Directory Nodes," below. + + + + + +(file, dirs) + + +Search for +file +in the path specified by +dirs. +dirs +may be a list of directory names or a single directory name. +In addition to searching for files that exist in the filesystem, +this function also searches for derived files +that have not yet been built. + +Example: + + +foo = env.FindFile('foo', ['dir1', 'dir2']) + + + + + + +() + + +Returns the list of targets set up by the +&b-link-Install; +or +&b-link-InstallAs; +builders. + +This function serves as a convenient method to select the contents of +a binary package. + +Example: + + +Install( '/bin', [ 'executable_a', 'executable_b' ] ) + +# will return the file node list +# [ '/bin/executable_a', '/bin/executable_b' ] +FindInstalledFiles() + +Install( '/lib', [ 'some_library' ] ) + +# will return the file node list +# [ '/bin/executable_a', '/bin/executable_b', '/lib/some_library' ] +FindInstalledFiles() + + + + + + +(node='"."') + + +Returns the list of nodes which serve as the source of the built files. +It does so by inspecting the dependency tree starting at the optional +argument +node +which defaults to the '"."'-node. It will then return all leaves of +node. +These are all children which have no further children. + +This function is a convenient method to select the contents of a Source +Package. + +Example: + + +Program( 'src/main_a.c' ) +Program( 'src/main_b.c' ) +Program( 'main_c.c' ) + +# returns ['main_c.c', 'src/main_a.c', 'SConstruct', 'src/main_b.c'] +FindSourceFiles() + +# returns ['src/main_b.c', 'src/main_a.c' ] +FindSourceFiles( 'src' ) + + +As you can see build support files (SConstruct in the above example) +will also be returned by this function. + + + + + +(sequence) + + +Takes a sequence (that is, a Python list or tuple) +that may contain nested sequences +and returns a flattened list containing +all of the individual elements in any sequence. +This can be helpful for collecting +the lists returned by calls to Builders; +other Builders will automatically +flatten lists specified as input, +but direct Python manipulation of +these lists does not. + +Examples: + + +foo = Object('foo.c') +bar = Object('bar.c') + +# Because `foo' and `bar' are lists returned by the Object() Builder, +# `objects' will be a list containing nested lists: +objects = ['f1.o', foo, 'f2.o', bar, 'f3.o'] + +# Passing such a list to another Builder is all right because +# the Builder will flatten the list automatically: +Program(source = objects) + +# If you need to manipulate the list directly using Python, you need to +# call Flatten() yourself, or otherwise handle nested lists: +for object in Flatten(objects): + print str(object) + + + + + + +(file, [...]) + + +Returns the +&scons; +path name (or names) for the specified +file +(or files). +The specified +file +or files +may be +&scons; +Nodes or strings representing path names. + + + + + +(pattern, [ondisk, source, strings]) + + +Returns Nodes (or strings) that match the specified +pattern, +relative to the directory of the current +&SConscript; +file. +The +env.Glob() +form performs string substition on +pattern +and returns whatever matches +the resulting expanded pattern. + +The specified +pattern +uses Unix shell style metacharacters for matching: + + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + +If the first character of a filename is a dot, +it must be matched explicitly. +Character matches do +not +span directory separators. + +The +&f-Glob; +knows about +repositories +(see the +&f-link-Repository; +function) +and source directories +(see the +&f-link-VariantDir; +function) +and +returns a Node (or string, if so configured) +in the local (SConscript) directory +if matching Node is found +anywhere in a corresponding +repository or source directory. + +The +ondisk +argument may be set to +False +(or any other non-true value) +to disable the search for matches on disk, +thereby only returning matches among +already-configured File or Dir Nodes. +The default behavior is to +return corresponding Nodes +for any on-disk matches found. + +The +source +argument may be set to +True +(or any equivalent value) +to specify that, +when the local directory is a +&f-VariantDir;, +the returned Nodes should be from the +corresponding source directory, +not the local directory. + +The +strings +argument may be set to +True +(or any equivalent value) +to have the +&f-Glob; +function return strings, not Nodes, +that represent the matched files or directories. +The returned strings will be relative to +the local (SConscript) directory. +(Note that This may make it easier to perform +arbitrary manipulation of file names, +but if the returned strings are +passed to a different +&SConscript; +file, +any Node translation will be relative +to the other +&SConscript; +directory, +not the original +&SConscript; +directory.) + +Examples: + + +Program('foo', Glob('*.c')) +Zip('/tmp/everything', Glob('.??*') + Glob('*')) + + + + + + + + +(target, dependency) + + +The specified dependency file(s) +will be ignored when deciding if +the target file(s) need to be rebuilt. + +You can also use +&f-Ignore; +to remove a target from the default build. +In order to do this you must specify the directory the target will +be built in as the target, and the file you want to skip building +as the dependency. + +Note that this will only remove the dependencies listed from +the files built by default. It will still be built if that +dependency is needed by another object being built. +See the third and forth examples below. + +Examples: + + +env.Ignore('foo', 'foo.c') +env.Ignore('bar', ['bar1.h', 'bar2.h']) +env.Ignore('.','foobar.obj') +env.Ignore('bar','bar/foobar.obj') + + + + + + +(string) + + +The specified +string +will be preserved as-is +and not have construction variables expanded. + + + + + +(targets) + + +The specified +targets +will have copies made in the local tree, +even if an already up-to-date copy +exists in a repository. +Returns a list of the target Node or Nodes. + + + + + + + +(arg, [unique]) + + +Merges the specified +arg +values to the construction environment's construction variables. +If the +arg +argument is not a dictionary, +it is converted to one by calling +&f-link-env-ParseFlags; +on the argument +before the values are merged. +Note that +arg +must be a single value, +so multiple strings must +be passed in as a list, +not as separate arguments to +&f-env-MergeFlags;. + +By default, +duplicate values are eliminated; +you can, however, specify +unique=0 +to allow duplicate +values to be added. +When eliminating duplicate values, +any construction variables that end with +the string +PATH +keep the left-most unique value. +All other construction variables keep +the right-most unique value. + +Examples: + + +# Add an optimization flag to $CCFLAGS. +env.MergeFlags('-O3') + +# Combine the flags returned from running pkg-config with an optimization +# flag and merge the result into the construction variables. +env.MergeFlags(['!pkg-config gtk+-2.0 --cflags', '-O3']) + +# Combine an optimization flag with the flags returned from running pkg-config +# twice and merge the result into the construction variables. +env.MergeFlags(['-O3', + '!pkg-config gtk+-2.0 --cflags --libs', + '!pkg-config libpng12 --cflags --libs']) + + + + + + +(target, ...) + + +Specifies a list of files which should +not +be cached whenever the +&f-link-CacheDir; +method has been activated. +The specified targets may be a list +or an individual target. + +Multiple files should be specified +either as separate arguments to the +&f-NoCache; +method, or as a list. +&f-NoCache; +will also accept the return value of any of the construction environment +Builder methods. + +Calling +&f-NoCache; +on directories and other non-File Node types has no effect because +only File Nodes are cached. + +Examples: + + +NoCache('foo.elf') +NoCache(env.Program('hello', 'hello.c')) + + + + + + +(target, ...) + + +Specifies a list of files or directories which should +not +be removed whenever the targets (or their dependencies) +are specified with the + +command line option. +The specified targets may be a list +or an individual target. +Multiple calls to +&f-NoClean; +are legal, +and prevent each specified target +from being removed by calls to the + +option. + +Multiple files or directories should be specified +either as separate arguments to the +&f-NoClean; +method, or as a list. +&f-NoClean; +will also accept the return value of any of the construction environment +Builder methods. + +Calling +&f-NoClean; +for a target overrides calling +&f-link-Clean; +for the same target, +and any targets passed to both functions will +not +be removed by the + +option. + +Examples: + + +NoClean('foo.elf') +NoClean(env.Program('hello', 'hello.c')) + + + + + + +(command, [function, unique]) + + +Calls the specified +function +to modify the environment as specified by the output of +command. +The default +function +is +&f-link-env-MergeFlags;, +which expects the output of a typical +*-config +command +(for example, +gtk-config) +and adds the options +to the appropriate construction variables. +By default, +duplicate values are not +added to any construction variables; +you can specify +unique=0 +to allow duplicate +values to be added. + +Interpreted options +and the construction variables they affect +are as specified for the +&f-link-env-ParseFlags; +method (which this method calls). +See that method's description, below, +for a table of options and construction variables. + + + + + +(filename, [must_exist, only_one]) + + +Parses the contents of the specified +filename +as a list of dependencies in the style of +&Make; +or +mkdep, +and explicitly establishes all of the listed dependencies. + +By default, +it is not an error +if the specified +filename +does not exist. +The optional +must_exist +argument may be set to a non-zero +value to have +scons +throw an exception and +generate an error if the file does not exist, +or is otherwise inaccessible. + +The optional +only_one +argument may be set to a non-zero +value to have +scons +thrown an exception and +generate an error +if the file contains dependency +information for more than one target. +This can provide a small sanity check +for files intended to be generated +by, for example, the +gcc -M +flag, +which should typically only +write dependency information for +one output file into a corresponding +.d +file. + +The +filename +and all of the files listed therein +will be interpreted relative to +the directory of the +&SConscript; +file which calls the +&f-ParseDepends; +function. + + + + + +(flags, ...) + + +Parses one or more strings containing +typical command-line flags for GCC tool chains +and returns a dictionary with the flag values +separated into the appropriate SCons construction variables. +This is intended as a companion to the +&f-link-env-MergeFlags; +method, but allows for the values in the returned dictionary +to be modified, if necessary, +before merging them into the construction environment. +(Note that +&f-env-MergeFlags; +will call this method if its argument is not a dictionary, +so it is usually not necessary to call +&f-link-env-ParseFlags; +directly unless you want to manipulate the values.) + +If the first character in any string is +an exclamation mark (!), +the rest of the string is executed as a command, +and the output from the command is +parsed as GCC tool chain command-line flags +and added to the resulting dictionary. + +Flag values are translated accordig to the prefix found, +and added to the following construction variables: + + +-arch CCFLAGS, LINKFLAGS +-D CPPDEFINES +-framework FRAMEWORKS +-frameworkdir= FRAMEWORKPATH +-include CCFLAGS +-isysroot CCFLAGS, LINKFLAGS +-I CPPPATH +-l LIBS +-L LIBPATH +-mno-cygwin CCFLAGS, LINKFLAGS +-mwindows LINKFLAGS +-pthread CCFLAGS, LINKFLAGS +-std= CFLAGS +-Wa, ASFLAGS, CCFLAGS +-Wl,-rpath= RPATH +-Wl,-R, RPATH +-Wl,-R RPATH +-Wl, LINKFLAGS +-Wp, CPPFLAGS +- CCFLAGS ++ CCFLAGS, LINKFLAGS + + +Any other strings not associated with options +are assumed to be the names of libraries +and added to the +&cv-LIBS; +construction variable. + +Examples (all of which produce the same result): + + +dict = env.ParseFlags('-O2 -Dfoo -Dbar=1') +dict = env.ParseFlags('-O2', '-Dfoo', '-Dbar=1') +dict = env.ParseFlags(['-O2', '-Dfoo -Dbar=1']) +dict = env.ParseFlags('-O2', '!echo -Dfoo -Dbar=1') + + + + + + +(string) + + +The +&f-Platform; +form returns a callable object +that can be used to initialize +a construction environment using the +platform keyword of the +&f-Environment; +function. + +Example: + + +env = Environment(platform = Platform('win32')) + + +The +&f-env-Platform; +form applies the callable object for the specified platform +string +to the environment through which the method was called. + + +env.Platform('posix') + + +Note that the +win32 +platform adds the +SystemDrive +and +SystemRoot +variables from the user's external environment +to the construction environment's +&cv-link-ENV; +dictionary. +This is so that any executed commands +that use sockets to connect with other systems +(such as fetching source files from +external CVS repository specifications like +:pserver:anonymous@cvs.sourceforge.net:/cvsroot/scons) +will work on Windows systems. + + + + + +(key=val, [...]) + + +Appends the specified keyword arguments +to the beginning of construction variables in the environment. +If the Environment does not have +the specified construction variable, +it is simply added to the environment. +If the values of the construction variable +and the keyword argument are the same type, +then the two values will be simply added together. +Otherwise, the construction variable +and the value of the keyword argument +are both coerced to lists, +and the lists are added together. +(See also the Append method, above.) + +Example: + + +env.Prepend(CCFLAGS = '-g ', FOO = ['foo.yyy']) + + + + + + +(name, newpath, [envname, sep, delete_existing]) + + +This appends new path elements to the given path in the +specified external environment +(&cv-ENV; +by default). +This will only add +any particular path once (leaving the first one it encounters and +ignoring the rest, to preserve path order), +and to help assure this, +will normalize all paths (using +os.path.normpath +and +os.path.normcase). +This can also handle the +case where the given old path variable is a list instead of a +string, in which case a list will be returned instead of a string. + +If +delete_existing +is 0, then adding a path that already exists +will not move it to the beginning; +it will stay where it is in the list. + +Example: + + +print 'before:',env['ENV']['INCLUDE'] +include_path = '/foo/bar:/foo' +env.PrependENVPath('INCLUDE', include_path) +print 'after:',env['ENV']['INCLUDE'] + + +The above example will print: + + +before: /biz:/foo +after: /foo/bar:/foo:/biz + + + + + + +(key=val, delete_existing=0, [...]) + + +Appends the specified keyword arguments +to the beginning of construction variables in the environment. +If the Environment does not have +the specified construction variable, +it is simply added to the environment. +If the construction variable being appended to is a list, +then any value(s) that already exist in the +construction variable will +not +be added again to the list. +However, if delete_existing is 1, +existing matching values are removed first, so +existing values in the arg list move to the front of the list. + +Example: + + +env.PrependUnique(CCFLAGS = '-g', FOO = ['foo.yyy']) + + + + + + +(key=val, [...]) + + +Replaces construction variables in the Environment +with the specified keyword arguments. + +Example: + + +env.Replace(CCFLAGS = '-g', FOO = 'foo.xxx') + + + + + + +(directory) + + +Specifies that +directory +is a repository to be searched for files. +Multiple calls to +&f-Repository; +are legal, +and each one adds to the list of +repositories that will be searched. + +To +&scons;, +a repository is a copy of the source tree, +from the top-level directory on down, +which may contain +both source files and derived files +that can be used to build targets in +the local source tree. +The canonical example would be an +official source tree maintained by an integrator. +If the repository contains derived files, +then the derived files should have been built using +&scons;, +so that the repository contains the necessary +signature information to allow +&scons; +to figure out when it is appropriate to +use the repository copy of a derived file, +instead of building one locally. + +Note that if an up-to-date derived file +already exists in a repository, +&scons; +will +not +make a copy in the local directory tree. +In order to guarantee that a local copy +will be made, +use the +&f-link-Local; +method. + + + + + +(target, prerequisite) + + +Specifies an order-only relationship +between the specified target file(s) +and the specified prerequisite file(s). +The prerequisite file(s) +will be (re)built, if necessary, +before +the target file(s), +but the target file(s) do not actually +depend on the prerequisites +and will not be rebuilt simply because +the prerequisite file(s) change. + +Example: + + +env.Requires('foo', 'file-that-must-be-built-before-foo') + + + + + + +(function, [argument, keys, path_function, node_class, node_factory, scan_check, recursive]) + + +Creates a Scanner object for +the specified +function. +See the section "Scanner Objects," +below, for a complete explanation of the arguments and behavior. + + + + + +(value) + + +By default, +&scons; +changes its working directory +to the directory in which each +subsidiary SConscript file lives. +This behavior may be disabled +by specifying either: + + +SConscriptChdir(0) +env.SConscriptChdir(0) + + +in which case +&scons; +will stay in the top-level directory +while reading all SConscript files. +(This may be necessary when building from repositories, +when all the directories in which SConscript files may be found +don't necessarily exist locally.) +You may enable and disable +this ability by calling +SConscriptChdir() +multiple times. + +Example: + + +env = Environment() +SConscriptChdir(0) +SConscript('foo/SConscript') # will not chdir to foo +env.SConscriptChdir(1) +SConscript('bar/SConscript') # will chdir to bar + + + + + + +([file, dbm_module]) + + +This tells +&scons; +to store all file signatures +in the specified database +file. +If the +file +name is omitted, +.sconsign +is used by default. +(The actual file name(s) stored on disk +may have an appropriated suffix appended +by the + dbm_module.) +If +file +is not an absolute path name, +the file is placed in the same directory as the top-level +&SConstruct; +file. + +If +file +is +None, +then +&scons; +will store file signatures +in a separate +.sconsign +file in each directory, +not in one global database file. +(This was the default behavior +prior to SCons 0.96.91 and 0.97.) + +The optional +dbm_module +argument can be used to specify +which Python database module +The default is to use a custom +SCons.dblite +module that uses pickled +Python data structures, +and which works on all Python versions. + +Examples: + + +# Explicitly stores signatures in ".sconsign.dblite" +# in the top-level SConstruct directory (the +# default behavior). +SConsignFile() + +# Stores signatures in the file "etc/scons-signatures" +# relative to the top-level SConstruct directory. +SConsignFile("etc/scons-signatures") + +# Stores signatures in the specified absolute file name. +SConsignFile("/home/me/SCons/signatures") + +# Stores signatures in a separate .sconsign file +# in each directory. +SConsignFile(None) + + + + + + +(key=val, [...]) + + +Sets construction variables to default values specified with the keyword +arguments if (and only if) the variables are not already set. +The following statements are equivalent: + + +env.SetDefault(FOO = 'foo') + +if 'FOO' not in env: env['FOO'] = 'foo' + + + + + + +(side_effect, target) + + +Declares +side_effect +as a side effect of building +target. +Both +side_effect +and +target +can be a list, a file name, or a node. +A side effect is a target file that is created or updated +as a side effect of building other targets. +For example, a Windows PDB +file is created as a side effect of building the .obj +files for a static library, +and various log files are created updated +as side effects of various TeX commands. +If a target is a side effect of multiple build commands, +&scons; +will ensure that only one set of commands +is executed at a time. +Consequently, you only need to use this method +for side-effect targets that are built as a result of +multiple build commands. + +Because multiple build commands may update +the same side effect file, +by default the +side_effect +target is +not +automatically removed +when the +target +is removed by the + +option. +(Note, however, that the +side_effect +might be removed as part of +cleaning the directory in which it lives.) +If you want to make sure the +side_effect +is cleaned whenever a specific +target +is cleaned, +you must specify this explicitly +with the +&f-link-Clean; +or +&f-env-Clean; +function. + + + + + +(entries, builder) + + +This function and its associate factory functions are deprecated. +There is no replacement. +The intended use was to keep a local tree in sync with an archive, +but in actuality the function only causes the archive +to be fetched on the first run. +Synchronizing with the archive is best done external to &SCons;. + +Arrange for non-existent source files to +be fetched from a source code management system +using the specified +builder. +The specified +entries +may be a Node, string or list of both, +and may represent either individual +source files or directories in which +source files can be found. + +For any non-existent source files, +&scons; +will search up the directory tree +and use the first +&f-SourceCode; +builder it finds. +The specified +builder +may be +None, +in which case +&scons; +will not use a builder to fetch +source files for the specified +entries, +even if a +&f-SourceCode; +builder has been specified +for a directory higher up the tree. + +&scons; +will, by default, +fetch files from SCCS or RCS subdirectories +without explicit configuration. +This takes some extra processing time +to search for the necessary +source code management files on disk. +You can avoid these extra searches +and speed up your build a little +by disabling these searches as follows: + + +env.SourceCode('.', None) + + +Note that if the specified +builder +is one you create by hand, +it must have an associated +construction environment to use +when fetching a source file. + +&scons; +provides a set of canned factory +functions that return appropriate +Builders for various popular +source code management systems. +Canonical examples of invocation include: + + +env.SourceCode('.', env.BitKeeper('/usr/local/BKsources')) +env.SourceCode('src', env.CVS('/usr/local/CVSROOT')) +env.SourceCode('/', env.RCS()) +env.SourceCode(['f1.c', 'f2.c'], env.SCCS()) +env.SourceCode('no_source.c', None) + + + + + + + +(type) + + +Note: Although it is not yet officially deprecated, +use of this function is discouraged. +See the +&f-link-Decider; +function for a more flexible and straightforward way +to configure SCons' decision-making. + +The +&f-SourceSignatures; +function tells +&scons; +how to decide if a source file +(a file that is not built from any other files) +has changed since the last time it +was used to build a particular target file. +Legal values are +MD5 +or +timestamp. + +If the environment method is used, +the specified type of source signature +is only used when deciding whether targets +built with that environment are up-to-date or must be rebuilt. +If the global function is used, +the specified type of source signature becomes the default +used for all decisions +about whether targets are up-to-date. + +MD5 +means +&scons; +decides that a source file has changed +if the MD5 checksum of its contents has changed since +the last time it was used to rebuild a particular target file. + +timestamp +means +&scons; +decides that a source file has changed +if its timestamp (modification time) has changed since +the last time it was used to rebuild a particular target file. +(Note that although this is similar to the behavior of Make, +by default it will also rebuild if the dependency is +older +than the last time it was used to rebuild the target file.) + +There is no different between the two behaviors +for Python +&f-Value; +node objects. + +MD5 +signatures take longer to compute, +but are more accurate than +timestamp +signatures. +The default value is +MD5. + +Note that the default +&f-link-TargetSignatures; +setting (see below) +is to use this +&f-SourceSignatures; +setting for any target files that are used +to build other target files. +Consequently, changing the value of +&f-SourceSignatures; +will, by default, +affect the up-to-date decision for all files in the build +(or all files built with a specific construction environment +when +&f-env-SourceSignatures; +is used). + + + + + +(arg) + + +Returns a list of file names or other objects. +If arg is a string, +it will be split on strings of white-space characters +within the string, +making it easier to write long lists of file names. +If arg is already a list, +the list will be returned untouched. +If arg is any other type of object, +it will be returned as a list +containing just the object. + +Example: + + +files = Split("f1.c f2.c f3.c") +files = env.Split("f4.c f5.c f6.c") +files = Split(""" + f7.c + f8.c + f9.c +""") + + + + + + +(input, [raw, target, source, conv]) + + +Performs construction variable interpolation +on the specified string or sequence argument +input. + +By default, +leading or trailing white space will +be removed from the result. +and all sequences of white space +will be compressed to a single space character. +Additionally, any +$( +and +$) +character sequences will be stripped from the returned string, +The optional +raw +argument may be set to +1 +if you want to preserve white space and +$(-$) +sequences. +The +raw +argument may be set to +2 +if you want to strip +all characters between +any +$( +and +$) +pairs +(as is done for signature calculation). + +If the input is a sequence +(list or tuple), +the individual elements of +the sequence will be expanded, +and the results will be returned as a list. + +The optional +target +and +source +keyword arguments +must be set to lists of +target and source nodes, respectively, +if you want the +&cv-TARGET;, +&cv-TARGETS;, +&cv-SOURCE; +and +&cv-SOURCES; +to be available for expansion. +This is usually necessary if you are +calling +&f-env-subst; +from within a Python function used +as an SCons action. + +Returned string values or sequence elements +are converted to their string representation by default. +The optional +conv +argument +may specify a conversion function +that will be used in place of +the default. +For example, if you want Python objects +(including SCons Nodes) +to be returned as Python objects, +you can use the Python +λ +idiom to pass in an unnamed function +that simply returns its unconverted argument. + +Example: + + +print env.subst("The C compiler is: $CC") + +def compile(target, source, env): + sourceDir = env.subst("${SOURCE.srcdir}", + target=target, + source=source) + +source_nodes = env.subst('$EXPAND_TO_NODELIST', + conv=lambda x: x) + + + + + + +(type) + + +Note: Although it is not yet officially deprecated, +use of this function is discouraged. +See the +&f-link-Decider; +function for a more flexible and straightforward way +to configure SCons' decision-making. + +The +&f-TargetSignatures; +function tells +&scons; +how to decide if a target file +(a file that +is +built from any other files) +has changed since the last time it +was used to build some other target file. +Legal values are +"build"; +"content" +(or its synonym +"MD5"); +"timestamp"; +or +"source". + +If the environment method is used, +the specified type of target signature is only used +for targets built with that environment. +If the global function is used, +the specified type of signature becomes the default +used for all target files that +don't have an explicit target signature type +specified for their environments. + +"content" +(or its synonym +"MD5") +means +&scons; +decides that a target file has changed +if the MD5 checksum of its contents has changed since +the last time it was used to rebuild some other target file. +This means +&scons; +will open up +MD5 sum the contents +of target files after they're built, +and may decide that it does not need to rebuild +"downstream" target files if a file was +rebuilt with exactly the same contents as the last time. + +"timestamp" +means +&scons; +decides that a target file has changed +if its timestamp (modification time) has changed since +the last time it was used to rebuild some other target file. +(Note that although this is similar to the behavior of Make, +by default it will also rebuild if the dependency is +older +than the last time it was used to rebuild the target file.) + +"source" +means +&scons; +decides that a target file has changed +as specified by the corresponding +&f-SourceSignatures; +setting +("MD5" +or +"timestamp"). +This means that +&scons; +will treat all input files to a target the same way, +regardless of whether they are source files +or have been built from other files. + +"build" +means +&scons; +decides that a target file has changed +if it has been rebuilt in this invocation +or if its content or timestamp have changed +as specified by the corresponding +&f-SourceSignatures; +setting. +This "propagates" the status of a rebuilt file +so that other "downstream" target files +will always be rebuilt, +even if the contents or the timestamp +have not changed. + +"build" +signatures are fastest because +"content" +(or +"MD5") +signatures take longer to compute, +but are more accurate than +"timestamp" +signatures, +and can prevent unnecessary "downstream" rebuilds +when a target file is rebuilt to the exact same contents +as the previous build. +The +"source" +setting provides the most consistent behavior +when other target files may be rebuilt from +both source and target input files. +The default value is +"source". + +Because the default setting is +"source", +using +&f-SourceSignatures; +is generally preferable to +&f-TargetSignatures;, +so that the up-to-date decision +will be consistent for all files +(or all files built with a specific construction environment). +Use of +&f-TargetSignatures; +provides specific control for how built target files +affect their "downstream" dependencies. + + + + + +(string, [toolpath, **kw]) + + +The +&f-Tool; +form of the function +returns a callable object +that can be used to initialize +a construction environment using the +tools keyword of the Environment() method. +The object may be called with a construction +environment as an argument, +in which case the object will +add the necessary variables +to the construction environment +and the name of the tool will be added to the +&cv-link-TOOLS; +construction variable. + +Additional keyword arguments are passed to the tool's +generate() +method. + +Examples: + + +env = Environment(tools = [ Tool('msvc') ]) + +env = Environment() +t = Tool('msvc') +t(env) # adds 'msvc' to the TOOLS variable +u = Tool('opengl', toolpath = ['tools']) +u(env) # adds 'opengl' to the TOOLS variable + + +The +&f-env-Tool; +form of the function +applies the callable object for the specified tool +string +to the environment through which the method was called. + +Additional keyword arguments are passed to the tool's +generate() +method. + + +env.Tool('gcc') +env.Tool('opengl', toolpath = ['build/tools']) + + + + + + +(value, [built_value]) + + +Returns a Node object representing the specified Python value. Value +Nodes can be used as dependencies of targets. If the result of +calling +str(value) +changes between SCons runs, any targets depending on +Value(value) +will be rebuilt. +(This is true even when using timestamps to decide if +files are up-to-date.) +When using timestamp source signatures, Value Nodes' +timestamps are equal to the system time when the Node is created. + +The returned Value Node object has a +write() +method that can be used to "build" a Value Node +by setting a new value. +The optional +built_value +argument can be specified +when the Value Node is created +to indicate the Node should already be considered +"built." +There is a corresponding +read() +method that will return the built value of the Node. + +Examples: + + +env = Environment() + +def create(target, source, env): + # A function that will write a 'prefix=$SOURCE' + # string into the file name specified as the + # $TARGET. + f = open(str(target[0]), 'wb') + f.write('prefix=' + source[0].get_contents()) + +# Fetch the prefix= argument, if any, from the command +# line, and use /usr/local as the default. +prefix = ARGUMENTS.get('prefix', '/usr/local') + +# Attach a .Config() builder for the above function action +# to the construction environment. +env['BUILDERS']['Config'] = Builder(action = create) +env.Config(target = 'package-config', source = Value(prefix)) + +def build_value(target, source, env): + # A function that "builds" a Python Value by updating + # the the Python value with the contents of the file + # specified as the source of the Builder call ($SOURCE). + target[0].write(source[0].get_contents()) + +output = env.Value('before') +input = env.Value('after') + +# Attach a .UpdateValue() builder for the above function +# action to the construction environment. +env['BUILDERS']['UpdateValue'] = Builder(action = build_value) +env.UpdateValue(target = Value(output), source = Value(input)) + + + + + + +(variant_dir, src_dir, [duplicate]) + + +Use the +&f-VariantDir; +function to create a copy of your sources in another location: +if a name under +variant_dir +is not found but exists under +src_dir, +the file or directory is copied to +variant_dir. +Target files can be built in a different directory +than the original sources by simply refering to the sources (and targets) +within the variant tree. + +&f-VariantDir; +can be called multiple times with the same +src_dir +to set up multiple builds with different options +(variants). +The +src_dir +location must be in or underneath the SConstruct file's directory, and +variant_dir +may not be underneath +src_dir. + + +The default behavior is for +&scons; +to physically duplicate the source files in the variant tree. +Thus, a build performed in the variant tree is guaranteed to be identical +to a build performed in the source tree even if +intermediate source files are generated during the build, +or preprocessors or other scanners search for included files +relative to the source file, +or individual compilers or other invoked tools are hard-coded +to put derived files in the same directory as source files. + +If possible on the platform, +the duplication is performed by linking rather than copying; +see also the + +command-line option. +Moreover, only the files needed for the build are duplicated; +files and directories that are not used are not present in +variant_dir. + +Duplicating the source tree may be disabled by setting the +duplicate +argument to +0 +(zero). +This will cause +&scons; +to invoke Builders using the path names of source files in +src_dir +and the path names of derived files within +variant_dir. +This is always more efficient than +duplicate=1, +and is usually safe for most builds +(but see above for cases that may cause problems). + +Note that +&f-VariantDir; +works most naturally with a subsidiary SConscript file. +However, you would then call the subsidiary SConscript file +not in the source directory, but in the +variant_dir, +regardless of the value of +duplicate. +This is how you tell +&scons; +which variant of a source tree to build: + + +# run src/SConscript in two variant directories +VariantDir('build/variant1', 'src') +SConscript('build/variant1/SConscript') +VariantDir('build/variant2', 'src') +SConscript('build/variant2/SConscript') + + +See also the +&f-link-SConscript; +function, described above, +for another way to specify a variant directory +in conjunction with calling a subsidiary SConscript file. + +Examples: + + +# use names in the build directory, not the source directory +VariantDir('build', 'src', duplicate=0) +Program('build/prog', 'build/source.c') + + + +# this builds both the source and docs in a separate subtree +VariantDir('build', '.', duplicate=0) +SConscript(dirs=['build/src','build/doc']) + + + +# same as previous example, but only uses SConscript +SConscript(dirs='src', variant_dir='build/src', duplicate=0) +SConscript(dirs='doc', variant_dir='build/doc', duplicate=0) + + + + + + +(program, [path, pathext, reject]) + + +Searches for the specified executable +program, +returning the full path name to the program +if it is found, +and returning None if not. +Searches the specified +path, +the value of the calling environment's PATH +(env['ENV']['PATH']), +or the user's current external PATH +(os.environ['PATH']) +by default. +On Windows systems, searches for executable +programs with any of the file extensions +listed in the specified +pathext, +the calling environment's PATHEXT +(env['ENV']['PATHEXT']) +or the user's current PATHEXT +(os.environ['PATHEXT']) +by default. +Will not select any +path name or names +in the specified +reject +list, if any. + + diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index e7a851f..9486331 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/EnvironmentTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/EnvironmentTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat @@ -763,6 +763,7 @@ sys.exit(0) 'ASFLAGS' : [], 'CFLAGS' : [], 'CCFLAGS' : [], + 'CXXFLAGS' : [], 'CPPDEFINES' : [], 'CPPFLAGS' : [], 'CPPPATH' : [], @@ -793,11 +794,14 @@ sys.exit(0) "-Wl,-Rrpath3 " + \ "-Wp,-cpp " + \ "-std=c99 " + \ + "-std=c++0x " + \ "-framework Carbon " + \ "-frameworkdir=fwd1 " + \ "-Ffwd2 " + \ "-F fwd3 " + \ + "-dylib_file foo-dylib " + \ "-pthread " + \ + "-fopenmp " + \ "-mno-cygwin -mwindows " + \ "-arch i386 -isysroot /tmp +DD64 " + \ "-DFOO -DBAR=value -D BAZ " @@ -807,9 +811,10 @@ sys.exit(0) assert d['ASFLAGS'] == ['-as'], d['ASFLAGS'] assert d['CFLAGS'] == ['-std=c99'] assert d['CCFLAGS'] == ['-X', '-Wa,-as', - '-pthread', '-mno-cygwin', + '-pthread', '-fopenmp', '-mno-cygwin', ('-arch', 'i386'), ('-isysroot', '/tmp'), - '+DD64'], d['CCFLAGS'] + '+DD64'], repr(d['CCFLAGS']) + assert d['CXXFLAGS'] == ['-std=c++0x'], repr(d['CXXFLAGS']) assert d['CPPDEFINES'] == ['FOO', ['BAR', 'value'], 'BAZ'], d['CPPDEFINES'] assert d['CPPFLAGS'] == ['-Wp,-cpp'], d['CPPFLAGS'] assert d['CPPPATH'] == ['/usr/include/fum', @@ -822,11 +827,13 @@ sys.exit(0) 'C:\\Program Files\\ASCEND'], d['LIBPATH'] LIBS = list(map(str, d['LIBS'])) assert LIBS == ['xxx', 'yyy', 'ascend'], (d['LIBS'], LIBS) - assert d['LINKFLAGS'] == ['-Wl,-link', '-pthread', + assert d['LINKFLAGS'] == ['-Wl,-link', + '-dylib_file', 'foo-dylib', + '-pthread', '-fopenmp', '-mno-cygwin', '-mwindows', ('-arch', 'i386'), ('-isysroot', '/tmp'), - '+DD64'], d['LINKFLAGS'] + '+DD64'], repr(d['LINKFLAGS']) assert d['RPATH'] == ['rpath1', 'rpath2', 'rpath3'], d['RPATH'] diff --git a/src/engine/SCons/Errors.py b/src/engine/SCons/Errors.py index 63f9d41..2501e36 100644 --- a/src/engine/SCons/Errors.py +++ b/src/engine/SCons/Errors.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ and user errors in SCons. """ -__revision__ = "src/engine/SCons/Errors.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Errors.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.Util diff --git a/src/engine/SCons/ErrorsTests.py b/src/engine/SCons/ErrorsTests.py index 2643244..fb2eb6a 100644 --- a/src/engine/SCons/ErrorsTests.py +++ b/src/engine/SCons/ErrorsTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/ErrorsTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/ErrorsTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index b31e348..f343568 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -6,7 +6,7 @@ Nodes. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ Nodes. # 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__ = "src/engine/SCons/Executor.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Executor.py 5357 2011/09/09 21:31:03 bdeegan" import collections diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index 077ae79..7f898f8 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/ExecutorTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/ExecutorTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Job.py b/src/engine/SCons/Job.py index 7866bb4..04bb4c4 100644 --- a/src/engine/SCons/Job.py +++ b/src/engine/SCons/Job.py @@ -7,7 +7,7 @@ stop, and wait on jobs. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ stop, and wait on jobs. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Job.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Job.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat diff --git a/src/engine/SCons/JobTests.py b/src/engine/SCons/JobTests.py index 145843c..85bc9ca 100644 --- a/src/engine/SCons/JobTests.py +++ b/src/engine/SCons/JobTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ # 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__ = "src/engine/SCons/JobTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/JobTests.py 5357 2011/09/09 21:31:03 bdeegan" import unittest import random diff --git a/src/engine/SCons/Memoize.py b/src/engine/SCons/Memoize.py index c76d6a5..ea7d58f 100644 --- a/src/engine/SCons/Memoize.py +++ b/src/engine/SCons/Memoize.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Memoize.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Memoize.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Memoizer diff --git a/src/engine/SCons/MemoizeTests.py b/src/engine/SCons/MemoizeTests.py index 37f6874..a542807 100644 --- a/src/engine/SCons/MemoizeTests.py +++ b/src/engine/SCons/MemoizeTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/MemoizeTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/MemoizeTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Node/Alias.py b/src/engine/SCons/Node/Alias.py index c0f3ece..9996e64 100644 --- a/src/engine/SCons/Node/Alias.py +++ b/src/engine/SCons/Node/Alias.py @@ -8,7 +8,7 @@ This creates a hash of global Aliases (dummy targets). """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -30,7 +30,7 @@ This creates a hash of global Aliases (dummy targets). # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Node/Alias.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/Alias.py 5357 2011/09/09 21:31:03 bdeegan" import collections diff --git a/src/engine/SCons/Node/AliasTests.py b/src/engine/SCons/Node/AliasTests.py index 6551ea4..49debc5 100644 --- a/src/engine/SCons/Node/AliasTests.py +++ b/src/engine/SCons/Node/AliasTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Node/AliasTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/AliasTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 0997fc0..9c1b05a 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -11,7 +11,7 @@ that can be used by scripts or modules looking for the canonical default. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,7 +32,7 @@ that can be used by scripts or modules looking for the canonical default. # 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__ = "src/engine/SCons/Node/FS.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/FS.py 5357 2011/09/09 21:31:03 bdeegan" import fnmatch import os @@ -56,6 +56,7 @@ import SCons.Warnings from SCons.Debug import Trace do_store_info = True +print_duplicate = 0 class EntryProxyAttributeError(AttributeError): @@ -110,33 +111,85 @@ def save_strings(val): # do_splitdrive = None +_my_splitdrive =None def initialize_do_splitdrive(): global do_splitdrive + global has_unc drive, path = os.path.splitdrive('X:/foo') - do_splitdrive = not not drive + has_unc = hasattr(os.path, 'splitunc') + + do_splitdrive = not not drive or has_unc + + global _my_splitdrive + if has_unc: + def splitdrive(p): + if p[1:2] == ':': + return p[:2], p[2:] + if p[0:2] == '//': + # Note that we leave a leading slash in the path + # because UNC paths are always absolute. + return '//', p[1:] + return '', p + else: + def splitdrive(p): + if p[1:2] == ':': + return p[:2], p[2:] + return '', p + _my_splitdrive = splitdrive + + # Keep some commonly used values in global variables to skip to + # module look-up costs. + global OS_SEP + global UNC_PREFIX + global os_sep_is_slash + + OS_SEP = os.sep + UNC_PREFIX = OS_SEP + OS_SEP + os_sep_is_slash = OS_SEP == '/' initialize_do_splitdrive() -# - -needs_normpath_check = None - -def initialize_normpath_check(): - """ - Initialize the normpath_check regular expression. - - This function is used by the unit tests to re-initialize the pattern - when testing for behavior with different values of os.sep. - """ - global needs_normpath_check - if os.sep == '/': - pattern = r'.*/|\.$|\.\.$' - else: - pattern = r'.*[/%s]|\.$|\.\.$' % re.escape(os.sep) - needs_normpath_check = re.compile(pattern) - -initialize_normpath_check() +# Used to avoid invoking os.path.normpath if not necessary. +needs_normpath_check = re.compile( + r''' + # We need to renormalize the path if it contains any consecutive + # '/' characters. + .*// | + + # We need to renormalize the path if it contains a '..' directory. + # Note that we check for all the following cases: + # + # a) The path is a single '..' + # b) The path starts with '..'. E.g. '../' or '../moredirs' + # but we not match '..abc/'. + # c) The path ends with '..'. E.g. '/..' or 'dirs/..' + # d) The path contains a '..' in the middle. + # E.g. dirs/../moredirs + + (.*/)?\.\.(?:/|$) | + + # We need to renormalize the path if it contains a '.' + # directory, but NOT if it is a single '.' '/' characters. We + # do not want to match a single '.' because this case is checked + # for explicitely since this is common enough case. + # + # Note that we check for all the following cases: + # + # a) We don't match a single '.' + # b) We match if the path starts with '.'. E.g. './' or + # './moredirs' but we not match '.abc/'. + # c) We match if the path ends with '.'. E.g. '/.' or + # 'dirs/.' + # d) We match if the path contains a '.' in the middle. + # E.g. dirs/./moredirs + + \./|.*/\.(?:/|$) + + ''', + re.VERBOSE + ) +needs_normpath_match = needs_normpath_check.match # # SCons.Action objects for interacting with the outside world. @@ -438,21 +491,21 @@ class EntryProxy(SCons.Util.Proxy): def __get_posix_path(self): """Return the path with / as the path separator, regardless of platform.""" - if os.sep == '/': + if os_sep_is_slash: return self else: entry = self.get() - r = entry.get_path().replace(os.sep, '/') + r = entry.get_path().replace(OS_SEP, '/') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix") def __get_windows_path(self): """Return the path with \ as the path separator, regardless of platform.""" - if os.sep == '\\': + if OS_SEP == '\\': return self else: entry = self.get() - r = entry.get_path().replace(os.sep, '\\') + r = entry.get_path().replace(OS_SEP, '\\') return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_windows") def __get_srcnode(self): @@ -533,9 +586,13 @@ class Base(SCons.Node.Node): # Filenames and paths are probably reused and are intern'ed to # save some memory. + + #: Filename with extension as it was specified when the object was + #: created; to obtain filesystem path, use Python str() function self.name = SCons.Util.silent_intern(name) + #: Cached filename extension self.suffix = SCons.Util.silent_intern(SCons.Util.splitext(name)[1]) - self.fs = fs + self.fs = fs #: Reference to parent Node.FS object assert directory, "A directory must be provided" @@ -606,7 +663,7 @@ class Base(SCons.Node.Node): else: result = srcnode.get_path() if not Save_Strings: - # We're not at the point where we're saving the string string + # We're not at the point where we're saving the string # representations of FS Nodes (because we haven't finished # reading the SConscript files and need to have str() return # things relative to them). That also means we can't yet @@ -695,11 +752,15 @@ class Base(SCons.Node.Node): if self == dir: return '.' path_elems = self.path_elements + pathname = '' try: i = path_elems.index(dir) - except ValueError: pass - else: path_elems = path_elems[i+1:] - path_elems = [n.name for n in path_elems] - return os.sep.join(path_elems) + except ValueError: + for p in path_elems[:-1]: + pathname += p.dirname + else: + for p in path_elems[i+1:-1]: + pathname += p.dirname + return pathname + path_elems[-1].name def set_src_builder(self, builder): """Set the source code builder for this node.""" @@ -1063,7 +1124,7 @@ class FS(LocalFS): self.pathTop = os.getcwd() else: self.pathTop = path - self.defaultDrive = _my_normcase(os.path.splitdrive(self.pathTop)[0]) + self.defaultDrive = _my_normcase(_my_splitdrive(self.pathTop)[0]) self.Top = self.Dir(self.pathTop) self.Top.path = '.' @@ -1083,7 +1144,10 @@ class FS(LocalFS): self.max_drift = max_drift def getcwd(self): - return self._cwd + if hasattr(self, "_cwd"): + return self._cwd + else: + return "" def chdir(self, dir, change_os_dir=0): """Change the current working directory for lookups. @@ -1147,54 +1211,110 @@ class FS(LocalFS): # str(p) in case it's something like a proxy object p = str(p) - initial_hash = (p[0:1] == '#') - if initial_hash: + if not os_sep_is_slash: + p = p.replace(OS_SEP, '/') + + if p[0:1] == '#': # There was an initial '#', so we strip it and override # whatever directory they may have specified with the # top-level SConstruct directory. p = p[1:] directory = self.Top - if directory and not isinstance(directory, Dir): - directory = self.Dir(directory) + # There might be a drive letter following the + # '#'. Although it is not described in the SCons man page, + # the regression test suite explicitly tests for that + # syntax. It seems to mean the following thing: + # + # Assuming the the SCons top dir is in C:/xxx/yyy, + # '#X:/toto' means X:/xxx/yyy/toto. + # + # i.e. it assumes that the X: drive has a directory + # structure similar to the one found on drive C:. + if do_splitdrive: + drive, p = _my_splitdrive(p) + if drive: + root = self.get_root(drive) + else: + root = directory.root + else: + root = directory.root - if do_splitdrive: - drive, p = os.path.splitdrive(p) - else: - drive = '' - if drive and not p: - # This causes a naked drive letter to be treated as a synonym - # for the root directory on that drive. - p = os.sep - absolute = os.path.isabs(p) - - needs_normpath = needs_normpath_check.match(p) - - if initial_hash or not absolute: - # This is a relative lookup, either to the top-level - # SConstruct directory (because of the initial '#') or to - # the current directory (the path name is not absolute). - # Add the string to the appropriate directory lookup path, - # after which the whole thing gets normalized. - if not directory: - directory = self._cwd - if p: + # We can only strip trailing after splitting the drive + # since the drive might the UNC '//' prefix. + p = p.strip('/') + + needs_normpath = needs_normpath_match(p) + + # The path is relative to the top-level SCons directory. + if p in ('', '.'): + p = directory.labspath + else: p = directory.labspath + '/' + p + else: + if do_splitdrive: + drive, p = _my_splitdrive(p) + if drive and not p: + # This causes a naked drive letter to be treated + # as a synonym for the root directory on that + # drive. + p = '/' else: - p = directory.labspath + drive = '' - if needs_normpath: - p = os.path.normpath(p) + # We can only strip trailing '/' since the drive might the + # UNC '//' prefix. + if p != '/': + p = p.rstrip('/') - if drive or absolute: - root = self.get_root(drive) - else: - if not directory: - directory = self._cwd - root = directory.root + needs_normpath = needs_normpath_match(p) + + if p[0:1] == '/': + # Absolute path + root = self.get_root(drive) + else: + # This is a relative lookup or to the current directory + # (the path name is not absolute). Add the string to the + # appropriate directory lookup path, after which the whole + # thing gets normalized. + if directory: + if not isinstance(directory, Dir): + directory = self.Dir(directory) + else: + directory = self._cwd + + if p in ('', '.'): + p = directory.labspath + else: + p = directory.labspath + '/' + p + + if drive: + root = self.get_root(drive) + else: + root = directory.root + + if needs_normpath is not None: + # Normalize a pathname. Will return the same result for + # equivalent paths. + # + # We take advantage of the fact that we have an absolute + # path here for sure. In addition, we know that the + # components of lookup path are separated by slashes at + # this point. Because of this, this code is about 2X + # faster than calling os.path.normpath() followed by + # replacing os.sep with '/' again. + ins = p.split('/')[1:] + outs = [] + for d in ins: + if d == '..': + try: + outs.pop() + except IndexError: + pass + elif d not in ('', '.'): + outs.append(d) + p = '/' + '/'.join(outs) - if os.sep != '/': - p = p.replace(os.sep, '/') return root._lookup_abs(p, fsclass, create) def Entry(self, name, directory = None, create = 1): @@ -1300,7 +1420,7 @@ class DirNodeInfo(SCons.Node.NodeInfoBase): top = self.fs.Top root = top.root if do_splitdrive: - drive, s = os.path.splitdrive(s) + drive, s = _my_splitdrive(s) if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): @@ -1350,11 +1470,34 @@ class Dir(Base): self.variant_dirs = [] self.root = self.dir.root + # For directories, we make a difference between the directory + # 'name' and the directory 'dirname'. The 'name' attribute is + # used when we need to print the 'name' of the directory or + # when we it is used as the last part of a path. The 'dirname' + # is used when the directory is not the last element of the + # path. The main reason for making that distinction is that + # for RoorDir's the dirname can not be easily inferred from + # the name. For example, we have to add a '/' after a drive + # letter but not after a UNC path prefix ('//'). + self.dirname = self.name + OS_SEP + # Don't just reset the executor, replace its action list, # because it might have some pre-or post-actions that need to # be preserved. - self.builder = get_MkdirBuilder() - self.get_executor().set_action_list(self.builder.action) + # + # But don't reset the executor if there is a non-null executor + # attached already. The existing executor might have other + # targets, in which case replacing the action list with a + # Mkdir action is a big mistake. + if not hasattr(self, 'executor'): + self.builder = get_MkdirBuilder() + self.get_executor().set_action_list(self.builder.action) + else: + # Prepend MkdirBuilder action to existing action list + l = self.get_executor().action_list + a = get_MkdirBuilder().action + l.insert(0, a) + self.get_executor().set_action_list(l) def diskcheck_match(self): diskcheck_match(self, self.isfile, @@ -1403,23 +1546,6 @@ class Dir(Base): """ return self.fs.File(name, self) - def _lookup_rel(self, name, klass, create=1): - """ - Looks up a *normalized* relative path name, relative to this - directory. - - This method is intended for use by internal lookups with - already-normalized path data. For general-purpose lookups, - use the Entry(), Dir() and File() methods above. - - This method does *no* input checking and will die or give - incorrect results if it's passed a non-normalized path name (e.g., - a path containing '..'), an absolute path name, a top-relative - ('#foo') path name, or any kind of object. - """ - name = self.entry_labspath(name) - return self.root._lookup_abs(name, klass, create) - def link(self, srcdir, duplicate): """Set this directory as the variant directory for the supplied source directory.""" @@ -1452,7 +1578,7 @@ class Dir(Base): if fname == '.': fname = dir.name else: - fname = dir.name + os.sep + fname + fname = dir.name + OS_SEP + fname dir = dir.up() self._memo['get_all_rdirs'] = list(result) @@ -1466,7 +1592,7 @@ class Dir(Base): self.__clearRepositoryCache() def up(self): - return self.entries['..'] + return self.dir def _rel_path_key(self, other): return str(other) @@ -1514,14 +1640,14 @@ class Dir(Base): if dir_rel_path == '.': result = other.name else: - result = dir_rel_path + os.sep + other.name + result = dir_rel_path + OS_SEP + other.name else: i = self.path_elements.index(other) + 1 path_elems = ['..'] * (len(self.path_elements) - i) \ + [n.name for n in other.path_elements[i:]] - result = os.sep.join(path_elems) + result = OS_SEP.join(path_elems) memo_dict[other] = result @@ -1691,16 +1817,16 @@ class Dir(Base): return stamp def entry_abspath(self, name): - return self.abspath + os.sep + name + return self.abspath + OS_SEP + name def entry_labspath(self, name): return self.labspath + '/' + name def entry_path(self, name): - return self.path + os.sep + name + return self.path + OS_SEP + name def entry_tpath(self, name): - return self.tpath + os.sep + name + return self.tpath + OS_SEP + name def entry_exists_on_disk(self, name): try: @@ -1721,7 +1847,7 @@ class Dir(Base): if result is None: # Belt-and-suspenders for Windows: check directly for # 8.3 file names that don't show up in os.listdir(). - result = os.path.exists(self.abspath + os.sep + name) + result = os.path.exists(self.abspath + OS_SEP + name) d[name] = result return result else: @@ -1742,7 +1868,7 @@ class Dir(Base): while dir: if dir.srcdir: result.append(dir.srcdir.Dir(dirname)) - dirname = dir.name + os.sep + dirname + dirname = dir.name + OS_SEP + dirname dir = dir.up() self._memo['srcdir_list'] = result @@ -1986,7 +2112,7 @@ class RootDir(Dir): add a separator when creating the path names of entries within this directory. """ - def __init__(self, name, fs): + def __init__(self, drive, fs): if __debug__: logInstanceCreation(self, 'Node.FS.RootDir') # We're going to be our own parent directory (".." entry and .dir # attribute) so we have to set up some values so Base.__init__() @@ -1998,29 +2124,47 @@ class RootDir(Dir): self.path_elements = [] self.duplicate = 0 self.root = self + + # Handle all the types of drives: + if drive == '': + # No drive, regular UNIX root or Windows default drive. + name = OS_SEP + dirname = OS_SEP + elif drive == '//': + # UNC path + name = UNC_PREFIX + dirname = UNC_PREFIX + else: + # Windows drive letter + name = drive + dirname = drive + OS_SEP + Base.__init__(self, name, self, fs) - # Now set our paths to what we really want them to be: the - # initial drive letter (the name) plus the directory separator, - # except for the "lookup abspath," which does not have the - # drive letter. - self.abspath = name + os.sep + # Now set our paths to what we really want them to be. The + # name should already contain any necessary separators, such + # as the initial drive letter (the name) plus the directory + # separator, except for the "lookup abspath," which does not + # have the drive letter. + self.abspath = dirname self.labspath = '' - self.path = name + os.sep - self.tpath = name + os.sep + self.path = dirname + self.tpath = dirname self._morph() + # Must be reset after Dir._morph() is invoked... + self.dirname = dirname + self._lookupDict = {} - # The // and os.sep + os.sep entries are necessary because - # os.path.normpath() seems to preserve double slashes at the - # beginning of a path (presumably for UNC path names), but - # collapses triple slashes to a single slash. self._lookupDict[''] = self self._lookupDict['/'] = self - self._lookupDict['//'] = self - self._lookupDict[os.sep] = self - self._lookupDict[os.sep + os.sep] = self + + # The // entry is necessary because os.path.normpath() + # preserves double slashes at the beginning of a path on Posix + # platforms. + if not has_unc: + self._lookupDict['//'] = self def must_be_same(self, klass): if klass is Dir: @@ -2039,7 +2183,7 @@ class RootDir(Dir): normalized absolute path; we merely let Python's dictionary look up and return the One True Node.FS object for the path. - If no Node for the specified "p" doesn't already exist, and + If a Node for the specified "p" doesn't already exist, and "create" is specified, the Node may be created after recursive invocation to find or create the parent directory or directories. """ @@ -2052,7 +2196,17 @@ class RootDir(Dir): raise SCons.Errors.UserError(msg) # There is no Node for this path name, and we're allowed # to create it. - dir_name, file_name = os.path.split(p) + # (note: would like to use p.rsplit('/',1) here but + # that's not in python 2.3) + # e.g.: dir_name, file_name = p.rsplit('/',1) + last_slash = p.rindex('/') + if (last_slash >= 0): + dir_name = p[:last_slash] + file_name = p[last_slash+1:] + else: + dir_name = p # shouldn't happen, just in case + file_name = '' + dir_node = self._lookup_abs(dir_name, Dir) result = klass(file_name, dir_node, self.fs) @@ -2111,7 +2265,7 @@ class FileNodeInfo(SCons.Node.NodeInfoBase): top = self.fs.Top root = top.root if do_splitdrive: - drive, s = os.path.splitdrive(s) + drive, s = _my_splitdrive(s) if drive: root = self.fs.get_root(drive) if not os.path.isabs(s): @@ -2129,7 +2283,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): usual string representation: relative to the top-level SConstruct directory, or an absolute path if it's outside. """ - if os.sep == '/': + if os_sep_is_slash: node_to_str = str else: def node_to_str(n): @@ -2138,7 +2292,7 @@ class FileBuildInfo(SCons.Node.BuildInfoBase): except AttributeError: s = str(n) else: - s = s.replace(os.sep, '/') + s = s.replace(OS_SEP, '/') return s for attr in ['bsources', 'bdepends', 'bimplicit']: try: @@ -2638,6 +2792,8 @@ class File(Base): def _rmv_existing(self): self.clear_memoized_values() + if print_duplicate: + print "dup: removing existing target %s"%self e = Unlink(self, [], None) if isinstance(e, SCons.Errors.BuildError): raise e @@ -2678,6 +2834,8 @@ class File(Base): def do_duplicate(self, src): self._createDir() + if print_duplicate: + print "dup: relinking variant '%s' from '%s'"%(self, src) Unlink(self, None, None) e = Link(self, src, None) if isinstance(e, SCons.Errors.BuildError): @@ -2711,6 +2869,8 @@ class File(Base): else: # The source file does not exist. Make sure no old # copy remains in the variant directory. + if print_duplicate: + print "dup: no src for %s, unlinking old variant copy"%self if Base.exists(self) or self.islink(): self.fs.unlink(self.path) # Return None explicitly because the Base.exists() call @@ -2982,8 +3142,8 @@ class FileFinder(object): if fd is None: fd = self.default_filedir dir, name = os.path.split(fd) - drive, d = os.path.splitdrive(dir) - if not name and d[:1] in ('/', os.sep): + drive, d = _my_splitdrive(dir) + if not name and d[:1] in ('/', OS_SEP): #return p.fs.get_root(drive).dir_on_disk(name) return p.fs.get_root(drive) if dir: diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 63b50ac..e471497 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,7 +22,7 @@ # from __future__ import division -__revision__ = "src/engine/SCons/Node/FSTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/FSTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat @@ -817,6 +817,107 @@ class FileBuildInfoTestCase(_tempdirTestCase): assert format == expect, (repr(expect), repr(format)) class FSTestCase(_tempdirTestCase): + def test_needs_normpath(self): + """Test the needs_normpath Regular expression + + This test case verifies that the regular expression used to + determine whether a path needs normalization works as + expected. + """ + needs_normpath_match = SCons.Node.FS.needs_normpath_match + + do_not_need_normpath = [ + ".", + "/", + "/a", + "/aa", + "/a/", + "/aa/", + "/a/b", + "/aa/bb", + "/a/b/", + "/aa/bb/", + + "", + "a", + "aa", + "a/", + "aa/", + "a/b", + "aa/bb", + "a/b/", + "aa/bb/", + + "a.", + "a..", + "/a.", + "/a..", + "a./", + "a../", + "/a./", + "/a../", + + + ".a", + "..a", + "/.a", + "/..a", + ".a/", + "..a/", + "/.a/", + "/..a/", + ] + for p in do_not_need_normpath: + assert needs_normpath_match(p) is None, p + + needs_normpath = [ + "//", + "//a", + "//aa", + "//a/", + "//a/", + "/aa//", + + "//a/b", + "//aa/bb", + "//a/b/", + "//aa/bb/", + + "/a//b", + "/aa//bb", + "/a/b//", + "/aa/bb//", + + "/a/b//", + "/aa/bb//", + + "a//", + "aa//", + "a//b", + "aa//bb", + "a//b/", + "aa//bb/", + "a/b//", + "aa/bb//", + + "..", + "/.", + "/..", + "./", + "../", + "/./", + "/../", + + "a/.", + "a/..", + "./a", + "../a", + "a/./a", + "a/../a", + ] + for p in needs_normpath: + assert needs_normpath_match(p) is not None, p + def test_runTest(self): """Test FS (file system) Node operations @@ -932,8 +1033,20 @@ class FSTestCase(_tempdirTestCase): path = strip_slash(path_) abspath = strip_slash(abspath_) up_path = strip_slash(up_path_) + name = abspath.split(os.sep)[-1] + if not name: + if drive: + name = drive + else: + name = os.sep + + if dir.up() is None: + dir_up_path = dir.path + else: + dir_up_path = dir.up().path + assert dir.name == name, \ "dir.name %s != expected name %s" % \ (dir.name, name) @@ -946,15 +1059,16 @@ class FSTestCase(_tempdirTestCase): assert dir.get_abspath() == abspath, \ "dir.abspath %s != expected absolute path %s" % \ (dir.get_abspath(), abspath) - assert dir.up().path == up_path, \ + assert dir_up_path == up_path, \ "dir.up().path %s != expected parent path %s" % \ - (dir.up().path, up_path) + (dir_up_path, up_path) for sep in seps: def Dir_test(lpath, path_, abspath_, up_path_, sep=sep, func=_do_Dir_test): return func(lpath, path_, abspath_, up_path_, sep) - + + Dir_test('/', '/', '/', '/') Dir_test('', './', sub_dir, sub) Dir_test('foo', 'foo/', sub_dir_foo, './') Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/') @@ -1423,12 +1537,12 @@ class FSTestCase(_tempdirTestCase): test.subdir('sub', ['sub', 'dir']) - def drive_workpath(drive, dirs, test=test): + def drive_workpath(dirs, test=test): x = test.workpath(*dirs) drive, path = os.path.splitdrive(x) return 'X:' + path - wp = drive_workpath('X:', ['']) + wp = drive_workpath(['']) if wp[-1] in (os.sep, '/'): tmp = os.path.split(wp[:-1])[0] @@ -1441,13 +1555,13 @@ class FSTestCase(_tempdirTestCase): tmp_foo = os.path.join(tmp, 'foo') - foo = drive_workpath('X:', ['foo']) - foo_bar = drive_workpath('X:', ['foo', 'bar']) - sub = drive_workpath('X:', ['sub', '']) - sub_dir = drive_workpath('X:', ['sub', 'dir', '']) - sub_dir_foo = drive_workpath('X:', ['sub', 'dir', 'foo', '']) - sub_dir_foo_bar = drive_workpath('X:', ['sub', 'dir', 'foo', 'bar', '']) - sub_foo = drive_workpath('X:', ['sub', 'foo', '']) + foo = drive_workpath(['foo']) + foo_bar = drive_workpath(['foo', 'bar']) + sub = drive_workpath(['sub', '']) + sub_dir = drive_workpath(['sub', 'dir', '']) + sub_dir_foo = drive_workpath(['sub', 'dir', 'foo', '']) + sub_dir_foo_bar = drive_workpath(['sub', 'dir', 'foo', 'bar', '']) + sub_foo = drive_workpath(['sub', 'foo', '']) fs = SCons.Node.FS.FS() @@ -1490,7 +1604,6 @@ class FSTestCase(_tempdirTestCase): os.path = ntpath os.sep = '\\' SCons.Node.FS.initialize_do_splitdrive() - SCons.Node.FS.initialize_normpath_check() for sep in seps: @@ -1517,7 +1630,117 @@ class FSTestCase(_tempdirTestCase): os.path = save_os_path os.sep = save_os_sep SCons.Node.FS.initialize_do_splitdrive() - SCons.Node.FS.initialize_normpath_check() + + def test_unc_path(self): + """Test UNC path look-ups""" + + test = self.test + + test.subdir('sub', ['sub', 'dir']) + + def strip_slash(p): + if p[-1] == os.sep and len(p) > 3: + p = p[:-1] + return p + + def unc_workpath(dirs, test=test): + import ntpath + x = apply(test.workpath, dirs) + drive, path = ntpath.splitdrive(x) + unc, path = ntpath.splitunc(path) + path = strip_slash(path) + return '//' + path[1:] + + wp = unc_workpath(['']) + + if wp[-1] in (os.sep, '/'): + tmp = os.path.split(wp[:-1])[0] + else: + tmp = os.path.split(wp)[0] + + parent_tmp = os.path.split(tmp)[0] + + tmp_foo = os.path.join(tmp, 'foo') + + foo = unc_workpath(['foo']) + foo_bar = unc_workpath(['foo', 'bar']) + sub = unc_workpath(['sub', '']) + sub_dir = unc_workpath(['sub', 'dir', '']) + sub_dir_foo = unc_workpath(['sub', 'dir', 'foo', '']) + sub_dir_foo_bar = unc_workpath(['sub', 'dir', 'foo', 'bar', '']) + sub_foo = unc_workpath(['sub', 'foo', '']) + + fs = SCons.Node.FS.FS() + + seps = [os.sep] + if os.sep != '/': + seps = seps + ['/'] + + def _do_Dir_test(lpath, path, up_path, sep, fileSys=fs): + dir = fileSys.Dir(lpath.replace('/', sep)) + + if os.sep != '/': + path = path.replace('/', os.sep) + up_path = up_path.replace('/', os.sep) + + if path == os.sep + os.sep: + name = os.sep + os.sep + else: + name = path.split(os.sep)[-1] + + if dir.up() is None: + dir_up_path = dir.path + else: + dir_up_path = dir.up().path + + assert dir.name == name, \ + "dir.name %s != expected name %s" % \ + (dir.name, name) + assert dir.path == path, \ + "dir.path %s != expected path %s" % \ + (dir.path, path) + assert str(dir) == path, \ + "str(dir) %s != expected path %s" % \ + (str(dir), path) + assert dir_up_path == up_path, \ + "dir.up().path %s != expected parent path %s" % \ + (dir.up().path, up_path) + + save_os_path = os.path + save_os_sep = os.sep + try: + import ntpath + os.path = ntpath + os.sep = '\\' + SCons.Node.FS.initialize_do_splitdrive() + + for sep in seps: + + def Dir_test(lpath, path_, up_path_, sep=sep, func=_do_Dir_test): + return func(lpath, path_, up_path_, sep) + + Dir_test('//foo', '//foo', '//') + Dir_test('//foo/bar', '//foo/bar', '//foo') + Dir_test('//', '//', '//') + Dir_test('//..', '//', '//') + Dir_test('//foo/..', '//', '//') + Dir_test('//../foo', '//foo', '//') + Dir_test('//.', '//', '//') + Dir_test('//./.', '//', '//') + Dir_test('//foo/./bar', '//foo/bar', '//foo') + Dir_test('//foo/../bar', '//bar', '//') + Dir_test('//foo/../../bar', '//bar', '//') + Dir_test('//foo/bar/../..', '//', '//') + Dir_test('#//', wp, tmp) + Dir_test('#//../foo', tmp_foo, tmp) + Dir_test('#//../foo', tmp_foo, tmp) + Dir_test('#//foo/bar', foo_bar, foo) + Dir_test('#//foo/bar', foo_bar, foo) + Dir_test('#//', wp, tmp) + finally: + os.path = save_os_path + os.sep = save_os_sep + SCons.Node.FS.initialize_do_splitdrive() def test_target_from_source(self): """Test the method for generating target nodes from sources""" @@ -1571,6 +1794,46 @@ class FSTestCase(_tempdirTestCase): above_path = os.path.join(*['..']*len(dirs) + ['above']) above = d2.Dir(above_path) + def test_lookup_abs(self): + """Exercise the _lookup_abs function""" + test = self.test + fs = self.fs + + root = fs.Dir('/') + d = root._lookup_abs('/tmp/foo-nonexistent/nonexistent-dir', SCons.Node.FS.Dir) + assert d.__class__ == SCons.Node.FS.Dir, str(d.__class__) + + def test_lookup_uncpath(self): + """Testing looking up a UNC path on Windows""" + if sys.platform not in ('win32',): + return + test = self.test + fs = self.fs + path='//servername/C$/foo' + f = self.fs._lookup('//servername/C$/foo', fs.Dir('#'), SCons.Node.FS.File) + # before the fix in this commit, this returned 'C:\servername\C$\foo' + # Should be a normalized Windows UNC path as below. + assert str(f) == r'\\servername\C$\foo', \ + 'UNC path %s got looked up as %s'%(path, f) + + def test_unc_drive_letter(self): + """Test drive-letter lookup for windows UNC-style directories""" + if sys.platform not in ('win32',): + return + share = self.fs.Dir(r'\\SERVER\SHARE\Directory') + assert str(share) == r'\\SERVER\SHARE\Directory', str(share) + + def test_UNC_dirs_2689(self): + """Test some UNC dirs that printed incorrectly and/or caused + infinite recursion errors prior to r5180 (SCons 2.1).""" + fs = self.fs + if sys.platform not in ('win32',): + return + p = fs.Dir(r"\\computername\sharename").abspath + assert p == r"\\computername\sharename", p + p = fs.Dir(r"\\\computername\sharename").abspath + assert p == r"\\computername\sharename", p + def test_rel_path(self): """Test the rel_path() method""" test = self.test @@ -1676,8 +1939,8 @@ class DirTestCase(_tempdirTestCase): x.add_post_action('post') e.must_be_same(SCons.Node.FS.Dir) a = x.get_action_list() - assert a[0] == 'pre', a - assert a[2] == 'post', a + assert 'pre' in a, a + assert 'post' in a, a def test_subclass(self): """Test looking up subclass of Dir nodes""" diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 39e7fd8..416c134 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ # 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__ = "src/engine/SCons/Node/NodeTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/NodeTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py index 3245005..b97f9d4 100644 --- a/src/engine/SCons/Node/Python.py +++ b/src/engine/SCons/Node/Python.py @@ -5,7 +5,7 @@ Python nodes. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ Python nodes. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Node/Python.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/Python.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.Node diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py index 3e9e687..b91c2d3 100644 --- a/src/engine/SCons/Node/PythonTests.py +++ b/src/engine/SCons/Node/PythonTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Node/PythonTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/PythonTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index b737798..a832a5f 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -20,7 +20,7 @@ be able to depend on any other type of "thing." """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -41,7 +41,7 @@ be able to depend on any other type of "thing." # 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__ = "src/engine/SCons/Node/__init__.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Node/__init__.py 5357 2011/09/09 21:31:03 bdeegan" import collections import copy @@ -628,9 +628,10 @@ class Node(object): if implicit_deps_unchanged or self.is_up_to_date(): return # one of this node's sources has changed, - # so we must recalculate the implicit deps: - self.implicit = [] - self.implicit_set = set() + # so we must recalculate the implicit deps for all targets + for tgt in executor.get_all_targets(): + tgt.implicit = [] + tgt.implicit_set = set() # Have the executor scan the sources. executor.scan_sources(self.builder.source_scanner) diff --git a/src/engine/SCons/Options/BoolOption.py b/src/engine/SCons/Options/BoolOption.py index 4609967..2b86533 100644 --- a/src/engine/SCons/Options/BoolOption.py +++ b/src/engine/SCons/Options/BoolOption.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/BoolOption.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/BoolOption.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/Options/EnumOption.py b/src/engine/SCons/Options/EnumOption.py index 1357984..5296209 100644 --- a/src/engine/SCons/Options/EnumOption.py +++ b/src/engine/SCons/Options/EnumOption.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/EnumOption.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/EnumOption.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/Options/ListOption.py b/src/engine/SCons/Options/ListOption.py index 1f34cd6..5672689 100644 --- a/src/engine/SCons/Options/ListOption.py +++ b/src/engine/SCons/Options/ListOption.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/ListOption.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/ListOption.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/Options/PackageOption.py b/src/engine/SCons/Options/PackageOption.py index 1bb88b1..930c18f 100644 --- a/src/engine/SCons/Options/PackageOption.py +++ b/src/engine/SCons/Options/PackageOption.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/PackageOption.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/PackageOption.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/Options/PathOption.py b/src/engine/SCons/Options/PathOption.py index 2e38de3..ebf0f24 100644 --- a/src/engine/SCons/Options/PathOption.py +++ b/src/engine/SCons/Options/PathOption.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/PathOption.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/PathOption.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/Options/__init__.py b/src/engine/SCons/Options/__init__.py index edb6273..b1428e9 100644 --- a/src/engine/SCons/Options/__init__.py +++ b/src/engine/SCons/Options/__init__.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Options/__init__.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Options/__init__.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Options module hierarchy diff --git a/src/engine/SCons/PathList.py b/src/engine/SCons/PathList.py index 4b27193..0ba07f5 100644 --- a/src/engine/SCons/PathList.py +++ b/src/engine/SCons/PathList.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/PathList.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/PathList.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """SCons.PathList diff --git a/src/engine/SCons/PathListTests.py b/src/engine/SCons/PathListTests.py index 0bda79f..889e10e 100644 --- a/src/engine/SCons/PathListTests.py +++ b/src/engine/SCons/PathListTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/PathListTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/PathListTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Platform/PlatformTests.py b/src/engine/SCons/Platform/PlatformTests.py index a2b10f2..4996df7 100644 --- a/src/engine/SCons/Platform/PlatformTests.py +++ b/src/engine/SCons/Platform/PlatformTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Platform/PlatformTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Platform/PlatformTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat diff --git a/src/engine/SCons/Platform/__init__.py b/src/engine/SCons/Platform/__init__.py index 7621e40..eb0108e 100644 --- a/src/engine/SCons/Platform/__init__.py +++ b/src/engine/SCons/Platform/__init__.py @@ -20,7 +20,7 @@ their own platform definition. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -42,7 +42,7 @@ their own platform definition. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Platform/__init__.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Platform/__init__.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat diff --git a/src/engine/SCons/Platform/__init__.xml b/src/engine/SCons/Platform/__init__.xml index f54d17f..0b6d102 100644 --- a/src/engine/SCons/Platform/__init__.xml +++ b/src/engine/SCons/Platform/__init__.xml @@ -1,5 +1,5 @@ + + + +(variable) + + +Returns a function +(actually a callable Python object) +intended to be used as the +path_function +of a Scanner object. +The returned object will look up the specified +variable +in a construction environment +and treat the construction variable's value as a list of +directory paths that should be searched +(like +&cv-link-CPPPATH;, +&cv-link-LIBPATH;, +etc.). + +Note that use of +&f-FindPathDirs; +is generally preferable to +writing your own +path_function +for the following reasons: +1) The returned list will contain all appropriate directories +found in source trees +(when +&f-link-VariantDir; +is used) +or in code repositories +(when +&f-Repository; +or the + +option are used). +2) scons will identify expansions of +variable +that evaluate to the same list of directories as, +in fact, the same list, +and avoid re-scanning the directories for files, +when possible. + +Example: + + +def my_scan(node, env, path, arg): + # Code to scan file contents goes here... + return include_files + +scanner = Scanner(name = 'myscanner', + function = my_scan, + path_function = FindPathDirs('MYPATH')) + + + diff --git a/src/engine/SCons/Script/Interactive.py b/src/engine/SCons/Script/Interactive.py index e2906d4..f2151fa 100644 --- a/src/engine/SCons/Script/Interactive.py +++ b/src/engine/SCons/Script/Interactive.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ # 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__ = "src/engine/SCons/Script/Interactive.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/Interactive.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """ SCons interactive mode diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 31bcff3..2f00e5c 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -13,7 +13,7 @@ it goes here. unsupported_python_version = (2, 3, 0) deprecated_python_version = (2, 4, 0) -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -34,7 +34,7 @@ deprecated_python_version = (2, 4, 0) # 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__ = "src/engine/SCons/Script/Main.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/Main.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat @@ -60,6 +60,7 @@ import SCons.Errors import SCons.Job import SCons.Node import SCons.Node.FS +import SCons.Platform import SCons.SConf import SCons.Script import SCons.Taskmaster @@ -653,6 +654,10 @@ def _set_debug_values(options): print_time = 1 if "tree" in debug_values: options.tree_printers.append(TreePrinter()) + if "prepare" in debug_values: + SCons.Taskmaster.print_prepare = 1 + if "duplicate" in debug_values: + SCons.Node.FS.print_duplicate = 1 def _create_path(plist): path = '.' @@ -665,15 +670,15 @@ def _create_path(plist): 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.""" + Prepends site_scons to sys.path, imports site_scons/site_init.py, + and prepends 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) + site_dir = os.path.join(topdir, 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) @@ -682,11 +687,12 @@ def _load_site_scons_dir(topdir, site_dir_name=None): site_init_filename = "site_init.py" site_init_modname = "site_init" site_tools_dirname = "site_tools" + # prepend to sys.path sys.path = [os.path.abspath(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 + import imp, re # TODO(2.4): turn this into try:-except:-finally: try: try: @@ -705,14 +711,26 @@ def _load_site_scons_dir(topdir, site_dir_name=None): fmt = 'cannot import site_init.py: missing SCons.Script module %s' raise SCons.Errors.InternalError(fmt % repr(e)) try: + sfx = description[0] + modname = os.path.basename(pathname)[:-len(sfx)] + site_m = {"__file__": pathname, "__name__": modname, "__doc__": None} + re_special = re.compile("__[^_]+__") + for k in m.__dict__.keys(): + if not re_special.match(k): + site_m[k] = m.__dict__[k] + # This is the magic. - exec fp in m.__dict__ + exec fp in site_m except KeyboardInterrupt: raise except Exception, e: fmt = '*** Error loading site_init file %s:\n' sys.stderr.write(fmt % repr(site_init_file)) raise + else: + for k in site_m: + if not re_special.match(k): + m.__dict__[k] = site_m[k] except KeyboardInterrupt: raise except ImportError, e: @@ -723,7 +741,55 @@ def _load_site_scons_dir(topdir, site_dir_name=None): if fp: fp.close() if os.path.exists(site_tools_dir): - SCons.Tool.DefaultToolpath.append(os.path.abspath(site_tools_dir)) + # prepend to DefaultToolpath + SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir)) + +def _load_all_site_scons_dirs(topdir, verbose=None): + """Load all of the predefined site_scons dir. + Order is significant; we load them in order from most generic + (machine-wide) to most specific (topdir). + The verbose argument is only for testing. + """ + platform = SCons.Platform.platform_default() + + def homedir(d): + return os.path.expanduser('~/'+d) + + if platform == 'win32' or platform == 'cygwin': + # Note we use $ here instead of %...% because older + # pythons (prior to 2.6?) didn't expand %...% on Windows. + # This set of dirs should work on XP, Vista, 7 and later. + sysdirs=[ + os.path.expandvars('$ALLUSERSPROFILE\\Application Data\\scons'), + os.path.expandvars('$USERPROFILE\\Local Settings\\Application Data\\scons')] + appdatadir = os.path.expandvars('$APPDATA\\scons') + if appdatadir not in sysdirs: + sysdirs.append(appdatadir) + sysdirs.append(homedir('.scons')) + + elif platform == 'darwin': # MacOS X + sysdirs=['/Library/Application Support/SCons', + '/opt/local/share/scons', # (for MacPorts) + '/sw/share/scons', # (for Fink) + homedir('Library/Application Support/SCons'), + homedir('.scons')] + elif platform == 'sunos': # Solaris + sysdirs=['/opt/sfw/scons', + '/usr/share/scons', + homedir('.scons')] + else: # Linux, HPUX, etc. + # assume posix-like, i.e. platform == 'posix' + sysdirs=['/usr/share/scons', + homedir('.scons')] + + dirs=sysdirs + [topdir] + for d in dirs: + if verbose: # this is used by unit tests. + print "Loading site dir ", d + _load_site_scons_dir(d) + +def test_load_all_site_scons_dirs(d): + _load_all_site_scons_dirs(d, True) def version_string(label, module): version = module.__version__ @@ -739,6 +805,10 @@ def version_string(label, module): module.__developer__, module.__buildsys__) +def path_string(label, module): + path = module.__path__ + return "\t%s path: %s\n"%(label,path) + def _main(parser): global exit_status global this_build_status @@ -860,9 +930,9 @@ def _main(parser): progress_display.set_mode(0) if options.site_dir: - _load_site_scons_dir(d, options.site_dir) + _load_site_scons_dir(d.path, options.site_dir) elif not options.no_site_dir: - _load_site_scons_dir(d) + _load_all_site_scons_dirs(d.path) if options.include_dir: sys.path = options.include_dir + sys.path @@ -1258,7 +1328,8 @@ def main(): # __main__.__version__, hence there is no script version. pass parts.append(version_string("engine", SCons)) - parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation") + parts.append(path_string("engine", SCons)) + parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation") version = ''.join(parts) import SConsOptions diff --git a/src/engine/SCons/Script/Main.xml b/src/engine/SCons/Script/Main.xml new file mode 100644 index 0000000..9c97826 --- /dev/null +++ b/src/engine/SCons/Script/Main.xml @@ -0,0 +1,710 @@ + + + + +(arguments) + + +This function adds a new command-line option to be recognized. +The specified +arguments +are the same as supported by the standard Python +optparse.add_option() +method (with a few additional capabilities noted below); +see the documentation for +optparse +for a thorough discussion of its option-processing capabities. + +In addition to the arguments and values supported by the +optparse.add_option() +method, +the SCons +&f-AddOption; +function allows you to set the +nargs +keyword value to +'?' +(a string with just the question mark) +to indicate that the specified long option(s) take(s) an +optional +argument. +When +nargs = '?' +is passed to the +&f-AddOption; +function, the +const +keyword argument +may be used to supply the "default" +value that should be used when the +option is specified on the command line +without an explicit argument. + +If no +default= +keyword argument is supplied when calling +&f-AddOption;, +the option will have a default value of +None. + +Once a new command-line option has been added with +&f-AddOption;, +the option value may be accessed using +&f-GetOption; +or +env.GetOption(). +The value may also be set, using +&f-SetOption; +or +env.SetOption(), +if conditions in a +&SConscript; +require overriding any default value. +Note, however, that a +value specified on the command line will +always +override a value set by any SConscript file. + +Any specified +help= +strings for the new option(s) +will be displayed by the + +or + +options +(the latter only if no other help text is +specified in the SConscript files). +The help text for the local options specified by +&f-AddOption; +will appear below the SCons options themselves, +under a separate +Local Options +heading. +The options will appear in the help text +in the order in which the +&f-AddOption; +calls occur. + +Example: + + +AddOption('--prefix', + dest='prefix', + nargs=1, type='string', + action='store', + metavar='DIR', + help='installation prefix') +env = Environment(PREFIX = GetOption('prefix')) + + + + + + +() + + +Returns a list of exceptions for the +actions that failed while +attempting to build targets. +Each element in the returned list is a +BuildError +object +with the following attributes +that record various aspects +of the build failure: + +.node +The node that was being built +when the build failure occurred. + +.status +The numeric exit status +returned by the command or Python function +that failed when trying to build the +specified Node. + +.errstr +The SCons error string +describing the build failure. +(This is often a generic +message like "Error 2" +to indicate that an executed +command exited with a status of 2.) + +.filename +The name of the file or +directory that actually caused the failure. +This may be different from the +.node +attribute. +For example, +if an attempt to build a target named +sub/dir/target +fails because the +sub/dir +directory could not be created, +then the +.node +attribute will be +sub/dir/target +but the +.filename +attribute will be +sub/dir. + +.executor +The SCons Executor object +for the target Node +being built. +This can be used to retrieve +the construction environment used +for the failed action. + +.action +The actual SCons Action object that failed. +This will be one specific action +out of the possible list of +actions that would have been +executed to build the target. + +.command +The actual expanded command that was executed and failed, +after expansion of +&cv-link-TARGET;, +&cv-link-SOURCE;, +and other construction variables. + +Note that the +&f-GetBuildFailures; +function +will always return an empty list +until any build failure has occurred, +which means that +&f-GetBuildFailures; +will always return an empty list +while the +&SConscript; +files are being read. +Its primary intended use is +for functions that will be +executed before SCons exits +by passing them to the +standard Python +atexit.register() +function. +Example: + + +import atexit + +def print_build_failures(): + from SCons.Script import GetBuildFailures + for bf in GetBuildFailures(): + print "%s failed: %s" % (bf.node, bf.errstr) + +atexit.register(print_build_failures) + + + + + + +(name) + + +This function provides a way to query the value of +SCons options set on scons command line +(or set using the +&f-link-SetOption; +function). +The options supported are: + + + +cache_debug + + +which corresponds to --cache-debug; + + + + +cache_disable + + +which corresponds to --cache-disable; + + + + +cache_force + + +which corresponds to --cache-force; + + + + +cache_show + + +which corresponds to --cache-show; + + + + +clean + + +which corresponds to -c, --clean and --remove; + + + + +config + + +which corresponds to --config; + + + + +directory + + +which corresponds to -C and --directory; + + + + +diskcheck + + +which corresponds to --diskcheck + + + + +duplicate + + +which corresponds to --duplicate; + + + + +file + + +which corresponds to -f, --file, --makefile and --sconstruct; + + + + +help + + +which corresponds to -h and --help; + + + + +ignore_errors + + +which corresponds to --ignore-errors; + + + + +implicit_cache + + +which corresponds to --implicit-cache; + + + + +implicit_deps_changed + + +which corresponds to --implicit-deps-changed; + + + + +implicit_deps_unchanged + + +which corresponds to --implicit-deps-unchanged; + + + + +interactive + + +which corresponds to --interact and --interactive; + + + + +keep_going + + +which corresponds to -k and --keep-going; + + + + +max_drift + + +which corresponds to --max-drift; + + + + +no_exec + + +which corresponds to -n, --no-exec, --just-print, --dry-run and --recon; + + + + +no_site_dir + + +which corresponds to --no-site-dir; + + + + +num_jobs + + +which corresponds to -j and --jobs; + + + + +profile_file + + +which corresponds to --profile; + + + + +question + + +which corresponds to -q and --question; + + + + +random + + +which corresponds to --random; + + + + +repository + + +which corresponds to -Y, --repository and --srcdir; + + + + +silent + + +which corresponds to -s, --silent and --quiet; + + + + +site_dir + + +which corresponds to --site-dir; + + + + +stack_size + + +which corresponds to --stack-size; + + + + +taskmastertrace_file + + +which corresponds to --taskmastertrace; and + + + + +warn + + +which corresponds to --warn and --warning. + + + + + +See the documentation for the +corresponding command line object for information about each specific +option. + + + + + +(callable, [interval]) + + +(string, [interval, file, overwrite]) + + +(list_of_strings, [interval, file, overwrite]) + + +Allows SCons to show progress made during the build +by displaying a string or calling a function while +evaluating Nodes (e.g. files). + +If the first specified argument is a Python callable +(a function or an object that has a +__call__() +method), +the function will be called +once every +interval +times a Node is evaluated. +The callable will be passed the evaluated Node +as its only argument. +(For future compatibility, +it's a good idea to also add +*args +and +**kw +as arguments to your function or method. +This will prevent the code from breaking +if SCons ever changes the interface +to call the function with additional arguments in the future.) + +An example of a simple custom progress function +that prints a string containing the Node name +every 10 Nodes: + + +def my_progress_function(node, *args, **kw): + print 'Evaluating node %s!' % node +Progress(my_progress_function, interval=10) + + +A more complicated example of a custom progress display object +that prints a string containing a count +every 100 evaluated Nodes. +Note the use of +\r +(a carriage return) +at the end so that the string +will overwrite itself on a display: + + +import sys +class ProgressCounter(object): + count = 0 + def __call__(self, node, *args, **kw): + self.count += 100 + sys.stderr.write('Evaluated %s nodes\r' % self.count) +Progress(ProgressCounter(), interval=100) + + +If the first argument +&f-link-Progress; +is a string, +the string will be displayed +every +interval +evaluated Nodes. +The default is to print the string on standard output; +an alternate output stream +may be specified with the +file= +argument. +The following will print a series of dots +on the error output, +one dot for every 100 evaluated Nodes: + + +import sys +Progress('.', interval=100, file=sys.stderr) + + +If the string contains the verbatim substring +&cv-TARGET;, +it will be replaced with the Node. +Note that, for performance reasons, this is +not +a regular SCons variable substition, +so you can not use other variables +or use curly braces. +The following example will print the name of +every evaluated Node, +using a +\r +(carriage return) to cause each line to overwritten by the next line, +and the +overwrite= +keyword argument to make sure the previously-printed +file name is overwritten with blank spaces: + + +import sys +Progress('$TARGET\r', overwrite=True) + + +If the first argument to +&f-Progress; +is a list of strings, +then each string in the list will be displayed +in rotating fashion every +interval +evaluated Nodes. +This can be used to implement a "spinner" +on the user's screen as follows: + + +Progress(['-\r', '\\\r', '|\r', '/\r'], interval=5) + + + + + + +(target, ...) + + +Marks each given +target +as precious so it is not deleted before it is rebuilt. Normally +&scons; +deletes a target before building it. +Multiple targets can be passed in to a single call to +&f-Precious;. + + + + + +(name, value) + + +This function provides a way to set a select subset of the scons command +line options from a SConscript file. The options supported are: + + + +clean + + +which corresponds to -c, --clean and --remove; + + + + +duplicate + + +which corresponds to --duplicate; + + + + +help + + +which corresponds to -h and --help; + + + + +implicit_cache + + +which corresponds to --implicit-cache; + + + + +max_drift + + +which corresponds to --max-drift; + + + + +no_exec + + +which corresponds to -n, --no-exec, --just-print, --dry-run and --recon; + + + + +num_jobs + + +which corresponds to -j and --jobs; + + + + +random + + +which corresponds to --random; and + + + + +stack_size + + +which corresponds to --stack-size. + + + + + +See the documentation for the +corresponding command line object for information about each specific +option. + +Example: + + +SetOption('max_drift', 1) + + + diff --git a/src/engine/SCons/Script/MainTests.py b/src/engine/SCons/Script/MainTests.py index 923f791..06780d8 100644 --- a/src/engine/SCons/Script/MainTests.py +++ b/src/engine/SCons/Script/MainTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Script/MainTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/MainTests.py 5357 2011/09/09 21:31:03 bdeegan" import unittest import SCons.Errors diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py index 8afedf6..79d9927 100644 --- a/src/engine/SCons/Script/SConsOptions.py +++ b/src/engine/SCons/Script/SConsOptions.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Script/SConsOptions.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/SConsOptions.py 5357 2011/09/09 21:31:03 bdeegan" import optparse import re @@ -596,9 +596,9 @@ def Parser(version): "tree" : '; please use --tree=all instead', } - debug_options = ["count", "explain", "findlibs", + debug_options = ["count", "duplicate", "explain", "findlibs", "includes", "memoizer", "memory", "objects", - "pdb", "presub", "stacktrace", + "pdb", "prepare", "presub", "stacktrace", "time"] + list(deprecated_debug_options.keys()) def opt_debug(option, opt, value, parser, @@ -867,7 +867,7 @@ def Parser(version): sys.stderr.write(msg) op.add_option('-l', '--load-average', '--max-load', - nargs=1, type="int", + nargs=1, type="float", dest="load_average", default=0, action="callback", callback=opt_not_yet, # action="store", diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 5e896f1..ee5e290 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -6,7 +6,7 @@ files. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ files. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from __future__ import division -__revision__ = "src/engine/SCons/Script/SConscript.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/SConscript.py 5357 2011/09/09 21:31:03 bdeegan" import SCons import SCons.Action diff --git a/src/engine/SCons/Script/SConscript.xml b/src/engine/SCons/Script/SConscript.xml new file mode 100644 index 0000000..f24ca78 --- /dev/null +++ b/src/engine/SCons/Script/SConscript.xml @@ -0,0 +1,509 @@ + + + + +(targets) + + +This specifies a list of default targets, +which will be built by +&scons; +if no explicit targets are given on the command line. +Multiple calls to +&f-Default; +are legal, +and add to the list of default targets. + +Multiple targets should be specified as +separate arguments to the +&f-Default; +method, or as a list. +&f-Default; +will also accept the Node returned by any +of a construction environment's +builder methods. + +Examples: + + +Default('foo', 'bar', 'baz') +env.Default(['a', 'b', 'c']) +hello = env.Program('hello', 'hello.c') +env.Default(hello) + + +An argument to +&f-Default; +of +None +will clear all default targets. +Later calls to +&f-Default; +will add to the (now empty) default-target list +like normal. + +The current list of targets added using the +&f-Default; +function or method is available in the +DEFAULT_TARGETS +list; +see below. + + + + + +(major, minor) + + +Ensure that the Python version is at least +major.minor. +This function will +print out an error message and exit SCons with a non-zero exit code if the +actual Python version is not late enough. + +Example: + + +EnsurePythonVersion(2,2) + + + + + + +(major, minor, [revision]) + + +Ensure that the SCons version is at least +major.minor, +or +major.minor.revision. +if +revision +is specified. +This function will +print out an error message and exit SCons with a non-zero exit code if the +actual SCons version is not late enough. + +Examples: + + +EnsureSConsVersion(0,14) + +EnsureSConsVersion(0,96,90) + + + + + + +([value]) + + +This tells +&scons; +to exit immediately +with the specified +value. +A default exit value of +0 +(zero) +is used if no value is specified. + + + + + +(vars) + + +This tells +&scons; +to export a list of variables from the current +SConscript file to all other SConscript files. +The exported variables are kept in a global collection, +so subsequent calls to +&f-Export; +will over-write previous exports that have the same name. +Multiple variable names can be passed to +&f-Export; +as separate arguments or as a list. +Keyword arguments can be used to provide names and their values. +A dictionary can be used to map variables to a different name when exported. +Both local variables and global variables can be exported. + +Examples: + + +env = Environment() +# Make env available for all SConscript files to Import(). +Export("env") + +package = 'my_name' +# Make env and package available for all SConscript files:. +Export("env", "package") + +# Make env and package available for all SConscript files: +Export(["env", "package"]) + +# Make env available using the name debug: +Export(debug = env) + +# Make env available using the name debug: +Export({"debug":env}) + + +Note that the +&f-SConscript; +function supports an +exports +argument that makes it easier to to export a variable or +set of variables to a single SConscript file. +See the description of the +&f-SConscript; +function, below. + + + + + +() + + +Returns the absolute path name of the directory from which +&scons; +was initially invoked. +This can be useful when using the +, + +or + +options, which internally +change to the directory in which the +&SConstruct; +file is found. + + + + + +(text) + + +This specifies help text to be printed if the + +argument is given to +&scons;. +If +&f-Help; +is called multiple times, the text is appended together in the order +that +&f-Help; +is called. + + + + + +(vars) + + +This tells +&scons; +to import a list of variables into the current SConscript file. This +will import variables that were exported with +&f-Export; +or in the +exports +argument to +&f-link-SConscript;. +Variables exported by +&f-SConscript; +have precedence. +Multiple variable names can be passed to +&f-Import; +as separate arguments or as a list. The variable "*" can be used +to import all variables. + +Examples: + + +Import("env") +Import("env", "variable") +Import(["env", "variable"]) +Import("*") + + + + + + +([vars..., stop=]) + + +By default, +this stops processing the current SConscript +file and returns to the calling SConscript file +the values of the variables named in the +vars +string arguments. +Multiple strings contaning variable names may be passed to +&f-Return;. +Any strings that contain white space + +The optional +stop= +keyword argument may be set to a false value +to continue processing the rest of the SConscript +file after the +&f-Return; +call. +This was the default behavior prior to SCons 0.98. +However, the values returned +are still the values of the variables in the named +vars +at the point +&f-Return; +is called. + +Examples: + + +# Returns without returning a value. +Return() + +# Returns the value of the 'foo' Python variable. +Return("foo") + +# Returns the values of the Python variables 'foo' and 'bar'. +Return("foo", "bar") + +# Returns the values of Python variables 'val1' and 'val2'. +Return('val1 val2') + + + + + + +(scripts, [exports, variant_dir, duplicate]) + + + +(dirs=subdirs, [name=script, exports, variant_dir, duplicate]) + + + +This tells +&scons; +to execute +one or more subsidiary SConscript (configuration) files. +Any variables returned by a called script using +&f-link-Return; +will be returned by the call to +&f-SConscript;. +There are two ways to call the +&f-SConscript; +function. + +The first way you can call +&f-SConscript; +is to explicitly specify one or more +scripts +as the first argument. +A single script may be specified as a string; +multiple scripts must be specified as a list +(either explicitly or as created by +a function like +&f-Split;). +Examples: + +SConscript('SConscript') # run SConscript in the current directory +SConscript('src/SConscript') # run SConscript in the src directory +SConscript(['src/SConscript', 'doc/SConscript']) +config = SConscript('MyConfig.py') + + +The second way you can call +&f-SConscript; +is to specify a list of (sub)directory names +as a +dirs=subdirs +keyword argument. +In this case, +&scons; +will, by default, +execute a subsidiary configuration file named +&SConscript; +in each of the specified directories. +You may specify a name other than +&SConscript; +by supplying an optional +name=script +keyword argument. +The first three examples below have the same effect +as the first three examples above: + +SConscript(dirs='.') # run SConscript in the current directory +SConscript(dirs='src') # run SConscript in the src directory +SConscript(dirs=['src', 'doc']) +SConscript(dirs=['sub1', 'sub2'], name='MySConscript') + + +The optional +exports +argument provides a list of variable names or a dictionary of +named values to export to the +script(s). +These variables are locally exported only to the specified +script(s), +and do not affect the global pool of variables used by the +&f-Export; +function. + +The subsidiary +script(s) +must use the +&f-link-Import; +function to import the variables. +Examples: + +foo = SConscript('sub/SConscript', exports='env') +SConscript('dir/SConscript', exports=['env', 'variable']) +SConscript(dirs='subdir', exports='env variable') +SConscript(dirs=['one', 'two', 'three'], exports='shared_info') + + +If the optional +variant_dir +argument is present, it causes an effect equivalent to the +&f-link-VariantDir; +method described below. +(If +variant_dir +is not present, the + +duplicate + +argument is ignored.) +The +variant_dir + +argument is interpreted relative to the directory of the calling +&SConscript; +file. +See the description of the +&f-VariantDir; +function below for additional details and restrictions. + +If +variant_dir +is present, + +the source directory is the directory in which the +&SConscript; +file resides and the +&SConscript; +file is evaluated as if it were in the +variant_dir +directory: + +SConscript('src/SConscript', variant_dir = 'build') + + +is equivalent to + + +VariantDir('build', 'src') +SConscript('build/SConscript') + + +This later paradigm is often used when the sources are +in the same directory as the +&SConstruct;: + + +SConscript('SConscript', variant_dir = 'build') + + +is equivalent to + + +VariantDir('build', '.') +SConscript('build/SConscript') + + + + +Here are some composite examples: + + +# collect the configuration information and use it to build src and doc +shared_info = SConscript('MyConfig.py') +SConscript('src/SConscript', exports='shared_info') +SConscript('doc/SConscript', exports='shared_info') + + + +# build debugging and production versions. SConscript +# can use Dir('.').path to determine variant. +SConscript('SConscript', variant_dir='debug', duplicate=0) +SConscript('SConscript', variant_dir='prod', duplicate=0) + + + +# build debugging and production versions. SConscript +# is passed flags to use. +opts = { 'CPPDEFINES' : ['DEBUG'], 'CCFLAGS' : '-pgdb' } +SConscript('SConscript', variant_dir='debug', duplicate=0, exports=opts) +opts = { 'CPPDEFINES' : ['NODEBUG'], 'CCFLAGS' : '-O' } +SConscript('SConscript', variant_dir='prod', duplicate=0, exports=opts) + + + +# build common documentation and compile for different architectures +SConscript('doc/SConscript', variant_dir='build/doc', duplicate=0) +SConscript('src/SConscript', variant_dir='build/x86', duplicate=0) +SConscript('src/SConscript', variant_dir='build/ppc', duplicate=0) + + + diff --git a/src/engine/SCons/Script/SConscriptTests.py b/src/engine/SCons/Script/SConscriptTests.py index 6d855ef..ebd89fc 100644 --- a/src/engine/SCons/Script/SConscriptTests.py +++ b/src/engine/SCons/Script/SConscriptTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Script/SConscriptTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/SConscriptTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.Script.SConscript diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index b4545ec..f2503ae 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -12,7 +12,7 @@ it goes here. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -34,7 +34,7 @@ it goes here. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Script/__init__.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Script/__init__.py 5357 2011/09/09 21:31:03 bdeegan" import time start_time = time.time() diff --git a/src/engine/SCons/Sig.py b/src/engine/SCons/Sig.py index 2a9bc8e..51c1b1a 100644 --- a/src/engine/SCons/Sig.py +++ b/src/engine/SCons/Sig.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Sig.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Sig.py 5357 2011/09/09 21:31:03 bdeegan" __doc__ = """Place-holder for the old SCons.Sig module hierarchy diff --git a/src/engine/SCons/Subst.py b/src/engine/SCons/Subst.py index 84e7150..d0c8c38 100644 --- a/src/engine/SCons/Subst.py +++ b/src/engine/SCons/Subst.py @@ -5,7 +5,7 @@ SCons string substitution. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -26,7 +26,7 @@ SCons string substitution. # 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__ = "src/engine/SCons/Subst.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Subst.py 5357 2011/09/09 21:31:03 bdeegan" import collections import re diff --git a/src/engine/SCons/Subst.xml b/src/engine/SCons/Subst.xml new file mode 100644 index 0000000..debc8c3 --- /dev/null +++ b/src/engine/SCons/Subst.xml @@ -0,0 +1,46 @@ + + + + +([exception, ...]) + + +Specifies the exceptions that will be allowed +when expanding construction variables. +By default, +any construction variable expansions that generate a +NameError +or +IndexError +exception will expand to a +'' +(a null string) and not cause scons to fail. +All exceptions not in the specified list +will generate an error message +and terminate processing. + +If +&f-AllowSubstExceptions; +is called multiple times, +each call completely overwrites the previous list +of allowed exceptions. + +Example: + + +# Requires that all construction variable names exist. +# (You may wish to do this if you want to enforce strictly +# that all construction variables must be defined before use.) +AllowSubstExceptions() + +# Also allow a string containing a zero-division expansion +# like '${1 / 0}' to evalute to ''. +AllowSubstExceptions(IndexError, NameError, ZeroDivisionError) + + + diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py index 502043b..0494aa0 100644 --- a/src/engine/SCons/SubstTests.py +++ b/src/engine/SCons/SubstTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/SubstTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/SubstTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat @@ -550,8 +550,10 @@ class scons_subst_TestCase(SubstTestCase): expect = [ # Python 2.3, 2.4 "TypeError `unsubscriptable object' trying to evaluate `${NONE[2]}'", - # Python 2.5 and later + # Python 2.5, 2.6 "TypeError `'NoneType' object is unsubscriptable' trying to evaluate `${NONE[2]}'", + # Python 2.7 and later + "TypeError `'NoneType' object is not subscriptable' trying to evaluate `${NONE[2]}'", ] assert str(e) in expect, e else: diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 019b2d7..e98a859 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -47,7 +47,7 @@ interface and the SCons build engine. There are two key classes here: target(s) that it decides need to be evaluated and/or built. """ -__revision__ = "src/engine/SCons/Taskmaster.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Taskmaster.py 5357 2011/09/09 21:31:03 bdeegan" from itertools import chain import operator @@ -66,6 +66,7 @@ NODE_UP_TO_DATE = SCons.Node.up_to_date NODE_EXECUTED = SCons.Node.executed NODE_FAILED = SCons.Node.failed +print_prepare = 0 # set by option --debug=prepare # 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 @@ -161,6 +162,7 @@ class Task(object): unlink underlying files and make all necessary directories before the Action is actually called to build the targets. """ + global print_prepare T = self.tm.trace if T: T.write(self.trace_message(u'Task.prepare()', self.node)) @@ -186,8 +188,14 @@ class Task(object): executor = self.targets[0].get_executor() executor.prepare() for t in executor.get_action_targets(): + if print_prepare: + print "Preparing target %s..."%t + for s in t.side_effects: + print "...with side-effect %s..."%s t.prepare() for s in t.side_effects: + if print_prepare: + print "...Preparing side-effect %s..."%s s.prepare() def get_target(self): diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index a9be079..8c026af 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,7 +22,7 @@ # from __future__ import division -__revision__ = "src/engine/SCons/TaskmasterTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/TaskmasterTests.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.compat diff --git a/src/engine/SCons/Tool/386asm.py b/src/engine/SCons/Tool/386asm.py index 1ba99fa..27748cb 100644 --- a/src/engine/SCons/Tool/386asm.py +++ b/src/engine/SCons/Tool/386asm.py @@ -10,7 +10,7 @@ selection method. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -32,7 +32,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/386asm.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Tool/386asm.py 5357 2011/09/09 21:31:03 bdeegan" from SCons.Tool.PharLapCommon import addPharLapPaths import SCons.Util diff --git a/src/engine/SCons/Tool/386asm.xml b/src/engine/SCons/Tool/386asm.xml index 7474317..8d45681 100644 --- a/src/engine/SCons/Tool/386asm.xml +++ b/src/engine/SCons/Tool/386asm.xml @@ -1,5 +1,5 @@ + + diff --git a/src/engine/SCons/Tool/ToolTests.py b/src/engine/SCons/Tool/ToolTests.py index 0817fa8..4c00932 100644 --- a/src/engine/SCons/Tool/ToolTests.py +++ b/src/engine/SCons/Tool/ToolTests.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -21,7 +21,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/ToolTests.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Tool/ToolTests.py 5357 2011/09/09 21:31:03 bdeegan" import sys import unittest diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 416d8de..ba90b06 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -14,7 +14,7 @@ tool definition. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -35,7 +35,7 @@ tool definition. # 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__ = "src/engine/SCons/Tool/__init__.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Tool/__init__.py 5357 2011/09/09 21:31:03 bdeegan" import imp import sys @@ -62,7 +62,7 @@ CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", ".h", ".H", ".hxx", ".hpp", ".hh", ".F", ".fpp", ".FPP", ".m", ".mm", - ".S", ".spp", ".SPP"] + ".S", ".spp", ".SPP", ".sx"] DSuffixes = ['.d'] diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml index a8a8507..788d096 100644 --- a/src/engine/SCons/Tool/__init__.xml +++ b/src/engine/SCons/Tool/__init__.xml @@ -1,5 +1,5 @@ + + +Set construction variables for generic POSIX Fortran 03 compilers. + + +F03 +F03FLAGS +F03COM +F03PPCOM +SHF03 +SHF03FLAGS +SHF03COM +SHF03PPCOM +_F03INCFLAGS + + +F03COMSTR +F03PPCOMSTR +SHF03COMSTR +SHF03PPCOMSTR + + + + + +The Fortran 03 compiler. +You should normally set the &cv-link-FORTRAN; variable, +which specifies the default Fortran compiler +for all Fortran versions. +You only need to set &cv-link-F03; if you need to use a specific compiler +or compiler version for Fortran 03 files. + + + + + +The command line used to compile a Fortran 03 source file to an object file. +You only need to set &cv-link-F03COM; if you need to use a specific +command line for Fortran 03 files. +You should normally set the &cv-link-FORTRANCOM; variable, +which specifies the default command line +for all Fortran versions. + + + + + +The string displayed when a Fortran 03 source file +is compiled to an object file. +If this is not set, then &cv-link-F03COM; or &cv-link-FORTRANCOM; +(the command line) is displayed. + + + + + +The list of file extensions for which the F03 dialect will be used. By +default, this is ['.f03'] + + + + + +The list of file extensions for which the compilation + preprocessor pass for +F03 dialect will be used. By default, this is empty + + + + + +General user-specified options that are passed to the Fortran 03 compiler. +Note that this variable does +not +contain + +(or similar) include search path options +that scons generates automatically from &cv-link-F03PATH;. +See +&cv-link-_F03INCFLAGS; +below, +for the variable that expands to those options. +You only need to set &cv-link-F03FLAGS; if you need to define specific +user options for Fortran 03 files. +You should normally set the &cv-link-FORTRANFLAGS; variable, +which specifies the user-specified options +passed to the default Fortran compiler +for all Fortran versions. + + + + + +An automatically-generated construction variable +containing the Fortran 03 compiler command-line options +for specifying directories to be searched for include files. +The value of &cv-link-_F03INCFLAGS; is created +by appending &cv-link-INCPREFIX; and &cv-link-INCSUFFIX; +to the beginning and end +of each directory in &cv-link-F03PATH;. + + + + + +The list of directories that the Fortran 03 compiler will search for include +directories. The implicit dependency scanner will search these +directories for include files. Don't explicitly put include directory +arguments in &cv-link-F03FLAGS; because the result will be non-portable +and the directories will not be searched by the dependency scanner. Note: +directory names in &cv-link-F03PATH; will be looked-up relative to the SConscript +directory when they are used in a command. To force +&scons; +to look-up a directory relative to the root of the source tree use #: +You only need to set &cv-link-F03PATH; if you need to define a specific +include path for Fortran 03 files. +You should normally set the &cv-link-FORTRANPATH; variable, +which specifies the include path +for the default Fortran compiler +for all Fortran versions. + + +env = Environment(F03PATH='#/include') + + +The directory look-up can also be forced using the +&Dir;() +function: + + +include = Dir('include') +env = Environment(F03PATH=include) + + +The directory list will be added to command lines +through the automatically-generated +&cv-link-_F03INCFLAGS; +construction variable, +which is constructed by +appending the values of the +&cv-link-INCPREFIX; and &cv-link-INCSUFFIX; +construction variables +to the beginning and end +of each directory in &cv-link-F03PATH;. +Any command lines you define that need +the F03PATH directory list should +include &cv-link-_F03INCFLAGS;: + + +env = Environment(F03COM="my_compiler $_F03INCFLAGS -c -o $TARGET $SOURCE") + + + + + + +The command line used to compile a Fortran 03 source file to an object file +after first running the file through the C preprocessor. +Any options specified in the &cv-link-F03FLAGS; and &cv-link-CPPFLAGS; construction variables +are included on this command line. +You only need to set &cv-link-F03PPCOM; if you need to use a specific +C-preprocessor command line for Fortran 03 files. +You should normally set the &cv-link-FORTRANPPCOM; variable, +which specifies the default C-preprocessor command line +for all Fortran versions. + + + + + +The string displayed when a Fortran 03 source file +is compiled to an object file +after first running the file through the C preprocessor. +If this is not set, then &cv-link-F03PPCOM; or &cv-link-FORTRANPPCOM; +(the command line) is displayed. + + + + + +The Fortran 03 compiler used for generating shared-library objects. +You should normally set the &cv-link-SHFORTRAN; variable, +which specifies the default Fortran compiler +for all Fortran versions. +You only need to set &cv-link-SHF03; if you need to use a specific compiler +or compiler version for Fortran 03 files. + + + + + +The command line used to compile a Fortran 03 source file +to a shared-library object file. +You only need to set &cv-link-SHF03COM; if you need to use a specific +command line for Fortran 03 files. +You should normally set the &cv-link-SHFORTRANCOM; variable, +which specifies the default command line +for all Fortran versions. + + + + + +The string displayed when a Fortran 03 source file +is compiled to a shared-library object file. +If this is not set, then &cv-link-SHF03COM; or &cv-link-SHFORTRANCOM; +(the command line) is displayed. + + + + + +Options that are passed to the Fortran 03 compiler +to generated shared-library objects. +You only need to set &cv-link-SHF03FLAGS; if you need to define specific +user options for Fortran 03 files. +You should normally set the &cv-link-SHFORTRANFLAGS; variable, +which specifies the user-specified options +passed to the default Fortran compiler +for all Fortran versions. + + + + + +The command line used to compile a Fortran 03 source file to a +shared-library object file +after first running the file through the C preprocessor. +Any options specified in the &cv-link-SHF03FLAGS; and &cv-link-CPPFLAGS; construction variables +are included on this command line. +You only need to set &cv-link-SHF03PPCOM; if you need to use a specific +C-preprocessor command line for Fortran 03 files. +You should normally set the &cv-link-SHFORTRANPPCOM; variable, +which specifies the default C-preprocessor command line +for all Fortran versions. + + + + + +The string displayed when a Fortran 03 source file +is compiled to a shared-library object file +after first running the file through the C preprocessor. +If this is not set, then &cv-link-SHF03PPCOM; or &cv-link-SHFORTRANPPCOM; +(the command line) is displayed. + + diff --git a/src/engine/SCons/Tool/f77.py b/src/engine/SCons/Tool/f77.py index cc2c852..db538d8 100644 --- a/src/engine/SCons/Tool/f77.py +++ b/src/engine/SCons/Tool/f77.py @@ -9,7 +9,7 @@ selection method. """ # -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -31,7 +31,7 @@ selection method. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -__revision__ = "src/engine/SCons/Tool/f77.py 5134 2010/08/16 23:02:40 bdeegan" +__revision__ = "src/engine/SCons/Tool/f77.py 5357 2011/09/09 21:31:03 bdeegan" import SCons.Defaults import SCons.Scanner.Fortran diff --git a/src/engine/SCons/Tool/f77.xml b/src/engine/SCons/Tool/f77.xml index f498898..1d0623c 100644 --- a/src/engine/SCons/Tool/f77.xml +++ b/src/engine/SCons/Tool/f77.xml @@ -1,5 +1,5 @@ \n') + + def printFilters(self, hierarchy, name): + sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) + + for key, value in sorteditems: + if SCons.Util.is_Dict(value): + filter_name = name + '\\' + key + self.filters_file.write('\t\t\n' + '\t\t\t%s\n' + '\t\t\n' % (filter_name, _generateGUID(self.dspabs, filter_name))) + self.printFilters(value, filter_name) + + def printSources(self, hierarchy, kind, commonprefix, filter_name): + keywords = {'Source Files': 'ClCompile', + 'Header Files': 'ClInclude', + 'Local Headers': 'ClInclude', + 'Resource Files': 'None', + 'Other Files': 'None'} + + sorteditems = sorted(hierarchy.items(), key = lambda a: a[0].lower()) + + # First folders, then files + for key, value in sorteditems: + if SCons.Util.is_Dict(value): + self.printSources(value, kind, commonprefix, filter_name + '\\' + key) + + for key, value in sorteditems: + if SCons.Util.is_String(value): + file = value + if commonprefix: + file = os.path.join(commonprefix, value) + file = os.path.normpath(file) + + self.file.write('\t\t<%s Include="%s" />\n' % (keywords[kind], file)) + self.filters_file.write('\t\t<%s Include="%s">\n' + '\t\t\t%s\n' + '\t\t\n' % (keywords[kind], file, filter_name, keywords[kind])) + + def PrintSourceFiles(self): + categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat', + 'Header Files': 'h;hpp;hxx;hm;inl', + 'Local Headers': 'h;hpp;hxx;hm;inl', + 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe', + 'Other Files': ''} + + cats = sorted([k for k in categories.keys() if self.sources[k]], + key = lambda a: a.lower()) + + # print vcxproj.filters file first + self.filters_file.write('\t\n') + for kind in cats: + self.filters_file.write('\t\t\n' + '\t\t\t{7b42d31d-d53c-4868-8b92-ca2bc9fc052f}\n' + '\t\t\t%s\n' + '\t\t\n' % (kind, categories[kind])) + + # First remove any common prefix + sources = self.sources[kind] + commonprefix = None + if len(sources) > 1: + s = list(map(os.path.normpath, sources)) + # take the dirname because the prefix may include parts + # of the filenames (e.g. if you have 'dir\abcd' and + # 'dir\acde' then the cp will be 'dir\a' ) + cp = os.path.dirname( os.path.commonprefix(s) ) + if cp and s[0][len(cp)] == os.sep: + # +1 because the filename starts after the separator + sources = [s[len(cp)+1:] for s in sources] + commonprefix = cp + elif len(sources) == 1: + commonprefix = os.path.dirname( sources[0] ) + sources[0] = os.path.basename( sources[0] ) + + hierarchy = makeHierarchy(sources) + self.printFilters(hierarchy, kind) + + self.filters_file.write('\t\n') + + # then print files and filters + for kind in cats: + self.file.write('\t\n') + self.filters_file.write('\t\n') + + # First remove any common prefix + sources = self.sources[kind] + commonprefix = None + if len(sources) > 1: + s = list(map(os.path.normpath, sources)) + # take the dirname because the prefix may include parts + # of the filenames (e.g. if you have 'dir\abcd' and + # 'dir\acde' then the cp will be 'dir\a' ) + cp = os.path.dirname( os.path.commonprefix(s) ) + if cp and s[0][len(cp)] == os.sep: + # +1 because the filename starts after the separator + sources = [s[len(cp)+1:] for s in sources] + commonprefix = cp + elif len(sources) == 1: + commonprefix = os.path.dirname( sources[0] ) + sources[0] = os.path.basename( sources[0] ) + + hierarchy = makeHierarchy(sources) + self.printSources(hierarchy, kind, commonprefix, kind) + + self.file.write('\t\n') + self.filters_file.write('\t\n') + + # add the SConscript file outside of the groups + self.file.write('\t\n' + '\t\t\n' + #'\t\t\n' + '\t\n' % str(self.sconscript)) + + def Parse(self): + print "_GenerateV10DSP.Parse()" + + def Build(self): + try: + self.file = open(self.dspabs, 'w') + except IOError, detail: + raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail)) + else: + self.PrintHeader() + self.PrintProject() + self.file.close() class _DSWGenerator(object): """ Base class for DSW generators """ def __init__(self, dswfile, source, env): self.dswfile = os.path.normpath(str(dswfile)) + self.dsw_folder_path = os.path.dirname(os.path.abspath(self.dswfile)) self.env = env if 'projects' not in env: @@ -846,12 +1217,14 @@ class _GenerateV7DSW(_DSWGenerator): self.version = self.env['MSVS_VERSION'] self.version_num, self.suite = msvs_parse_version(self.version) self.versionstr = '7.00' - if self.version_num >= 8.0: + if self.version_num >= 10.0: + self.versionstr = '11.00' + elif self.version_num >= 9.0: + self.versionstr = '10.00' + elif self.version_num >= 8.0: self.versionstr = '9.00' elif self.version_num >= 7.1: self.versionstr = '8.00' - if self.version_num >= 8.0: - self.versionstr = '9.00' if 'slnguid' in env and env['slnguid']: self.slnguid = env['slnguid'] @@ -896,6 +1269,26 @@ class _GenerateV7DSW(_DSWGenerator): if not platform in self.platforms: self.platforms.append(platform) + def GenerateProjectFilesInfo(self): + for dspfile in self.dspfiles: + dsp_folder_path, name = os.path.split(dspfile) + dsp_folder_path = os.path.abspath(dsp_folder_path) + dsp_relative_folder_path = os.path.relpath(dsp_folder_path, self.dsw_folder_path) + if dsp_relative_folder_path == os.curdir: + dsp_relative_file_path = name + else: + dsp_relative_file_path = os.path.join(dsp_relative_folder_path, name) + dspfile_info = {'NAME': name, + 'GUID': _generateGUID(dspfile, ''), + 'FOLDER_PATH': dsp_folder_path, + 'FILE_PATH': dspfile, + 'SLN_RELATIVE_FOLDER_PATH': dsp_relative_folder_path, + 'SLN_RELATIVE_FILE_PATH': dsp_relative_file_path} + self.dspfiles_info.append(dspfile_info) + + self.dspfiles_info = [] + GenerateProjectFilesInfo(self) + def Parse(self): try: dswfile = open(self.dswfile,'r') @@ -928,16 +1321,19 @@ class _GenerateV7DSW(_DSWGenerator): def PrintSolution(self): """Writes a solution file""" self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr ) - if self.version_num >= 8.0: + if self.version_num >= 10.0: + self.file.write('# Visual Studio 2010\n') + elif self.version_num >= 9.0: + self.file.write('# Visual Studio 2008\n') + elif self.version_num >= 8.0: self.file.write('# Visual Studio 2005\n') - for p in self.dspfiles: - name = os.path.basename(p) + for dspinfo in self.dspfiles_info: + name = dspinfo['NAME'] base, suffix = SCons.Util.splitext(name) if suffix == '.vcproj': name = base - guid = _generateGUID(p, '') self.file.write('Project("%s") = "%s", "%s", "%s"\n' - % ( external_makefile_guid, name, p, guid ) ) + % (external_makefile_guid, name, dspinfo['SLN_RELATIVE_FILE_PATH'], dspinfo['GUID'])) if self.version_num >= 7.1 and self.version_num < 8.0: self.file.write('\tProjectSection(ProjectDependencies) = postProject\n' '\tEndProjectSection\n') @@ -947,30 +1343,36 @@ class _GenerateV7DSW(_DSWGenerator): env = self.env if 'MSVS_SCC_PROVIDER' in env: - dspfile_base = os.path.basename(self.dspfile) + scc_number_of_projects = len(self.dspfiles) + 1 slnguid = self.slnguid - scc_provider = env.get('MSVS_SCC_PROVIDER', '') - scc_provider = scc_provider.replace(' ', r'\u0020') - scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '') - # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '') - scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '') - scc_project_base_path = env.get('MSVS_SCC_PROJECT_BASE_PATH', '') - # project_guid = env.get('MSVS_PROJECT_GUID', '') - + scc_provider = env.get('MSVS_SCC_PROVIDER', '').replace(' ', r'\u0020') + scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '').replace(' ', r'\u0020') + scc_connection_root = env.get('MSVS_SCC_CONNECTION_ROOT', os.curdir) + scc_local_path = os.path.relpath(scc_connection_root, self.dsw_folder_path).replace('\\', '\\\\') self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n' - '\t\tSccNumberOfProjects = 2\n' - '\t\tSccProjectUniqueName0 = %(dspfile_base)s\n' + '\t\tSccNumberOfProjects = %(scc_number_of_projects)d\n' + '\t\tSccProjectName0 = %(scc_project_name)s\n' '\t\tSccLocalPath0 = %(scc_local_path)s\n' - '\t\tCanCheckoutShared = true\n' - '\t\tSccProjectFilePathRelativizedFromConnection0 = %(scc_project_base_path)s\n' - '\t\tSccProjectName1 = %(scc_project_name)s\n' - '\t\tSccLocalPath1 = %(scc_local_path)s\n' - '\t\tSccProvider1 = %(scc_provider)s\n' - '\t\tCanCheckoutShared = true\n' - '\t\tSccProjectFilePathRelativizedFromConnection1 = %(scc_project_base_path)s\n' - '\t\tSolutionUniqueID = %(slnguid)s\n' - '\tEndGlobalSection\n' % locals()) - + '\t\tSccProvider0 = %(scc_provider)s\n' + '\t\tCanCheckoutShared = true\n' % locals()) + sln_relative_path_from_scc = os.path.relpath(self.dsw_folder_path, scc_connection_root) + if sln_relative_path_from_scc != os.curdir: + self.file.write('\t\tSccProjectFilePathRelativizedFromConnection0 = %s\\\\\n' + % sln_relative_path_from_scc.replace('\\', '\\\\')) + if self.version_num < 8.0: + # When present, SolutionUniqueID is automatically removed by VS 2005 + # TODO: check for Visual Studio versions newer than 2005 + self.file.write('\t\tSolutionUniqueID = %s\n' % slnguid) + for dspinfo in self.dspfiles_info: + i = self.dspfiles_info.index(dspinfo) + 1 + dsp_relative_file_path = dspinfo['SLN_RELATIVE_FILE_PATH'].replace('\\', '\\\\') + dsp_scc_relative_folder_path = os.path.relpath(dspinfo['FOLDER_PATH'], scc_connection_root).replace('\\', '\\\\') + self.file.write('\t\tSccProjectUniqueName%(i)s = %(dsp_relative_file_path)s\n' + '\t\tSccLocalPath%(i)d = %(scc_local_path)s\n' + '\t\tCanCheckoutShared = true\n' + '\t\tSccProjectFilePathRelativizedFromConnection%(i)s = %(dsp_scc_relative_folder_path)s\\\\\n' + % locals()) + self.file.write('\tEndGlobalSection\n') if self.version_num >= 8.0: self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n') else: @@ -987,7 +1389,7 @@ class _GenerateV7DSW(_DSWGenerator): self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant)) cnt = cnt + 1 self.file.write('\tEndGlobalSection\n') - if self.version_num < 7.1: + if self.version_num <= 7.1: self.file.write('\tGlobalSection(ProjectDependencies) = postSolution\n' '\tEndGlobalSection\n') if self.version_num >= 8.0: @@ -999,13 +1401,13 @@ class _GenerateV7DSW(_DSWGenerator): variant = self.configs[name].variant platform = self.configs[name].platform if self.version_num >= 8.0: - for p in self.dspfiles: - guid = _generateGUID(p, '') + for dspinfo in self.dspfiles_info: + guid = dspinfo['GUID'] self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n' '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform)) else: - for p in self.dspfiles: - guid = _generateGUID(p, '') + for dspinfo in self.dspfiles_info: + guid = dspinfo['GUID'] self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n' '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,variant,variant,platform,guid,variant,variant,platform)) @@ -1072,7 +1474,7 @@ class _GenerateV6DSW(_DSWGenerator): def PrintWorkspace(self): """ writes a DSW file """ name = self.name - dspfile = self.dspfiles[0] + dspfile = os.path.relpath(self.dspfiles[0], self.dsw_folder_path) self.file.write(V6DSWHeader % locals()) def Build(self): @@ -1091,7 +1493,10 @@ def GenerateDSP(dspfile, source, env): version_num = 6.0 if 'MSVS_VERSION' in env: version_num, suite = msvs_parse_version(env['MSVS_VERSION']) - if version_num >= 7.0: + if version_num >= 10.0: + g = _GenerateV10DSP(dspfile, source, env) + g.Build() + elif version_num >= 7.0: g = _GenerateV7DSP(dspfile, source, env) g.Build() else: @@ -1118,10 +1523,10 @@ def GenerateDSW(dswfile, source, env): ############################################################################## def GetMSVSProjectSuffix(target, source, env, for_signature): - return env['MSVS']['PROJECTSUFFIX'] + return env['MSVS']['PROJECTSUFFIX'] def GetMSVSSolutionSuffix(target, source, env, for_signature): - return env['MSVS']['SOLUTIONSUFFIX'] + return env['MSVS']['SOLUTIONSUFFIX'] def GenerateProject(target, source, env): # generate the dsp file, according to the version of MSVS. @@ -1178,6 +1583,12 @@ def projectEmitter(target, source, env): source = source + env.subst('$MSVSSCONSCOM', 1) source = source + env.subst('$MSVSENCODING', 1) + # Project file depends on CPPDEFINES and CPPPATH + preprocdefs = xmlify(';'.join(processDefines(env.get('CPPDEFINES', [])))) + includepath_Dirs = processIncludes(env.get('CPPPATH', []), env, None, None) + includepath = xmlify(';'.join([str(x) for x in includepath_Dirs])) + source = source + "; ppdefs:%s incpath:%s"%(preprocdefs, includepath) + if 'buildtarget' in env and env['buildtarget'] != None: if SCons.Util.is_String(env['buildtarget']): source = source + ' "%s"' % env['buildtarget'] @@ -1246,7 +1657,7 @@ def projectEmitter(target, source, env): sourcelist = source if env.get('auto_build_solution', 1): - env['projects'] = targetlist + env['projects'] = [env.File(t).srcnode() for t in targetlist] t, s = solutionEmitter(target, target, env) targetlist = targetlist + t @@ -1354,7 +1765,6 @@ def generate(env): env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"' - env['MSVSENCODING'] = 'Windows-1252' # Set-up ms tools paths for default version msvc_setup_env_once(env) @@ -1368,9 +1778,17 @@ def generate(env): if (version_num < 7.0): env['MSVS']['PROJECTSUFFIX'] = '.dsp' env['MSVS']['SOLUTIONSUFFIX'] = '.dsw' - else: + elif (version_num < 10.0): env['MSVS']['PROJECTSUFFIX'] = '.vcproj' env['MSVS']['SOLUTIONSUFFIX'] = '.sln' + else: + env['MSVS']['PROJECTSUFFIX'] = '.vcxproj' + env['MSVS']['SOLUTIONSUFFIX'] = '.sln' + + if (version_num >= 10.0): + env['MSVSENCODING'] = 'utf-8' + else: + env['MSVSENCODING'] = 'Windows-1252' env['GET_MSVSPROJECTSUFFIX'] = GetMSVSProjectSuffix env['GET_MSVSSOLUTIONSUFFIX'] = GetMSVSSolutionSuffix diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml index d97cff3..ca3bf03 100644 --- a/src/engine/SCons/Tool/msvs.xml +++ b/src/engine/SCons/Tool/msvs.xml @@ -1,5 +1,5 @@ -