summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-x[-rw-r--r--]src/Announce.txt60
-rwxr-xr-x[-rw-r--r--]src/CHANGES.txt433
-rw-r--r--src/LICENSE.txt2
-rw-r--r--src/README.txt21
-rwxr-xr-x[-rw-r--r--]src/RELEASE.txt94
-rw-r--r--src/engine/MANIFEST-xml.in8
-rw-r--r--src/engine/MANIFEST.in7
-rw-r--r--src/engine/SCons/Action.py60
-rw-r--r--src/engine/SCons/Action.xml2
-rw-r--r--src/engine/SCons/ActionTests.py604
-rw-r--r--src/engine/SCons/Builder.py37
-rw-r--r--src/engine/SCons/BuilderTests.py46
-rw-r--r--src/engine/SCons/CacheDir.py133
-rw-r--r--src/engine/SCons/CacheDirTests.py16
-rw-r--r--src/engine/SCons/Conftest.py42
-rw-r--r--src/engine/SCons/Debug.py4
-rw-r--r--src/engine/SCons/Defaults.py17
-rw-r--r--src/engine/SCons/Defaults.xml32
-rw-r--r--src/engine/SCons/DefaultsTests.py19
-rw-r--r--src/engine/SCons/Environment.py83
-rw-r--r--src/engine/SCons/Environment.xml42
-rw-r--r--src/engine/SCons/EnvironmentTests.py105
-rw-r--r--src/engine/SCons/EnvironmentValues.py1
-rw-r--r--src/engine/SCons/Errors.py29
-rw-r--r--src/engine/SCons/ErrorsTests.py34
-rw-r--r--src/engine/SCons/Executor.py29
-rw-r--r--src/engine/SCons/ExecutorTests.py13
-rw-r--r--src/engine/SCons/Job.py38
-rw-r--r--src/engine/SCons/JobTests.py132
-rw-r--r--src/engine/SCons/Memoize.py4
-rw-r--r--src/engine/SCons/MemoizeTests.py16
-rw-r--r--src/engine/SCons/Node/Alias.py4
-rw-r--r--src/engine/SCons/Node/AliasTests.py17
-rw-r--r--src/engine/SCons/Node/FS.py389
-rw-r--r--src/engine/SCons/Node/FSTests.py845
-rw-r--r--src/engine/SCons/Node/NodeTests.py25
-rw-r--r--src/engine/SCons/Node/Python.py17
-rw-r--r--src/engine/SCons/Node/PythonTests.py23
-rw-r--r--src/engine/SCons/Node/__init__.py125
-rw-r--r--src/engine/SCons/Options/PackageOption.py50
-rw-r--r--src/engine/SCons/Options/PathOption.py76
-rw-r--r--src/engine/SCons/Options/__init__.py67
-rw-r--r--src/engine/SCons/PathList.py4
-rw-r--r--src/engine/SCons/PathListTests.py4
-rw-r--r--src/engine/SCons/Platform/PlatformTests.py78
-rw-r--r--src/engine/SCons/Platform/__init__.py79
-rw-r--r--src/engine/SCons/Platform/__init__.xml37
-rw-r--r--src/engine/SCons/Platform/aix.py4
-rw-r--r--src/engine/SCons/Platform/cygwin.py13
-rw-r--r--src/engine/SCons/Platform/darwin.py15
-rw-r--r--src/engine/SCons/Platform/hpux.py4
-rw-r--r--src/engine/SCons/Platform/irix.py4
-rw-r--r--src/engine/SCons/Platform/mingw.py (renamed from src/engine/SCons/Options/ListOption.py)41
-rw-r--r--src/engine/SCons/Platform/os2.py4
-rw-r--r--src/engine/SCons/Platform/posix.py11
-rw-r--r--src/engine/SCons/Platform/posix.xml6
-rw-r--r--src/engine/SCons/Platform/sunos.py4
-rw-r--r--src/engine/SCons/Platform/sunos.xml2
-rw-r--r--src/engine/SCons/Platform/virtualenv.py120
-rw-r--r--src/engine/SCons/Platform/virtualenvTests.py243
-rw-r--r--src/engine/SCons/Platform/win32.py47
-rw-r--r--src/engine/SCons/Platform/win32.xml2
-rw-r--r--src/engine/SCons/SConf.py84
-rw-r--r--src/engine/SCons/SConfTests.py34
-rw-r--r--src/engine/SCons/SConsign.py19
-rw-r--r--src/engine/SCons/SConsignTests.py4
-rw-r--r--src/engine/SCons/Scanner/C.py4
-rw-r--r--src/engine/SCons/Scanner/CTests.py20
-rw-r--r--src/engine/SCons/Scanner/D.py6
-rw-r--r--src/engine/SCons/Scanner/DTests.py16
-rw-r--r--src/engine/SCons/Scanner/Dir.py4
-rw-r--r--src/engine/SCons/Scanner/DirTests.py13
-rw-r--r--src/engine/SCons/Scanner/Fortran.py42
-rw-r--r--src/engine/SCons/Scanner/FortranTests.py141
-rw-r--r--src/engine/SCons/Scanner/IDL.py4
-rw-r--r--src/engine/SCons/Scanner/IDLTests.py12
-rw-r--r--src/engine/SCons/Scanner/LaTeX.py36
-rw-r--r--src/engine/SCons/Scanner/LaTeXTests.py37
-rw-r--r--src/engine/SCons/Scanner/Prog.py4
-rw-r--r--src/engine/SCons/Scanner/ProgTests.py7
-rw-r--r--src/engine/SCons/Scanner/RC.py10
-rw-r--r--src/engine/SCons/Scanner/RCTests.py9
-rw-r--r--src/engine/SCons/Scanner/SWIG.py6
-rw-r--r--src/engine/SCons/Scanner/ScannerTests.py62
-rw-r--r--src/engine/SCons/Scanner/__init__.py6
-rw-r--r--src/engine/SCons/Scanner/__init__.xml2
-rw-r--r--src/engine/SCons/Script/Interactive.py4
-rw-r--r--src/engine/SCons/Script/Main.py59
-rw-r--r--src/engine/SCons/Script/Main.xml2
-rw-r--r--src/engine/SCons/Script/MainTests.py13
-rw-r--r--src/engine/SCons/Script/SConsOptions.py69
-rw-r--r--src/engine/SCons/Script/SConscript.py83
-rw-r--r--src/engine/SCons/Script/SConscript.xml25
-rw-r--r--src/engine/SCons/Script/SConscriptTests.py4
-rw-r--r--src/engine/SCons/Script/__init__.py27
-rw-r--r--src/engine/SCons/Subst.py30
-rw-r--r--src/engine/SCons/Subst.xml2
-rw-r--r--src/engine/SCons/SubstTests.py29
-rw-r--r--src/engine/SCons/Taskmaster.py19
-rw-r--r--src/engine/SCons/TaskmasterTests.py9
-rw-r--r--src/engine/SCons/Tool/386asm.py4
-rw-r--r--src/engine/SCons/Tool/386asm.xml2
-rw-r--r--src/engine/SCons/Tool/DCommon.py4
-rw-r--r--src/engine/SCons/Tool/DCommon.xml2
-rw-r--r--src/engine/SCons/Tool/FortranCommon.py7
-rw-r--r--src/engine/SCons/Tool/FortranCommonTests.py125
-rw-r--r--src/engine/SCons/Tool/GettextCommon.py68
-rw-r--r--src/engine/SCons/Tool/JavaCommon.py232
-rw-r--r--src/engine/SCons/Tool/JavaCommonTests.py128
-rw-r--r--src/engine/SCons/Tool/MSCommon/__init__.py4
-rw-r--r--src/engine/SCons/Tool/MSCommon/arch.py12
-rw-r--r--src/engine/SCons/Tool/MSCommon/common.py17
-rw-r--r--src/engine/SCons/Tool/MSCommon/netframework.py6
-rw-r--r--src/engine/SCons/Tool/MSCommon/sdk.py14
-rw-r--r--src/engine/SCons/Tool/MSCommon/vc.py375
-rw-r--r--src/engine/SCons/Tool/MSCommon/vcTests.py180
-rw-r--r--src/engine/SCons/Tool/MSCommon/vs.py32
-rw-r--r--src/engine/SCons/Tool/PharLapCommon.py7
-rw-r--r--src/engine/SCons/Tool/ToolTests.py88
-rw-r--r--src/engine/SCons/Tool/__init__.py601
-rw-r--r--src/engine/SCons/Tool/__init__.xml2
-rw-r--r--src/engine/SCons/Tool/aixc++.py4
-rw-r--r--src/engine/SCons/Tool/aixc++.xml2
-rw-r--r--src/engine/SCons/Tool/aixcc.py4
-rw-r--r--src/engine/SCons/Tool/aixcc.xml2
-rw-r--r--src/engine/SCons/Tool/aixcxx.py4
-rw-r--r--src/engine/SCons/Tool/aixf77.py4
-rw-r--r--src/engine/SCons/Tool/aixf77.xml2
-rw-r--r--src/engine/SCons/Tool/aixlink.py4
-rw-r--r--src/engine/SCons/Tool/aixlink.xml2
-rw-r--r--src/engine/SCons/Tool/applelink.py155
-rw-r--r--src/engine/SCons/Tool/applelink.xml379
-rw-r--r--src/engine/SCons/Tool/ar.py4
-rw-r--r--src/engine/SCons/Tool/ar.xml2
-rw-r--r--src/engine/SCons/Tool/as.py4
-rw-r--r--src/engine/SCons/Tool/as.xml2
-rw-r--r--src/engine/SCons/Tool/bcc32.py4
-rw-r--r--src/engine/SCons/Tool/bcc32.xml2
-rw-r--r--src/engine/SCons/Tool/c++.py4
-rw-r--r--src/engine/SCons/Tool/c++.xml2
-rw-r--r--src/engine/SCons/Tool/cc.py4
-rw-r--r--src/engine/SCons/Tool/cc.xml2
-rw-r--r--src/engine/SCons/Tool/clang.py18
-rw-r--r--src/engine/SCons/Tool/clang.xml2
-rw-r--r--src/engine/SCons/Tool/clangCommon/__init__.py17
-rw-r--r--src/engine/SCons/Tool/clangxx.py20
-rw-r--r--src/engine/SCons/Tool/clangxx.xml2
-rw-r--r--src/engine/SCons/Tool/cvf.py4
-rw-r--r--src/engine/SCons/Tool/cvf.xml2
-rw-r--r--src/engine/SCons/Tool/cxx.py4
-rw-r--r--src/engine/SCons/Tool/cyglink.py2
-rw-r--r--src/engine/SCons/Tool/cyglink.xml2
-rw-r--r--src/engine/SCons/Tool/default.py4
-rw-r--r--src/engine/SCons/Tool/default.xml2
-rw-r--r--src/engine/SCons/Tool/dmd.py4
-rw-r--r--src/engine/SCons/Tool/dmd.xml2
-rw-r--r--src/engine/SCons/Tool/docbook/__init__.py186
-rw-r--r--src/engine/SCons/Tool/docbook/__init__.xml2
-rw-r--r--src/engine/SCons/Tool/docbook/docs/manual.xml2
-rw-r--r--src/engine/SCons/Tool/dvi.py4
-rw-r--r--src/engine/SCons/Tool/dvi.xml2
-rw-r--r--src/engine/SCons/Tool/dvipdf.py4
-rw-r--r--src/engine/SCons/Tool/dvipdf.xml2
-rw-r--r--src/engine/SCons/Tool/dvips.py4
-rw-r--r--src/engine/SCons/Tool/dvips.xml2
-rw-r--r--src/engine/SCons/Tool/f03.py4
-rw-r--r--src/engine/SCons/Tool/f03.xml2
-rw-r--r--src/engine/SCons/Tool/f08.py4
-rw-r--r--src/engine/SCons/Tool/f08.xml2
-rw-r--r--src/engine/SCons/Tool/f77.py4
-rw-r--r--src/engine/SCons/Tool/f77.xml2
-rw-r--r--src/engine/SCons/Tool/f90.py4
-rw-r--r--src/engine/SCons/Tool/f90.xml2
-rw-r--r--src/engine/SCons/Tool/f95.py4
-rw-r--r--src/engine/SCons/Tool/f95.xml2
-rw-r--r--src/engine/SCons/Tool/filesystem.py4
-rw-r--r--src/engine/SCons/Tool/fortran.py4
-rw-r--r--src/engine/SCons/Tool/fortran.xml15
-rw-r--r--src/engine/SCons/Tool/g++.py4
-rw-r--r--src/engine/SCons/Tool/g++.xml2
-rw-r--r--src/engine/SCons/Tool/g77.py4
-rw-r--r--src/engine/SCons/Tool/g77.xml2
-rw-r--r--src/engine/SCons/Tool/gas.py4
-rw-r--r--src/engine/SCons/Tool/gas.xml2
-rw-r--r--src/engine/SCons/Tool/gcc.py51
-rw-r--r--src/engine/SCons/Tool/gcc.xml2
-rw-r--r--src/engine/SCons/Tool/gdc.py4
-rw-r--r--src/engine/SCons/Tool/gdc.xml2
-rw-r--r--src/engine/SCons/Tool/gettext.xml2
-rw-r--r--src/engine/SCons/Tool/gettext_tool.py16
-rw-r--r--src/engine/SCons/Tool/gfortran.py6
-rw-r--r--src/engine/SCons/Tool/gfortran.xml2
-rw-r--r--src/engine/SCons/Tool/gnulink.py4
-rw-r--r--src/engine/SCons/Tool/gnulink.xml2
-rw-r--r--src/engine/SCons/Tool/gs.py4
-rw-r--r--src/engine/SCons/Tool/gs.xml2
-rw-r--r--src/engine/SCons/Tool/gxx.py8
-rw-r--r--src/engine/SCons/Tool/hpc++.py4
-rw-r--r--src/engine/SCons/Tool/hpc++.xml2
-rw-r--r--src/engine/SCons/Tool/hpcc.py4
-rw-r--r--src/engine/SCons/Tool/hpcc.xml2
-rw-r--r--src/engine/SCons/Tool/hpcxx.py7
-rw-r--r--src/engine/SCons/Tool/hplink.py4
-rw-r--r--src/engine/SCons/Tool/hplink.xml2
-rw-r--r--src/engine/SCons/Tool/icc.py4
-rw-r--r--src/engine/SCons/Tool/icc.xml2
-rw-r--r--src/engine/SCons/Tool/icl.py4
-rw-r--r--src/engine/SCons/Tool/icl.xml2
-rw-r--r--src/engine/SCons/Tool/ifl.py4
-rw-r--r--src/engine/SCons/Tool/ifl.xml2
-rw-r--r--src/engine/SCons/Tool/ifort.py4
-rw-r--r--src/engine/SCons/Tool/ifort.xml2
-rw-r--r--src/engine/SCons/Tool/ilink.py4
-rw-r--r--src/engine/SCons/Tool/ilink.xml2
-rw-r--r--src/engine/SCons/Tool/ilink32.py4
-rw-r--r--src/engine/SCons/Tool/ilink32.xml2
-rw-r--r--src/engine/SCons/Tool/install.py4
-rw-r--r--src/engine/SCons/Tool/install.xml2
-rw-r--r--src/engine/SCons/Tool/intelc.py19
-rw-r--r--src/engine/SCons/Tool/intelc.xml2
-rw-r--r--src/engine/SCons/Tool/ipkg.py10
-rw-r--r--src/engine/SCons/Tool/jar.py137
-rw-r--r--src/engine/SCons/Tool/jar.xml2
-rw-r--r--src/engine/SCons/Tool/javac.py24
-rw-r--r--src/engine/SCons/Tool/javac.xml515
-rw-r--r--src/engine/SCons/Tool/javacTests.py11
-rw-r--r--src/engine/SCons/Tool/javah.py14
-rw-r--r--src/engine/SCons/Tool/javah.xml2
-rw-r--r--src/engine/SCons/Tool/latex.py4
-rw-r--r--src/engine/SCons/Tool/latex.xml2
-rw-r--r--src/engine/SCons/Tool/ldc.py4
-rw-r--r--src/engine/SCons/Tool/ldc.xml2
-rw-r--r--src/engine/SCons/Tool/lex.py54
-rw-r--r--src/engine/SCons/Tool/lex.xml11
-rw-r--r--src/engine/SCons/Tool/link.py185
-rw-r--r--src/engine/SCons/Tool/link.xml2
-rw-r--r--src/engine/SCons/Tool/linkloc.py4
-rw-r--r--src/engine/SCons/Tool/linkloc.xml2
-rw-r--r--src/engine/SCons/Tool/m4.py4
-rw-r--r--src/engine/SCons/Tool/m4.xml2
-rw-r--r--src/engine/SCons/Tool/masm.py4
-rw-r--r--src/engine/SCons/Tool/masm.xml2
-rw-r--r--src/engine/SCons/Tool/midl.py6
-rw-r--r--src/engine/SCons/Tool/midl.xml2
-rw-r--r--src/engine/SCons/Tool/mingw.py134
-rw-r--r--src/engine/SCons/Tool/mingw.xml2
-rw-r--r--src/engine/SCons/Tool/msgfmt.py18
-rw-r--r--src/engine/SCons/Tool/msgfmt.xml2
-rw-r--r--src/engine/SCons/Tool/msginit.py18
-rw-r--r--src/engine/SCons/Tool/msginit.xml2
-rw-r--r--src/engine/SCons/Tool/msgmerge.py19
-rw-r--r--src/engine/SCons/Tool/msgmerge.xml2
-rw-r--r--src/engine/SCons/Tool/mslib.py15
-rw-r--r--src/engine/SCons/Tool/mslib.xml2
-rw-r--r--src/engine/SCons/Tool/mslink.py19
-rw-r--r--src/engine/SCons/Tool/mslink.xml2
-rw-r--r--src/engine/SCons/Tool/mssdk.py4
-rw-r--r--src/engine/SCons/Tool/mssdk.xml2
-rw-r--r--src/engine/SCons/Tool/msvc.py30
-rw-r--r--src/engine/SCons/Tool/msvc.xml15
-rw-r--r--src/engine/SCons/Tool/msvs.py209
-rw-r--r--src/engine/SCons/Tool/msvs.xml1000
-rw-r--r--src/engine/SCons/Tool/msvsTests.py192
-rw-r--r--src/engine/SCons/Tool/mwcc.py4
-rw-r--r--src/engine/SCons/Tool/mwcc.xml2
-rw-r--r--src/engine/SCons/Tool/mwld.py4
-rw-r--r--src/engine/SCons/Tool/mwld.xml2
-rw-r--r--src/engine/SCons/Tool/nasm.py4
-rw-r--r--src/engine/SCons/Tool/nasm.xml2
-rw-r--r--src/engine/SCons/Tool/packaging.xml2
-rw-r--r--src/engine/SCons/Tool/packaging/__init__.py49
-rw-r--r--src/engine/SCons/Tool/packaging/__init__.xml61
-rw-r--r--src/engine/SCons/Tool/packaging/ipk.py26
-rw-r--r--src/engine/SCons/Tool/packaging/msi.py36
-rw-r--r--src/engine/SCons/Tool/packaging/rpm.py57
-rw-r--r--src/engine/SCons/Tool/packaging/src_tarbz2.py6
-rw-r--r--src/engine/SCons/Tool/packaging/src_targz.py6
-rw-r--r--src/engine/SCons/Tool/packaging/src_tarxz.py (renamed from src/engine/SCons/Options/BoolOption.py)33
-rw-r--r--src/engine/SCons/Tool/packaging/src_zip.py4
-rw-r--r--src/engine/SCons/Tool/packaging/tarbz2.py8
-rw-r--r--src/engine/SCons/Tool/packaging/targz.py6
-rw-r--r--src/engine/SCons/Tool/packaging/tarxz.py (renamed from src/engine/SCons/Options/EnumOption.py)34
-rw-r--r--src/engine/SCons/Tool/packaging/zip.py4
-rw-r--r--src/engine/SCons/Tool/pdf.py4
-rw-r--r--src/engine/SCons/Tool/pdf.xml2
-rw-r--r--src/engine/SCons/Tool/pdflatex.py4
-rw-r--r--src/engine/SCons/Tool/pdflatex.xml2
-rw-r--r--src/engine/SCons/Tool/pdftex.py4
-rw-r--r--src/engine/SCons/Tool/pdftex.xml2
-rw-r--r--src/engine/SCons/Tool/qt.py70
-rw-r--r--src/engine/SCons/Tool/qt.xml2
-rw-r--r--src/engine/SCons/Tool/rmic.py17
-rw-r--r--src/engine/SCons/Tool/rmic.xml2
-rw-r--r--src/engine/SCons/Tool/rpcgen.py6
-rw-r--r--src/engine/SCons/Tool/rpcgen.xml2
-rw-r--r--src/engine/SCons/Tool/rpm.py27
-rw-r--r--src/engine/SCons/Tool/rpmutils.py43
-rw-r--r--src/engine/SCons/Tool/sgiar.py4
-rw-r--r--src/engine/SCons/Tool/sgiar.xml2
-rw-r--r--src/engine/SCons/Tool/sgic++.py4
-rw-r--r--src/engine/SCons/Tool/sgic++.xml2
-rw-r--r--src/engine/SCons/Tool/sgicc.py4
-rw-r--r--src/engine/SCons/Tool/sgicc.xml2
-rw-r--r--src/engine/SCons/Tool/sgicxx.py4
-rw-r--r--src/engine/SCons/Tool/sgilink.py4
-rw-r--r--src/engine/SCons/Tool/sgilink.xml2
-rw-r--r--src/engine/SCons/Tool/sunar.py4
-rw-r--r--src/engine/SCons/Tool/sunar.xml2
-rw-r--r--src/engine/SCons/Tool/sunc++.py4
-rw-r--r--src/engine/SCons/Tool/sunc++.xml2
-rw-r--r--src/engine/SCons/Tool/suncc.py4
-rw-r--r--src/engine/SCons/Tool/suncc.xml2
-rw-r--r--src/engine/SCons/Tool/suncxx.py20
-rw-r--r--src/engine/SCons/Tool/sunf77.py4
-rw-r--r--src/engine/SCons/Tool/sunf77.xml2
-rw-r--r--src/engine/SCons/Tool/sunf90.py4
-rw-r--r--src/engine/SCons/Tool/sunf90.xml2
-rw-r--r--src/engine/SCons/Tool/sunf95.py4
-rw-r--r--src/engine/SCons/Tool/sunf95.xml2
-rw-r--r--src/engine/SCons/Tool/sunlink.py4
-rw-r--r--src/engine/SCons/Tool/sunlink.xml2
-rw-r--r--src/engine/SCons/Tool/swig.py43
-rw-r--r--src/engine/SCons/Tool/swig.xml9
-rw-r--r--src/engine/SCons/Tool/tar.py4
-rw-r--r--src/engine/SCons/Tool/tar.xml2
-rw-r--r--src/engine/SCons/Tool/tex.py34
-rw-r--r--src/engine/SCons/Tool/tex.xml2
-rw-r--r--src/engine/SCons/Tool/textfile.py4
-rw-r--r--src/engine/SCons/Tool/textfile.xml6
-rw-r--r--src/engine/SCons/Tool/tlib.py4
-rw-r--r--src/engine/SCons/Tool/tlib.xml2
-rw-r--r--src/engine/SCons/Tool/wix.py4
-rw-r--r--src/engine/SCons/Tool/wixTests.py8
-rw-r--r--src/engine/SCons/Tool/xgettext.py59
-rw-r--r--src/engine/SCons/Tool/xgettext.xml2
-rw-r--r--src/engine/SCons/Tool/yacc.py49
-rw-r--r--src/engine/SCons/Tool/yacc.xml2
-rw-r--r--src/engine/SCons/Tool/zip.py4
-rw-r--r--src/engine/SCons/Tool/zip.xml2
-rw-r--r--src/engine/SCons/Util.py250
-rw-r--r--src/engine/SCons/UtilTests.py338
-rw-r--r--src/engine/SCons/Variables/BoolVariable.py4
-rw-r--r--src/engine/SCons/Variables/BoolVariableTests.py9
-rw-r--r--src/engine/SCons/Variables/EnumVariable.py6
-rw-r--r--src/engine/SCons/Variables/EnumVariableTests.py9
-rw-r--r--src/engine/SCons/Variables/ListVariable.py6
-rw-r--r--src/engine/SCons/Variables/ListVariableTests.py9
-rw-r--r--src/engine/SCons/Variables/PackageVariable.py4
-rw-r--r--src/engine/SCons/Variables/PackageVariableTests.py9
-rw-r--r--src/engine/SCons/Variables/PathVariable.py4
-rw-r--r--src/engine/SCons/Variables/PathVariableTests.py9
-rw-r--r--src/engine/SCons/Variables/VariablesTests.py44
-rw-r--r--src/engine/SCons/Variables/__init__.py15
-rw-r--r--src/engine/SCons/Warnings.py25
-rw-r--r--src/engine/SCons/WarningsTests.py9
-rw-r--r--src/engine/SCons/__init__.py14
-rw-r--r--src/engine/SCons/compat/__init__.py31
-rw-r--r--src/engine/SCons/compat/_scons_dbm.py4
-rw-r--r--src/engine/SCons/cpp.py45
-rw-r--r--src/engine/SCons/cppTests.py145
-rw-r--r--src/engine/SCons/dblite.py16
-rw-r--r--src/engine/SCons/exitfuncs.py4
-rw-r--r--src/script/scons-configure-cache.py143
-rw-r--r--src/script/scons-time.py105
-rw-r--r--src/script/scons.bat12
-rwxr-xr-x[-rw-r--r--]src/script/scons.py115
-rw-r--r--src/script/sconsign.py301
-rwxr-xr-x[-rw-r--r--]src/setup.py61
-rw-r--r--src/test_files.py4
-rw-r--r--src/test_interrupts.py7
-rw-r--r--src/test_pychecker.py7
-rw-r--r--src/test_setup.py37
-rw-r--r--src/test_strings.py21
373 files changed, 9135 insertions, 4785 deletions
diff --git a/src/Announce.txt b/src/Announce.txt
index ebda22e..2ceb8bc 100644..100755
--- a/src/Announce.txt
+++ b/src/Announce.txt
@@ -18,24 +18,73 @@ So that everyone using SCons can help each other learn how to use it more
effectively, please go to http://scons.org/lists.html#users to sign up for
the scons-users mailing list.
-RELEASE 3.0.0 - Mon, 18 Sep 2017 08:32:04 -0700
+RELEASE 3.1.0 - Mon, 20 Jul 2019 16:59:23 -0700
Please consult the RELEASE.txt file for a summary of changes since the last
release and consult the CHANGES.txt file for complete a list of changes
since last release. This announcement highlights only the important
changes.
+ Please note the following important changes since release 3.0.4:
+ - Change the default for AppendENVPath to delete_existing=0, so path
+ order will not be changed, unless explicitly set (Issue #3276)
+ - Add lex construction variable LEXUNISTD for turning off unix headers on windows
+ - Update lex tool to use win_flex on windows if available
+ - Add the textfile tool to the default tool list
+ - The mingw tool now respects SHCCCOMSTR, SHLINKCOMSTR and LDMODULECOMSTR
+ - Add support for finding vswhere under 32 bit Windows installs
+
+
+ Please note the following important changes since release 3.0.3:
+ - Added TEMPFILESUFFIX to allow user to specify suffix for tempfiles used for long command lines
+ - Initial support for ARM architectures with Microsoft Visual Studio 2017. You must set TARGET_ARCH
+ to arm or arm64 to enable.
+ - Fixed issue detecting installs of Microsoft Visual Studio 2017 as well as Microsoft build tools 2017.
+
Please note the following important changes since release 2.5.1:
- *IT IS NOT READY FOR PRODUCTION USE*
This is the initial release supporting both python 3.5+ and 2.7.x and pypy
There are some important changes:
- - Any print statements must now use python 3 syntax of "print()"
+ - Properly support versioned shared libraries for MacOS. We've also introduced two
+ new env variables APPLELINK_CURRENT_VERSION and APPLELINK_COMPATIBILITY_VERSION which will specify
+ what is passed to the linkers -current_version and -compatibility_version flags. If not specified
+ they will be derived from SHLIBVERSION as such:
+ - APPLELINK_CURRENT_VERSION = SHLIBVERSION
+ - APPLELINK_COMPATIBILITY_VERSION = all but the last digit in SHLIBVERSION with .0 appended.
+ Note that the values of the above will be validated. Valid format for either APPLELINK variable is
+ X[.Y[.Z]] where 0 <= X <= 65535, 0 <= Y <= 255, 0 <= Z <= 255.
+ - Fix issue #2980 with credit to Piotr Bartosik (and William Blevins). This is an issue where using
+ TimeStamp-MD5 Decider and CacheDir can yield incorrect md5's being written into the .sconsign.
+ The difference between Piotr Bartosik's patch and the current code is that the more complicated
+ creation of file to csig map is only done when the count of children for the current node doesn't
+ match the previous count which is loaded from the sconsign.
+ - Add flag must_exist to SConscript() call to fail on missing script.
+ Not failing on missing script is now considered deprecated, and the first instance will print a
+ deprecation message.
+ - Add xz compression format to packaging choices.
+ - Add Textfile/Substfile to default environment. (issue #3147)
+ - Remove long deprecated SCons.Options which have been replaced by *Variable()
+ many years ago.
+ - Updated logic for mingw and clang on win32 to search default tool install paths if not
+ found in normal SCons PATH. If the user specifies PATH or tool specific paths they
+ will be used and the default paths below will be ignored.
+ - Default path for clang/clangxx : C:\Program Files\LLVM\bin
+ - Default path for mingw : C:\MinGW\bin and/or C:\mingw-w64\*\mingw64\bin
+ - Key program to locate mingw : mingw32-make (as the gcc with mingw prefix has no fixed name)
+ - Added virtualenv support. A new function Virtualenv() determines whether
+ SCons runs in a virtualenv. The search PATH may also be extended to
+ prefer executables from the current virtualenv over the ones provided by
+ base environment. New option --enable-virtualenv provided to import some
+ virtualenv-related variables to SCons and extend every env['ENV']['PATH']
+ automatically. New option --ignore-virtualenv disables this. Two
+ environment variables, SCONS_ENABLE_VIRTUALENV and
+ SCONS_IGNORE_VIRTUALENV are supported for the same purpose.
+ - Recognize new java 9, 10, 11 (as 9.0 and 10.0, 11.0)
- All node content should be in bytes. This is the default in python 2.7.x,
in Python 3 all strings are by default unicode. byte and/or bytearray
should be used if you construct content for return by a custom node type's
get_content() method.
- - This is some (as yet unresolved issue) using Literal()'s in some context with
+ - There are some (as yet unresolved issue) using Literal()'s in some context with
Python 3
- pypy should be supported, please report any issues to the user's mailing list.
- Currently if you switch back and forth between python 2.7.x and 3.5+ you will
@@ -1266,6 +1315,3 @@ improve SCons for your needs.
-- The SCons Development Team
Gary Oberbrunner and Bill Deegan, maintainers
Thanks to all the contributors for all your help!
-
-Copyright (c) 2001 - 2017 The SCons Foundation
-src/Announce.txt rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index ff28506..a23140c 100644..100755
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -4,6 +4,431 @@
Change Log
+RELEASE 3.1.0 - Mon, 20 Jul 2019 16:59:23 -0700
+
+ From Joseph Brill:
+ - Code to supply correct version-specifier argument to vswhere for
+ VS version selection.
+
+ From William Deegan:
+ - Enhanced --debug=explain output. Now the separate components of the dependency list are split up
+ as follows:
+
+ scons: rebuilding `file3' because:
+ the dependency order changed:
+ ->Sources
+ Old:xxx New:zzz
+ Old:yyy New:yyy
+ Old:zzz New:xxx
+ ->Depends
+ ->Implicit
+ Old:/usr/bin/python New:/usr/bin/python
+ - Fix Issue #3350 - SCons Exception EnvironmentError is conflicting with Python's EnvironmentError.
+ - Fix spurious rebuilds on second build for cases where builder has > 1 target and the source file
+ is generated. This was causing the > 1th target to not have it's implicit list cleared when the source
+ file was actually built, leaving an implicit list similar to follows for 2nd and higher target
+ ['/usr/bin/python', 'xxx', 'yyy', 'zzz']
+ This was getting persisted to SConsign and on rebuild it would be corrected to be similar to this
+ ['zzz', 'yyy', 'xxx', '/usr/bin/python']
+ Which would trigger a rebuild because the order changed.
+ The fix involved added logic to mark all shared targets as peers and then ensure they're implicit
+ list is all cleared together.
+ - Fix Issue #3349 - SCons Exception EnvironmentError is conflicting with Python's EnvironmentError.
+ Renamed to SConsEnvironmentError
+ - Fix Issue #3350 - mslink failing when too many objects. This is resolved by adding TEMPFILEARGJOIN variable
+ which specifies what character to join all the argements output into the tempfile. The default remains a space
+ when mslink, msvc, or mslib tools are loaded they change the TEMPFILEARGJOIN to be a line separator (\r\n on win32)
+ - Fix performance degradation for MD5-timestamp decider. NOTE: This changes the Decider() function arguments.
+ From:
+ def my_decider(dependency, target, prev_ni):
+ To:
+ def my_decider(dependency, target, prev_ni, repo_node):
+ Where repo_node is the repository (or other) node to use to check if the node is out of date instead of dependency.
+
+ From Peter Diener:
+ - Additional fix to issue #3135 - Also handle 'pure' and 'elemental' type bound procedures
+ - Fix issue #3135 - Handle Fortran submodules and type bound procedures
+
+ From Adam Gross:
+ - Upgraded and improved Visual Studio solution/project generation code using the MSVSProject builder.
+ - Added support for Visual Studio 2017 and 2019.
+ - Added support for the following per-variant parameters to the builder:
+ - cpppaths: Provides per-variant include paths.
+ - cppdefines: Provides per-variant preprocessor definitions.
+
+ From Michael Hartmann:
+ - Fix handling of Visual Studio Compilers to properly reject any unknown HOST_PLATFORM or TARGET_PLATFORM
+
+ From Bert Huijben:
+ - Added support for Visual Studio 2019 toolset.
+
+ From Mathew Robinson:
+ - Update cache debug output to include cache hit rate.
+ - No longer unintentionally hide exceptions in Action.py
+ - Allow builders and pseudo-builders to inherit from OverrideEnvironments
+
+ From Leonard de Ruijter:
+ - Add logic to derive correct version argument to vswhere
+
+ From Lukas Schrangl:
+ - Enable LaTeX scanner to find more than one include per line
+
+ From Mats Wichmann:
+ - scons-time takes more care closing files and uses safer mkdtemp to avoid
+ possible races on multi-job runs.
+ - Use importlib to dynamically load tool and platform modules instead of imp module
+ - sconsign: default to .sconsign.dblite if no filename is specified.
+ Be more informative in case of unsupported pickle protocol (py2 only).
+ - Fix issue #3336 - on Windows, paths were being added to PATH even if
+ tools were not found in those paths.
+ - More fixes for newer Java versions (since 9): handle new jdk directory
+ naming (jdk-X.Y instead of jdkX.Y) on Windows; handle two-digit major
+ version. Docstrings improved.
+ - Fixups for pylint: exception types, redefined functions,
+ globals, etc. Some old code removed to resolve issues (hashlib is
+ always present on modern Pythons; no longer need the code for
+ 2.5-and-earlier optparse). cmp is not a builtin function in Py3,
+ drop one (unused) use; replace one. Fix another instance of
+ renaming to SConsEnvironmentError. Trailing whitespace.
+ Consistently use not is/in (if not x is y -> if x is not y).
+ - Add a PY3-only function for setting up the cachedir that should be less
+ prone to races. Add a hack to the PY2 version (from Issue #3351) to
+ be less prone to a race in the check for old-style cache.
+ - Fix coding error in docbook tool only exercised when using python lxml
+ - Recognize two additional GNU compiler header directory options in
+ ParseFlags: -iquote and -idirafter.
+ - Fix more re patterns that contain \ but not specified as raw strings
+ (affects scanners for D, LaTeX, swig)
+
+
+RELEASE 3.0.5 - Mon, 26 Mar 2019 15:04:42 -0700
+
+ From William Deegan:
+
+ - Fix Issue #3283 - Handle using --config=force in combination with Decider('MD5-timestamp').
+ 3.0.2 in fix for issue #2980 added that deciders can throw DeciderNeedsNode exception.
+ The Configure logic directly calls the decider when using --config=force but wasn't handling
+ that exception. This would yield minimally configure tests using TryLink() not running and
+ leaving TypeError Nonetype exception in config.log
+ - Fix Issue #3303 - Handle --config=force overwriting the Environment passed into Configure()'s
+ Decider and not clearing it when the configure context is completed.
+ - Add default paths for yacc tool on windows to include cygwin, mingw, and chocolatey
+ - Fix issue #2799 - Fix mingw tool to respect SHCCCOMSTR, SHLINKCOMSTR and LDMODULECOMSTR
+ - Fix Issue #3329 - Add support for MS SDK V10.0A (which is commonly installed with VS2017)
+ - Fix Issue #3333 - Add support for finding vswhere under 32 bit windows installs.
+
+ From Maciej Kumorek:
+ - Update the MSVC tool to include the nologo flag by default in RCFLAGS
+
+From Daniel Moody:
+ - Change the default for AppendENVPath to delete_existing=0, so path
+ order will not be changed, unless explicitly set (Issue #3276)
+ - Fixed bug which threw error when running SCons on windows system with no MSVC installed.
+ - Update link tool to convert target to node before accessing node member
+ - Update mingw tool to remove MSVC like nologo CCFLAG
+ - Add default paths for lex tool on windows to include cygwin, mingw, and chocolatey
+ - Add lex construction variable LEXUNISTD for turning off unix headers on windows
+ - Update lex tool to use win_flex on windows if available
+
+ From Mats Wichmann:
+ - Quiet open file ResourceWarnings on Python >= 3.6 caused by
+ not using a context manager around Popen.stdout
+ - Add the textfile tool to the default tool list
+ - Fix syntax on is/is not clauses: should not use with a literal
+ - Properly retrieve exit code when catching SystemExit
+ - scons-time now uses context managers around file opens
+ - Fix regex patterns that were not specified as raw strings
+
+ From Bernhard M. Wiedemann:
+ - Do not store build host+user name if reproducible builds are wanted
+
+
+RELEASE 3.0.4 - Mon, 20 Jan 2019 22:49:27 +0000
+
+ From Mats Wichmann:
+ - Improve finding of Microsoft compiler: add a 'products' wildcard
+ in case 2017 Build Tools only is installed as it is considered a separate
+ product from the default Visual Studio
+ - Add TEMPFILESUFFIX to allow a customizable filename extension, as
+ described in the patch attached to issue #2431.
+ - scons.py and sconsign.py stopped working if script called as a symlink
+ to location in scons-local location.
+ - Fix issue running scons using a symlink to scons.py in an scons-local dir
+ - Doc updates around Default(), and the various *TARGETS variables.
+
+ From Daniel Moody:
+ - Improved support for VC14.1 and Visual Studio 2017, as well as arm and arm64 targets.
+ Issues #3268 & Issue #3222
+ - Initial support for ARM targets with Visual Studio 2017 - Issue #3182 (You must set TARGET_ARCH for this to work)
+ - Update TempFileMunge class to use PRINT_CMD_LINE_FUNC
+
+ From Tobias Herzog
+ - Enhance cpp scanner regex logic to detect if/elif expressions without whitespaces but
+ parenthesis like "#if(defined FOO)" or "#elif!(BAR)" correctly.
+
+
+RELEASE 3.0.3 - Mon, 07 Jan 2019 20:05:22 -0400
+ NOTE: 3.0.2 release was dropped because there was a packaging bug. Please consider all 3.0.2
+ content.
+
+ From William Deegan:
+ - Fixes to packaging logic. Ensuring the SCons.Tool.clangCommon module is added
+ to the release packages.
+ - Modify scons.bat script to check for scons python script without .py extension if no file
+ scons.py exists. This enables an all platform wheel to work.
+
+ From Mats Wichmann:
+ - Update doc examples to work with Python 3.5+: map() now returns an iterable instead of a list.
+
+
+RELEASE 3.0.2 - Mon, 31 Dec 2018 16:00:12 -0700
+
+ From Bernard Blackham:
+ - Fixed handling of side-effects in task master (fixes #3013).
+
+ From William Deegan:
+ - Remove long deprecated SCons.Options code and tests. This removes BoolOption,EnumOption,
+ ListOption,PackageOption, and PathOption which have been replaced by *Variable() many years ago.
+ - Re-Enable parallel SCons (-j) when running via Pypy
+ - Move SCons test framework files to testing/framework and remove all references to QMtest.
+ QMTest has not been used by SCons for some time now.
+ - Updated logic for mingw and clang on win32 to search default tool install paths if not
+ found in normal SCons PATH. If the user specifies PATH or tool specific paths they
+ will be used and the default paths below will be ignored.
+ - Default path for clang/clangxx : C:\Program Files\LLVM\bin
+ - Default path for mingw : C:\MinGW\bin and/or C:\mingw-w64\*\mingw64\bin
+ - Key program to locate mingw : mingw32-make (as the gcc with mingw prefix has no fixed name)
+ - Fixed issue causing stack trace when python Action function contains a unicode string when being
+ run with Python 2.7
+ - Add alternate path to QT install for Centos in qt tool: /usr/lib64/qt-3.3/bin
+ - Fix Java tools to search reasonable default paths for Win32, Linux, macOS. Add required paths
+ for swig and java native interface to JAVAINCLUDES. You should add these to your CPPPATH if you need
+ to compile with them. This handles spaces in paths in default Java paths on windows.
+ - Added more java paths to match install for Centos 7 of openjdk
+ - Fix new logic which populates JAVAINCLUDES to handle the case where javac is not found.
+ - Fix GH Issue #2580 - # in FRAMEWORKPATH doesn't get properly expanded. The # is left in the
+ command line.
+ - Fix issue #2980 with credit to Piotr Bartosik (and William Blevins). This is an issue where using
+ TimeStamp-MD5 Decider and CacheDir can yield incorrect md5's being written into the .sconsign.
+ The difference between Piotr Bartosik's patch and the current code is that the more complicated
+ creation of file to csig map is only done when the count of children for the current node doesn't
+ match the previous count which is loaded from the sconsign.
+ - Fix issue # 3106 MSVC if using MSVC_BATCH and target dir had a space would fail due to quirk in
+ MSVC's handling of escaped targetdirs when batch compiling.
+ - Fix GH Issue #3141 unicode string in a TryAction() with python 2.7 crashes.
+ - Fix GH Issue #3212 - Use of Py3 and CacheDir + Configure's TryCompile (or likely and Python Value Nodes)
+ yielded trying to combine strings and bytes which threw exception.
+ - Fix GH Issue #3225 SCons.Util.Flatten() doesn't handle MappingView's produced by dictionary as return
+ values from dict().{items(), keys(), values()}.
+ - Fix GH Issue #3241 - Properly support versioned shared libraries for MacOS. We've also introduced two
+ new env variables APPLELINK_CURRENT_VERSION and APPLELINK_COMPATIBILITY_VERSION which will specify
+ what is passed to the linkers -current_version and -compatibility_version flags. If not specified
+ they will be derived from SHLIBVERSION as such:
+ - APPLELINK_CURRENT_VERSION = SHLIBVERSION
+ - APPLELINK_COMPATIBILITY_VERSION = all but the last digit in SHLIBVERSION with .0 appended.
+ Note that the values of the above will be validated. Valid format for either APPLELINK variable is
+ X[.Y[.Z]] where 0 <= X <= 65535, 0 <= Y <= 255, 0 <= Z <= 255.
+ The new variables have been added to the documents and should show up in user guide and manpage.
+ - Fix GH Issue #3136 no longer wrap io.{BufferedReader,BufferedWriter,BufferedRWPair,BufferedRandom,TextIOWrapper
+ with logic to set HANDLE_FLAG_INHERIT flag on the file handle. Python 3.4+ automatically sets this according
+ to Python docs: https://docs.python.org/3/library/os.html#fd-inheritance
+
+ From Ray Donnelly:
+ - Fix the PATH created by scons.bat (and other .bat files) to provide a normalized
+ PATH. Some pythons in the 3.6 series are no longer able to handle paths which
+ have ".." in them and end up crashing. This is done by cd'ing into the directory
+ we want to add to the path and then using %CD% to give us the normalized directory
+ See bug filed under Python 3.6: https://bugs.python.org/issue32457.
+ Note: On Win32 PATH's which have not been normalized may cause undefined behavior
+ by other executables being run by SCons (or any subprocesses of executables being run by SCons).
+ Resolving this issue should eliminate that possibility going forward.
+
+ From Andrew Featherstone
+ - Removed unused --warn options from the man page and source code.
+
+ From Arda Fu
+ - Fix cpp scanner regex logic to treat ifndef for py3.5+. Previously it was
+ not properly differentiating between if, ifdef, and ifndef.
+
+ From Philipp Maierhöfer
+ - Added a __hash__ method to the class Scons.Subst.Literal. Required when substituting Literal
+ objects when SCons runs with Python 3.
+ - Added missing FORTRANMODDIRPREFIX to the gfortran tool.
+
+ From Matthew Marinets:
+ - Fixed an issue that caused the Java emitter to incorrectly parse arguments to constructors that
+ implemented a class.
+
+ From Fredrik Medley:
+ - Fix exception when printing of EnviromentError messages.
+ Specifically, this fixes error reporting of the race condition when
+ initializing the cache which error previously was hidden.
+
+ From Daniel Moody:
+ - Updated Jar builder to handle nodes and directories better
+ - Updated Jar builder to flatten source list which could contain embedded lists
+ - Removed some magic numbers from jar.py on behalf of Mats Wichmann (mats@linux.com)
+ - Set the pickling protocal back to highest which was causing issues
+ with variant dir tests. This will cause issues if reading sconsigns
+ pickled with the previous lower protocal.
+ - Updated swig to setup default paths for windows
+ - Updated gettext tools to setup default paths for windows with Cygwin/MinGW setups
+ - Add common location for default paths for cygwin and mingw in Platform modules
+ - Updated YACC tool to work on windows with Cygwin/MinGW setups
+ - Set the pickling protocal back to highest which was causing issues
+ with variant dir tests. This will cause issues if reading sconsigns
+ pickled with the previous lower protocal.
+ - Updated FS.py to handle removal of splitunc function from python 3.7
+ - Updated the vc.py to ignore MSVS versions where not compiler could be found
+
+ From Gary Oberbrunner:
+ - Fix bug when Installing multiple subdirs outside the source tree
+ - fix to_str to handle None without raising exception
+ - Fix -jN for python 3.7
+
+ From Jonathon Reinhart:
+ - Replace all instances of `int main()` in C code with `int main(void)`.
+ Specifically, this fixes the test cases use by Configure.CheckCC() which
+ would fail when using -Wstrict-prototypes.
+
+ From Zachary Tessler:
+ - Fix calculation of signatures for FunctionActions that contain list (or set,...)
+ comprehensions whose expressions involve constant literals. Those constants had
+ been ignored in signatures, so changing them did not cause targets to be rebuilt.
+
+ From Paweł Tomulik:
+ - In the testing framework, module TestCommon, fixed must_contain(),
+ must_not_contain(), and related methods of TestCommon class to work with
+ substrings located at zero offset.
+ - Added virtualenv support. A new function Virtualenv() determines whether
+ SCons runs in a virtualenv. The search PATH may also be extended to
+ prefer executables from the current virtualenv over the ones provided by
+ base environment. New option --enable-virtualenv provided to import some
+ virtualenv-related variables to SCons and extend every env['ENV']['PATH']
+ automatically. New option --ignore-virtualenv disables this. Two
+ environment variables, SCONS_ENABLE_VIRTUALENV and
+ SCONS_IGNORE_VIRTUALENV are supported for the same purpose.
+
+ From Richard West:
+ - Add SConstruct.py, Sconstruct.py, sconstruct.py to the search path for the root SConstruct file.
+ Allows easier debugging within Visual Studio
+ - Change setup.py to change the install directory (via pip, or setup.py install) from scons-#.#.#
+ to scons (Yielding <pythondir>/lib/scons/SCons/ instead of <pythondir>/lib/scons/SCons-#.#.#/).
+ This changes SCons to better comply with normal Python installation practices.
+
+ From Mats Wichmann:
+ - Recognize new java 9, 10, 11 (as 9.0 and 10.0, 11.0)
+ - Updated manpage scons.xml to fix a nested list problem
+ - Updated doc terminiology: use prepend instead of append as appropriate
+ - XML validity fixes from SConstruct.py change
+ - Update wiki links to new github location
+ - Update bug links to new github location
+ - Make it easier for SConscript() call to fail on missing script.
+ It was possible to call SCons.Warnings.warningAsException
+ (not documented as a user API) to make all warnings fail. Now
+ SConscript can take an optional must_exist flag which if true fails
+ if the script does not exist. Not failing on missing script is
+ now considered deprecated, and the first instance will print a
+ deprecation message. It is now also possible to flip the scons
+ behavior (which still defaults to warn, not fail) by calling
+ SCons.Script.set_missing_sconscript_error, which is also not a
+ documented interface at the moment.
+ - Convert TestCmd.read to use with statement on open (quiets 17 py3 warnings)
+ - Quiet py3 warning in UtilTests.py
+ - Fix tests specifying octal constants for py3
+ - Fix must_contain tests for py3
+ - RPM package generation:
+ - Fix supplying a build architecture
+ - Disable auto debug package generation on certain rpmbuild versions
+ - Adjust some tests to only supply build-id file on certain rpmbuild versions
+ - Tests now use a file fixture for the repeated (trivial) main.c program.
+ - Document and comment cleanup.
+ - Added new Environment Value X_RPM_EXTRADEFS to supply custom settings
+ to the specfile without adding specific logic for each one to scons.
+ - The test for Python.h needed by swig tests is moved to get_python_platform
+ so it does not have to be repeated in every test; picks up one failure
+ which did not make the (previously needed) check. Windows version
+ of get_python_platform needed some rework in case running in virtualenv.
+ - If test opens os.devnull, register with atexit so file opens do not leak.
+ - Fix bugs in Win32 process spawn logic to handle OSError exception correctly.
+ - Use time.perf_counter instead of time.clock if it exists.
+ time.clock deprecated since py3.3, due to remove in 3.8. deprecation
+ warnings from py3.7 were failing a bunch of tests on Windows since they
+ mess up expected stderr.
+ - Prefer Py3's inspect.getfullargspec over deprecated inspect.getargspec.
+ Switched to "new" (standard in Py2.7) usage of receiving a namedtuple -
+ we were unpacking to a four-tuple, two of the items of which were unused;
+ getfullargspec returns a named tuple with seven elements so it is a
+ cleaner drop-in replacement using the namedtuple.
+ - Updated the test-framework.rst documentation.
+ - Remove obsoleted internal implementaiton of OrderedDict.
+ - Test for tar packaging fixups
+ - Stop using deprecated unittest asserts
+ - messages in strip-install-dir test now os-neutral
+ - Add xz compression format to packaging choices.
+ - Syntax cleanups - trailing blanks, use "is" to compare with None, etc.
+ Three uses of variables not defined are changed.
+ - Some script changes in trying to find scons engine
+ - Update (pep8) configure-cache script, add a --show option.
+ - Fix for a couple of "what if tool not found" exceptions in framework.
+ - Add Textfile/Substfile to default environment. (issue #3147)
+ - sconsign: a couple of python3 fixes; be more tolerant of implicit
+ entries which have no signatures; minor PEP8 changes.
+ - Fix a couple of type mistakes (list-> string, filter type -> list)
+ - Fix a couple of type mistakes in packaging tools: list-> string in msi,
+ filter type -> list in ipk
+
+ From Bernhard M. Wiedemann:
+ - Update SCons' internal scons build logic to allow overriding build date
+ with SOURCE_DATE_EPOCH for SCons itself.
+ - Change the datestamps in SCons' docs and embedded in code use ISO 8601 format and UTC
+
+ From Hao Wu
+ - Typo in customized decider example in user guide
+ - Replace usage of unittest.TestSuite with unittest.main() (fix #3113)
+
+RELEASE 3.0.1 - Mon, 12 Nov 2017 15:31:33 -0700
+
+ From Daniel Moody:
+ - Jar can take multiple targets, and will make a duplicate jar from the sources for each target
+ - Added some warnings in case the Jar builder makes an implicit target
+ - Added Jar method and changed jar build to be more specific. Jar method will take in
+ directories or classes as source. Added more tests to JAR to ensure the jar was
+ packaged with the correct compiled class files.
+ - Added a No result test case to handle bug which seems unrelated to java in the
+ swig-dependencies.py test, more info here: http://scons.tigris.org/issues/show_bug.cgi?id=2907
+ - Added a travis script to test on ubuntu trusty now that the project is on github
+ so that Continuus Integration tests can be run automatically. It tests most case and considers
+ no result a pass as well. Improving this script can install more dependincies allowing for more
+ tests to be run.
+
+ From Daniel Moody:
+ - Updated the Jar Builder tool in Tool/__init__.py so that is doesn't force class files as
+ sources, allowing directories to be passed, which was causing test/Java/JAR.py to fail.
+
+ From William Deegan:
+ - Fix issue where code in utility routine to_String_for_subst() had code whose result was never
+ properly returned.
+ (Found by: James Rinkevich https://pairlist4.pair.net/pipermail/scons-users/2017-October/006358.html )
+ - Fixed Variables.GenerateHelpText() to now use the sort parameter. Due to incorrect 2to3 fixer changes
+ 8 years ago it was being used as a boolean parameter. Now you can specify sort to be a callable, or boolean
+ value. (True = normal sort). Manpage also updated.
+ - Fixed Tool loading logic from exploding sys.path with many site_scons/site_tools prepended on py3.
+ - Added additional output with time to process each SConscript file when using --debug=time.
+
+ From Thomas Berg:
+ - Fixed a regression in scons-3.0.0 where "from __future__ import print_function" was imposed
+ on the scope where SConstruct is executed, breaking existing builds using PY 2.7.
+
+ From William Deegan:
+ - Fix broken subst logic where a string with "$$(abc)" was being treated as "$(abc) and the
+ logic for removing the signature escapes was then failing because there was no closing "$)".
+ This was introduced by a pull request to allow recursive variable evaluations to yield a string
+ such as "$( $( some stuff $) $)".
+
+ From Zachary Tessler:
+ - Fix incorrect warning for repeated identical builder calls that use overrides
+
RELEASE 3.0.0 - Mon, 18 Sep 2017 08:32:04 -0700
@@ -77,9 +502,9 @@ will cause rebuilds.
- Add support for Visual Studio 2017. This support requires vswhere.exe a helper
tool installed with newer installs of 2017. SCons expects it to be located at
"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
- It can be downloaded separately at
+ It can be downloaded separately at
https://github.com/Microsoft/vswhere
-
+
From Tom Tanner:
- Allow nested $( ... $) sections
@@ -6135,7 +6560,3 @@ A brief overview of important functionality available in release 0.01:
- Windows installer available.
-
-
-Copyright (c) 2001 - 2017 The SCons Foundation
-src/CHANGES.txt rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog
diff --git a/src/LICENSE.txt b/src/LICENSE.txt
index ff04f2e..6b6cd6c 100644
--- a/src/LICENSE.txt
+++ b/src/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 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/src/README.txt b/src/README.txt
index ffba407..40d7217 100644
--- a/src/README.txt
+++ b/src/README.txt
@@ -2,7 +2,7 @@
SCons - a software construction tool
- Version 3.0.0
+ Version 3.0.3
This is SCons, a tool for building software (and other files). SCons is
@@ -28,8 +28,7 @@ the latest version by checking the SCons download page at:
EXECUTION REQUIREMENTS
======================
-Running SCons requires Python version 2.7.*. Currently it does not
-run on the Python 3.x release. There should be
+Running SCons requires Python version 2.7.* or 3.5.* and above. There should be
no other dependencies or requirements to run SCons. (There is, however,
an additional requirement to *install* SCons from this particular
package; see the next section.)
@@ -57,7 +56,7 @@ provided Python-standard setup script as follows:
By default, the above command will do the following:
- -- Install the version-numbered "scons-3.0.0" and "sconsign-3.0.0"
+ -- Install the version-numbered "scons-3.0.3" and "sconsign-3.0.3"
scripts in the default system script directory (/usr/bin or
C:\Python*\Scripts, for example). This can be disabled by
specifying the "--no-version-script" option on the command
@@ -71,17 +70,17 @@ By default, the above command will do the following:
making it the default on your system.
On UNIX or Linux systems, you can have the "scons" and "sconsign"
- scripts be hard links or symbolic links to the "scons-3.0.0" and
- "sconsign-3.0.0" scripts by specifying the "--hardlink-scons"
+ scripts be hard links or symbolic links to the "scons-3.0.3" and
+ "sconsign-3.0.3" scripts by specifying the "--hardlink-scons"
or "--symlink-scons" options on the command line.
- -- Install "scons-3.0.0.bat" and "scons.bat" wrapper scripts in the
+ -- Install "scons-3.0.3.bat" and "scons.bat" wrapper scripts in the
Python prefix directory on Windows (C:\Python*, for example).
This can be disabled by specifying the "--no-install-bat" option
on the command line.
On UNIX or Linux systems, the "--install-bat" option may be
- specified to have "scons-3.0.0.bat" and "scons.bat" files
+ specified to have "scons-3.0.3.bat" and "scons.bat" files
installed in the default system script directory, which is useful
if you want to install SCons in a shared file system directory
that can be used to execute SCons from both UNIX/Linux and
@@ -89,7 +88,7 @@ By default, the above command will do the following:
-- Install the SCons build engine (a Python module) in an
appropriate version-numbered SCons library directory
- (/usr/lib/scons-3.0.0 or C:\Python*\scons-3.0.0, for example).
+ (/usr/lib/scons-3.0.3 or C:\Python*\scons-3.0.3, for example).
See below for more options related to installing the build
engine library.
@@ -146,7 +145,7 @@ of small examples for getting started using SCons.
Additional documentation for SCons is available at:
- http://www.scons.org/doc.html
+ https://scons.org/documentation.html
LICENSING
@@ -247,4 +246,4 @@ many contributors, including but not at all limited to:
\... and many others.
-Copyright (c) 2001 - 2015 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 82a0c5a..9d0e092 100644..100755
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -1,51 +1,77 @@
- A new SCons checkpoint release, 3.0.0, is now available
+ A new SCons checkpoint release, 3.1.0, is now available
on the SCons download page:
- http://www.scons.org/download.php
+ https://scons.org/pages/download.html
-
- Here is a summary of the changes since 2.5.1:
+ Here is a summary of the changes since 3.0.5:
NEW FUNCTIONALITY
- - Initial support for Python 3.5+
- - I
-
- DEPRECATED FUNCTIONALITY
+ - Added variable TEMPFILEARGJOIN to specify how to join arguments written
+ to temp files used when command lines exceed MAXLINELENGTH when the
+ command uses $TEMPFILE{...}
+ - Support for MSVC 2019
+ - Upgraded and improved Visual Studio solution/project generation code using the MSVSProject builder.
+ - Added support for Visual Studio 2017 and 2019.
+ - Added support for the following per-variant parameters to the builder:
+ - cpppaths: Provides per-variant include paths.
+ - cppdefines: Provides per-variant preprocessor definitions.
- - List anything that's been deprecated since the last release
CHANGED/ENHANCED EXISTING FUNCTIONALITY
- - List modifications to existing features, where the previous behavior
- wouldn't actually be considered a bug
+ - Fix performance degradation for MD5-timestamp decider. NOTE: This changes the Decider() function arguments.
+ From:
+ def my_decider(dependency, target, prev_ni):
+ To:
+ def my_decider(dependency, target, prev_ni, repo_node):
+ Where repo_node is the repository (or other) node to use to check if the node is out of date instead of dependency.
+
+ - Enhanced --debug=explain output. Now the separate components of the dependency list are split up
+ as follows:
+
+ scons: rebuilding `file3' because:
+ the dependency order changed:
+ ->Sources
+ Old:xxx New:zzz
+ Old:yyy New:yyy
+ Old:zzz New:xxx
+ ->Depends
+ ->Implicit
+ Old:/usr/bin/python New:/usr/bin/python
+
+ - Changed: Pseudo-builders now inherit OverrideEnvironments. For
+ example when calling a pseudo-builder from another
+ pseudo-builder the override variables passed to the first
+ pseudo-builder call had to be explicitly passed on to the
+ internal pseudo-builder call. Now the second pseudo-builder call
+ will automatically inherit these override values.
FIXES
-
- - List fixes of outright bugs
-
- IMPROVEMENTS
-
- - List improvements that wouldn't be visible to the user in the
- documentation: performance improvements (describe the circumstances
+ - Fix Issue #3350 - SCons Exception EnvironmentError is conflicting with Python's EnvironmentError.
+ - Fix spurious rebuilds on second build for cases where builder has > 1 target and the source file
+ is generated. This was causing the > 1th target to not have it's implicit list cleared when the source
+ file was actually built, leaving an implicit list similar to follows for 2nd and higher target
+ ['/usr/bin/python', 'xxx', 'yyy', 'zzz']
+ This was getting persisted to SConsign and on rebuild it would be corrected to be similar to this
+ ['zzz', 'yyy', 'xxx', '/usr/bin/python']
+ Which would trigger a rebuild because the order changed.
+ The fix involved added logic to mark all shared targets as peers and then ensure they're implicit
+ list is all cleared together.
+ - Fix Issue #3349 - SCons Exception EnvironmentError is conflicting with Python's EnvironmentError.
+ Renamed to SConsEnvironmentError
+ - Fix Issue #3350 - mslink failing when too many objects. This is resolved by adding TEMPFILEARGJOIN variable
+ which specifies what character to join all the argements output into the tempfile. The default remains a space
+ when mslink, msvc, or mslib tools are loaded they change the TEMPFILEARGJOIN to be a line separator (\r\n on win32)
+ - Additional fix to issue #3135 - Also handle 'pure' and 'elemental' type bound procedures
+
+ - Fix handling of Visual Studio Compilers to properly reject any unknown HOST_PLATFORM or TARGET_PLATFORM
+ - Enable LaTeX scanner to find more than one include per line
+
under which they would be observed), or major code cleanups
- PACKAGING
-
- - List changes in the way SCons is packaged and/or released
-
- DOCUMENTATION
-
- - List any significant changes to the documentation (not individual
- typo fixes, even if they're mentioned in src/CHANGES.txt to give
- the contributor credit)
-
- DEVELOPMENT
-
- - List visible changes in the way SCons is developed
-
Thanks to CURLY, LARRY, and MOE for their contributions to this release.
Contributors are listed alphabetically by their last name.
-Copyright (c) 2001 - 2017 The SCons Foundation
-src/RELEASE.txt rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog
+Copyright (c) 2001 - 2019 The SCons Foundation
+src/RELEASE.txt e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan
diff --git a/src/engine/MANIFEST-xml.in b/src/engine/MANIFEST-xml.in
deleted file mode 100644
index cfbfd3a..0000000
--- a/src/engine/MANIFEST-xml.in
+++ /dev/null
@@ -1,8 +0,0 @@
-SCons/*.xml
-SCons/Platform/*.xml
-SCons/Scanner/__init__.xml
-SCons/Script/*.xml
-SCons/Tool/*.xml
-SCons/Tool/docbook/__init__.xml
-SCons/Tool/docbook/utils/xmldepend.xsl
-SCons/Tool/packaging/__init__.xml
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 2df278e..3125824 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -1,4 +1,5 @@
SCons/__init__.py
+SCons/__main__.py
SCons/Action.py
SCons/Builder.py
SCons/compat/*.py
@@ -18,7 +19,6 @@ SCons/Node/__init__.py
SCons/Node/Alias.py
SCons/Node/FS.py
SCons/Node/Python.py
-SCons/Options/*.py
SCons/PathList.py
SCons/Platform/__init__.py
SCons/Platform/aix.py
@@ -27,9 +27,11 @@ SCons/Platform/darwin.py
SCons/Platform/hpux.py
SCons/Platform/irix.py
SCons/Platform/os2.py
+SCons/Platform/mingw.py
SCons/Platform/posix.py
SCons/Platform/sunos.py
SCons/Platform/win32.py
+SCons/Platform/virtualenv.py
SCons/Scanner/__init__.py
SCons/Scanner/C.py
SCons/Scanner/D.py
@@ -64,6 +66,7 @@ SCons/Tool/c++.py
SCons/Tool/cxx.py
SCons/Tool/cc.py
SCons/Tool/cyglink.py
+SCons/Tool/clangCommon/__init__.py
SCons/Tool/clang.py
SCons/Tool/clangxx.py
SCons/Tool/cvf.py
@@ -177,3 +180,5 @@ SCons/Tool/msgfmt.py
SCons/Tool/msginit.py
SCons/Tool/msgmerge.py
SCons/Tool/xgettext.py
+#SCons/Tool/docbook/docbook-xsl-1.76.1/**
+#SCons/Tool/docbook/utils/**
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 97040a4..b541256 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -77,7 +77,7 @@ way for wrapping up the functions.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -98,7 +98,7 @@ way for wrapping up the functions.
# 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/Action.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Action.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import pickle
@@ -107,6 +107,7 @@ import sys
import subprocess
import itertools
import inspect
+from collections import OrderedDict
import SCons.Debug
from SCons.Debug import logInstanceCreation
@@ -115,8 +116,7 @@ import SCons.Util
import SCons.Subst
# we use these a lot, so try to optimize them
-is_String = SCons.Util.is_String
-is_List = SCons.Util.is_List
+from SCons.Util import is_String, is_List
class _null(object):
pass
@@ -211,7 +211,7 @@ def _object_contents(obj):
def _code_contents(code, docstring=None):
- """Return the signature contents of a code object.
+ r"""Return the signature contents of a code object.
By providing direct access to the code object of the
function, Python makes this extremely easy. Hooray!
@@ -258,8 +258,7 @@ def _code_contents(code, docstring=None):
# function. Note that we have to call _object_contents on each
# constants because the code object of nested functions can
# show-up among the constants.
-
- z = [_object_contents(cc) for cc in code.co_consts[1:]]
+ z = [_object_contents(cc) for cc in code.co_consts if cc != docstring]
contents.extend(b',(')
contents.extend(bytearray(',', 'utf-8').join(z))
contents.extend(b')')
@@ -535,7 +534,7 @@ class ActionBase(object):
result = self.get_presig(target, source, env)
if not isinstance(result,(bytes, bytearray)):
- result = bytearray("",'utf-8').join([ SCons.Util.to_bytes(r) for r in result ])
+ result = bytearray(result, 'utf-8')
else:
# Make a copy and put in bytearray, without this the contents returned by get_presig
# can be changed by the logic below, appending with each call and causing very
@@ -768,16 +767,22 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
it'll have to be tweaked to get the full desired functionality.
one special arg (so far?), 'error', to tell what to do with exceptions.
"""
- # allow std{in,out,err} to be "'devnull'"
- io = kw.get('stdin')
- if is_String(io) and io == 'devnull':
- kw['stdin'] = open(os.devnull)
- io = kw.get('stdout')
- if is_String(io) and io == 'devnull':
- kw['stdout'] = open(os.devnull, 'w')
- io = kw.get('stderr')
- if is_String(io) and io == 'devnull':
- kw['stderr'] = open(os.devnull, 'w')
+ # allow std{in,out,err} to be "'devnull'". This is like
+ # subprocess.DEVNULL, which does not exist for Py2. Use the
+ # subprocess one if possible.
+ # Clean this up when Py2 support is dropped
+ try:
+ from subprocess import DEVNULL
+ except ImportError:
+ DEVNULL = None
+
+ for stream in 'stdin', 'stdout', 'stderr':
+ io = kw.get(stream)
+ if is_String(io) and io == 'devnull':
+ if DEVNULL:
+ kw[stream] = DEVNULL
+ else:
+ kw[stream] = open(os.devnull, "r+")
# Figure out what shell environment to use
ENV = kw.get('env', None)
@@ -803,7 +808,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
kw['env'] = new_env
try:
- return subprocess.Popen(cmd, **kw)
+ pobj = subprocess.Popen(cmd, **kw)
except EnvironmentError as e:
if error == 'raise': raise
# return a dummy Popen instance that only returns error
@@ -817,7 +822,14 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):
def readline(self): return ''
def __iter__(self): return iter(())
stdout = stderr = f()
- return dummyPopen(e)
+ pobj = dummyPopen(e)
+ finally:
+ # clean up open file handles stored in parent's kw
+ for k, v in kw.items():
+ if inspect.ismethod(getattr(v, 'close', None)):
+ v.close()
+
+ return pobj
class CommandAction(_ActionAction):
@@ -837,8 +849,8 @@ class CommandAction(_ActionAction):
_ActionAction.__init__(self, **kw)
if is_List(cmd):
if [c for c in cmd if is_List(c)]:
- raise TypeError("CommandAction should be given only " \
- "a single command")
+ raise TypeError("CommandAction should be given only "
+ "a single command")
self.cmd_list = cmd
def __str__(self):
@@ -1086,7 +1098,7 @@ class LazyAction(CommandGeneratorAction, CommandAction):
def get_parent_class(self, env):
c = env.get(self.var)
- if is_String(c) and not '\n' in c:
+ if is_String(c) and '\n' not in c:
return CommandAction
return CommandGeneratorAction
@@ -1289,7 +1301,7 @@ class ListAction(ActionBase):
return result
def get_varlist(self, target, source, env, executor=None):
- result = SCons.Util.OrderedDict()
+ result = OrderedDict()
for act in self.list:
for var in act.get_varlist(target, source, env, executor):
result[var] = True
diff --git a/src/engine/SCons/Action.xml b/src/engine/SCons/Action.xml
index 99f4e86..9cb186c 100644
--- a/src/engine/SCons/Action.xml
+++ b/src/engine/SCons/Action.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index ed2412b..9372240 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,8 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/ActionTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/ActionTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
# Define a null function and a null class for use as builder actions.
# Where these are defined in the file seems to affect their byte-code
@@ -30,10 +31,12 @@ __revision__ = "src/engine/SCons/ActionTests.py rel_3.0.0:4395:8972f6a2f699 2017
def GlobalFunc():
pass
+
class GlobalActFunc(object):
def __call__(self):
pass
+
import collections
import io
import os
@@ -41,13 +44,13 @@ import re
import sys
import types
import unittest
+import subprocess
import SCons.Action
import SCons.Environment
import SCons.Errors
import TestCmd
-import TestUnit
# Initial setup of the common environment for all tests,
# a temporary working directory containing a
@@ -56,29 +59,32 @@ import TestUnit
# We don't do this as a setUp() method because it's
# unnecessary to create a separate directory and script
# for each test, they can just use the one.
-test = TestCmd.TestCmd(workdir = '')
+test = TestCmd.TestCmd(workdir='')
test.write('act.py', """\
import os, string, sys
-f = open(sys.argv[1], 'w')
-f.write("act.py: '" + "' '".join(sys.argv[2:]) + "'\\n")
-try:
- if sys.argv[3]:
- f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
-except:
- pass
-f.close()
+
+with open(sys.argv[1], 'w') as f:
+ f.write("act.py: '" + "' '".join(sys.argv[2:]) + "'\\n")
+ try:
+ if sys.argv[3]:
+ f.write("act.py: '" + os.environ[sys.argv[3]] + "'\\n")
+ except:
+ pass
+
if 'ACTPY_PIPE' in os.environ:
if 'PIPE_STDOUT_FILE' in os.environ:
- stdout_msg = open(os.environ['PIPE_STDOUT_FILE'], 'r').read()
+ with open(os.environ['PIPE_STDOUT_FILE'], 'r') as f:
+ stdout_msg = f.read()
else:
stdout_msg = "act.py: stdout: executed act.py %s\\n" % ' '.join(sys.argv[1:])
sys.stdout.write( stdout_msg )
if 'PIPE_STDERR_FILE' in os.environ:
- stderr_msg = open(os.environ['PIPE_STDERR_FILE'], 'r').read()
+ with open(os.environ['PIPE_STDERR_FILE'], 'r') as f:
+ stderr_msg = f.read()
else:
stderr_msg = "act.py: stderr: executed act.py %s\\n" % ' '.join(sys.argv[1:])
- sys.stderr.write( stderr_msg )
+ sys.stderr.write(stderr_msg)
sys.exit(0)
""")
@@ -100,6 +106,7 @@ scons_env = SCons.Environment.Environment()
# so it doesn't clutter the output.
sys.stdout = io.StringIO()
+
class CmdStringHolder(object):
def __init__(self, cmd, literal=None):
self.data = str(cmd)
@@ -125,6 +132,7 @@ class CmdStringHolder(object):
else:
return self.data
+
class Environment(object):
def __init__(self, **kw):
self.d = {}
@@ -134,53 +142,70 @@ class Environment(object):
self.d['ESCAPE'] = scons_env['ESCAPE']
for k, v in kw.items():
self.d[k] = v
+
# Just use the underlying scons_subst*() utility methods.
def subst(self, strSubst, raw=0, target=[], source=[], conv=None):
return SCons.Subst.scons_subst(strSubst, self, raw,
target, source, self.d, conv=conv)
+
subst_target_source = subst
+
def subst_list(self, strSubst, raw=0, target=[], source=[], conv=None):
return SCons.Subst.scons_subst_list(strSubst, self, raw,
- target, source, self.d, conv=conv)
+ target, source, self.d, conv=conv)
+
def __getitem__(self, item):
return self.d[item]
+
def __setitem__(self, item, value):
self.d[item] = value
+
def has_key(self, item):
return item in self.d
+
def get(self, key, value=None):
return self.d.get(key, value)
+
def items(self):
return list(self.d.items())
+
def Dictionary(self):
return self.d
+
def Clone(self, **kw):
res = Environment()
res.d = SCons.Util.semi_deepcopy(self.d)
for k, v in kw.items():
res.d[k] = v
return res
+
def sig_dict(self):
d = {}
- for k,v in self.items(): d[k] = v
+ for k, v in self.items(): d[k] = v
d['TARGETS'] = ['__t1__', '__t2__', '__t3__', '__t4__', '__t5__', '__t6__']
d['TARGET'] = d['TARGETS'][0]
d['SOURCES'] = ['__s1__', '__s2__', '__s3__', '__s4__', '__s5__', '__s6__']
d['SOURCE'] = d['SOURCES'][0]
return d
+
class DummyNode(object):
def __init__(self, name):
self.name = name
+
def str_for_display(self):
return '"' + self.name + '"'
+
def __str__(self):
return self.name
+
def rfile(self):
return self
+
def get_subst_proxy(self):
return self
+
if os.name == 'java':
python = os.path.join(sys.prefix, 'jython')
else:
@@ -189,6 +214,7 @@ _python_ = test.escape(python)
_null = SCons.Action._null
+
def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
def call_action(a, pos_call=pos_call, str_call=str_call, kw=kw):
a = SCons.Action.Action(*a, **kw)
@@ -226,6 +252,7 @@ def test_varlist(pos_call, str_call, cmd, cmdstrfunc, **kw):
a = call_action((cmd, cmdstrfunc, 'a', 'b', 'c'))
assert a.varlist == ('a', 'b', 'c', 'x', 'y', 'z'), a.varlist
+
def test_positional_args(pos_callback, cmd, **kw):
"""Test that Action() returns the expected type and that positional args work.
"""
@@ -235,7 +262,9 @@ def test_positional_args(pos_callback, cmd, **kw):
if not isinstance(act, SCons.Action._ActionAction):
# only valid cmdstrfunc is None
- def none(a): pass
+ def none(a):
+ pass
+
test_varlist(pos_callback, none, cmd, None, **kw)
else:
# _ActionAction should have set these
@@ -244,22 +273,27 @@ def test_positional_args(pos_callback, cmd, **kw):
assert act.presub is _null, act.presub
assert act.chdir is None, act.chdir
assert act.exitstatfunc is SCons.Action.default_exitstatfunc, \
- act.exitstatfunc
+ act.exitstatfunc
def cmdstr(a):
assert hasattr(a, 'strfunction')
assert a.cmdstr == 'cmdstr', a.cmdstr
+
test_varlist(pos_callback, cmdstr, cmd, 'cmdstr', **kw)
- def fun(): pass
+ def fun():
+ pass
+
def strfun(a, fun=fun):
assert a.strfunction is fun, a.strfunction
assert a.cmdstr == _null, a.cmdstr
+
test_varlist(pos_callback, strfun, cmd, fun, **kw)
def none(a):
assert hasattr(a, 'strfunction')
assert a.cmdstr is None, a.cmdstr
+
test_varlist(pos_callback, none, cmd, None, **kw)
"""Test handling of bad cmdstrfunc arguments """
@@ -274,18 +308,21 @@ def test_positional_args(pos_callback, cmd, **kw):
return act
+
class ActionTestCase(unittest.TestCase):
"""Test the Action() factory function"""
def test_FunctionAction(self):
"""Test the Action() factory's creation of FunctionAction objects
"""
+
def foo():
pass
def func_action(a, foo=foo):
assert isinstance(a, SCons.Action.FunctionAction), a
assert a.execfunction == foo, a.execfunction
+
test_positional_args(func_action, foo)
# a singleton list returns the contained action
test_positional_args(func_action, [foo])
@@ -293,28 +330,33 @@ class ActionTestCase(unittest.TestCase):
def test_CommandAction(self):
"""Test the Action() factory's creation of CommandAction objects
"""
+
def cmd_action(a):
assert isinstance(a, SCons.Action.CommandAction), a
assert a.cmd_list == "string", a.cmd_list
+
test_positional_args(cmd_action, "string")
# a singleton list returns the contained action
test_positional_args(cmd_action, ["string"])
- try: unicode
- except NameError: pass
+ try:
+ unicode
+ except NameError:
+ pass
else:
a2 = eval("SCons.Action.Action(u'string')")
assert isinstance(a2, SCons.Action.CommandAction), a2
def line_action(a):
assert isinstance(a, SCons.Action.CommandAction), a
- assert a.cmd_list == [ "explicit", "command", "line" ], a.cmd_list
- test_positional_args(line_action, [[ "explicit", "command", "line" ]])
+ assert a.cmd_list == ["explicit", "command", "line"], a.cmd_list
+
+ test_positional_args(line_action, [["explicit", "command", "line"]])
def test_ListAction(self):
"""Test the Action() factory's creation of ListAction objects
"""
- a1 = SCons.Action.Action(["x", "y", "z", [ "a", "b", "c"]])
+ a1 = SCons.Action.Action(["x", "y", "z", ["a", "b", "c"]])
assert isinstance(a1, SCons.Action.ListAction), a1
assert a1.varlist == (), a1.varlist
assert isinstance(a1.list[0], SCons.Action.CommandAction), a1.list[0]
@@ -324,7 +366,7 @@ class ActionTestCase(unittest.TestCase):
assert isinstance(a1.list[2], SCons.Action.CommandAction), a1.list[2]
assert a1.list[2].cmd_list == "z", a1.list[2].cmd_list
assert isinstance(a1.list[3], SCons.Action.CommandAction), a1.list[3]
- assert a1.list[3].cmd_list == [ "a", "b", "c" ], a1.list[3].cmd_list
+ assert a1.list[3].cmd_list == ["a", "b", "c"], a1.list[3].cmd_list
a2 = SCons.Action.Action("x\ny\nz")
assert isinstance(a2, SCons.Action.ListAction), a2
@@ -372,20 +414,24 @@ class ActionTestCase(unittest.TestCase):
def test_CommandGeneratorAction(self):
"""Test the Action() factory's creation of CommandGeneratorAction objects
"""
+
def foo(): pass
def gen_action(a, foo=foo):
assert isinstance(a, SCons.Action.CommandGeneratorAction), a
assert a.generator is foo, a.generator
+
test_positional_args(gen_action, foo, generator=1)
def test_LazyCmdGeneratorAction(self):
"""Test the Action() factory's creation of lazy CommandGeneratorAction objects
"""
+
def lazy_action(a):
assert isinstance(a, SCons.Action.LazyAction), a
assert a.var == "FOO", a.var
assert a.cmd_list == "${FOO}", a.cmd_list
+
test_positional_args(lazy_action, "$FOO")
test_positional_args(lazy_action, "${FOO}")
@@ -406,6 +452,7 @@ class ActionTestCase(unittest.TestCase):
a2 = SCons.Action.Action(a1)
assert a2 is a1, a2
+
class _ActionActionTestCase(unittest.TestCase):
def test__init__(self):
@@ -429,7 +476,7 @@ class _ActionActionTestCase(unittest.TestCase):
assert a.chdir is None, a.chdir
assert a.exitstatfunc is SCons.Action.default_exitstatfunc, a.exitstatfunc
- assert SCons.Action._ActionAction(kwarg = 1)
+ assert SCons.Action._ActionAction(kwarg=1)
assert not hasattr(a, 'kwarg')
assert not hasattr(a, 'strfunction')
assert a.cmdstr is _null, a.cmdstr
@@ -447,13 +494,13 @@ class _ActionActionTestCase(unittest.TestCase):
a = SCons.Action._ActionAction(cmdstr='cmdstr')
assert not hasattr(a, 'strfunction')
- assert a.cmdstr is 'cmdstr', a.cmdstr
+ assert a.cmdstr == 'cmdstr', a.cmdstr
a = SCons.Action._ActionAction(cmdstr=None)
assert not hasattr(a, 'strfunction')
assert a.cmdstr is None, a.cmdstr
- t = ('a','b','c')
+ t = ('a', 'b', 'c')
a = SCons.Action._ActionAction(varlist=t)
assert a.varlist == t, a.varlist
@@ -461,22 +508,22 @@ class _ActionActionTestCase(unittest.TestCase):
assert a.presub is func1, a.presub
a = SCons.Action._ActionAction(chdir=1)
- assert a.chdir is 1, a.chdir
+ assert a.chdir == 1, a.chdir
a = SCons.Action._ActionAction(exitstatfunc=func1)
assert a.exitstatfunc is func1, a.exitstatfunc
a = SCons.Action._ActionAction(
- # alphabetical order ...
- chdir='x',
- cmdstr='cmdstr',
- exitstatfunc=func3,
- presub=func2,
- strfunction=func1,
- varlist=t,
- )
- assert a.chdir is 'x', a.chdir
- assert a.cmdstr is 'cmdstr', a.cmdstr
+ # alphabetical order ...
+ chdir='x',
+ cmdstr='cmdstr',
+ exitstatfunc=func3,
+ presub=func2,
+ strfunction=func1,
+ varlist=t,
+ )
+ assert a.chdir == 'x', a.chdir
+ assert a.cmdstr == 'cmdstr', a.cmdstr
assert a.exitstatfunc is func3, a.exitstatfunc
assert a.presub is func2, a.presub
assert a.strfunction is func1, a.strfunction
@@ -485,7 +532,10 @@ class _ActionActionTestCase(unittest.TestCase):
def test_dup_keywords(self):
"""Test handling of both cmdstr and strfunction arguments
"""
- def func(): pass
+
+ def func():
+ pass
+
try:
a = SCons.Action.Action('foo', cmdstr='string', strfunction=func)
except SCons.Errors.UserError as e:
@@ -513,6 +563,7 @@ class _ActionActionTestCase(unittest.TestCase):
try:
def execfunc(target, source, env):
pass
+
a = SCons.Action.Action(execfunc)
sio = io.StringIO()
@@ -532,9 +583,9 @@ class _ActionActionTestCase(unittest.TestCase):
save_print_actions = SCons.Action.print_actions
save_print_actions_presub = SCons.Action.print_actions_presub
save_execute_actions = SCons.Action.execute_actions
- #SCons.Action.print_actions = 0
+ # SCons.Action.print_actions = 0
- test = TestCmd.TestCmd(workdir = '')
+ test = TestCmd.TestCmd(workdir='')
test.subdir('sub', 'xyz')
os.chdir(test.workpath())
@@ -545,16 +596,19 @@ class _ActionActionTestCase(unittest.TestCase):
assert isinstance(target, list), type(target)
assert isinstance(source, list), type(source)
return 7
+
a = SCons.Action.Action(execfunc)
def firstfunc(target, source, env):
assert isinstance(target, list), type(target)
assert isinstance(source, list), type(source)
return 0
+
def lastfunc(target, source, env):
assert isinstance(target, list), type(target)
assert isinstance(source, list), type(source)
return 9
+
b = SCons.Action.Action([firstfunc, execfunc, lastfunc])
sio = io.StringIO()
@@ -694,8 +748,10 @@ class _ActionActionTestCase(unittest.TestCase):
SCons.Action.execute_actions = 1
result = []
+
def my_print_cmd_line(s, target, source, env, result=result):
result.append(s)
+
env['PRINT_CMD_LINE_FUNC'] = my_print_cmd_line
a("output", "input", env)
assert result == ["execfunc(['output'], ['input'])"], result
@@ -721,39 +777,43 @@ class _ActionActionTestCase(unittest.TestCase):
def func():
pass
+
a = SCons.Action.Action(func)
s = a.presub_lines(env)
assert s == ["func(target, source, env)"], s
def gen(target, source, env, for_signature):
return 'generat' + env.get('GEN', 'or')
+
a = SCons.Action.Action(gen, generator=1)
s = a.presub_lines(env)
assert s == ["generator"], s
- s = a.presub_lines(Environment(GEN = 'ed'))
+ s = a.presub_lines(Environment(GEN='ed'))
assert s == ["generated"], s
a = SCons.Action.Action("$ACT")
s = a.presub_lines(env)
assert s == [''], s
- s = a.presub_lines(Environment(ACT = 'expanded action'))
+ s = a.presub_lines(Environment(ACT='expanded action'))
assert s == ['expanded action'], s
def test_add(self):
"""Test adding Actions to stuff."""
+
# Adding actions to other Actions or to stuff that can
# be converted into an Action should produce a ListAction
# containing all the Actions.
def bar():
return None
+
baz = SCons.Action.Action(bar, generator=1)
act1 = SCons.Action.Action('foo bar')
- act2 = SCons.Action.Action([ 'foo', bar ])
+ act2 = SCons.Action.Action(['foo', bar])
sum = act1 + act2
assert isinstance(sum, SCons.Action.ListAction), str(sum)
assert len(sum.list) == 3, len(sum.list)
- assert [isinstance(x, SCons.Action.ActionBase) for x in sum.list] == [ 1, 1, 1 ]
+ assert [isinstance(x, SCons.Action.ActionBase) for x in sum.list] == [1, 1, 1]
sum = act1 + act1
assert isinstance(sum, SCons.Action.ListAction), str(sum)
@@ -789,13 +849,13 @@ class _ActionActionTestCase(unittest.TestCase):
assert len(sum.list) == 3, len(sum.list)
assert isinstance(sum.list[0], SCons.Action.CommandAction)
- sum = [ 'foo', 'bar' ] + act1
+ sum = ['foo', 'bar'] + act1
assert isinstance(sum, SCons.Action.ListAction), str(sum)
assert len(sum.list) == 3, sum.list
assert isinstance(sum.list[0], SCons.Action.CommandAction)
assert isinstance(sum.list[1], SCons.Action.CommandAction)
- sum = act2 + [ baz, bar ]
+ sum = act2 + [baz, bar]
assert isinstance(sum, SCons.Action.ListAction), str(sum)
assert len(sum.list) == 4, len(sum.list)
assert isinstance(sum.list[2], SCons.Action.CommandGeneratorAction)
@@ -822,17 +882,18 @@ class _ActionActionTestCase(unittest.TestCase):
else:
assert 0, "Should have thrown a TypeError adding to an int."
+
class CommandActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a command Action
"""
a = SCons.Action.CommandAction(["xyzzy"])
- assert a.cmd_list == [ "xyzzy" ], a.cmd_list
+ assert a.cmd_list == ["xyzzy"], a.cmd_list
assert a.cmdstr is _null, a.cmdstr
a = SCons.Action.CommandAction(["abra"], cmdstr="cadabra")
- assert a.cmd_list == [ "abra" ], a.cmd_list
+ assert a.cmd_list == ["abra"], a.cmd_list
assert a.cmdstr == "cadabra", a.cmdstr
def test___str__(self):
@@ -952,6 +1013,7 @@ class CommandActionTestCase(unittest.TestCase):
def sf(target, source, env):
return "sf was called"
+
act = SCons.Action.CommandAction('foo', strfunction=sf)
s = act.strfunction([], [], env)
assert s == "sf was called", s
@@ -959,26 +1021,35 @@ class CommandActionTestCase(unittest.TestCase):
class actclass1(object):
def __init__(self, targets, sources, env):
pass
+
def __call__(self):
return 1
+
class actclass2(object):
def __init__(self, targets, sources, env):
self.strfunction = 5
+
def __call__(self):
return 2
+
class actclass3(object):
def __init__(self, targets, sources, env):
pass
+
def __call__(self):
return 3
+
def strfunction(self, targets, sources, env):
- return 'actclass3 on %s to get %s'%(str(sources[0]),
- str(targets[0]))
+ return 'actclass3 on %s to get %s' % (str(sources[0]),
+ str(targets[0]))
+
class actclass4(object):
def __init__(self, targets, sources, env):
pass
+
def __call__(self):
return 4
+
strfunction = None
act1 = SCons.Action.Action(actclass1([t1], [s1], env))
@@ -1075,7 +1146,7 @@ class CommandActionTestCase(unittest.TestCase):
act = SCons.Action.CommandAction(cmd4)
sources = [DummyNode('three'), DummyNode('four'), DummyNode('five')]
env2 = env.Clone()
- r = act([], source = sources, env = env2)
+ r = act([], source=sources, env=env2)
assert r == 0
c = test.read(outfile, 'r')
assert c == "act.py: 'three' 'four'\n", c
@@ -1092,13 +1163,13 @@ class CommandActionTestCase(unittest.TestCase):
PATH = ''
env5['ENV']['XYZZY'] = 'xyzzy'
- r = act(target = DummyNode('out5'), source = [], env = env5)
+ r = act(target=DummyNode('out5'), source=[], env=env5)
act = SCons.Action.CommandAction(cmd5)
- r = act(target = DummyNode('out5'),
- source = [],
- env = env.Clone(ENV = {'XYZZY' : 'xyzzy5',
- 'PATH' : PATH}))
+ r = act(target=DummyNode('out5'),
+ source=[],
+ env=env.Clone(ENV={'XYZZY': 'xyzzy5',
+ 'PATH': PATH}))
assert r == 0
c = test.read(outfile, 'r')
assert c == "act.py: 'out5' 'XYZZY'\nact.py: 'xyzzy5'\n", c
@@ -1106,19 +1177,22 @@ class CommandActionTestCase(unittest.TestCase):
class Obj(object):
def __init__(self, str):
self._str = str
+
def __str__(self):
return self._str
+
def rfile(self):
return self
+
def get_subst_proxy(self):
return self
cmd6 = r'%s %s %s ${TARGETS[1]} $TARGET ${SOURCES[:2]}' % (_python_, act_py, outfile)
act = SCons.Action.CommandAction(cmd6)
- r = act(target = [Obj('111'), Obj('222')],
- source = [Obj('333'), Obj('444'), Obj('555')],
- env = env.Clone())
+ r = act(target=[Obj('111'), Obj('222')],
+ source=[Obj('333'), Obj('444'), Obj('555')],
+ env=env.Clone())
assert r == 0
c = test.read(outfile, 'r')
assert c == "act.py: '222' '111' '333' '444'\n", c
@@ -1133,7 +1207,7 @@ class CommandActionTestCase(unittest.TestCase):
expect_nonexistent = 127
# Newer cygwin seems to return 126 for following
expect_nonexecutable_file = 126
- expect_nonexecutable_dir = 127
+ expect_nonexecutable_dir = 127
elif sys.platform.find('sunos') != -1:
expect_nonexistent = 1
expect_nonexecutable_file = 1
@@ -1141,22 +1215,22 @@ class CommandActionTestCase(unittest.TestCase):
else:
expect_nonexistent = 127
expect_nonexecutable_file = 126
- expect_nonexecutable_dir = 126
+ expect_nonexecutable_dir = 126
# Test that a nonexistent command returns 127
act = SCons.Action.CommandAction(python + "_no_such_command_")
- r = act([], [], env.Clone(out = outfile))
+ r = act([], [], env.Clone(out=outfile))
assert r.status == expect_nonexistent, r.status
# Test that trying to execute a directory returns 126
dir, tail = os.path.split(python)
act = SCons.Action.CommandAction(dir)
- r = act([], [], env.Clone(out = outfile))
+ r = act([], [], env.Clone(out=outfile))
assert r.status == expect_nonexecutable_file, r.status
# Test that trying to execute a non-executable file returns 126
act = SCons.Action.CommandAction(outfile)
- r = act([], [], env.Clone(out = outfile))
+ r = act([], [], env.Clone(out=outfile))
assert r.status == expect_nonexecutable_dir, r.status
act = SCons.Action.CommandAction('%s %s 1' % (_python_, exit_py))
@@ -1190,51 +1264,59 @@ class CommandActionTestCase(unittest.TestCase):
def test_set_handler(self):
"""Test setting the command handler...
"""
+
class Test(object):
def __init__(self):
self.executed = 0
- t=Test()
+
+ t = Test()
+
def func(sh, escape, cmd, args, env, test=t):
test.executed = args
test.shell = sh
return 0
+
def escape_func(cmd):
return '**' + cmd + '**'
class LiteralStr(object):
def __init__(self, x):
self.data = x
+
def __str__(self):
return self.data
+
def escape(self, escape_func):
return escape_func(self.data)
+
def is_literal(self):
return 1
a = SCons.Action.CommandAction(["xyzzy"])
- e = Environment(SPAWN = func)
+ e = Environment(SPAWN=func)
a([], [], e)
- assert t.executed == [ 'xyzzy' ], t.executed
+ assert t.executed == ['xyzzy'], t.executed
a = SCons.Action.CommandAction(["xyzzy"])
- e = Environment(SPAWN = '$FUNC', FUNC = func)
+ e = Environment(SPAWN='$FUNC', FUNC=func)
a([], [], e)
- assert t.executed == [ 'xyzzy' ], t.executed
+ assert t.executed == ['xyzzy'], t.executed
a = SCons.Action.CommandAction(["xyzzy"])
- e = Environment(SPAWN = func, SHELL = 'fake shell')
+ e = Environment(SPAWN=func, SHELL='fake shell')
a([], [], e)
- assert t.executed == [ 'xyzzy' ], t.executed
+ assert t.executed == ['xyzzy'], t.executed
assert t.shell == 'fake shell', t.shell
- a = SCons.Action.CommandAction([ LiteralStr("xyzzy") ])
- e = Environment(SPAWN = func, ESCAPE = escape_func)
+ a = SCons.Action.CommandAction([LiteralStr("xyzzy")])
+ e = Environment(SPAWN=func, ESCAPE=escape_func)
a([], [], e)
- assert t.executed == [ '**xyzzy**' ], t.executed
+ assert t.executed == ['**xyzzy**'], t.executed
def test_get_contents(self):
"""Test fetching the contents of a command Action
"""
+
def CmdGen(target, source, env, for_signature):
assert for_signature
return "%s %s" % \
@@ -1242,10 +1324,10 @@ class CommandActionTestCase(unittest.TestCase):
# The number 1 is there to make sure all args get converted to strings.
a = SCons.Action.CommandAction(["|", "$(", "$foo", "|", "$(", "$bar",
- "$)", "stuff", "$)", "|", "$baz", 1])
+ "$)", "stuff", "$)", "|", "$baz", 1])
c = a.get_contents(target=[], source=[],
- env=Environment(foo = 'FFF', bar = 'BBB',
- baz = CmdGen))
+ env=Environment(foo='FFF', bar='BBB',
+ baz=CmdGen))
assert c == b"| | FFF BBB 1", c
# Make sure that CommandActions use an Environment's
@@ -1254,9 +1336,9 @@ class CommandActionTestCase(unittest.TestCase):
def subst_target_source(self, strSubst, raw=0, target=[], source=[]):
return 'subst_target_source: ' + strSubst
- c = a.get_contents(target=DummyNode('ttt'), source = DummyNode('sss'),
- env=SpecialEnvironment(foo = 'GGG', bar = 'CCC',
- baz = 'ZZZ'))
+ c = a.get_contents(target=DummyNode('ttt'), source=DummyNode('sss'),
+ env=SpecialEnvironment(foo='GGG', bar='CCC',
+ baz='ZZZ'))
assert c == b'subst_target_source: | $( $foo | $( $bar $) stuff $) | $baz 1', c
# We've discussed using the real target and source names in a
@@ -1304,6 +1386,7 @@ class CommandActionTestCase(unittest.TestCase):
c = a.get_contents(target=t, source=s, env=env)
assert c == b"s4 s5", c
+
class CommandGeneratorActionTestCase(unittest.TestCase):
def factory(self, act, **kw):
@@ -1313,16 +1396,18 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a command generator Action
"""
+
def f(target, source, env):
pass
+
a = self.factory(f)
assert a.generator == f
def test___str__(self):
"""Test the pre-substitution strings for command generator Actions
"""
- def f(target, source, env, for_signature, self=self):
+ def f(target, source, env, for_signature, self=self):
# See if "env" is really a construction environment (or
# looks like one) by accessing the FindIxes attribute.
# (The Tool/mingw.py module has a generator that uses this,
@@ -1331,6 +1416,7 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
env.FindIxes
return "FOO"
+
a = self.factory(f)
s = str(a)
assert s == 'FOO', s
@@ -1338,10 +1424,12 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def test_genstring(self):
"""Test the command generator Action genstring() method
"""
+
def f(target, source, env, for_signature, self=self):
dummy = env['dummy']
self.dummy = dummy
return "$FOO $TARGET $SOURCE $TARGETS $SOURCES"
+
a = self.factory(f)
self.dummy = 0
s = a.genstring([], [], env=Environment(FOO='xyzzy', dummy=1))
@@ -1358,13 +1446,16 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
s = env.subst("$FOO")
assert s == 'foo baz\nbar ack', s
return "$FOO"
+
def func_action(target, source, env, self=self):
- dummy=env['dummy']
+ dummy = env['dummy']
s = env.subst('$foo')
assert s == 'bar', s
- self.dummy=dummy
+ self.dummy = dummy
+
def f2(target, source, env, for_signature, f=func_action):
return f
+
def ch(sh, escape, cmd, args, env, self=self):
self.cmd.append(cmd)
self.args.append(args)
@@ -1373,30 +1464,34 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
self.dummy = 0
self.cmd = []
self.args = []
- a([], [], env=Environment(FOO = 'foo baz\nbar ack',
- dummy = 1,
- SPAWN = ch))
+ a([], [], env=Environment(FOO='foo baz\nbar ack',
+ dummy=1,
+ SPAWN=ch))
assert self.dummy == 1, self.dummy
assert self.cmd == ['foo', 'bar'], self.cmd
- assert self.args == [[ 'foo', 'baz' ], [ 'bar', 'ack' ]], self.args
+ assert self.args == [['foo', 'baz'], ['bar', 'ack']], self.args
b = self.factory(f2)
self.dummy = 0
- b(target=[], source=[], env=Environment(foo = 'bar',
- dummy = 2 ))
- assert self.dummy==2, self.dummy
+ b(target=[], source=[], env=Environment(foo='bar',
+ dummy=2))
+ assert self.dummy == 2, self.dummy
del self.dummy
class DummyFile(object):
def __init__(self, t):
self.t = t
+
def rfile(self):
self.t.rfile_called = 1
return self
+
def get_subst_proxy(self):
return self
+
def f3(target, source, env, for_signature):
return ''
+
c = self.factory(f3)
c(target=[], source=DummyFile(self), env=Environment())
assert self.rfile_called
@@ -1404,19 +1499,20 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def test_get_contents(self):
"""Test fetching the contents of a command generator Action
"""
+
def f(target, source, env, for_signature):
foo = env['foo']
bar = env['bar']
assert for_signature, for_signature
return [["guux", foo, "$(", "$ignore", "$)", bar,
- '${test("$( foo $bar $)")}' ]]
+ '${test("$( foo $bar $)")}']]
def test(mystr):
assert mystr == "$( foo $bar $)", mystr
return "test"
- env = Environment(foo = 'FFF', bar = 'BBB',
- ignore = 'foo', test=test)
+ env = Environment(foo='FFF', bar='BBB',
+ ignore='foo', test=test)
a = self.factory(f)
c = a.get_contents(target=[], source=[], env=env)
assert c == b"guux FFF BBB test", c
@@ -1430,9 +1526,11 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
# Since the python bytecode has per version differences, we need different expected results per version
func_matches = {
- (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (2, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 5): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 6): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
}
meth_matches = [
@@ -1446,29 +1544,31 @@ class CommandGeneratorActionTestCase(unittest.TestCase):
def f_local(target, source, env, for_signature):
return SCons.Action.Action(LocalFunc)
- env = Environment(XYZ = 'foo')
+ env = Environment(XYZ='foo')
a = self.factory(f_global)
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr(
+ func_matches[sys.version_info[:2]])
a = self.factory(f_local)
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + repr(
+ func_matches[sys.version_info[:2]])
- def f_global(target, source, env, for_signature):
+ def f_global2(target, source, env, for_signature):
return SCons.Action.Action(GlobalFunc, varlist=['XYZ'])
- def f_local(target, source, env, for_signature):
+ def f_local2(target, source, env, for_signature):
return SCons.Action.Action(LocalFunc, varlist=['XYZ'])
matches_foo = func_matches[sys.version_info[:2]] + b'foo'
- a = self.factory(f_global)
+ a = self.factory(f_global2)
c = a.get_contents(target=[], source=[], env=env)
assert c in matches_foo, repr(c)
- a = self.factory(f_local)
+ a = self.factory(f_local2)
c = a.get_contents(target=[], source=[], env=env)
assert c in matches_foo, repr(c)
@@ -1478,12 +1578,16 @@ class FunctionActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a function Action
"""
+
def func1():
pass
+
def func2():
pass
+
def func3():
pass
+
def func4():
pass
@@ -1491,15 +1595,17 @@ class FunctionActionTestCase(unittest.TestCase):
assert a.execfunction == func1, a.execfunction
assert isinstance(a.strfunction, types.MethodType), type(a.strfunction)
- a = SCons.Action.FunctionAction(func2, { 'strfunction' : func3 })
+ a = SCons.Action.FunctionAction(func2, {'strfunction': func3})
assert a.execfunction == func2, a.execfunction
assert a.strfunction == func3, a.strfunction
def test___str__(self):
"""Test the __str__() method for function Actions
"""
+
def func1():
pass
+
a = SCons.Action.FunctionAction(func1, {})
s = str(a)
assert s == "func1(target, source, env)", s
@@ -1507,6 +1613,7 @@ class FunctionActionTestCase(unittest.TestCase):
class class1(object):
def __call__(self):
pass
+
a = SCons.Action.FunctionAction(class1(), {})
s = str(a)
assert s == "class1(target, source, env)", s
@@ -1515,22 +1622,25 @@ class FunctionActionTestCase(unittest.TestCase):
"""Test executing a function Action
"""
self.inc = 0
+
def f(target, source, env):
s = env['s']
s.inc = s.inc + 1
s.target = target
- s.source=source
+ s.source = source
assert env.subst("$BAR") == 'foo bar', env.subst("$BAR")
return 0
+
a = SCons.Action.FunctionAction(f, {})
- a(target=1, source=2, env=Environment(BAR = 'foo bar',
- s = self))
+ a(target=1, source=2, env=Environment(BAR='foo bar',
+ s=self))
assert self.inc == 1, self.inc
assert self.source == [2], self.source
assert self.target == [1], self.target
global count
count = 0
+
def function1(target, source, env):
global count
count = count + 1
@@ -1540,7 +1650,7 @@ class FunctionActionTestCase(unittest.TestCase):
return 1
act = SCons.Action.FunctionAction(function1, {})
- r = act(target = [outfile, outfile2], source=[], env=Environment())
+ r = act(target=[outfile, outfile2], source=[], env=Environment())
assert r.status == 1, r.status
assert count == 1, count
@@ -1555,7 +1665,7 @@ class FunctionActionTestCase(unittest.TestCase):
f.write("class1a\n")
act = SCons.Action.FunctionAction(class1a, {})
- r = act([], [], Environment(out = outfile))
+ r = act([], [], Environment(out=outfile))
assert isinstance(r.status, class1a), r.status
c = test.read(outfile, 'r')
assert c == "class1a\n", c
@@ -1567,7 +1677,7 @@ class FunctionActionTestCase(unittest.TestCase):
return 2
act = SCons.Action.FunctionAction(class1b(), {})
- r = act([], [], Environment(out = outfile))
+ r = act([], [], Environment(out=outfile))
assert r.status == 2, r.status
c = test.read(outfile, 'r')
assert c == "class1b\n", c
@@ -1575,11 +1685,13 @@ class FunctionActionTestCase(unittest.TestCase):
def build_it(target, source, env, executor=None, self=self):
self.build_it = 1
return 0
+
def string_it(target, source, env, executor=None, self=self):
self.string_it = 1
return None
+
act = SCons.Action.FunctionAction(build_it,
- { 'strfunction' : string_it })
+ {'strfunction': string_it})
r = act([], [], Environment())
assert r == 0, r
assert self.build_it
@@ -1593,15 +1705,20 @@ class FunctionActionTestCase(unittest.TestCase):
pass
func_matches = {
- (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (2, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 5): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 6): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+
}
meth_matches = {
- (2,7) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,5) : bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,6) : bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (2, 7): bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 5): bytearray(b'1, 1, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 6): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 7): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 8): bytearray(b'1, 1, 0, 0,(),(),(d\x00S\x00),(),()'),
}
def factory(act, **kw):
@@ -1609,18 +1726,20 @@ class FunctionActionTestCase(unittest.TestCase):
a = factory(GlobalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
-
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
a = factory(LocalFunc)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
matches_foo = func_matches[sys.version_info[:2]] + b'foo'
a = factory(GlobalFunc, varlist=['XYZ'])
c = a.get_contents(target=[], source=[], env=Environment())
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
# assert c in func_matches, repr(c)
c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
@@ -1631,8 +1750,8 @@ class FunctionActionTestCase(unittest.TestCase):
a = factory(GlobalFunc, varlist='XYZ')
c = a.get_contents(target=[], source=[], env=Environment())
# assert c in func_matches, repr(c)
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
-
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
c = a.get_contents(target=[], source=[], env=Environment(XYZ='foo'))
assert c in matches_foo, repr(c)
@@ -1640,6 +1759,7 @@ class FunctionActionTestCase(unittest.TestCase):
class Foo(object):
def get_contents(self, target, source, env):
return b'xyzzy'
+
a = factory(Foo())
c = a.get_contents(target=[], source=[], env=Environment())
assert c == b'xyzzy', repr(c)
@@ -1647,14 +1767,17 @@ class FunctionActionTestCase(unittest.TestCase):
class LocalClass(object):
def LocalMethod(self):
pass
+
lc = LocalClass()
a = factory(lc.LocalMethod)
c = a.get_contents(target=[], source=[], env=Environment())
- assert c == meth_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(meth_matches[sys.version_info[:2]])
+ assert c == meth_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ meth_matches[sys.version_info[:2]])
def test_strfunction(self):
"""Test the FunctionAction.strfunction() method
"""
+
def func():
pass
@@ -1673,13 +1796,16 @@ class FunctionActionTestCase(unittest.TestCase):
s = a.strfunction(target=[], source=[], env=Environment())
assert s == 'function', s
+
class ListActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a list of subsidiary Actions
"""
+
def func():
pass
+
a = SCons.Action.ListAction(["x", func, ["y", "z"]])
assert isinstance(a.list[0], SCons.Action.CommandAction)
assert isinstance(a.list[1], SCons.Action.FunctionAction)
@@ -1689,10 +1815,13 @@ class ListActionTestCase(unittest.TestCase):
def test___str__(self):
"""Test the __str__() method for a list of subsidiary Actions
"""
- def f(target,source,env):
+
+ def f(target, source, env):
pass
- def g(target,source,env):
+
+ def g(target, source, env):
pass
+
a = SCons.Action.ListAction([f, g, "XXX", f])
s = str(a)
assert s == "f(target, source, env)\ng(target, source, env)\nXXX\nf(target, source, env)", s
@@ -1700,10 +1829,13 @@ class ListActionTestCase(unittest.TestCase):
def test_genstring(self):
"""Test the genstring() method for a list of subsidiary Actions
"""
- def f(target,source,env):
+
+ def f(target, source, env):
pass
- def g(target,source,env,for_signature):
+
+ def g(target, source, env, for_signature):
return 'generated %s %s' % (target[0], source[0])
+
g = SCons.Action.Action(g, generator=1)
a = SCons.Action.ListAction([f, g, "XXX", f])
s = a.genstring(['foo.x'], ['bar.y'], Environment())
@@ -1713,11 +1845,13 @@ class ListActionTestCase(unittest.TestCase):
"""Test executing a list of subsidiary Actions
"""
self.inc = 0
- def f(target,source,env):
+
+ def f(target, source, env):
s = env['s']
s.inc = s.inc + 1
+
a = SCons.Action.ListAction([f, f, f])
- a([], [], Environment(s = self))
+ a([], [], Environment(s=self))
assert self.inc == 3, self.inc
cmd2 = r'%s %s %s syzygy' % (_python_, act_py, outfile)
@@ -1737,8 +1871,9 @@ class ListActionTestCase(unittest.TestCase):
def __init__(self, target, source, env):
with open(env['out'], 'a') as f:
f.write("class2b\n")
+
act = SCons.Action.ListAction([cmd2, function2, class2a(), class2b])
- r = act([], [], Environment(out = outfile))
+ r = act([], [], Environment(out=outfile))
assert isinstance(r.status, class2b), r.status
c = test.read(outfile, 'r')
assert c == "act.py: 'syzygy'\nfunction2\nclass2a\nclass2b\n", c
@@ -1746,18 +1881,21 @@ class ListActionTestCase(unittest.TestCase):
def test_get_contents(self):
"""Test fetching the contents of a list of subsidiary Actions
"""
- self.foo=0
+ self.foo = 0
+
def gen(target, source, env, for_signature):
s = env['s']
- s.foo=1
+ s.foo = 1
return "y"
+
a = SCons.Action.ListAction(["x",
SCons.Action.Action(gen, generator=1),
"z"])
- c = a.get_contents(target=[], source=[], env=Environment(s = self))
- assert self.foo==1, self.foo
+ c = a.get_contents(target=[], source=[], env=Environment(s=self))
+ assert self.foo == 1, self.foo
assert c == b"xyz", c
+
class LazyActionTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of a lazy-evaluation Action
@@ -1776,8 +1914,10 @@ class LazyActionTestCase(unittest.TestCase):
def test_genstring(self):
"""Test the lazy-evaluation Action genstring() method
"""
+
def f(target, source, env):
pass
+
a = SCons.Action.Action('$BAR')
env1 = Environment(BAR=f, s=self)
env2 = Environment(BAR='xxx', s=self)
@@ -1789,15 +1929,17 @@ class LazyActionTestCase(unittest.TestCase):
def test_execute(self):
"""Test executing a lazy-evaluation Action
"""
+
def f(target, source, env):
s = env['s']
- s.test=1
+ s.test = 1
return 0
+
a = SCons.Action.Action('$BAR')
- a([], [], env=Environment(BAR = f, s = self))
+ a([], [], env=Environment(BAR=f, s=self))
assert self.test == 1, self.test
cmd = r'%s %s %s lazy' % (_python_, act_py, outfile)
- a([], [], env=Environment(BAR = cmd, s = self))
+ a([], [], env=Environment(BAR=cmd, s=self))
c = test.read(outfile, 'r')
assert c == "act.py: 'lazy'\n", c
@@ -1805,7 +1947,7 @@ class LazyActionTestCase(unittest.TestCase):
"""Test fetching the contents of a lazy-evaluation Action
"""
a = SCons.Action.Action("${FOO}")
- env = Environment(FOO = [["This", "is", "a", "test"]])
+ env = Environment(FOO=[["This", "is", "a", "test"]])
c = a.get_contents(target=[], source=[], env=env)
assert c == b"This is a test", c
@@ -1816,11 +1958,12 @@ class LazyActionTestCase(unittest.TestCase):
def LocalFunc():
pass
-
func_matches = {
- (2,7) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,5) : bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
- (3,6) : bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (2, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 5): bytearray(b'0, 0, 0, 0,(),(),(d\x00\x00S),(),()'),
+ (3, 6): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 7): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
+ (3, 8): bytearray(b'0, 0, 0, 0,(),(),(d\x00S\x00),(),()'),
}
meth_matches = [
@@ -1831,27 +1974,26 @@ class LazyActionTestCase(unittest.TestCase):
def factory(act, **kw):
return SCons.Action.FunctionAction(act, kw)
-
a = SCons.Action.Action("${FOO}")
- env = Environment(FOO = factory(GlobalFunc))
+ env = Environment(FOO=factory(GlobalFunc))
c = a.get_contents(target=[], source=[], env=env)
# assert c in func_matches, "Got\n"+repr(c)+"\nExpected one of \n"+"\n".join([repr(f) for f in func_matches])
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
-
-
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
- env = Environment(FOO = factory(LocalFunc))
+ env = Environment(FOO=factory(LocalFunc))
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
# matches_foo = [x + b"foo" for x in func_matches]
matches_foo = func_matches[sys.version_info[:2]] + b'foo'
-
- env = Environment(FOO = factory(GlobalFunc, varlist=['XYZ']))
+ env = Environment(FOO=factory(GlobalFunc, varlist=['XYZ']))
c = a.get_contents(target=[], source=[], env=env)
- assert c == func_matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(func_matches[sys.version_info[:2]])
+ assert c == func_matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ func_matches[sys.version_info[:2]])
env['XYZ'] = 'foo'
c = a.get_contents(target=[], source=[], env=env)
@@ -1861,36 +2003,40 @@ class LazyActionTestCase(unittest.TestCase):
class ActionCallerTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of an ActionCaller"""
- ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO' : 4, 'BAR' : 5})
+ ac = SCons.Action.ActionCaller(1, [2, 3], {'FOO': 4, 'BAR': 5})
assert ac.parent == 1, ac.parent
assert ac.args == [2, 3], ac.args
- assert ac.kw == {'FOO' : 4, 'BAR' : 5}, ac.kw
+ assert ac.kw == {'FOO': 4, 'BAR': 5}, ac.kw
def test_get_contents(self):
"""Test fetching the contents of an ActionCaller"""
+
def strfunc():
pass
def LocalFunc():
pass
-
matches = {
- (2,7) : b'd\x00\x00S',
- (3,5) : b'd\x00\x00S',
- (3,6) : b'd\x00S\x00',
- }
+ (2, 7): b'd\x00\x00S',
+ (3, 5): b'd\x00\x00S',
+ (3, 6): b'd\x00S\x00',
+ (3, 7): b'd\x00S\x00',
+ (3, 8): b'd\x00S\x00',
+ }
af = SCons.Action.ActionFactory(GlobalFunc, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ matches[sys.version_info[:2]])
af = SCons.Action.ActionFactory(LocalFunc, strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ matches[sys.version_info[:2]])
class LocalActFunc(object):
def __call__(self):
@@ -1899,12 +2045,14 @@ class ActionCallerTestCase(unittest.TestCase):
af = SCons.Action.ActionFactory(GlobalActFunc(), strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ matches[sys.version_info[:2]])
af = SCons.Action.ActionFactory(LocalActFunc(), strfunc)
ac = SCons.Action.ActionCaller(af, [], {})
c = ac.get_contents([], [], Environment())
- assert c == matches[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected one of \n"+repr(matches[sys.version_info[:2]])
+ assert c == matches[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected one of \n" + repr(
+ matches[sys.version_info[:2]])
matches = [
b"<built-in function str>",
@@ -1922,12 +2070,14 @@ class ActionCallerTestCase(unittest.TestCase):
def test___call__(self):
"""Test calling an ActionCaller"""
actfunc_args = []
+
def actfunc(a1, a2, a3, args=actfunc_args):
args.extend([a1, a2, a3])
+
def strfunc(a1, a2, a3):
pass
- e = Environment(FOO = 2, BAR = 5)
+ e = Environment(FOO=2, BAR=5)
af = SCons.Action.ActionFactory(actfunc, strfunc)
ac = SCons.Action.ActionCaller(af, ['$__env__', '$FOO', 3], {})
@@ -1937,7 +2087,7 @@ class ActionCallerTestCase(unittest.TestCase):
assert actfunc_args[2] == 3, actfunc_args
del actfunc_args[:]
- ac = SCons.Action.ActionCaller(af, [], {'a3' : '$__env__', 'a2' : '$BAR', 'a1' : 4})
+ ac = SCons.Action.ActionCaller(af, [], {'a3': '$__env__', 'a2': '$BAR', 'a1': 4})
ac([], [], e)
assert actfunc_args[0] == 4, actfunc_args
assert actfunc_args[1] == '5', actfunc_args
@@ -1947,29 +2097,35 @@ class ActionCallerTestCase(unittest.TestCase):
def test_strfunction(self):
"""Test calling the ActionCaller strfunction() method"""
strfunc_args = []
+
def actfunc(a1, a2, a3, a4):
pass
+
def strfunc(a1, a2, a3, a4, args=strfunc_args):
args.extend([a1, a2, a3, a4])
af = SCons.Action.ActionFactory(actfunc, strfunc)
ac = SCons.Action.ActionCaller(af, [1, '$FOO', 3, '$WS'], {})
- ac.strfunction([], [], Environment(FOO = 2, WS='white space'))
+ ac.strfunction([], [], Environment(FOO=2, WS='white space'))
assert strfunc_args == [1, '2', 3, 'white space'], strfunc_args
del strfunc_args[:]
- d = {'a3' : 6, 'a2' : '$BAR', 'a1' : 4, 'a4' : '$WS'}
+ d = {'a3': 6, 'a2': '$BAR', 'a1': 4, 'a4': '$WS'}
ac = SCons.Action.ActionCaller(af, [], d)
- ac.strfunction([], [], Environment(BAR = 5, WS='w s'))
+ ac.strfunction([], [], Environment(BAR=5, WS='w s'))
assert strfunc_args == [4, '5', 6, 'w s'], strfunc_args
+
class ActionFactoryTestCase(unittest.TestCase):
def test___init__(self):
"""Test creation of an ActionFactory"""
+
def actfunc():
pass
+
def strfunc():
pass
+
ac = SCons.Action.ActionFactory(actfunc, strfunc)
assert ac.actfunc is actfunc, ac.actfunc
assert ac.strfunc is strfunc, ac.strfunc
@@ -1978,10 +2134,13 @@ class ActionFactoryTestCase(unittest.TestCase):
"""Test calling whatever's returned from an ActionFactory"""
actfunc_args = []
strfunc_args = []
+
def actfunc(a1, a2, a3, args=actfunc_args):
args.extend([a1, a2, a3])
+
def strfunc(a1, a2, a3, args=strfunc_args):
args.extend([a1, a2, a3])
+
af = SCons.Action.ActionFactory(actfunc, strfunc)
af(3, 6, 9)([], [], Environment())
assert actfunc_args == [3, 6, 9], actfunc_args
@@ -1995,8 +2154,8 @@ class ActionCompareTestCase(unittest.TestCase):
Basically ensures we can locate the builder, comparing it to
itself along the way."""
- bar = SCons.Builder.Builder(action = {})
- env = Environment( BUILDERS = {'BAR' : bar} )
+ bar = SCons.Builder.Builder(action={})
+ env = Environment(BUILDERS={'BAR': bar})
name = bar.get_name(env)
assert name == 'BAR', name
@@ -2005,12 +2164,12 @@ class ActionCompareTestCase(unittest.TestCase):
Ensure that we can compare builders (and thereby actions) to
each other safely."""
- foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
- bar = SCons.Builder.Builder(action = {})
+ foo = SCons.Builder.Builder(action='$FOO', suffix='.foo')
+ bar = SCons.Builder.Builder(action={})
assert foo != bar
assert foo.action != bar.action
- env = Environment( BUILDERS = {'FOO' : foo,
- 'BAR' : bar} )
+ env = Environment(BUILDERS={'FOO': foo,
+ 'BAR': bar})
name = foo.get_name(env)
assert name == 'FOO', name
name = bar.get_name(env)
@@ -2024,14 +2183,14 @@ class ActionCompareTestCase(unittest.TestCase):
where one of the builders has a suffix dictionary with a None
key."""
- foo = SCons.Builder.Builder(action = '$FOO', suffix = '.foo')
- bar = SCons.Builder.Builder(action = {}, suffix={None:'.bar'})
+ foo = SCons.Builder.Builder(action='$FOO', suffix='.foo')
+ bar = SCons.Builder.Builder(action={}, suffix={None: '.bar'})
bar.add_action('.cow', "$MOO")
- dog = SCons.Builder.Builder(suffix = '.bar')
+ dog = SCons.Builder.Builder(suffix='.bar')
- env = Environment( BUILDERS = {'FOO' : foo,
- 'BAR' : bar,
- 'DOG' : dog} )
+ env = Environment(BUILDERS={'FOO': foo,
+ 'BAR': bar,
+ 'DOG': dog})
assert foo.get_name(env) == 'FOO', foo.get_name(env)
assert bar.get_name(env) == 'BAR', bar.get_name(env)
@@ -2040,9 +2199,11 @@ class ActionCompareTestCase(unittest.TestCase):
class TestClass(object):
"""A test class used by ObjectContentsTestCase.test_object_contents"""
+
def __init__(self):
self.a = "a"
self.b = "b"
+
def method(self, arg):
pass
@@ -2058,14 +2219,16 @@ class ObjectContentsTestCase(unittest.TestCase):
# Since the python bytecode has per version differences, we need different expected results per version
expected = {
- (2,7) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
- (3,5) : bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
- (3,6) : bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
+ (2, 7): bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
+ (3, 5): bytearray(b'3, 3, 0, 0,(),(),(|\x00\x00S),(),()'),
+ (3, 6): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
+ (3, 7): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
+ (3, 8): bytearray(b'3, 3, 0, 0,(),(),(|\x00S\x00),(),()'),
}
c = SCons.Action._function_contents(func1)
- assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]])
-
+ assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(
+ expected[sys.version_info[:2]])
def test_object_contents(self):
"""Test that Action._object_contents works"""
@@ -2078,12 +2241,20 @@ class ObjectContentsTestCase(unittest.TestCase):
# Since the python bytecode has per version differences, we need different expected results per version
expected = {
- (2,7): bytearray(b"{TestClass:__main__}[[[(<type \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<type \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
- (3,5): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
- (3,6): bytearray(b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"),
+ (2, 7): bytearray(
+ b"{TestClass:__main__}[[[(<type \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<type \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
+ (3, 5): bytearray(
+ b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01\x00|\x00\x00_\x00\x00d\x02\x00|\x00\x00_\x01\x00d\x00\x00S),(),(),2, 2, 0, 0,(),(),(d\x00\x00S),(),()}}{{{a=a,b=b}}}"),
+ (3, 6): bytearray(
+ b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"),
+ (3, 7): bytearray(
+ b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"),
+ (3, 8): bytearray(
+ b"{TestClass:__main__}[[[(<class \'object\'>, ()), [(<class \'__main__.TestClass\'>, (<class \'object\'>,))]]]]{{1, 1, 0, 0,(a,b),(a,b),(d\x01|\x00_\x00d\x02|\x00_\x01d\x00S\x00),(),(),2, 2, 0, 0,(),(),(d\x00S\x00),(),()}}{{{a=a,b=b}}}"),
}
- assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+repr(expected[sys.version_info[:2]])
+ assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(
+ expected[sys.version_info[:2]])
def test_code_contents(self):
"""Test that Action._code_contents works"""
@@ -2093,36 +2264,35 @@ class ObjectContentsTestCase(unittest.TestCase):
# Since the python bytecode has per version differences, we need different expected results per version
expected = {
- (2,7) : bytearray(b'0, 0, 0, 0,(N.),(),(d\x00\x00GHd\x01\x00S)'),
- (3,5) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'),
- (3,6) : bytearray(b'0, 0, 0, 0,(N.),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
+ (2, 7): bytearray(b'0, 0, 0, 0,(Hello, World!),(),(d\x00\x00GHd\x01\x00S)'),
+ (3, 5): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00\x00d\x00\x00\x83\x01\x00\x01d\x01\x00S)'),
+ (3, 6): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
+ (3, 7): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
+ (3, 8): bytearray(b'0, 0, 0, 0,(Hello, World!),(print),(e\x00d\x00\x83\x01\x01\x00d\x01S\x00)'),
}
- assert c == expected[sys.version_info[:2]], "Got\n"+repr(c)+"\nExpected \n"+"\n"+expected[sys.version_info[:2]]
+ assert c == expected[sys.version_info[:2]], "Got\n" + repr(c) + "\nExpected \n" + "\n" + repr(expected[
+ sys.version_info[:2]])
+ def test_uncaught_exception_bubbles(self):
+ """Test that _subproc bubbles uncaught exceptions"""
+ try:
+ pobj = SCons.Action._subproc(Environment(),
+ None,
+ stdin='devnull',
+ stderr='devnull',
+ stdout=subprocess.PIPE)
+ pobj.wait()
+ except EnvironmentError:
+ pass
+ except Exception:
+ # pass the test
+ return
+ raise Exception("expected a non-EnvironmentError exception")
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ _ActionActionTestCase,
- ActionTestCase,
- CommandActionTestCase,
- CommandGeneratorActionTestCase,
- FunctionActionTestCase,
- ListActionTestCase,
- LazyActionTestCase,
- ActionCallerTestCase,
- ActionFactoryTestCase,
- ActionCompareTestCase,
- ObjectContentsTestCase ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
-
- TestUnit.run(suite)
-
- # Swap this for above to debug otherwise you can't run individual tests as TestUnit is swallowing arguments
- # unittest.main()
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 9cb0f86..7777436 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -77,7 +77,7 @@ There are the following methods for internal use within this module:
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -98,7 +98,7 @@ There are the following methods for internal use within this module:
# 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/Builder.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Builder.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import collections
@@ -274,7 +274,7 @@ def Builder(**kw):
result = BuilderBase(**kw)
- if not composite is None:
+ if composite is not None:
result = CompositeBuilder(result, composite)
return result
@@ -291,7 +291,14 @@ def _node_errors(builder, env, tlist, slist):
if t.side_effect:
raise UserError("Multiple ways to build the same target were specified for: %s" % t)
if t.has_explicit_builder():
- if not t.env is None and not t.env is env:
+ # Check for errors when the environments are different
+ # No error if environments are the same Environment instance
+ if (t.env is not None and t.env is not env and
+ # Check OverrideEnvironment case - no error if wrapped Environments
+ # are the same instance, and overrides lists match
+ not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
+ getattr(t.env, 'overrides', 0) == getattr(env, 'overrides', 1) and
+ not builder.multi)):
action = t.builder.action
t_contents = t.builder.action.get_contents(tlist, slist, t.env)
contents = builder.action.get_contents(tlist, slist, env)
@@ -300,7 +307,10 @@ def _node_errors(builder, env, tlist, slist):
msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
else:
- msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8'))
+ try:
+ msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8'))
+ except UnicodeDecodeError:
+ msg = "Two environments with different actions were specified for the same target: %s"%t
raise UserError(msg)
if builder.multi:
if t.builder != builder:
@@ -414,7 +424,7 @@ class BuilderBase(object):
if name:
self.name = name
self.executor_kw = {}
- if not chdir is _null:
+ if chdir is not _null:
self.executor_kw['chdir'] = chdir
self.is_explicit = is_explicit
@@ -544,8 +554,10 @@ class BuilderBase(object):
result = []
if target is None: target = [None]*len(source)
for tgt, src in zip(target, source):
- if not tgt is None: tgt = [tgt]
- if not src is None: src = [src]
+ if tgt is not None:
+ tgt = [tgt]
+ if src is not None:
+ src = [src]
result.extend(self._execute(env, tgt, src, overwarn))
return SCons.Node.NodeList(result)
@@ -553,6 +565,13 @@ class BuilderBase(object):
tlist, slist = self._create_nodes(env, target, source)
+ # If there is more than one target ensure that if we need to reset
+ # the implicit list to new scan of dependency all targets implicit lists
+ # are cleared. (SCons GH Issue #2811 and MongoDB SERVER-33111)
+ if len(tlist) > 1:
+ for t in tlist:
+ t.target_peers = tlist
+
# Check for errors with the specified target/source lists.
_node_errors(self, env, tlist, slist)
@@ -734,7 +753,7 @@ class BuilderBase(object):
for s in SCons.Util.flatten(source):
if SCons.Util.is_String(s):
match_suffix = match_src_suffix(env.subst(s))
- if not match_suffix and not '.' in s:
+ if not match_suffix and '.' not in s:
src_suf = self.get_src_suffix(env)
s = self._adjustixes(s, None, src_suf)[0]
else:
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index edc4ca8..dd9a917 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 print_function
-__revision__ = "src/engine/SCons/BuilderTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/BuilderTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -409,10 +409,6 @@ class BuilderTestCase(unittest.TestCase):
builder = SCons.Builder.Builder(generator=generator)
assert builder.action.generator == generator
- def test_get_name(self):
- """Test the get_name() method
- """
-
def test_cmp(self):
"""Test simple comparisons of Builder objects
"""
@@ -552,7 +548,7 @@ class BuilderTestCase(unittest.TestCase):
def test_src_suffix(self):
"""Test Builder creation with a specified source file suffix
-
+
Make sure that the '.' separator is appended to the
beginning if it isn't already present.
"""
@@ -680,10 +676,12 @@ class BuilderTestCase(unittest.TestCase):
def test_single_source(self):
"""Test Builder with single_source flag set"""
def func(target, source, env):
- open(str(target[0]), "w")
+ """create the file"""
+ with open(str(target[0]), "w"):
+ pass
if (len(source) == 1 and len(target) == 1):
env['CNT'][0] = env['CNT'][0] + 1
-
+
env = Environment()
infiles = []
outfiles = []
@@ -730,16 +728,18 @@ class BuilderTestCase(unittest.TestCase):
pass
else:
assert 0
-
-
+
+
def test_lists(self):
"""Testing handling lists of targets and source"""
def function2(target, source, env, tlist = [outfile, outfile2], **kw):
for t in target:
- open(str(t), 'w').write("function2\n")
+ with open(str(t), 'w') as f:
+ f.write("function2\n")
for t in tlist:
if not t in list(map(str, target)):
- open(t, 'w').write("function2\n")
+ with open(t, 'w') as f:
+ f.write("function2\n")
return 1
env = Environment()
@@ -765,10 +765,12 @@ class BuilderTestCase(unittest.TestCase):
def function3(target, source, env, tlist = [sub1_out, sub2_out]):
for t in target:
- open(str(t), 'w').write("function3\n")
+ with open(str(t), 'w') as f:
+ f.write("function3\n")
for t in tlist:
if not t in list(map(str, target)):
- open(t, 'w').write("function3\n")
+ with open(t, 'w') as f:
+ f.write("function3\n")
return 1
builder = SCons.Builder.Builder(action = function3)
@@ -875,7 +877,7 @@ class BuilderTestCase(unittest.TestCase):
def func(self):
pass
-
+
scanner = SCons.Scanner.Base(func, name='fooscan')
b1 = SCons.Builder.Builder(action='bld', target_scanner=scanner)
@@ -884,8 +886,8 @@ class BuilderTestCase(unittest.TestCase):
assert b1 == b2
assert b1 != b3
-
- def test_src_scanner(slf):
+
+ def test_src_scanner(self):
"""Testing ability to set a source file scanner through a builder."""
class TestScanner(object):
def key(self, env):
@@ -1239,7 +1241,7 @@ class BuilderTestCase(unittest.TestCase):
for t in target:
t.builder = nb
return [nn], source
-
+
builder=SCons.Builder.Builder(action='foo',
emitter=emit,
target_factory=MyNode,
@@ -1315,7 +1317,7 @@ class BuilderTestCase(unittest.TestCase):
builder2 = SCons.Builder.Builder(action='foo',
emitter='$EMITTERLIST',
node_factory=MyNode)
-
+
env = Environment(EMITTERLIST = [emit2a, emit2b])
tgts = builder2(env, target='target-2', source='aaa.2')
@@ -1413,7 +1415,7 @@ class BuilderTestCase(unittest.TestCase):
b6 = SCons.Builder.Builder(action='foo')
assert isinstance(b4, SCons.Builder.CompositeBuilder)
assert isinstance(b4.action, SCons.Action.CommandGeneratorAction)
-
+
env = Environment(BUILDERS={'bldr1': b1,
'bldr2': b2,
'bldr3': b3,
@@ -1475,7 +1477,7 @@ class CompositeBuilderTestCase(unittest.TestCase):
tgt = builder(env, source=[])
assert tgt == [], tgt
-
+
assert isinstance(builder, SCons.Builder.CompositeBuilder)
assert isinstance(builder.action, SCons.Action.CommandGeneratorAction)
diff --git a/src/engine/SCons/CacheDir.py b/src/engine/SCons/CacheDir.py
index 8815eb3..c9e8ea7 100644
--- a/src/engine/SCons/CacheDir.py
+++ b/src/engine/SCons/CacheDir.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,12 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/CacheDir.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/CacheDir.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """
CacheDir support
"""
+import hashlib
import json
import os
import stat
@@ -34,6 +35,7 @@ import sys
import SCons.Action
import SCons.Warnings
+from SCons.Util import PY3
cache_enabled = True
cache_debug = False
@@ -45,16 +47,22 @@ def CacheRetrieveFunc(target, source, env):
t = target[0]
fs = t.fs
cd = env.get_CacheDir()
+ cd.requests += 1
cachedir, cachefile = cd.cachepath(t)
if not fs.exists(cachefile):
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
return 1
+ cd.hits += 1
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
if SCons.Action.execute_actions:
if fs.islink(cachefile):
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
else:
env.copy_from_cache(cachefile, t.get_internal_path())
+ try:
+ os.utime(cachefile, None)
+ except OSError:
+ pass
st = fs.stat(cachefile)
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
return 0
@@ -106,7 +114,7 @@ def CachePushFunc(target, source, env):
# has beaten us creating the directory.
if not fs.isdir(cachedir):
msg = errfmt % (str(target), cachefile)
- raise SCons.Errors.EnvironmentError(msg)
+ raise SCons.Errors.SConsEnvironmentError(msg)
try:
if fs.islink(t.get_internal_path()):
@@ -134,40 +142,97 @@ warned = dict()
class CacheDir(object):
def __init__(self, path):
- try:
- import hashlib
- except ImportError:
- msg = "No hashlib or MD5 module available, CacheDir() not supported"
- SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg)
- path = None
+ """
+ Initialize a CacheDir object.
+
+ The cache configuration is stored in the object. It
+ is read from the config file in the supplied path if
+ one exists, if not the config file is created and
+ the default config is written, as well as saved in the object.
+ """
+ self.requests = 0
+ self.hits = 0
self.path = path
self.current_cache_debug = None
self.debugFP = None
self.config = dict()
if path is None:
return
- # See if there's a config file in the cache directory. If there is,
- # use it. If there isn't, and the directory exists and isn't empty,
- # produce a warning. If the directory doesn't exist or is empty,
- # write a config file.
+
+ if PY3:
+ self._readconfig3(path)
+ else:
+ self._readconfig2(path)
+
+
+ def _readconfig3(self, path):
+ """
+ Python3 version of reading the cache config.
+
+ If directory or config file do not exist, create. Take advantage
+ of Py3 capability in os.makedirs() and in file open(): just try
+ the operation and handle failure appropriately.
+
+ Omit the check for old cache format, assume that's old enough
+ there will be none of those left to worry about.
+
+ :param path: path to the cache directory
+ """
+ config_file = os.path.join(path, 'config')
+ try:
+ os.makedirs(path, exist_ok=True)
+ except FileExistsError:
+ pass
+ except OSError:
+ msg = "Failed to create cache directory " + path
+ raise SCons.Errors.EnvironmentError(msg)
+
+ try:
+ with open(config_file, 'x') as config:
+ self.config['prefix_len'] = 2
+ try:
+ json.dump(self.config, config)
+ except Exception:
+ msg = "Failed to write cache configuration for " + path
+ raise SCons.Errors.EnvironmentError(msg)
+ except FileExistsError:
+ try:
+ with open(config_file) as config:
+ self.config = json.load(config)
+ except ValueError:
+ msg = "Failed to read cache configuration for " + path
+ raise SCons.Errors.EnvironmentError(msg)
+
+
+ def _readconfig2(self, path):
+ """
+ Python2 version of reading cache config.
+
+ See if there is a config file in the cache directory. If there is,
+ use it. If there isn't, and the directory exists and isn't empty,
+ produce a warning. If the directory does not exist or is empty,
+ write a config file.
+
+ :param path: path to the cache directory
+ """
config_file = os.path.join(path, 'config')
if not os.path.exists(config_file):
- # A note: There is a race hazard here, if two processes start and
+ # A note: There is a race hazard here if two processes start and
# attempt to create the cache directory at the same time. However,
- # python doesn't really give you the option to do exclusive file
- # creation (it doesn't even give you the option to error on opening
- # an existing file for writing...). The ordering of events here
- # as an attempt to alleviate this, on the basis that it's a pretty
- # unlikely occurence (it'd require two builds with a brand new cache
+ # Python 2.x does not give you the option to do exclusive file
+ # creation (not even the option to error on opening an existing
+ # file for writing...). The ordering of events here is an attempt
+ # to alleviate this, on the basis that it's a pretty unlikely
+ # occurrence (would require two builds with a brand new cache
# directory)
- if os.path.isdir(path) and len(os.listdir(path)) != 0:
+ if os.path.isdir(path) and any(f != "config" for f in os.listdir(path)):
self.config['prefix_len'] = 1
# When building the project I was testing this on, the warning
# was output over 20 times. That seems excessive
global warned
if self.path not in warned:
msg = "Please upgrade your cache by running " +\
- " scons-configure-cache.py " + self.path
+ "scons-configure-cache.py " + self.path
SCons.Warnings.warn(SCons.Warnings.CacheVersionWarning, msg)
warned[self.path] = True
else:
@@ -178,24 +243,24 @@ class CacheDir(object):
# If someone else is trying to create the directory at
# the same time as me, bad things will happen
msg = "Failed to create cache directory " + path
- raise SCons.Errors.EnvironmentError(msg)
-
+ raise SCons.Errors.SConsEnvironmentError(msg)
+
self.config['prefix_len'] = 2
if not os.path.exists(config_file):
try:
with open(config_file, 'w') as config:
json.dump(self.config, config)
- except:
+ except Exception:
msg = "Failed to write cache configuration for " + path
- raise SCons.Errors.EnvironmentError(msg)
+ raise SCons.Errors.SConsEnvironmentError(msg)
else:
try:
with open(config_file) as config:
self.config = json.load(config)
except ValueError:
msg = "Failed to read cache configuration for " + path
- raise SCons.Errors.EnvironmentError(msg)
-
+ raise SCons.Errors.SConsEnvironmentError(msg)
+
def CacheDebug(self, fmt, target, cachefile):
if cache_debug != self.current_cache_debug:
@@ -208,9 +273,19 @@ class CacheDir(object):
self.current_cache_debug = cache_debug
if self.debugFP:
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
+ self.debugFP.write("requests: %d, hits: %d, misses: %d, hit rate: %.2f%%\n" %
+ (self.requests, self.hits, self.misses, self.hit_ratio))
+
+ @property
+ def hit_ratio(self):
+ return (100.0 * self.hits / self.requests if self.requests > 0 else 100)
+
+ @property
+ def misses(self):
+ return self.requests - self.hits
def is_enabled(self):
- return cache_enabled and not self.path is None
+ return cache_enabled and self.path is not None
def is_readonly(self):
return cache_readonly
@@ -222,7 +297,9 @@ class CacheDir(object):
return None, None
sig = node.get_cachedir_bsig()
+
subdir = sig[:self.config['prefix_len']].upper()
+
dir = os.path.join(self.path, subdir)
return dir, os.path.join(dir, sig)
diff --git a/src/engine/SCons/CacheDirTests.py b/src/engine/SCons/CacheDirTests.py
index e7db18c..f96dab5 100644
--- a/src/engine/SCons/CacheDirTests.py
+++ b/src/engine/SCons/CacheDirTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/CacheDirTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/CacheDirTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import shutil
@@ -29,7 +29,6 @@ import sys
import unittest
from TestCmd import TestCmd
-import TestUnit
import SCons.CacheDir
@@ -287,16 +286,7 @@ class FileTestCase(BaseTestCase):
SCons.CacheDir.CacheRetrieveSilent = save_CacheRetrieveSilent
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- CacheDirTestCase,
- FileTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
-
+ unittest.main()
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Conftest.py b/src/engine/SCons/Conftest.py
index abaf00d..1163aa3 100644
--- a/src/engine/SCons/Conftest.py
+++ b/src/engine/SCons/Conftest.py
@@ -136,7 +136,7 @@ def CheckBuilder(context, text = None, language = None):
if not text:
text = """
-int main() {
+int main(void) {
return 0;
}
"""
@@ -157,7 +157,7 @@ def CheckCC(context):
"""
context.Display("Checking whether the C compiler works... ")
text = """
-int main()
+int main(void)
{
return 0;
}
@@ -177,7 +177,7 @@ def CheckSHCC(context):
"""
context.Display("Checking whether the (shared) C compiler works... ")
text = """
-int foo()
+int foo(void)
{
return 0;
}
@@ -197,7 +197,7 @@ def CheckCXX(context):
"""
context.Display("Checking whether the C++ compiler works... ")
text = """
-int main()
+int main(void)
{
return 0;
}
@@ -217,7 +217,7 @@ def CheckSHCXX(context):
"""
context.Display("Checking whether the (shared) C++ compiler works... ")
text = """
-int main()
+int main(void)
{
return 0;
}
@@ -290,7 +290,7 @@ char %s();""" % function_name
#include <assert.h>
%(hdr)s
-int main() {
+int main(void) {
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
fail fail fail
#else
@@ -354,7 +354,7 @@ def CheckHeader(context, header_name, header = None, language = None,
context.Display("Checking for %s header file %s... " % (lang, header_name))
ret = context.CompileProg(text, suffix)
- _YesNoResult(context, ret, "HAVE_" + header_name, text,
+ _YesNoResult(context, ret, "HAVE_" + header_name, text,
"Define to 1 if you have the <%s> header file." % header_name)
return ret
@@ -400,7 +400,7 @@ def CheckType(context, type_name, fallback = None,
%(include)s
%(header)s
-int main() {
+int main(void) {
if ((%(name)s *) 0)
return 0;
if (sizeof (%(name)s))
@@ -439,7 +439,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
Returns:
status : int
0 if the check failed, or the found size of the type if the check succeeded."""
-
+
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
if context.headerfilename:
includetext = '#include "%s"' % context.headerfilename
@@ -454,8 +454,8 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
return msg
- src = includetext + header
- if not expect is None:
+ src = includetext + header
+ if expect is not None:
# Only check if the given size is the right one
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
@@ -465,7 +465,7 @@ def CheckTypeSize(context, type_name, header = None, language = None, expect = N
src = src + r"""
typedef %s scons_check_type;
-int main()
+int main(void)
{
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
test_array[0] = 0;
@@ -477,7 +477,7 @@ int main()
st = context.CompileProg(src % (type_name, expect), suffix)
if not st:
context.Display("yes\n")
- _Have(context, "SIZEOF_%s" % type_name, expect,
+ _Have(context, "SIZEOF_%s" % type_name, expect,
"The size of `%s', as computed by sizeof." % type_name)
return expect
else:
@@ -498,7 +498,7 @@ int main()
src = src + """
#include <stdlib.h>
#include <stdio.h>
-int main() {
+int main(void) {
printf("%d", (int)sizeof(""" + type_name + """));
return 0;
}
@@ -541,7 +541,7 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
Returns:
status : bool
True if the check failed, False if succeeded."""
-
+
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
if context.headerfilename:
includetext = '#include "%s"' % context.headerfilename
@@ -556,11 +556,11 @@ def CheckDeclaration(context, symbol, includes = None, language = None):
context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
return msg
- src = includetext + includes
+ src = includetext + includes
context.Display('Checking whether %s is declared... ' % symbol)
src = src + r"""
-int main()
+int main(void)
{
#ifndef %s
(void) %s;
@@ -677,7 +677,7 @@ return 0;
"Define to 1 if you have the `%s' library." % lib_name)
if oldLIBS != -1 and (ret or not autoadd):
context.SetLIBS(oldLIBS)
-
+
if not ret:
return ret
@@ -704,7 +704,7 @@ def CheckProg(context, prog_name):
#
def _YesNoResult(context, ret, key, text, comment = None):
- """
+ r"""
Handle the result of a test with a "yes" or "no" result.
:Parameters:
@@ -723,7 +723,7 @@ def _YesNoResult(context, ret, key, text, comment = None):
def _Have(context, key, have, comment = None):
- """
+ r"""
Store result of a test in context.havedict and context.headerfilename.
:Parameters:
@@ -751,7 +751,7 @@ def _Have(context, key, have, comment = None):
line = "#define %s %d\n" % (key_up, have)
else:
line = "#define %s %s\n" % (key_up, str(have))
-
+
if comment is not None:
lines = "\n/* %s */\n" % comment + line
else:
diff --git a/src/engine/SCons/Debug.py b/src/engine/SCons/Debug.py
index d1ee991..c19862a 100644
--- a/src/engine/SCons/Debug.py
+++ b/src/engine/SCons/Debug.py
@@ -9,7 +9,7 @@ caller_trace()
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ caller_trace()
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Debug.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Debug.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import sys
diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py
index 4a18045..30c0052 100644
--- a/src/engine/SCons/Defaults.py
+++ b/src/engine/SCons/Defaults.py
@@ -10,7 +10,7 @@ from distutils.msvccompiler.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ from distutils.msvccompiler.
#
from __future__ import division
-__revision__ = "src/engine/SCons/Defaults.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Defaults.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
@@ -193,7 +193,7 @@ def chmod_func(dest, mode):
SCons.Node.FS.invalidate_node_memos(dest)
if not SCons.Util.is_List(dest):
dest = [dest]
- if SCons.Util.is_String(mode) and not 0 in [i in digits for i in mode]:
+ if SCons.Util.is_String(mode) and 0 not in [i in digits for i in mode]:
mode = int(mode, 8)
if not SCons.Util.is_String(mode):
for element in dest:
@@ -210,7 +210,7 @@ def chmod_func(dest, mode):
else:
raise SyntaxError("Could not find +, - or =")
operation_list = operation.split(operator)
- if len(operation_list) is not 2:
+ if len(operation_list) != 2:
raise SyntaxError("More than one operator found")
user = operation_list[0].strip().replace("a", "ugo")
permission = operation_list[1].strip()
@@ -333,8 +333,8 @@ def touch_func(dest):
if os.path.exists(file):
atime = os.path.getatime(file)
else:
- open(file, 'w')
- atime = mtime
+ with open(file, 'w'):
+ atime = mtime
os.utime(file, (atime, mtime))
Touch = ActionFactory(touch_func,
@@ -342,6 +342,7 @@ Touch = ActionFactory(touch_func,
# Internal utility functions
+
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
"""
Creates a new list from 'list' by first interpolating each element
@@ -358,6 +359,7 @@ def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
return _concat_ixes(prefix, list, suffix, env)
+
def _concat_ixes(prefix, list, suffix, env):
"""
Creates a new list from 'list' by concatenating the 'prefix' and
@@ -395,6 +397,7 @@ def _concat_ixes(prefix, list, suffix, env):
return result
+
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
"""
This is a wrapper around _concat()/_concat_ixes() that checks for
@@ -565,7 +568,6 @@ ConstructionEnvironment = {
'DSUFFIXES' : SCons.Tool.DSuffixes,
'ENV' : {},
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
-# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
'_concat' : _concat,
'_defines' : _defines,
'_stripixes' : _stripixes,
@@ -580,6 +582,7 @@ ConstructionEnvironment = {
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
'TEMPFILE' : NullCmdGenerator,
+ 'TEMPFILEARGJOIN': ' ',
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
'File' : Variable_Method_Caller('TARGET', 'File'),
diff --git a/src/engine/SCons/Defaults.xml b/src/engine/SCons/Defaults.xml
index cef1e93..e568c92 100644
--- a/src/engine/SCons/Defaults.xml
+++ b/src/engine/SCons/Defaults.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -76,7 +76,8 @@ An automatically-generated construction variable
containing the C preprocessor command-line options
to define values.
The value of &cv-_CPPDEFFLAGS; is created
-by appending &cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
+by respectively prepending and appending
+&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
to the beginning and end
of each definition in &cv-CPPDEFINES;.
</para>
@@ -99,7 +100,8 @@ If &cv-CPPDEFINES; is a string,
the values of the
&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
construction variables
-will be added to the beginning and end.
+will be respectively prepended and appended to the beginning and end
+of each definition in &cv-CPPDEFINES;.
</para>
<example_commands>
@@ -113,7 +115,7 @@ If &cv-CPPDEFINES; is a list,
the values of the
&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
construction variables
-will be appended to the beginning and end
+will be respectively prepended and appended to the beginning and end
of each element in the list.
If any element is a list or tuple,
then the first item is the name being
@@ -131,7 +133,7 @@ If &cv-CPPDEFINES; is a dictionary,
the values of the
&cv-CPPDEFPREFIX; and &cv-CPPDEFSUFFIX;
construction variables
-will be appended to the beginning and end
+will be respectively prepended and appended to the beginning and end
of each item from the dictionary.
The key of each dictionary item
is a name being defined
@@ -159,7 +161,7 @@ env = Environment(CPPDEFINES={'B':2, 'A':None})
<para>
The prefix used to specify preprocessor definitions
on the C compiler command line.
-This will be appended to the beginning of each definition
+This will be prepended to the beginning of each definition
in the &cv-CPPDEFINES; construction variable
when the &cv-_CPPDEFFLAGS; variable is automatically generated.
</para>
@@ -185,7 +187,7 @@ An automatically-generated construction variable
containing the C preprocessor command-line options
for specifying directories to be searched for include files.
The value of &cv-_CPPINCFLAGS; is created
-by appending &cv-INCPREFIX; and &cv-INCSUFFIX;
+by respectively prepending and appending &cv-INCPREFIX; and &cv-INCSUFFIX;
to the beginning and end
of each directory in &cv-CPPPATH;.
</para>
@@ -227,7 +229,7 @@ through the automatically-generated
&cv-_CPPINCFLAGS;
construction variable,
which is constructed by
-appending the values of the
+respectively prepending and appending the value of the
&cv-INCPREFIX; and &cv-INCSUFFIX;
construction variables
to the beginning and end
@@ -304,7 +306,7 @@ The default list is:
<para>
The prefix used to specify an include directory on the C compiler command
line.
-This will be appended to the beginning of each directory
+This will be prepended to the beginning of each directory
in the &cv-CPPPATH; and &cv-FORTRANPATH; construction variables
when the &cv-_CPPINCFLAGS; and &cv-_FORTRANINCFLAGS;
variables are automatically generated.
@@ -388,7 +390,7 @@ An automatically-generated construction variable
containing the linker command-line options
for specifying directories to be searched for library.
The value of &cv-_LIBDIRFLAGS; is created
-by appending &cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX;
+by respectively prepending and appending &cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX;
to the beginning and end
of each directory in &cv-LIBPATH;.
</para>
@@ -399,7 +401,7 @@ of each directory in &cv-LIBPATH;.
<summary>
<para>
The prefix used to specify a library directory on the linker command line.
-This will be appended to the beginning of each directory
+This will be prepended to the beginning of each directory
in the &cv-LIBPATH; construction variable
when the &cv-_LIBDIRFLAGS; variable is automatically generated.
</para>
@@ -424,7 +426,7 @@ An automatically-generated construction variable
containing the linker command-line options
for specifying libraries to be linked with the resulting target.
The value of &cv-_LIBFLAGS; is created
-by appending &cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX;
+by respectively prepending and appending &cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX;
to the beginning and end
of each filename in &cv-LIBS;.
</para>
@@ -435,7 +437,7 @@ of each filename in &cv-LIBS;.
<summary>
<para>
The prefix used to specify a library to link on the linker command line.
-This will be appended to the beginning of each library
+This will be prepended to the beginning of each library
in the &cv-LIBS; construction variable
when the &cv-_LIBFLAGS; variable is automatically generated.
</para>
@@ -489,7 +491,7 @@ through the automatically-generated
&cv-_LIBDIRFLAGS;
construction variable,
which is constructed by
-appending the values of the
+respectively prepending and appending the values of the
&cv-LIBDIRPREFIX; and &cv-LIBDIRSUFFIX;
construction variables
to the beginning and end
@@ -520,7 +522,7 @@ through the automatically-generated
&cv-_LIBFLAGS;
construction variable,
which is constructed by
-appending the values of the
+respectively prepending and appending the values of the
&cv-LIBLINKPREFIX; and &cv-LIBLINKSUFFIX;
construction variables
to the beginning and end
diff --git a/src/engine/SCons/DefaultsTests.py b/src/engine/SCons/DefaultsTests.py
index fc9934b..4e0328a 100644
--- a/src/engine/SCons/DefaultsTests.py
+++ b/src/engine/SCons/DefaultsTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/DefaultsTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/DefaultsTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -32,7 +32,6 @@ import unittest
from collections import UserDict
import TestCmd
-import TestUnit
import SCons.Errors
@@ -70,20 +69,14 @@ class DefaultsTestCase(unittest.TestCase):
test.write(file, "test\n")
try:
mkdir_func(file)
- except os.error as e:
+ except OSError as e:
pass
else:
- fail("expected os.error")
-
+ self.fail("expected OSError")
+
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ DefaultsTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index 64210aa..31a4721 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -10,7 +10,7 @@ Environment
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Environment
# 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/Environment.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Environment.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import copy
@@ -150,7 +150,7 @@ def _set_BUILDERS(env, key, value):
for k in list(bd.keys()):
del bd[k]
except KeyError:
- bd = BuilderDict(kwbd, env)
+ bd = BuilderDict(bd, env)
env._dict[key] = bd
for k, v in value.items():
if not SCons.Builder.is_a_Builder(v):
@@ -608,7 +608,7 @@ class SubstitutionEnvironment(object):
Removes the specified function's MethodWrapper from the
added_methods list, so we don't re-bind it when making a clone.
"""
- self.added_methods = [dm for dm in self.added_methods if not dm.method is function]
+ self.added_methods = [dm for dm in self.added_methods if dm.method is not function]
def Override(self, overrides):
"""
@@ -719,6 +719,12 @@ class SubstitutionEnvironment(object):
elif append_next_arg_to == '-isystem':
t = ('-isystem', arg)
dict['CCFLAGS'].append(t)
+ elif append_next_arg_to == '-iquote':
+ t = ('-iquote', arg)
+ dict['CCFLAGS'].append(t)
+ elif append_next_arg_to == '-idirafter':
+ t = ('-idirafter', arg)
+ dict['CCFLAGS'].append(t)
elif append_next_arg_to == '-arch':
t = ('-arch', arg)
dict['CCFLAGS'].append(t)
@@ -791,7 +797,7 @@ class SubstitutionEnvironment(object):
elif arg[0] == '+':
dict['CCFLAGS'].append(arg)
dict['LINKFLAGS'].append(arg)
- elif arg in ['-include', '-isysroot', '-isystem', '-arch']:
+ elif arg in ['-include', '-isysroot', '-isystem', '-iquote', '-idirafter', '-arch']:
append_next_arg_to = arg
else:
dict['CCFLAGS'].append(arg)
@@ -858,18 +864,21 @@ class SubstitutionEnvironment(object):
return self
-def default_decide_source(dependency, target, prev_ni):
+def default_decide_source(dependency, target, prev_ni, repo_node=None):
f = SCons.Defaults.DefaultEnvironment().decide_source
- return f(dependency, target, prev_ni)
+ return f(dependency, target, prev_ni, repo_node)
-def default_decide_target(dependency, target, prev_ni):
+
+def default_decide_target(dependency, target, prev_ni, repo_node=None):
f = SCons.Defaults.DefaultEnvironment().decide_target
- return f(dependency, target, prev_ni)
+ return f(dependency, target, prev_ni, repo_node)
+
def default_copy_from_cache(src, dst):
f = SCons.Defaults.DefaultEnvironment().copy_from_cache
return f(src, dst)
+
class Base(SubstitutionEnvironment):
"""Base class for "real" construction Environments. These are the
primary objects used to communicate dependency and construction
@@ -1217,7 +1226,7 @@ class Base(SubstitutionEnvironment):
return path
def AppendENVPath(self, name, newpath, envname = 'ENV',
- sep = os.pathsep, delete_existing=1):
+ sep = os.pathsep, delete_existing=0):
"""Append path elements to the path 'name' in the 'ENV'
dictionary for this environment. Will only add any particular
path once, and will normpath and normcase all paths to help
@@ -1342,7 +1351,7 @@ class Base(SubstitutionEnvironment):
dk = list(filter(lambda x, val=val: x not in val, dk))
self._dict[key] = dk + [val]
else:
- if not val in dk:
+ if val not in dk:
self._dict[key] = dk + [val]
else:
if key == 'CPPDEFINES':
@@ -1428,30 +1437,30 @@ class Base(SubstitutionEnvironment):
_warn_copy_deprecated = False
return self.Clone(*args, **kw)
- def _changed_build(self, dependency, target, prev_ni):
- if dependency.changed_state(target, prev_ni):
+ def _changed_build(self, dependency, target, prev_ni, repo_node=None):
+ if dependency.changed_state(target, prev_ni, repo_node):
return 1
- return self.decide_source(dependency, target, prev_ni)
+ return self.decide_source(dependency, target, prev_ni, repo_node)
- def _changed_content(self, dependency, target, prev_ni):
- return dependency.changed_content(target, prev_ni)
+ def _changed_content(self, dependency, target, prev_ni, repo_node=None):
+ return dependency.changed_content(target, prev_ni, repo_node)
- def _changed_source(self, dependency, target, prev_ni):
+ def _changed_source(self, dependency, target, prev_ni, repo_node=None):
target_env = dependency.get_build_env()
type = target_env.get_tgt_sig_type()
if type == 'source':
- return target_env.decide_source(dependency, target, prev_ni)
+ return target_env.decide_source(dependency, target, prev_ni, repo_node)
else:
- return target_env.decide_target(dependency, target, prev_ni)
+ return target_env.decide_target(dependency, target, prev_ni, repo_node)
- def _changed_timestamp_then_content(self, dependency, target, prev_ni):
- return dependency.changed_timestamp_then_content(target, prev_ni)
+ def _changed_timestamp_then_content(self, dependency, target, prev_ni, repo_node=None):
+ return dependency.changed_timestamp_then_content(target, prev_ni, repo_node)
- def _changed_timestamp_newer(self, dependency, target, prev_ni):
- return dependency.changed_timestamp_newer(target, prev_ni)
+ def _changed_timestamp_newer(self, dependency, target, prev_ni, repo_node=None):
+ return dependency.changed_timestamp_newer(target, prev_ni, repo_node)
- def _changed_timestamp_match(self, dependency, target, prev_ni):
- return dependency.changed_timestamp_match(target, prev_ni)
+ def _changed_timestamp_match(self, dependency, target, prev_ni, repo_node=None):
+ return dependency.changed_timestamp_match(target, prev_ni, repo_node)
def _copy_from_cache(self, src, dst):
return self.fs.copy(src, dst)
@@ -1568,12 +1577,12 @@ class Base(SubstitutionEnvironment):
"""
filename = self.subst(filename)
try:
- fp = open(filename, 'r')
+ with open(filename, 'r') as fp:
+ lines = SCons.Util.LogicalLines(fp).readlines()
except IOError:
if must_exist:
raise
return
- lines = SCons.Util.LogicalLines(fp).readlines()
lines = [l for l in lines if l[0] != '#']
tdlist = []
for line in lines:
@@ -1722,7 +1731,7 @@ class Base(SubstitutionEnvironment):
dk = [x for x in dk if x not in val]
self._dict[key] = [val] + dk
else:
- if not val in dk:
+ if val not in dk:
self._dict[key] = [val] + dk
else:
if delete_existing:
@@ -2258,7 +2267,7 @@ class Base(SubstitutionEnvironment):
while (node != node.srcnode()):
node = node.srcnode()
return node
- sources = list(map( final_source, sources ));
+ sources = list(map(final_source, sources))
# remove duplicates
return list(set(sources))
@@ -2299,7 +2308,20 @@ class OverrideEnvironment(Base):
# Methods that make this class act like a proxy.
def __getattr__(self, name):
- return getattr(self.__dict__['__subject'], name)
+ attr = getattr(self.__dict__['__subject'], name)
+ # Here we check if attr is one of the Wrapper classes. For
+ # example when a pseudo-builder is being called from an
+ # OverrideEnvironment.
+ #
+ # These wrappers when they're constructed capture the
+ # Environment they are being constructed with and so will not
+ # have access to overrided values. So we rebuild them with the
+ # OverrideEnvironment so they have access to overrided values.
+ if isinstance(attr, (MethodWrapper, BuilderWrapper)):
+ return attr.clone(self)
+ else:
+ return attr
+
def __setattr__(self, name, value):
setattr(self.__dict__['__subject'], name, value)
@@ -2372,6 +2394,7 @@ class OverrideEnvironment(Base):
kw = copy_non_reserved_keywords(kw)
self.__dict__['overrides'].update(semi_deepcopy(kw))
+
# The entry point that will be used by the external world
# to refer to a construction environment. This allows the wrapper
# interface to extend a construction environment for its own purposes
diff --git a/src/engine/SCons/Environment.xml b/src/engine/SCons/Environment.xml
index 0127bc2..9b392d5 100644
--- a/src/engine/SCons/Environment.xml
+++ b/src/engine/SCons/Environment.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -60,7 +60,7 @@ or this:
<example_commands>
env = Environment()
-env['BUILDERS]['NewBuilder'] = foo
+env['BUILDERS']['NewBuilder'] = foo
</example_commands>
</summary>
</cvar>
@@ -549,7 +549,7 @@ string, in which case a list will be returned instead of a string.
</para>
<para>
-If
+If
<varname>delete_existing</varname>
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.
@@ -588,7 +588,7 @@ then any value(s) that already exist in the
construction variable will
<emphasis>not</emphasis>
be added again to the list.
-However, if delete_existing is 1,
+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.
</para>
@@ -883,12 +883,14 @@ env4 = env.Clone(tools = ['msvc', MyTool])
<para>
The
<varname>parse_flags</varname>
-keyword argument is also recognized:
+keyword argument is also recognized to allow merging command-line
+style arguments into the appropriate construction
+variables (see &f-link-env-MergeFlags;).
</para>
<example_commands>
# create an environment for compiling programs that use wxWidgets
-wx_env = env.Clone(parse_flags = '!wx-config --cflags --cxxflags')
+wx_env = env.Clone(parse_flags='!wx-config --cflags --cxxflags')
</example_commands>
</summary>
</scons_function>
@@ -1211,6 +1213,17 @@ size, or content signature.
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+<term><parameter>repo_node</parameter></term>
+<listitem>
+<para>
+Use this node instead of the one specified by
+<varname>dependency</varname>
+ to determine if the dependency has changed.
+</para>
+</listitem>
+</varlistentry>
+
</variablelist>
</para>
@@ -1247,7 +1260,7 @@ Example:
</para>
<example_commands>
-def my_decider(dependency, target, prev_ni):
+def my_decider(dependency, target, prev_ni, repo_node=None):
return not os.path.exists(str(target))
env.Decider(my_decider)
@@ -1880,9 +1893,9 @@ as the dependency.
</para>
<para>
-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.
+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.
</para>
@@ -1954,8 +1967,8 @@ not as separate arguments to
<para>
New values are prepended to the environment variable by default,
-unless prepend=0 is specified.
-Duplicate values are always eliminated,
+unless prepend=0 is specified.
+Duplicate values are always eliminated,
since this function calls
&f-link-AppendENVPath;
or
@@ -2294,6 +2307,9 @@ and added to the following construction variables:
-frameworkdir= FRAMEWORKPATH
-include CCFLAGS
-isysroot CCFLAGS, LINKFLAGS
+-isystem CCFLAGS
+-iquote CCFLAGS
+-idirafter CCFLAGS
-I CPPPATH
-l LIBS
-L LIBPATH
@@ -2489,7 +2505,7 @@ then any value(s) that already exist in the
construction variable will
<emphasis>not</emphasis>
be added again to the list.
-However, if delete_existing is 1,
+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.
</para>
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index 70eda9e..1ce1007 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
from __future__ import print_function
-__revision__ = "src/engine/SCons/EnvironmentTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/EnvironmentTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -74,7 +74,7 @@ def diff_dict(d1, d2):
s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
else:
s1 = s1 + " " + repr(k) + " : " + repr(d1[k]) + "\n"
- elif k in env2:
+ elif k in d2:
s2 = s2 + " " + repr(k) + " : " + repr(d2[k]) + "\n"
s1 = s1 + "}\n"
s2 = s2 + "}\n"
@@ -139,10 +139,6 @@ class CLVar(UL):
return UL.__add__(self, CLVar(other))
def __radd__(self, other):
return UL.__radd__(self, CLVar(other))
- def __coerce__(self, other):
- return (self, CLVar(other))
-
-
class DummyNode(object):
def __init__(self, name):
@@ -267,39 +263,39 @@ class SubstitutionTestCase(unittest.TestCase):
nodes = env.arg2nodes("Util.py UtilTests.py", Factory)
assert len(nodes) == 1, nodes
assert isinstance(nodes[0], X)
- assert nodes[0].name == "Util.py UtilTests.py"
+ assert nodes[0].name == "Util.py UtilTests.py", nodes[0].name
nodes = env.arg2nodes(u"Util.py UtilTests.py", Factory)
assert len(nodes) == 1, nodes
assert isinstance(nodes[0], X)
- assert nodes[0].name == u"Util.py UtilTests.py"
+ assert nodes[0].name == u"Util.py UtilTests.py", nodes[0].name
nodes = env.arg2nodes(["Util.py", "UtilTests.py"], Factory)
assert len(nodes) == 2, nodes
assert isinstance(nodes[0], X)
assert isinstance(nodes[1], X)
- assert nodes[0].name == "Util.py"
- assert nodes[1].name == "UtilTests.py"
+ assert nodes[0].name == "Util.py", nodes[0].name
+ assert nodes[1].name == "UtilTests.py", nodes[1].name
n1 = Factory("Util.py")
nodes = env.arg2nodes([n1, "UtilTests.py"], Factory)
assert len(nodes) == 2, nodes
assert isinstance(nodes[0], X)
assert isinstance(nodes[1], X)
- assert nodes[0].name == "Util.py"
- assert nodes[1].name == "UtilTests.py"
+ assert nodes[0].name == "Util.py", nodes[0].name
+ assert nodes[1].name == "UtilTests.py", nodes[1].name
class SConsNode(SCons.Node.Node):
pass
nodes = env.arg2nodes(SConsNode())
assert len(nodes) == 1, nodes
- assert isinstance(nodes[0], SConsNode), node
+ assert isinstance(nodes[0], SConsNode), nodes[0]
class OtherNode(object):
pass
nodes = env.arg2nodes(OtherNode())
assert len(nodes) == 1, nodes
- assert isinstance(nodes[0], OtherNode), node
+ assert isinstance(nodes[0], OtherNode), nodes[0]
def lookup_a(str, F=Factory):
if str[0] == 'a':
@@ -488,7 +484,7 @@ class SubstitutionTestCase(unittest.TestCase):
env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = 'c')
l = env.subst_list("$AAA ${AAA}A ${AAA}B $BBB")
- assert l == [["c", "cA", "cB", "c"]], mystr
+ assert l == [["c", "cA", "cB", "c"]], l
env = SubstitutionEnvironment(AAA = '$BBB', BBB = '$CCC', CCC = [ 'a', 'b\nc' ])
lst = env.subst_list([ "$AAA", "B $CCC" ])
@@ -804,7 +800,9 @@ sys.exit(0)
"-fopenmp " + \
"-mno-cygwin -mwindows " + \
"-arch i386 -isysroot /tmp " + \
- "-isystem /usr/include/foo " + \
+ "-iquote /usr/include/foo1 " + \
+ "-isystem /usr/include/foo2 " + \
+ "-idirafter /usr/include/foo3 " + \
"+DD64 " + \
"-DFOO -DBAR=value -D BAZ "
@@ -813,10 +811,12 @@ sys.exit(0)
assert d['ASFLAGS'] == ['-as'], d['ASFLAGS']
assert d['CFLAGS'] == ['-std=c99']
assert d['CCFLAGS'] == ['-X', '-Wa,-as',
- '-pthread', '-fopenmp', '-mno-cygwin',
- ('-arch', 'i386'), ('-isysroot', '/tmp'),
- ('-isystem', '/usr/include/foo'),
- '+DD64'], repr(d['CCFLAGS'])
+ '-pthread', '-fopenmp', '-mno-cygwin',
+ ('-arch', 'i386'), ('-isysroot', '/tmp'),
+ ('-iquote', '/usr/include/foo1'),
+ ('-isystem', '/usr/include/foo2'),
+ ('-idirafter', '/usr/include/foo3'),
+ '+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']
@@ -967,7 +967,7 @@ class BaseTestCase(unittest.TestCase,TestEnvironmentFixture):
self.assertRaises(AttributeError, getattr, bw, 'foobar')
bw.foobar = 42
- assert bw.foobar is 42
+ assert bw.foobar == 42
# This unit test is currently disabled because we don't think the
# underlying method it tests (Environment.BuilderWrapper.execute())
@@ -1199,7 +1199,7 @@ env4.builder1.env, env3)
test_it('foo.bar')
test_it('foo-bar')
- def test_autogenerate(dict):
+ def test_autogenerate(self):
"""Test autogenerating variables in a dictionary."""
drive, p = os.path.splitdrive(os.getcwd())
@@ -1210,9 +1210,9 @@ env4.builder1.env, env3)
drive, path = os.path.splitdrive(path)
return drive.lower() + path
- env = dict.TestEnvironment(LIBS = [ 'foo', 'bar', 'baz' ],
- LIBLINKPREFIX = 'foo',
- LIBLINKSUFFIX = 'bar')
+ env = self.TestEnvironment(LIBS = [ 'foo', 'bar', 'baz' ],
+ LIBLINKPREFIX = 'foo',
+ LIBLINKSUFFIX = 'bar')
def RDirs(pathlist, fs=env.fs):
return fs.Dir('xx').Rfindalldirs(pathlist)
@@ -1627,9 +1627,9 @@ def exists(env):
env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
- env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';', delete_existing=1)
# this should do nothing since delete_existing is 0
- env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';', delete_existing=0)
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
@@ -1781,15 +1781,15 @@ def exists(env):
env2 = env1.Clone()
env3 = env1.Clone(tools=[bar, baz])
- assert env1.get('FOO') is 1
+ assert env1.get('FOO') == 1
assert env1.get('BAR') is None
assert env1.get('BAZ') is None
- assert env2.get('FOO') is 1
+ assert env2.get('FOO') == 1
assert env2.get('BAR') is None
assert env2.get('BAZ') is None
- assert env3.get('FOO') is 1
- assert env3.get('BAR') is 2
- assert env3.get('BAZ') is 3
+ assert env3.get('FOO') == 1
+ assert env3.get('BAR') == 2
+ assert env3.get('BAZ') == 3
# Ensure that recursive variable substitution when copying
# environments works properly.
@@ -2026,7 +2026,9 @@ def generate(env):
"-pthread " + \
"-mno-cygwin -mwindows " + \
"-arch i386 -isysroot /tmp " + \
- "-isystem /usr/include/foo " + \
+ "-iquote /usr/include/foo1 " + \
+ "-isystem /usr/include/foo2 " + \
+ "-idirafter /usr/include/foo3 " + \
"+DD64 " + \
"-DFOO -DBAR=value")
env.ParseConfig("fake $COMMAND")
@@ -2035,7 +2037,9 @@ def generate(env):
assert env['CCFLAGS'] == ['', '-X', '-Wa,-as',
'-pthread', '-mno-cygwin',
('-arch', 'i386'), ('-isysroot', '/tmp'),
- ('-isystem', '/usr/include/foo'),
+ ('-iquote', '/usr/include/foo1'),
+ ('-isystem', '/usr/include/foo2'),
+ ('-idirafter', '/usr/include/foo3'),
'+DD64'], env['CCFLAGS']
assert env['CPPDEFINES'] == ['FOO', ['BAR', 'value']], env['CPPDEFINES']
assert env['CPPFLAGS'] == ['', '-Wp,-cpp'], env['CPPFLAGS']
@@ -2437,16 +2441,16 @@ f5: \
exc_caught = None
try:
env.Tool('does_not_exist')
- except SCons.Errors.EnvironmentError:
+ except SCons.Errors.SConsEnvironmentError:
exc_caught = 1
- assert exc_caught, "did not catch expected EnvironmentError"
+ assert exc_caught, "did not catch expected SConsEnvironmentError"
exc_caught = None
try:
env.Tool('$NONE')
- except SCons.Errors.EnvironmentError:
+ except SCons.Errors.SConsEnvironmentError:
exc_caught = 1
- assert exc_caught, "did not catch expected EnvironmentError"
+ assert exc_caught, "did not catch expected SConsEnvironmentError"
# Use a non-existent toolpath directory just to make sure we
# can call Tool() with the keyword argument.
@@ -3276,11 +3280,11 @@ def generate(env):
s = e.src_builder()
assert s is None, s
- def test_SourceSignatures(type):
+ def test_SourceSignatures(self):
"""Test the SourceSignatures() method"""
import SCons.Errors
- env = type.TestEnvironment(M = 'MD5', T = 'timestamp')
+ env = self.TestEnvironment(M = 'MD5', T = 'timestamp')
exc_caught = None
try:
@@ -3316,7 +3320,7 @@ def generate(env):
def test_Split(self):
"""Test the Split() method"""
- env = self.TestEnvironment(FOO='fff', BAR='bbb')
+ env = self.TestEnvironment(FOO = 'fff', BAR = 'bbb')
s = env.Split("foo bar")
assert s == ["foo", "bar"], s
s = env.Split("$FOO bar")
@@ -3330,11 +3334,11 @@ def generate(env):
s = env.Split("$FOO$BAR")
assert s == ["fffbbb"], s
- def test_TargetSignatures(type):
+ def test_TargetSignatures(self):
"""Test the TargetSignatures() method"""
import SCons.Errors
- env = type.TestEnvironment(B = 'build', C = 'content')
+ env = self.TestEnvironment(B='build', C='content')
exc_caught = None
try:
@@ -3401,7 +3405,7 @@ def generate(env):
- def test_Environment_global_variable(type):
+ def test_Environment_global_variable(self):
"""Test setting Environment variable to an Environment.Base subclass"""
class MyEnv(SCons.Environment.Base):
def xxx(self, string):
@@ -3583,6 +3587,10 @@ class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
def setUp(self):
env = Environment()
env._dict = {'XXX' : 'x', 'YYY' : 'y'}
+ def verify_value(env, key, value, *args, **kwargs):
+ """Verifies that key is value on the env this is called with."""
+ assert env[key] == value
+ env.AddMethod(verify_value)
env2 = OverrideEnvironment(env, {'XXX' : 'x2'})
env3 = OverrideEnvironment(env2, {'XXX' : 'x3', 'YYY' : 'y3', 'ZZZ' : 'z3'})
self.envs = [ env, env2, env3 ]
@@ -3773,6 +3781,13 @@ class OverrideEnvironmentTestCase(unittest.TestCase,TestEnvironmentFixture):
# """Test the OverrideEnvironment WhereIs() method"""
# pass
+ def test_PseudoBuilderInherits(self):
+ """Test that pseudo-builders inherit the overrided values."""
+ env, env2, env3 = self.envs
+ env.verify_value('XXX', 'x')
+ env2.verify_value('XXX', 'x2')
+ env3.verify_value('XXX', 'x3')
+
def test_Dir(self):
"""Test the OverrideEnvironment Dir() method"""
env, env2, env3 = self.envs
diff --git a/src/engine/SCons/EnvironmentValues.py b/src/engine/SCons/EnvironmentValues.py
index e2efccb..d94bf3a 100644
--- a/src/engine/SCons/EnvironmentValues.py
+++ b/src/engine/SCons/EnvironmentValues.py
@@ -84,6 +84,7 @@ class EnvironmentValue(object):
"""
parts = []
for c in self.value:
+ pass
diff --git a/src/engine/SCons/Errors.py b/src/engine/SCons/Errors.py
index 8388a0f..28f58be 100644
--- a/src/engine/SCons/Errors.py
+++ b/src/engine/SCons/Errors.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Errors.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import shutil
import SCons.Util
@@ -95,7 +95,7 @@ class BuildError(Exception):
# py3: errstr should be string and not bytes.
- self.errstr = SCons.Util.to_str(errstr)
+ self.errstr = SCons.Util.to_String(errstr)
self.status = status
self.exitstatus = exitstatus
self.filename = filename
@@ -124,7 +124,7 @@ class UserError(Exception):
class StopError(Exception):
pass
-class EnvironmentError(Exception):
+class SConsEnvironmentError(Exception):
pass
class MSVCError(IOError):
@@ -176,28 +176,27 @@ def convert_to_BuildError(status, exc_info=None):
filename = status.filename
except AttributeError:
filename = None
-
- buildError = BuildError(
+
+ buildError = BuildError(
errstr=status.args[0],
status=status.errno,
exitstatus=2,
filename=filename,
exc_info=exc_info)
- elif isinstance(status, (EnvironmentError, OSError, IOError)):
+ elif isinstance(status, (SConsEnvironmentError, OSError, IOError)):
# If an IOError/OSError happens, raise a BuildError.
# Report the name of the file or directory that caused the
# error, which might be different from the target being built
# (for example, failure to create the directory in which the
# target file will appear).
- try:
- filename = status.filename
- except AttributeError:
- filename = None
+ filename = getattr(status, 'filename', None)
+ strerror = getattr(status, 'strerror', str(status))
+ errno = getattr(status, 'errno', 2)
- buildError = BuildError(
- errstr=status.strerror,
- status=status.errno,
+ buildError = BuildError(
+ errstr=strerror,
+ status=errno,
exitstatus=2,
filename=filename,
exc_info=exc_info)
@@ -217,7 +216,7 @@ def convert_to_BuildError(status, exc_info=None):
errstr="Error %s" % status,
status=status,
exitstatus=2)
-
+
#import sys
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
return buildError
diff --git a/src/engine/SCons/ErrorsTests.py b/src/engine/SCons/ErrorsTests.py
index 6ad44e3..a1bc048 100644
--- a/src/engine/SCons/ErrorsTests.py
+++ b/src/engine/SCons/ErrorsTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/ErrorsTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/ErrorsTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import errno
+import os
import sys
import unittest
-import TestUnit
-
import SCons.Errors
@@ -100,9 +100,31 @@ class ErrorsTestCase(unittest.TestCase):
except SCons.Errors.ExplicitExit as e:
assert e.node == "node"
+ def test_convert_EnvironmentError_to_BuildError(self):
+ """Test the convert_to_BuildError function on SConsEnvironmentError
+ exceptions.
+ """
+ ee = SCons.Errors.SConsEnvironmentError("test env error")
+ be = SCons.Errors.convert_to_BuildError(ee)
+ assert be.errstr == "test env error"
+ assert be.status == 2
+ assert be.exitstatus == 2
+ assert be.filename is None
+
+ def test_convert_OSError_to_BuildError(self):
+ """Test the convert_to_BuildError function on OSError
+ exceptions.
+ """
+ ose = OSError(7, 'test oserror')
+ be = SCons.Errors.convert_to_BuildError(ose)
+ assert be.errstr == 'test oserror'
+ assert be.status == 7
+ assert be.exitstatus == 2
+ assert be.filename is None
+
+
if __name__ == "__main__":
- suite = unittest.makeSuite(ErrorsTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py
index 9fabf70..c6ffe81 100644
--- a/src/engine/SCons/Executor.py
+++ b/src/engine/SCons/Executor.py
@@ -6,7 +6,7 @@ Nodes.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Nodes.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-__revision__ = "src/engine/SCons/Executor.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Executor.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import collections
@@ -36,15 +36,16 @@ import SCons.Debug
from SCons.Debug import logInstanceCreation
import SCons.Errors
import SCons.Memoize
+import SCons.Util
from SCons.compat import with_metaclass, NoSlotsPyPy
class Batch(object):
"""Remembers exact association between targets
and sources of executor."""
-
+
__slots__ = ('targets',
'sources')
-
+
def __init__(self, targets=[], sources=[]):
self.targets = targets
self.sources = sources
@@ -71,7 +72,7 @@ class TSList(collections.UserList):
return nl[i]
def __getslice__(self, i, j):
nl = self.func()
- i = max(i, 0); j = max(j, 0)
+ i, j = max(i, 0), max(j, 0)
return nl[i:j]
def __str__(self):
nl = self.func()
@@ -127,13 +128,13 @@ def execute_action_list(obj, target, kw):
status = act(*args, **kw)
if isinstance(status, SCons.Errors.BuildError):
status.executor = obj
- raise status
+ raise status # TODO pylint E0702: raising int not allowed
elif status:
msg = "Error %s" % status
raise SCons.Errors.BuildError(
- errstr=msg,
+ errstr=msg,
node=obj.batches[0].targets,
- executor=obj,
+ executor=obj,
action=act)
return status
@@ -450,6 +451,8 @@ class Executor(object, with_metaclass(NoSlotsPyPy)):
"""Fetch the signature contents. This is the main reason this
class exists, so we can compute this once and cache it regardless
of how many target or source Nodes there are.
+
+ Returns bytes
"""
try:
return self._memo['get_contents']
@@ -570,7 +573,6 @@ def AddBatchExecutor(key, executor):
nullenv = None
-import SCons.Util
class NullEnvironment(SCons.Util.Null):
import SCons.CacheDir
_CacheDir_path = None
@@ -595,7 +597,7 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
disassociate Builders from Nodes entirely, so we're not
going to worry about unit tests for this--at least for now.
"""
-
+
__slots__ = ('pre_actions',
'post_actions',
'env',
@@ -611,9 +613,10 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
'action_list',
'_do_execute',
'_execute_str')
-
+
def __init__(self, *args, **kw):
- if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Null')
+ if SCons.Debug.track_instances:
+ logInstanceCreation(self, 'Executor.Null')
self.batches = [Batch(kw['targets'][:], [])]
def get_build_env(self):
return get_NullEnvironment()
@@ -647,7 +650,7 @@ class Null(object, with_metaclass(NoSlotsPyPy)):
"""Morph this Null executor to a real Executor object."""
batches = self.batches
self.__class__ = Executor
- self.__init__([])
+ self.__init__([])
self.batches = batches
# The following methods require morphing this Null Executor to a
diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py
index 519dff0..353e6f2 100644
--- a/src/engine/SCons/ExecutorTests.py
+++ b/src/engine/SCons/ExecutorTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/ExecutorTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/ExecutorTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Executor
@@ -483,12 +481,7 @@ class ExecutorTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ ExecutorTestCase ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Job.py b/src/engine/SCons/Job.py
index 7f3544f..12ba19f 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 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Job.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -53,14 +53,14 @@ interrupt_msg = 'Build interrupted.'
class InterruptState(object):
- def __init__(self):
- self.interrupted = False
+ def __init__(self):
+ self.interrupted = False
- def set(self):
- self.interrupted = True
+ def set(self):
+ self.interrupted = True
- def __call__(self):
- return self.interrupted
+ def __call__(self):
+ return self.interrupted
class Jobs(object):
@@ -87,7 +87,7 @@ class Jobs(object):
stack_size = explicit_stack_size
if stack_size is None:
stack_size = default_stack_size
-
+
try:
self.job = Parallel(taskmaster, num, stack_size)
self.num_jobs = num
@@ -172,14 +172,14 @@ class Serial(object):
"""
def __init__(self, taskmaster):
- """Create a new serial job given a taskmaster.
+ """Create a new serial job given a taskmaster.
The taskmaster's next_task() method should return the next task
that needs to be executed, or None if there are no more tasks. The
taskmaster's executed() method will be called for each task when it
is successfully executed, or failed() will be called if it failed to
execute (e.g. execute() raised an exception)."""
-
+
self.taskmaster = taskmaster
self.interrupted = InterruptState()
@@ -188,7 +188,7 @@ class Serial(object):
and executing them, and return when there are no more tasks. If a task
fails to execute (i.e. execute() raises an exception), then the job will
stop."""
-
+
while True:
task = self.taskmaster.next_task()
@@ -199,7 +199,7 @@ class Serial(object):
task.prepare()
if task.needs_execute():
task.execute()
- except:
+ except Exception:
if self.interrupted():
try:
raise SCons.Errors.BuildError(
@@ -269,7 +269,7 @@ else:
def __init__(self, num, stack_size, interrupted):
"""Create the request and reply queues, and 'num' worker threads.
-
+
One must specify the stack size of the worker threads. The
stack size is specified in kilobytes.
"""
@@ -277,11 +277,11 @@ else:
self.resultsQueue = queue.Queue(0)
try:
- prev_size = threading.stack_size(stack_size*1024)
+ prev_size = threading.stack_size(stack_size*1024)
except AttributeError as e:
# Only print a warning if the stack size has been
# explicitly set.
- if not explicit_stack_size is None:
+ if explicit_stack_size is not None:
msg = "Setting stack size is unsupported by this version of Python:\n " + \
e.args[0]
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
@@ -322,7 +322,7 @@ else:
self.requestQueue.put(None)
# Wait for all of the workers to terminate.
- #
+ #
# If we don't do this, later Python versions (2.4, 2.5) often
# seem to raise exceptions during shutdown. This happens
# in requestQueue.get(), as an assertion failure that
@@ -339,7 +339,7 @@ else:
self.workers = []
class Parallel(object):
- """This class is used to execute tasks in parallel, and is somewhat
+ """This class is used to execute tasks in parallel, and is somewhat
less efficient than Serial, but is appropriate for parallel builds.
This class is thread safe.
@@ -373,7 +373,7 @@ else:
an exception), then the job will stop."""
jobs = 0
-
+
while True:
# Start up as many available tasks as we're
# allowed to.
diff --git a/src/engine/SCons/JobTests.py b/src/engine/SCons/JobTests.py
index cc17c1b..d46ab30 100644
--- a/src/engine/SCons/JobTests.py
+++ b/src/engine/SCons/JobTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,24 +20,47 @@
# 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/JobTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
import random
import math
import sys
import time
+import os
import TestUnit
import SCons.Job
+def get_cpu_nums():
+ # Linux, Unix and MacOS:
+ if hasattr( os, "sysconf" ):
+ if "SC_NPROCESSORS_ONLN" in os.sysconf_names:
+ # Linux & Unix:
+ ncpus = os.sysconf( "SC_NPROCESSORS_ONLN" )
+ if isinstance(ncpus, int) and ncpus > 0:
+ return ncpus
+ else: # OSX:
+ return int( os.popen2( "sysctl -n hw.ncpu")[1].read() )
+ # Windows:
+ if "NUMBER_OF_PROCESSORS" in os.environ:
+ ncpus = int( os.environ[ "NUMBER_OF_PROCESSORS" ] );
+ if ncpus > 0:
+ return ncpus
+ return 1 # Default
+
# a large number
-num_sines = 10000
+num_sines = 500
# how many parallel jobs to perform for the test
-num_jobs = 11
+num_jobs = get_cpu_nums()*2
+
+# in case we werent able to detect num cpus for this test
+# just make a hardcoded suffcient large number, though not future proof
+if(num_jobs == 2):
+ num_jobs = 33
# how many tasks to perform for the test
num_tasks = num_jobs*5
@@ -50,7 +73,7 @@ class DummyLock(object):
def release(self):
pass
-class NoThreadsException(object):
+class NoThreadsException(Exception):
"raised by the ParallelTestCase if threads are not supported"
def __str__(self):
@@ -75,14 +98,24 @@ class Task(object):
return True
def execute(self):
- self.taskmaster.test_case.failUnless(self.was_prepared,
+ self.taskmaster.test_case.assertTrue(self.was_prepared,
"the task wasn't prepared")
self.taskmaster.guard.acquire()
self.taskmaster.begin_list.append(self.i)
self.taskmaster.guard.release()
+ # while task is executing, represent this in the parallel_list
+ # and then turn it off
+ self.taskmaster.parallel_list[self.i] = 1
self._do_something()
+ self.taskmaster.parallel_list[self.i] = 0
+
+ # check if task was executing while another was also executing
+ for j in range(1, self.taskmaster.num_tasks):
+ if(self.taskmaster.parallel_list[j+1] == 1):
+ self.taskmaster.found_parallel = True
+ break
self.was_executed = 1
@@ -93,26 +126,29 @@ class Task(object):
def executed(self):
self.taskmaster.num_executed = self.taskmaster.num_executed + 1
- self.taskmaster.test_case.failUnless(self.was_prepared,
+ self.taskmaster.test_case.assertTrue(self.was_prepared,
"the task wasn't prepared")
- self.taskmaster.test_case.failUnless(self.was_executed,
+ self.taskmaster.test_case.assertTrue(self.was_executed,
"the task wasn't really executed")
- self.taskmaster.test_case.failUnless(isinstance(self, Task),
+ self.taskmaster.test_case.assertTrue(isinstance(self, Task),
"the task wasn't really a Task instance")
def failed(self):
self.taskmaster.num_failed = self.taskmaster.num_failed + 1
self.taskmaster.stop = 1
- self.taskmaster.test_case.failUnless(self.was_prepared,
+ self.taskmaster.test_case.assertTrue(self.was_prepared,
"the task wasn't prepared")
def postprocess(self):
self.taskmaster.num_postprocessed = self.taskmaster.num_postprocessed + 1
+ def exception_set(self):
+ pass
+
class RandomTask(Task):
def _do_something(self):
# do something that will take some random amount of time:
- for i in range(random.randrange(0, num_sines, 1)):
+ for i in range(random.randrange(0, 100 + num_sines, 1)):
x = math.sin(i)
time.sleep(0.01)
@@ -135,17 +171,17 @@ class ExceptionTask(object):
def executed(self):
self.taskmaster.num_executed = self.taskmaster.num_executed + 1
- self.taskmaster.test_case.failUnless(self.was_prepared,
+ self.taskmaster.test_case.assertTrue(self.was_prepared,
"the task wasn't prepared")
- self.taskmaster.test_case.failUnless(self.was_executed,
+ self.taskmaster.test_case.assertTrue(self.was_executed,
"the task wasn't really executed")
- self.taskmaster.test_case.failUnless(self.__class__ is Task,
+ self.taskmaster.test_case.assertTrue(self.__class__ is Task,
"the task wasn't really a Task instance")
def failed(self):
self.taskmaster.num_failed = self.taskmaster.num_failed + 1
self.taskmaster.stop = 1
- self.taskmaster.test_case.failUnless(self.was_prepared,
+ self.taskmaster.test_case.assertTrue(self.was_prepared,
"the task wasn't prepared")
def postprocess(self):
@@ -167,7 +203,10 @@ class Taskmaster(object):
self.num_executed = 0
self.num_failed = 0
self.num_postprocessed = 0
+ self.parallel_list = [0] * (n+1)
+ self.found_parallel = False
self.Task = Task
+
# 'guard' guards 'task_begin_list' and 'task_end_list'
try:
import threading
@@ -199,12 +238,7 @@ class Taskmaster(object):
def tasks_were_serial(self):
"analyze the task order to see if they were serial"
- serial = 1 # assume the tasks were serial
- for i in range(num_tasks):
- serial = serial and (self.begin_list[i]
- == self.end_list[i]
- == (i + 1))
- return serial
+ return not self.found_parallel
def exception_set(self):
pass
@@ -228,15 +262,15 @@ class ParallelTestCase(unittest.TestCase):
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
jobs.run()
- self.failUnless(not taskmaster.tasks_were_serial(),
+ self.assertTrue(not taskmaster.tasks_were_serial(),
"the tasks were not executed in parallel")
- self.failUnless(taskmaster.all_tasks_are_executed(),
+ self.assertTrue(taskmaster.all_tasks_are_executed(),
"all the tests were not executed")
- self.failUnless(taskmaster.all_tasks_are_iterated(),
+ self.assertTrue(taskmaster.all_tasks_are_iterated(),
"all the tests were not iterated over")
- self.failUnless(taskmaster.all_tasks_are_postprocessed(),
+ self.assertTrue(taskmaster.all_tasks_are_postprocessed(),
"all the tests were not postprocessed")
- self.failIf(taskmaster.num_failed,
+ self.assertFalse(taskmaster.num_failed,
"some task(s) failed to execute")
# Verify that parallel jobs will pull all of the completed tasks
@@ -248,7 +282,7 @@ class ParallelTestCase(unittest.TestCase):
class SleepTask(Task):
def _do_something(self):
- time.sleep(0.1)
+ time.sleep(0.01)
global SaveThreadPool
SaveThreadPool = SCons.Job.ThreadPool
@@ -258,7 +292,7 @@ class ParallelTestCase(unittest.TestCase):
ThreadPoolCallList.append('put(%s)' % task.i)
return SaveThreadPool.put(self, task)
def get(self):
- time.sleep(0.5)
+ time.sleep(0.05)
result = SaveThreadPool.get(self)
ThreadPoolCallList.append('get(%s)' % result[0].i)
return result
@@ -291,15 +325,15 @@ class SerialTestCase(unittest.TestCase):
jobs = SCons.Job.Jobs(1, taskmaster)
jobs.run()
- self.failUnless(taskmaster.tasks_were_serial(),
+ self.assertTrue(taskmaster.tasks_were_serial(),
"the tasks were not executed in series")
- self.failUnless(taskmaster.all_tasks_are_executed(),
+ self.assertTrue(taskmaster.all_tasks_are_executed(),
"all the tests were not executed")
- self.failUnless(taskmaster.all_tasks_are_iterated(),
+ self.assertTrue(taskmaster.all_tasks_are_iterated(),
"all the tests were not iterated over")
- self.failUnless(taskmaster.all_tasks_are_postprocessed(),
+ self.assertTrue(taskmaster.all_tasks_are_postprocessed(),
"all the tests were not postprocessed")
- self.failIf(taskmaster.num_failed,
+ self.assertFalse(taskmaster.num_failed,
"some task(s) failed to execute")
class NoParallelTestCase(unittest.TestCase):
@@ -312,18 +346,18 @@ class NoParallelTestCase(unittest.TestCase):
try:
taskmaster = Taskmaster(num_tasks, self, RandomTask)
jobs = SCons.Job.Jobs(2, taskmaster)
- self.failUnless(jobs.num_jobs == 1,
+ self.assertTrue(jobs.num_jobs == 1,
"unexpected number of jobs %d" % jobs.num_jobs)
jobs.run()
- self.failUnless(taskmaster.tasks_were_serial(),
+ self.assertTrue(taskmaster.tasks_were_serial(),
"the tasks were not executed in series")
- self.failUnless(taskmaster.all_tasks_are_executed(),
+ self.assertTrue(taskmaster.all_tasks_are_executed(),
"all the tests were not executed")
- self.failUnless(taskmaster.all_tasks_are_iterated(),
+ self.assertTrue(taskmaster.all_tasks_are_iterated(),
"all the tests were not iterated over")
- self.failUnless(taskmaster.all_tasks_are_postprocessed(),
+ self.assertTrue(taskmaster.all_tasks_are_postprocessed(),
"all the tests were not postprocessed")
- self.failIf(taskmaster.num_failed,
+ self.assertFalse(taskmaster.num_failed,
"some task(s) failed to execute")
finally:
SCons.Job.Parallel = save_Parallel
@@ -337,13 +371,13 @@ class SerialExceptionTestCase(unittest.TestCase):
jobs = SCons.Job.Jobs(1, taskmaster)
jobs.run()
- self.failIf(taskmaster.num_executed,
+ self.assertFalse(taskmaster.num_executed,
"a task was executed")
- self.failUnless(taskmaster.num_iterated == 1,
+ self.assertTrue(taskmaster.num_iterated == 1,
"exactly one task should have been iterated")
- self.failUnless(taskmaster.num_failed == 1,
+ self.assertTrue(taskmaster.num_failed == 1,
"exactly one task should have failed")
- self.failUnless(taskmaster.num_postprocessed == 1,
+ self.assertTrue(taskmaster.num_postprocessed == 1,
"exactly one task should have been postprocessed")
class ParallelExceptionTestCase(unittest.TestCase):
@@ -354,13 +388,13 @@ class ParallelExceptionTestCase(unittest.TestCase):
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
jobs.run()
- self.failIf(taskmaster.num_executed,
+ self.assertFalse(taskmaster.num_executed,
"a task was executed")
- self.failUnless(taskmaster.num_iterated >= 1,
+ self.assertTrue(taskmaster.num_iterated >= 1,
"one or more task should have been iterated")
- self.failUnless(taskmaster.num_failed >= 1,
+ self.assertTrue(taskmaster.num_failed >= 1,
"one or more tasks should have failed")
- self.failUnless(taskmaster.num_postprocessed >= 1,
+ self.assertTrue(taskmaster.num_postprocessed >= 1,
"one or more tasks should have been postprocessed")
#---------------------------------------------------------------------
@@ -491,10 +525,10 @@ class _SConsTaskTest(unittest.TestCase):
for N in testnodes:
state = N.get_state()
- self.failUnless(state in [SCons.Node.no_state, N.expect_to_be],
+ self.assertTrue(state in [SCons.Node.no_state, N.expect_to_be],
"Node %s got unexpected result: %s" % (N, state))
- self.failUnless([N for N in testnodes if N.get_state()],
+ self.assertTrue([N for N in testnodes if N.get_state()],
"no nodes ran at all.")
diff --git a/src/engine/SCons/Memoize.py b/src/engine/SCons/Memoize.py
index 5fe481d..f7b45bf 100644
--- a/src/engine/SCons/Memoize.py
+++ b/src/engine/SCons/Memoize.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 print_function
-__revision__ = "src/engine/SCons/Memoize.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Memoize.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """Memoizer
diff --git a/src/engine/SCons/MemoizeTests.py b/src/engine/SCons/MemoizeTests.py
index 559232f..f3b5329 100644
--- a/src/engine/SCons/MemoizeTests.py
+++ b/src/engine/SCons/MemoizeTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/MemoizeTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/MemoizeTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Memoize
# Enable memoization counting
@@ -165,15 +163,7 @@ class CountValueTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- CountDictTestCase,
- CountValueTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/Alias.py b/src/engine/SCons/Node/Alias.py
index 567f663..a9defb6 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 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/Alias.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import collections
diff --git a/src/engine/SCons/Node/AliasTests.py b/src/engine/SCons/Node/AliasTests.py
index e1929f6..764ac67 100644
--- a/src/engine/SCons/Node/AliasTests.py
+++ b/src/engine/SCons/Node/AliasTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Node/AliasTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/AliasTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Node.Alias
@@ -113,16 +111,7 @@ class AliasBuildInfoTestCase(unittest.TestCase):
bi = SCons.Node.Alias.AliasBuildInfo()
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- AliasTestCase,
- AliasBuildInfoTestCase,
- AliasNodeInfoTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index a953890..21ccecc 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 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ that can be used by scripts or modules looking for the canonical default.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-__revision__ = "src/engine/SCons/Node/FS.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/FS.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import fnmatch
import os
@@ -43,6 +43,7 @@ import stat
import sys
import time
import codecs
+from itertools import chain
import SCons.Action
import SCons.Debug
@@ -59,6 +60,8 @@ from SCons.Debug import Trace
print_duplicate = 0
+MD5_TIMESTAMP_DEBUG = False
+
def sconsign_none(node):
raise NotImplementedError
@@ -74,6 +77,9 @@ def sconsign_dir(node):
_sconsign_map = {0 : sconsign_none,
1 : sconsign_dir}
+class FileBuildInfoFileToCsigMappingError(Exception):
+ pass
+
class EntryProxyAttributeError(AttributeError):
"""
An AttributeError subclass for recording and displaying the name
@@ -132,7 +138,10 @@ def initialize_do_splitdrive():
global do_splitdrive
global has_unc
drive, path = os.path.splitdrive('X:/foo')
- has_unc = hasattr(os.path, 'splitunc')
+ # splitunc is removed from python 3.7 and newer
+ # so we can also just test if splitdrive works with UNC
+ has_unc = (hasattr(os.path, 'splitunc')
+ or os.path.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive')
do_splitdrive = not not drive or has_unc
@@ -272,7 +281,7 @@ def set_duplicate(duplicate):
'copy' : _copy_func
}
- if not duplicate in Valid_Duplicates:
+ if duplicate not in Valid_Duplicates:
raise SCons.Errors.InternalError("The argument of set_duplicate "
"should be in Valid_Duplicates")
global Link_Funcs
@@ -282,11 +291,13 @@ def set_duplicate(duplicate):
Link_Funcs.append(link_dict[func])
def LinkFunc(target, source, env):
- # Relative paths cause problems with symbolic links, so
- # we use absolute paths, which may be a problem for people
- # who want to move their soft-linked src-trees around. Those
- # people should use the 'hard-copy' mode, softlinks cannot be
- # used for that; at least I have no idea how ...
+ """
+ Relative paths cause problems with symbolic links, so
+ we use absolute paths, which may be a problem for people
+ who want to move their soft-linked src-trees around. Those
+ people should use the 'hard-copy' mode, softlinks cannot be
+ used for that; at least I have no idea how ...
+ """
src = source[0].get_abspath()
dest = target[0].get_abspath()
dir, file = os.path.split(dest)
@@ -328,7 +339,12 @@ Unlink = SCons.Action.Action(UnlinkFunc, None)
def MkdirFunc(target, source, env):
t = target[0]
- if not t.exists():
+ # This os.path.exists test looks redundant, but it's possible
+ # when using Install() to install multiple dirs outside the
+ # source tree to get a case where t.exists() is true but
+ # the path does already exist, so this prevents spurious
+ # build failures in that case. See test/Install/multi-dir.
+ if not t.exists() and not os.path.exists(t.get_abspath()):
t.fs.mkdir(t.get_abspath())
return 0
@@ -463,7 +479,7 @@ class EntryProxy(SCons.Util.Proxy):
return SCons.Subst.SpecialAttrWrapper(r, entry.name + "_posix")
def __get_windows_path(self):
- """Return the path with \ as the path separator,
+ r"""Return the path with \ as the path separator,
regardless of platform."""
if OS_SEP == '\\':
return self
@@ -514,7 +530,7 @@ class EntryProxy(SCons.Util.Proxy):
except KeyError:
try:
attr = SCons.Util.Proxy.__getattr__(self, name)
- except AttributeError as e:
+ except AttributeError:
# Raise our own AttributeError subclass with an
# overridden __str__() method that identifies the
# name of the entry that caused the exception.
@@ -682,10 +698,15 @@ class Base(SCons.Node.Node):
@SCons.Memoize.CountMethodCall
def stat(self):
- try: return self._memo['stat']
- except KeyError: pass
- try: result = self.fs.stat(self.get_abspath())
- except os.error: result = None
+ try:
+ return self._memo['stat']
+ except KeyError:
+ pass
+ try:
+ result = self.fs.stat(self.get_abspath())
+ except os.error:
+ result = None
+
self._memo['stat'] = result
return result
@@ -697,13 +718,17 @@ class Base(SCons.Node.Node):
def getmtime(self):
st = self.stat()
- if st: return st[stat.ST_MTIME]
- else: return None
+ if st:
+ return st[stat.ST_MTIME]
+ else:
+ return None
def getsize(self):
st = self.stat()
- if st: return st[stat.ST_SIZE]
- else: return None
+ if st:
+ return st[stat.ST_SIZE]
+ else:
+ return None
def isdir(self):
st = self.stat()
@@ -1048,21 +1073,22 @@ _classEntry = Entry
class LocalFS(object):
-
- # This class implements an abstraction layer for operations involving
- # a local file system. Essentially, this wraps any function in
- # the os, os.path or shutil modules that we use to actually go do
- # anything with or to the local file system.
- #
- # Note that there's a very good chance we'll refactor this part of
- # the architecture in some way as we really implement the interface(s)
- # for remote file system Nodes. For example, the right architecture
- # might be to have this be a subclass instead of a base class.
- # Nevertheless, we're using this as a first step in that direction.
- #
- # We're not using chdir() yet because the calling subclass method
- # needs to use os.chdir() directly to avoid recursion. Will we
- # really need this one?
+ """
+ This class implements an abstraction layer for operations involving
+ a local file system. Essentially, this wraps any function in
+ the os, os.path or shutil modules that we use to actually go do
+ anything with or to the local file system.
+
+ Note that there's a very good chance we'll refactor this part of
+ the architecture in some way as we really implement the interface(s)
+ for remote file system Nodes. For example, the right architecture
+ might be to have this be a subclass instead of a base class.
+ Nevertheless, we're using this as a first step in that direction.
+
+ We're not using chdir() yet because the calling subclass method
+ needs to use os.chdir() directly to avoid recursion. Will we
+ really need this one?
+ """
#def chdir(self, path):
# return os.chdir(path)
def chmod(self, path, mode):
@@ -1389,10 +1415,10 @@ class FS(LocalFS):
if not isinstance(d, SCons.Node.Node):
d = self.Dir(d)
self.Top.addRepository(d)
-
+
def PyPackageDir(self, modulename):
- """Locate the directory of a given python module name
-
+ r"""Locate the directory of a given python module name
+
For example scons might resolve to
Windows: C:\Python27\Lib\site-packages\scons-2.5.1
Linux: /usr/lib/scons
@@ -1662,7 +1688,7 @@ class Dir(Base):
return result
def addRepository(self, dir):
- if dir != self and not dir in self.repositories:
+ if dir != self and dir not in self.repositories:
self.repositories.append(dir)
dir._tpath = '.'
self.__clearRepositoryCache()
@@ -1702,7 +1728,7 @@ class Dir(Base):
if self is other:
result = '.'
- elif not other in self._path_elements:
+ elif other not in self._path_elements:
try:
other_dir = other.get_dir()
except AttributeError:
@@ -2234,7 +2260,7 @@ class RootDir(Dir):
this directory.
"""
- __slots__ = ['_lookupDict']
+ __slots__ = ('_lookupDict', )
def __init__(self, drive, fs):
if SCons.Debug.track_instances: logInstanceCreation(self, 'Node.FS.RootDir')
@@ -2440,7 +2466,7 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
"""
state = getattr(self, '__dict__', {}).copy()
for obj in type(self).mro():
- for name in getattr(obj,'__slots__',()):
+ for name in getattr(obj, '__slots__', ()):
if hasattr(self, name):
state[name] = getattr(self, name)
@@ -2462,11 +2488,42 @@ class FileNodeInfo(SCons.Node.NodeInfoBase):
if key not in ('__weakref__',):
setattr(self, key, value)
+ def __eq__(self, other):
+ return self.csig == other.csig and self.timestamp == other.timestamp and self.size == other.size
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
class FileBuildInfo(SCons.Node.BuildInfoBase):
- __slots__ = ()
+ """
+ This is info loaded from sconsign.
+
+ Attributes unique to FileBuildInfo:
+ dependency_map : Caches file->csig mapping
+ for all dependencies. Currently this is only used when using
+ MD5-timestamp decider.
+ It's used to ensure that we copy the correct
+ csig from previous build to be written to .sconsign when current build
+ is done. Previously the matching of csig to file was strictly by order
+ they appeared in bdepends, bsources, or bimplicit, and so a change in order
+ or count of any of these could yield writing wrong csig, and then false positive
+ rebuilds
+ """
+ __slots__ = ['dependency_map', ]
current_version_id = 2
+ def __setattr__(self, key, value):
+
+ # If any attributes are changed in FileBuildInfo, we need to
+ # invalidate the cached map of file name to content signature
+ # heald in dependency_map. Currently only used with
+ # MD5-timestamp decider
+ if key != 'dependency_map' and hasattr(self, 'dependency_map'):
+ del self.dependency_map
+
+ return super(FileBuildInfo, self).__setattr__(key, value)
+
def convert_to_sconsign(self):
"""
Converts this FileBuildInfo object for writing to a .sconsign file
@@ -3225,46 +3282,230 @@ class File(Base):
self._memo['changed'] = has_changed
return has_changed
- def changed_content(self, target, prev_ni):
+ def changed_content(self, target, prev_ni, repo_node=None):
cur_csig = self.get_csig()
try:
return cur_csig != prev_ni.csig
except AttributeError:
return 1
- def changed_state(self, target, prev_ni):
+ def changed_state(self, target, prev_ni, repo_node=None):
return self.state != SCons.Node.up_to_date
- def changed_timestamp_then_content(self, target, prev_ni):
- if not self.changed_timestamp_match(target, prev_ni):
+
+ # Caching node -> string mapping for the below method
+ __dmap_cache = {}
+ __dmap_sig_cache = {}
+
+
+ def _build_dependency_map(self, binfo):
+ """
+ Build mapping from file -> signature
+
+ Args:
+ self - self
+ binfo - buildinfo from node being considered
+
+ Returns:
+ dictionary of file->signature mappings
+ """
+
+ # For an "empty" binfo properties like bsources
+ # do not exist: check this to avoid exception.
+ if (len(binfo.bsourcesigs) + len(binfo.bdependsigs) + \
+ len(binfo.bimplicitsigs)) == 0:
+ return {}
+
+ binfo.dependency_map = { child:signature for child, signature in zip(chain(binfo.bsources, binfo.bdepends, binfo.bimplicit),
+ chain(binfo.bsourcesigs, binfo.bdependsigs, binfo.bimplicitsigs))}
+
+ return binfo.dependency_map
+
+ # @profile
+ def _add_strings_to_dependency_map(self, dmap):
+ """
+ In the case comparing node objects isn't sufficient, we'll add the strings for the nodes to the dependency map
+ :return:
+ """
+
+ first_string = str(next(iter(dmap)))
+
+ # print("DMAP:%s"%id(dmap))
+ if first_string not in dmap:
+ string_dict = {str(child): signature for child, signature in dmap.items()}
+ dmap.update(string_dict)
+ return dmap
+
+ def _get_previous_signatures(self, dmap):
+ """
+ Return a list of corresponding csigs from previous
+ build in order of the node/files in children.
+
+ Args:
+ self - self
+ dmap - Dictionary of file -> csig
+
+ Returns:
+ List of csigs for provided list of children
+ """
+ prev = []
+ # MD5_TIMESTAMP_DEBUG = False
+
+ if len(dmap) == 0:
+ if MD5_TIMESTAMP_DEBUG: print("Nothing dmap shortcutting")
+ return None
+ elif MD5_TIMESTAMP_DEBUG: print("len(dmap):%d"%len(dmap))
+
+
+ # First try retrieving via Node
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self is in map:%s id:%s type:%s"%(str(self), id(self), type(self)))
+ df = dmap.get(self, False)
+ if df:
+ return df
+
+ # Now check if self's repository file is in map.
+ rf = self.rfile()
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self.rfile is in map:%s id:%s type:%s"%(str(rf), id(rf), type(rf)))
+ rfm = dmap.get(rf, False)
+ if rfm:
+ return rfm
+
+ # get default string for node and then also string swapping os.altsep for os.sep (/ for \)
+ c_strs = [str(self)]
+
+ if os.altsep:
+ c_strs.append(c_strs[0].replace(os.sep, os.altsep))
+
+ # In some cases the dependency_maps' keys are already strings check.
+ # Check if either string is now in dmap.
+ for s in c_strs:
+ if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map :%s" % s)
+ df = dmap.get(s, False)
+ if df:
+ return df
+
+ # Strings don't exist in map, add them and try again
+ # If there are no strings in this dmap, then add them.
+ # This may not be necessary, we could walk the nodes in the dmap and check each string
+ # rather than adding ALL the strings to dmap. In theory that would be n/2 vs 2n str() calls on node
+ # if not dmap.has_strings:
+ dmap = self._add_strings_to_dependency_map(dmap)
+
+ # In some cases the dependency_maps' keys are already strings check.
+ # Check if either string is now in dmap.
+ for s in c_strs:
+ if MD5_TIMESTAMP_DEBUG: print("Checking if str(self) is in map (now with strings) :%s" % s)
+ df = dmap.get(s, False)
+ if df:
+ return df
+
+ # Lastly use nodes get_path() to generate string and see if that's in dmap
+ if not df:
try:
- self.get_ninfo().csig = prev_ni.csig
+ # this should yield a path which matches what's in the sconsign
+ c_str = self.get_path()
+ if os.altsep:
+ c_str = c_str.replace(os.sep, os.altsep)
+
+ if MD5_TIMESTAMP_DEBUG: print("Checking if self.get_path is in map (now with strings) :%s" % s)
+
+ df = dmap.get(c_str, None)
+
+ except AttributeError as e:
+ raise FileBuildInfoFileToCsigMappingError("No mapping from file name to content signature for :%s"%c_str)
+
+ return df
+
+ def changed_timestamp_then_content(self, target, prev_ni, node=None):
+ """
+ Used when decider for file is Timestamp-MD5
+
+ NOTE: If the timestamp hasn't changed this will skip md5'ing the
+ file and just copy the prev_ni provided. If the prev_ni
+ is wrong. It will propagate it.
+ See: https://github.com/SCons/scons/issues/2980
+
+ Args:
+ self - dependency
+ target - target
+ prev_ni - The NodeInfo object loaded from previous builds .sconsign
+ node - Node instance. Check this node for file existence/timestamp
+ if specified.
+
+ Returns:
+ Boolean - Indicates if node(File) has changed.
+ """
+
+ # Now get sconsign name -> csig map and then get proper prev_ni if possible
+ bi = node.get_stored_info().binfo
+ rebuilt = False
+ try:
+ dependency_map = bi.dependency_map
+ except AttributeError as e:
+ dependency_map = self._build_dependency_map(bi)
+ rebuilt = True
+
+ if len(dependency_map) == 0:
+ # If there's no dependency map, there's no need to find the
+ # prev_ni as there aren't any
+ # shortcut the rest of the logic
+ if MD5_TIMESTAMP_DEBUG: print("Skipping checks len(dmap)=0")
+
+ # We still need to get the current file's csig
+ # This should be slightly faster than calling self.changed_content(target, new_prev_ni)
+ self.get_csig()
+ return True
+
+ new_prev_ni = self._get_previous_signatures(dependency_map)
+ new = self.changed_timestamp_match(target, new_prev_ni)
+
+ if MD5_TIMESTAMP_DEBUG:
+ old = self.changed_timestamp_match(target, prev_ni)
+
+ if old != new:
+ print("Mismatch self.changed_timestamp_match(%s, prev_ni) old:%s new:%s"%(str(target), old, new))
+ new_prev_ni = self._get_previous_signatures(dependency_map)
+
+ if not new:
+ try:
+ # NOTE: We're modifying the current node's csig in a query.
+ self.get_ninfo().csig = new_prev_ni.csig
except AttributeError:
pass
return False
- return self.changed_content(target, prev_ni)
+ return self.changed_content(target, new_prev_ni)
- def changed_timestamp_newer(self, target, prev_ni):
+ def changed_timestamp_newer(self, target, prev_ni, repo_node=None):
try:
return self.get_timestamp() > target.get_timestamp()
except AttributeError:
return 1
- def changed_timestamp_match(self, target, prev_ni):
+ def changed_timestamp_match(self, target, prev_ni, repo_node=None):
+ """
+ Return True if the timestamps don't match or if there is no previous timestamp
+ :param target:
+ :param prev_ni: Information about the node from the previous build
+ :return:
+ """
try:
return self.get_timestamp() != prev_ni.timestamp
except AttributeError:
return 1
def is_up_to_date(self):
+ """Check for whether the Node is current
+ In all cases self is the target we're checking to see if it's up to date
+ """
+
T = 0
if T: Trace('is_up_to_date(%s):' % self)
if not self.exists():
if T: Trace(' not self.exists():')
- # The file doesn't exist locally...
+ # The file (always a target) doesn't exist locally...
r = self.rfile()
if r != self:
- # ...but there is one in a Repository...
+ # ...but there is one (always a target) in a Repository...
if not self.changed(r):
if T: Trace(' changed(%s):' % r)
# ...and it's even up-to-date...
@@ -3272,7 +3513,9 @@ class File(Base):
# ...and they'd like a local copy.
e = LocalCopy(self, r, None)
if isinstance(e, SCons.Errors.BuildError):
- raise
+ # Likely this should be re-raising exception e
+ # (which would be BuildError)
+ raise e
SCons.Node.store_info_map[self.store_info](self)
if T: Trace(' 1\n')
return 1
@@ -3293,11 +3536,14 @@ class File(Base):
result = self
if not self.exists():
norm_name = _my_normcase(self.name)
- for dir in self.dir.get_all_rdirs():
- try: node = dir.entries[norm_name]
- except KeyError: node = dir.file_on_disk(self.name)
+ for repo_dir in self.dir.get_all_rdirs():
+ try:
+ node = repo_dir.entries[norm_name]
+ except KeyError:
+ node = repo_dir.file_on_disk(self.name)
+
if node and node.exists() and \
- (isinstance(node, File) or isinstance(node, Entry) \
+ (isinstance(node, File) or isinstance(node, Entry)
or not node.is_derived()):
result = node
# Copy over our local attributes to the repository
@@ -3317,6 +3563,28 @@ class File(Base):
self._memo['rfile'] = result
return result
+ def find_repo_file(self):
+ """
+ For this node, find if there exists a corresponding file in one or more repositories
+ :return: list of corresponding files in repositories
+ """
+ retvals = []
+
+ norm_name = _my_normcase(self.name)
+ for repo_dir in self.dir.get_all_rdirs():
+ try:
+ node = repo_dir.entries[norm_name]
+ except KeyError:
+ node = repo_dir.file_on_disk(self.name)
+
+ if node and node.exists() and \
+ (isinstance(node, File) or isinstance(node, Entry) \
+ or not node.is_derived()):
+ retvals.append(node)
+
+ return retvals
+
+
def rstr(self):
return str(self.rfile())
@@ -3374,6 +3642,8 @@ class File(Base):
because multiple targets built by the same action will all
have the same build signature, and we have to differentiate
them somehow.
+
+ Signature should normally be string of hex digits.
"""
try:
return self.cachesig
@@ -3383,10 +3653,13 @@ class File(Base):
# Collect signatures for all children
children = self.children()
sigs = [n.get_cachedir_csig() for n in children]
+
# Append this node's signature...
sigs.append(self.get_contents_sig())
+
# ...and it's path
sigs.append(self.get_internal_path())
+
# Merge this all into a single signature
result = self.cachesig = SCons.Util.MD5collect(sigs)
return result
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 3a36894..2366a4d 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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, print_function
-__revision__ = "src/engine/SCons/Node/FSTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/FSTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -41,59 +41,79 @@ import SCons.Errors
import SCons.Node.FS
import SCons.Util
import SCons.Warnings
+import SCons.Environment
built_it = None
scanner_count = 0
+
class Scanner(object):
def __init__(self, node=None):
global scanner_count
scanner_count = scanner_count + 1
self.hash = scanner_count
self.node = node
+
def path(self, env, dir, target=None, source=None):
return ()
+
def __call__(self, node, env, path):
return [self.node]
+
def __hash__(self):
return self.hash
+
def select(self, node):
return self
+
def recurse_nodes(self, nodes):
return nodes
+
class Environment(object):
def __init__(self):
self.scanner = Scanner()
+
def Dictionary(self, *args):
return {}
+
def autogenerate(self, **kw):
return {}
+
def get_scanner(self, skey):
return self.scanner
+
def Override(self, overrides):
return self
+
def _update(self, dict):
pass
+
class Action(object):
def __call__(self, targets, sources, env, **kw):
global built_it
if kw.get('execute', 1):
built_it = 1
return 0
+
def show(self, string):
pass
+
def get_contents(self, target, source, env):
- return bytearray("",'utf-8')
+ return bytearray("", 'utf-8')
+
def genstring(self, target, source, env):
return ""
+
def strfunction(self, targets, sources, env):
return ""
+
def get_implicit_deps(self, target, source, env):
return []
+
class Builder(object):
def __init__(self, factory, action=Action()):
self.factory = factory
@@ -109,6 +129,7 @@ class Builder(object):
def source_factory(self, name):
return self.factory(name)
+
class _tempdirTestCase(unittest.TestCase):
def setUp(self):
self.save_cwd = os.getcwd()
@@ -120,10 +141,11 @@ class _tempdirTestCase(unittest.TestCase):
def tearDown(self):
os.chdir(self.save_cwd)
+
class VariantDirTestCase(unittest.TestCase):
def runTest(self):
"""Test variant dir functionality"""
- test=TestCmd(workdir='')
+ test = TestCmd(workdir='')
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
@@ -168,30 +190,30 @@ class VariantDirTestCase(unittest.TestCase):
test.subdir(['rep1', 'build', 'var2'])
# A source file in the source directory
- test.write([ 'work', 'src', 'test.in' ], 'test.in')
+ test.write(['work', 'src', 'test.in'], 'test.in')
# A source file in a subdir of the source directory
- test.subdir([ 'work', 'src', 'new_dir' ])
- test.write([ 'work', 'src', 'new_dir', 'test9.out' ], 'test9.out\n')
+ test.subdir(['work', 'src', 'new_dir'])
+ test.write(['work', 'src', 'new_dir', 'test9.out'], 'test9.out\n')
# A source file in the repository
- test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
+ test.write(['rep1', 'src', 'test2.in'], 'test2.in')
# Some source files in the variant directory
- test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
- test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
+ test.write(['work', 'build', 'var2', 'test.in'], 'test.old')
+ test.write(['work', 'build', 'var2', 'test2.in'], 'test2.old')
# An old derived file in the variant directories
- test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
- test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
+ test.write(['work', 'build', 'var1', 'test.out'], 'test.old')
+ test.write(['work', 'build', 'var2', 'test.out'], 'test.old')
# And just in case we are weird, a derived file in the source
# dir.
- test.write([ 'work', 'src', 'test.out' ], 'test.out.src')
+ test.write(['work', 'src', 'test.out'], 'test.out.src')
# A derived file in the repository
- test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
- test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
+ test.write(['rep1', 'build', 'var1', 'test2.out'], 'test2.out_rep')
+ test.write(['rep1', 'build', 'var2', 'test2.out'], 'test2.out_rep')
os.chdir(test.workpath('work'))
@@ -210,8 +232,8 @@ class VariantDirTestCase(unittest.TestCase):
f2out_2.builder = 1
fs.Repository(test.workpath('rep1'))
- assert f1.srcnode().get_internal_path() == os.path.normpath('src/test.in'),\
- f1.srcnode().get_internal_path()
+ assert f1.srcnode().get_internal_path() == os.path.normpath('src/test.in'), \
+ f1.srcnode().get_internal_path()
# str(node) returns source path for duplicate = 0
assert str(f1) == os.path.normpath('src/test.in'), str(f1)
# Build path does not exist
@@ -221,26 +243,26 @@ class VariantDirTestCase(unittest.TestCase):
# And duplicate=0 should also work just like a Repository
assert f1.rexists()
# rfile() should point to the source path
- assert f1.rfile().get_internal_path() == os.path.normpath('src/test.in'),\
- f1.rfile().get_internal_path()
+ assert f1.rfile().get_internal_path() == os.path.normpath('src/test.in'), \
+ f1.rfile().get_internal_path()
- assert f2.srcnode().get_internal_path() == os.path.normpath('src/test.in'),\
- f2.srcnode().get_internal_path()
+ assert f2.srcnode().get_internal_path() == os.path.normpath('src/test.in'), \
+ f2.srcnode().get_internal_path()
# str(node) returns build path for duplicate = 1
assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
# Build path exists
assert f2.exists()
# ...and exists() should copy the file from src to build path
- assert test.read(['work', 'build', 'var2', 'test.in']) == bytearray('test.in','utf-8'),\
- test.read(['work', 'build', 'var2', 'test.in'])
+ assert test.read(['work', 'build', 'var2', 'test.in']) == bytearray('test.in', 'utf-8'), \
+ test.read(['work', 'build', 'var2', 'test.in'])
# Since exists() is true, so should rexists() be
assert f2.rexists()
f3 = fs.File('build/var1/test2.in')
f4 = fs.File('build/var2/test2.in')
- assert f3.srcnode().get_internal_path() == os.path.normpath('src/test2.in'),\
- f3.srcnode().get_internal_path()
+ assert f3.srcnode().get_internal_path() == os.path.normpath('src/test2.in'), \
+ f3.srcnode().get_internal_path()
# str(node) returns source path for duplicate = 0
assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
# Build path does not exist
@@ -250,22 +272,22 @@ class VariantDirTestCase(unittest.TestCase):
# But we do have a file in the Repository
assert f3.rexists()
# rfile() should point to the source path
- assert f3.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/src/test2.in')),\
- f3.rfile().get_internal_path()
+ assert f3.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/src/test2.in')), \
+ f3.rfile().get_internal_path()
- assert f4.srcnode().get_internal_path() == os.path.normpath('src/test2.in'),\
- f4.srcnode().get_internal_path()
+ assert f4.srcnode().get_internal_path() == os.path.normpath('src/test2.in'), \
+ f4.srcnode().get_internal_path()
# str(node) returns build path for duplicate = 1
assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
# Build path should exist
assert f4.exists()
# ...and copy over the file into the local build path
- assert test.read(['work', 'build', 'var2', 'test2.in']) == bytearray('test2.in','utf-8')
+ assert test.read(['work', 'build', 'var2', 'test2.in']) == bytearray('test2.in', 'utf-8')
# should exist in repository, since exists() is true
assert f4.rexists()
# rfile() should point to ourselves
- assert f4.rfile().get_internal_path() == os.path.normpath('build/var2/test2.in'),\
- f4.rfile().get_internal_path()
+ assert f4.rfile().get_internal_path() == os.path.normpath('build/var2/test2.in'), \
+ f4.rfile().get_internal_path()
f5 = fs.File('build/var1/test.out')
f6 = fs.File('build/var2/test.out')
@@ -273,12 +295,12 @@ class VariantDirTestCase(unittest.TestCase):
assert f5.exists()
# We should not copy the file from the source dir, since this is
# a derived file.
- assert test.read(['work', 'build', 'var1', 'test.out']) == bytearray('test.old','utf-8')
+ assert test.read(['work', 'build', 'var1', 'test.out']) == bytearray('test.old', 'utf-8')
assert f6.exists()
# We should not copy the file from the source dir, since this is
# a derived file.
- assert test.read(['work', 'build', 'var2', 'test.out']) == bytearray('test.old','utf-8')
+ assert test.read(['work', 'build', 'var2', 'test.out']) == bytearray('test.old', 'utf-8')
f7 = fs.File('build/var1/test2.out')
f8 = fs.File('build/var2/test2.out')
@@ -291,8 +313,8 @@ class VariantDirTestCase(unittest.TestCase):
assert not f8.exists()
assert f8.rexists()
- assert f8.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/build/var2/test2.out')),\
- f8.rfile().get_internal_path()
+ assert f8.rfile().get_internal_path() == os.path.normpath(test.workpath('rep1/build/var2/test2.out')), \
+ f8.rfile().get_internal_path()
# Verify the Mkdir and Link actions are called
d9 = fs.Dir('build/var2/new_dir')
@@ -301,6 +323,7 @@ class VariantDirTestCase(unittest.TestCase):
class MkdirAction(Action):
def __init__(self, dir_made):
self.dir_made = dir_made
+
def __call__(self, target, source, env, executor=None):
if executor:
target = executor.get_all_targets()
@@ -309,8 +332,10 @@ class VariantDirTestCase(unittest.TestCase):
save_Link = SCons.Node.FS.Link
link_made = []
+
def link_func(target, source, env, link_made=link_made):
link_made.append(target)
+
SCons.Node.FS.Link = link_func
try:
@@ -331,10 +356,10 @@ class VariantDirTestCase(unittest.TestCase):
# happen if you switch from duplicate=1 to duplicate=0, then
# delete a source file. At one time, this would cause exists()
# to return a 1 but get_contents() to throw.
- test.write([ 'work', 'build', 'var1', 'asourcefile' ], 'stuff')
+ test.write(['work', 'build', 'var1', 'asourcefile'], 'stuff')
f10 = fs.File('build/var1/asourcefile')
assert f10.exists()
- assert f10.get_contents() == bytearray('stuff','utf-8'), f10.get_contents()
+ assert f10.get_contents() == bytearray('stuff', 'utf-8'), f10.get_contents()
f11 = fs.File('src/file11')
t, m = f11.alter_targets()
@@ -360,8 +385,10 @@ class VariantDirTestCase(unittest.TestCase):
fIO = fs.File("build/var2/IOError")
save_Link = SCons.Node.FS.Link
+
def Link_IOError(target, source, env):
raise IOError(17, "Link_IOError")
+
SCons.Node.FS.Link = SCons.Action.Action(Link_IOError, None)
test.write(['work', 'src', 'IOError'], "work/src/IOError\n")
@@ -378,16 +405,16 @@ class VariantDirTestCase(unittest.TestCase):
SCons.Node.FS.Link = save_Link
# Test to see if Link() works...
- test.subdir('src','build')
+ test.subdir('src', 'build')
test.write('src/foo', 'src/foo\n')
os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
fs.File(test.workpath('src/foo')),
None)
os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
- st=os.stat(test.workpath('build/foo'))
+ st = os.stat(test.workpath('build/foo'))
assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
- stat.S_IMODE(st[stat.ST_MODE])
+ stat.S_IMODE(st[stat.ST_MODE])
# This used to generate a UserError when we forbid the source
# directory from being outside the top-level SConstruct dir.
@@ -403,8 +430,8 @@ class VariantDirTestCase(unittest.TestCase):
exc_caught = 1
assert exc_caught, "Should have caught a UserError."
finally:
- test.unlink( "src/foo" )
- test.unlink( "build/foo" )
+ test.unlink("src/foo")
+ test.unlink("build/foo")
fs = SCons.Node.FS.FS()
fs.VariantDir('build', 'src1')
@@ -423,18 +450,20 @@ class VariantDirTestCase(unittest.TestCase):
# Test against a former bug. Make sure we can get a repository
# path for the variant directory itself!
- fs=SCons.Node.FS.FS(test.workpath('work'))
- test.subdir('work')
+ fs = SCons.Node.FS.FS(test.workpath('work'))
+
+ # not needed this subdir is created above near line 188
+ # test.subdir('work')
fs.VariantDir('build/var3', 'src', duplicate=0)
d1 = fs.Dir('build/var3')
r = d1.rdir()
assert r == d1, "%s != %s" % (r, d1)
# verify the link creation attempts in file_link()
- class LinkSimulator (object):
+ class LinkSimulator(object):
"""A class to intercept os.[sym]link() calls and track them."""
- def __init__( self, duplicate, link, symlink, copy ) :
+ def __init__(self, duplicate, link, symlink, copy):
self.duplicate = duplicate
self.have = {}
self.have['hard'] = link
@@ -446,27 +475,28 @@ class VariantDirTestCase(unittest.TestCase):
if self.have[link]:
self.links_to_be_called.append(link)
- def link_fail( self , src , dest ) :
+ def link_fail(self, src, dest):
next_link = self.links_to_be_called.pop(0)
assert next_link == "hard", \
- "Wrong link order: expected %s to be called "\
- "instead of hard" % next_link
- raise OSError( "Simulating hard link creation error." )
+ "Wrong link order: expected %s to be called " \
+ "instead of hard" % next_link
+ raise OSError("Simulating hard link creation error.")
- def symlink_fail( self , src , dest ) :
+ def symlink_fail(self, src, dest):
next_link = self.links_to_be_called.pop(0)
assert next_link == "soft", \
- "Wrong link order: expected %s to be called "\
- "instead of soft" % next_link
- raise OSError( "Simulating symlink creation error." )
+ "Wrong link order: expected %s to be called " \
+ "instead of soft" % next_link
+ raise OSError("Simulating symlink creation error.")
- def copy( self , src , dest ) :
+ def copy(self, src, dest):
next_link = self.links_to_be_called.pop(0)
assert next_link == "copy", \
- "Wrong link order: expected %s to be called "\
- "instead of copy" % next_link
+ "Wrong link order: expected %s to be called " \
+ "instead of copy" % next_link
# copy succeeds, but use the real copy
self.have['copy'](src, dest)
+
# end class LinkSimulator
try:
@@ -538,33 +568,33 @@ class VariantDirTestCase(unittest.TestCase):
fs.VariantDir('work/src/b1/b2', 'work/src')
dir_list = [
- 'work/src',
- 'work/src/b1',
- 'work/src/b1/b2',
- 'work/src/b1/b2/b1',
- 'work/src/b1/b2/b1/b2',
- 'work/src/b1/b2/b1/b2/b1',
- 'work/src/b1/b2/b1/b2/b1/b2',
+ 'work/src',
+ 'work/src/b1',
+ 'work/src/b1/b2',
+ 'work/src/b1/b2/b1',
+ 'work/src/b1/b2/b1/b2',
+ 'work/src/b1/b2/b1/b2/b1',
+ 'work/src/b1/b2/b1/b2/b1/b2',
]
srcnode_map = {
- 'work/src/b1/b2' : 'work/src',
- 'work/src/b1/b2/f' : 'work/src/f',
- 'work/src/b1/b2/b1' : 'work/src/b1/',
- 'work/src/b1/b2/b1/f' : 'work/src/b1/f',
- 'work/src/b1/b2/b1/b2' : 'work/src/b1/b2',
- 'work/src/b1/b2/b1/b2/f' : 'work/src/b1/b2/f',
- 'work/src/b1/b2/b1/b2/b1' : 'work/src/b1/b2/b1',
- 'work/src/b1/b2/b1/b2/b1/f' : 'work/src/b1/b2/b1/f',
- 'work/src/b1/b2/b1/b2/b1/b2' : 'work/src/b1/b2/b1/b2',
- 'work/src/b1/b2/b1/b2/b1/b2/f' : 'work/src/b1/b2/b1/b2/f',
+ 'work/src/b1/b2': 'work/src',
+ 'work/src/b1/b2/f': 'work/src/f',
+ 'work/src/b1/b2/b1': 'work/src/b1/',
+ 'work/src/b1/b2/b1/f': 'work/src/b1/f',
+ 'work/src/b1/b2/b1/b2': 'work/src/b1/b2',
+ 'work/src/b1/b2/b1/b2/f': 'work/src/b1/b2/f',
+ 'work/src/b1/b2/b1/b2/b1': 'work/src/b1/b2/b1',
+ 'work/src/b1/b2/b1/b2/b1/f': 'work/src/b1/b2/b1/f',
+ 'work/src/b1/b2/b1/b2/b1/b2': 'work/src/b1/b2/b1/b2',
+ 'work/src/b1/b2/b1/b2/b1/b2/f': 'work/src/b1/b2/b1/b2/f',
}
alter_map = {
- 'work/src' : 'work/src/b1/b2',
- 'work/src/f' : 'work/src/b1/b2/f',
- 'work/src/b1' : 'work/src/b1/b2/b1',
- 'work/src/b1/f' : 'work/src/b1/b2/b1/f',
+ 'work/src': 'work/src/b1/b2',
+ 'work/src/f': 'work/src/b1/b2/f',
+ 'work/src/b1': 'work/src/b1/b2/b1',
+ 'work/src/b1/f': 'work/src/b1/b2/b1/f',
}
errors = 0
@@ -605,7 +635,8 @@ class VariantDirTestCase(unittest.TestCase):
print("File `%s' alter_targets() `%s' != expected `%s'" % (f, tp, expect))
errors = errors + 1
- self.failIf(errors)
+ self.assertFalse(errors)
+
class BaseTestCase(_tempdirTestCase):
def test_stat(self):
@@ -702,18 +733,21 @@ class BaseTestCase(_tempdirTestCase):
nonexistent = fs.Entry('nonexistent')
assert not nonexistent.islink()
+
class DirNodeInfoTestCase(_tempdirTestCase):
def test___init__(self):
"""Test DirNodeInfo initialization"""
ddd = self.fs.Dir('ddd')
ni = SCons.Node.FS.DirNodeInfo()
+
class DirBuildInfoTestCase(_tempdirTestCase):
def test___init__(self):
"""Test DirBuildInfo initialization"""
ddd = self.fs.Dir('ddd')
bi = SCons.Node.FS.DirBuildInfo()
+
class FileNodeInfoTestCase(_tempdirTestCase):
def test___init__(self):
"""Test FileNodeInfo initialization"""
@@ -759,6 +793,7 @@ class FileNodeInfoTestCase(_tempdirTestCase):
size = st[stat.ST_SIZE]
assert ni.size != size, (ni.size, size)
+
class FileBuildInfoTestCase(_tempdirTestCase):
def test___init__(self):
"""Test File.BuildInfo initialization"""
@@ -820,6 +855,7 @@ class FileBuildInfoTestCase(_tempdirTestCase):
format = bi1.format()
assert format == expect, (repr(expect), repr(format))
+
class FSTestCase(_tempdirTestCase):
def test_needs_normpath(self):
"""Test the needs_normpath Regular expression
@@ -861,7 +897,6 @@ class FSTestCase(_tempdirTestCase):
"/a./",
"/a../",
-
".a",
"..a",
"/.a",
@@ -870,7 +905,7 @@ class FSTestCase(_tempdirTestCase):
"..a/",
"/.a/",
"/..a/",
- ]
+ ]
for p in do_not_need_normpath:
assert needs_normpath_match(p) is None, p
@@ -918,7 +953,7 @@ class FSTestCase(_tempdirTestCase):
"../a",
"a/./a",
"a/../a",
- ]
+ ]
for p in needs_normpath:
assert needs_normpath_match(p) is not None, p
@@ -951,7 +986,7 @@ class FSTestCase(_tempdirTestCase):
assert isinstance(d1, SCons.Node.FS.Dir)
assert d1.cwd is d1, d1
- f1 = fs.File('f1', directory = d1)
+ f1 = fs.File('f1', directory=d1)
assert isinstance(f1, SCons.Node.FS.File)
d1_f1 = os.path.join('d1', 'f1')
@@ -1034,6 +1069,7 @@ class FSTestCase(_tempdirTestCase):
if p[0] == os.sep:
p = drive + p
return p
+
path = strip_slash(path_)
abspath = strip_slash(abspath_)
up_path = strip_slash(up_path_)
@@ -1047,51 +1083,51 @@ class FSTestCase(_tempdirTestCase):
name = os.sep
if dir.up() is None:
- dir_up_path = dir.get_internal_path()
+ dir_up_path = dir.get_internal_path()
else:
- dir_up_path = dir.up().get_internal_path()
+ dir_up_path = dir.up().get_internal_path()
assert dir.name == name, \
- "dir.name %s != expected name %s" % \
- (dir.name, name)
+ "dir.name %s != expected name %s" % \
+ (dir.name, name)
assert dir.get_internal_path() == path, \
- "dir.path %s != expected path %s" % \
- (dir.get_internal_path(), path)
+ "dir.path %s != expected path %s" % \
+ (dir.get_internal_path(), path)
assert str(dir) == path, \
- "str(dir) %s != expected path %s" % \
- (str(dir), path)
+ "str(dir) %s != expected path %s" % \
+ (str(dir), path)
assert dir.get_abspath() == abspath, \
- "dir.abspath %s != expected absolute path %s" % \
- (dir.get_abspath(), abspath)
+ "dir.abspath %s != expected absolute path %s" % \
+ (dir.get_abspath(), abspath)
assert dir_up_path == up_path, \
- "dir.up().path %s != expected parent path %s" % \
- (dir_up_path, up_path)
+ "dir.up().path %s != expected parent path %s" % \
+ (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/')
- Dir_test('/foo', '/foo/', '/foo/', '/')
- Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
- Dir_test('..', sub, sub, wp)
- Dir_test('foo/..', './', sub_dir, sub)
- Dir_test('../foo', sub_foo, sub_foo, sub)
- Dir_test('.', './', sub_dir, sub)
- Dir_test('./.', './', sub_dir, sub)
- Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
- Dir_test('#../foo', sub_foo, sub_foo, sub)
- Dir_test('#/../foo', sub_foo, sub_foo, sub)
- Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
- Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
- Dir_test('#', './', sub_dir, sub)
+
+ 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/')
+ Dir_test('/foo', '/foo/', '/foo/', '/')
+ Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
+ Dir_test('..', sub, sub, wp)
+ Dir_test('foo/..', './', sub_dir, sub)
+ Dir_test('../foo', sub_foo, sub_foo, sub)
+ Dir_test('.', './', sub_dir, sub)
+ Dir_test('./.', './', sub_dir, sub)
+ Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
+ Dir_test('#../foo', sub_foo, sub_foo, sub)
+ Dir_test('#/../foo', sub_foo, sub_foo, sub)
+ Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
+ Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
+ Dir_test('#', './', sub_dir, sub)
try:
- f2 = fs.File(sep.join(['f1', 'f2']), directory = d1)
+ f2 = fs.File(sep.join(['f1', 'f2']), directory=d1)
except TypeError as x:
assert str(x) == ("Tried to lookup File '%s' as a Dir." %
d1_f1), x
@@ -1133,13 +1169,15 @@ class FSTestCase(_tempdirTestCase):
e1 = fs.Entry(p)
e2 = fs.Entry(path)
assert e1 is e2, (e1, e2)
- assert str(e1) is str(e2), (str(e1), str(e2))
+ a = str(e1)
+ b = str(e2)
+ assert a == b, ("Strings should match for same file/node\n%s\n%s" % (a, b))
# Test for a bug in 0.04 that did not like looking up
# dirs with a trailing slash on Windows.
- d=fs.Dir('./')
+ d = fs.Dir('./')
assert d.get_internal_path() == '.', d.get_abspath()
- d=fs.Dir('foo/')
+ d = fs.Dir('foo/')
assert d.get_internal_path() == 'foo', d.get_abspath()
# Test for sub-classing of node building.
@@ -1147,7 +1185,7 @@ class FSTestCase(_tempdirTestCase):
built_it = None
assert not built_it
- d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
+ d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
d1.builder_set(Builder(fs.File))
d1.reset_executor()
d1.env_set(Environment())
@@ -1156,7 +1194,7 @@ class FSTestCase(_tempdirTestCase):
built_it = None
assert not built_it
- f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
+ f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
f1.builder_set(Builder(fs.File))
f1.reset_executor()
f1.env_set(Environment())
@@ -1240,9 +1278,11 @@ class FSTestCase(_tempdirTestCase):
class MyScanner(Scanner):
call_count = 0
+
def __call__(self, node, env, path):
self.call_count = self.call_count + 1
return Scanner.__call__(self, node, env, path)
+
s = MyScanner(xyz)
deps = f12.get_found_includes(env, s, t1)
@@ -1261,8 +1301,6 @@ class FSTestCase(_tempdirTestCase):
assert deps == [xyz], deps
assert s.call_count == 3, s.call_count
-
-
# Make sure we can scan this file even if the target isn't
# a file that has a scanner (it might be an Alias, e.g.).
class DummyNode(object):
@@ -1292,7 +1330,7 @@ class FSTestCase(_tempdirTestCase):
f1 = fs.File(test.workpath("do_i_exist"))
assert not f1.exists()
- test.write("do_i_exist","\n")
+ test.write("do_i_exist", "\n")
assert not f1.exists(), "exists() call not cached"
f1.built()
assert f1.exists(), "exists() call caching not reset"
@@ -1306,14 +1344,14 @@ class FSTestCase(_tempdirTestCase):
# get_contents() returns the binary contents.
test.write("binary_file", "Foo\x1aBar")
f1 = fs.File(test.workpath("binary_file"))
- assert f1.get_contents() == bytearray("Foo\x1aBar",'utf-8'), f1.get_contents()
+ assert f1.get_contents() == bytearray("Foo\x1aBar", 'utf-8'), f1.get_contents()
# This tests to make sure we can decode UTF-8 text files.
test_string = u"Foo\x1aBar"
test.write("utf8_file", test_string.encode('utf-8'))
f1 = fs.File(test.workpath("utf8_file"))
assert eval('f1.get_text_contents() == u"Foo\x1aBar"'), \
- f1.get_text_contents()
+ f1.get_text_contents()
# Check for string which doesn't have BOM and isn't valid
# ASCII
@@ -1321,11 +1359,11 @@ class FSTestCase(_tempdirTestCase):
test.write('latin1_file', test_string)
f1 = fs.File(test.workpath("latin1_file"))
assert f1.get_text_contents() == test_string.decode('latin-1'), \
- f1.get_text_contents()
+ f1.get_text_contents()
def nonexistent(method, s):
try:
- x = method(s, create = 0)
+ x = method(s, create=0)
except SCons.Errors.UserError:
pass
else:
@@ -1363,15 +1401,15 @@ class FSTestCase(_tempdirTestCase):
f = fs.File('f_local')
assert f._local == 0
- #XXX test_is_up_to_date() for directories
+ # XXX test_is_up_to_date() for directories
- #XXX test_sconsign() for directories
+ # XXX test_sconsign() for directories
- #XXX test_set_signature() for directories
+ # XXX test_set_signature() for directories
- #XXX test_build() for directories
+ # XXX test_build() for directories
- #XXX test_root()
+ # XXX test_root()
# test Entry.get_contents()
e = fs.Entry('does_not_exist')
@@ -1383,7 +1421,7 @@ class FSTestCase(_tempdirTestCase):
try:
e = fs.Entry('file')
c = e.get_contents()
- assert c == bytearray("file\n",'utf-8'), c
+ assert c == bytearray("file\n", 'utf-8'), c
assert e.__class__ == SCons.Node.FS.File
finally:
test.unlink("file")
@@ -1537,7 +1575,7 @@ class FSTestCase(_tempdirTestCase):
f = fs.Entry('foo/bar/baz')
assert f.for_signature() == 'baz', f.for_signature()
assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
- f.get_string(0)
+ f.get_string(0)
assert f.get_string(1) == 'baz', f.get_string(1)
def test_drive_letters(self):
@@ -1552,26 +1590,26 @@ class FSTestCase(_tempdirTestCase):
drive, path = os.path.splitdrive(x)
return 'X:' + path
- wp = drive_workpath([''])
+ wp = drive_workpath([''])
if wp[-1] in (os.sep, '/'):
- tmp = os.path.split(wp[:-1])[0]
+ tmp = os.path.split(wp[:-1])[0]
else:
- tmp = os.path.split(wp)[0]
+ tmp = os.path.split(wp)[0]
- parent_tmp = os.path.split(tmp)[0]
+ parent_tmp = os.path.split(tmp)[0]
if parent_tmp == 'X:':
parent_tmp = 'X:' + os.sep
- tmp_foo = os.path.join(tmp, 'foo')
+ tmp_foo = os.path.join(tmp, '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', ''])
+ 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', ''])
+ sub_foo = drive_workpath(['sub', 'foo', ''])
fs = SCons.Node.FS.FS()
@@ -1590,22 +1628,23 @@ class FSTestCase(_tempdirTestCase):
if p[-1] == os.sep and len(p) > 3:
p = p[:-1]
return p
+
path = strip_slash(path_)
up_path = strip_slash(up_path_)
name = path.split(os.sep)[-1]
assert dir.name == name, \
- "dir.name %s != expected name %s" % \
- (dir.name, name)
+ "dir.name %s != expected name %s" % \
+ (dir.name, name)
assert dir.get_internal_path() == path, \
- "dir.path %s != expected path %s" % \
- (dir.get_internal_path(), path)
+ "dir.path %s != expected path %s" % \
+ (dir.get_internal_path(), path)
assert str(dir) == path, \
- "str(dir) %s != expected path %s" % \
- (str(dir), path)
+ "str(dir) %s != expected path %s" % \
+ (str(dir), path)
assert dir.up().get_internal_path() == up_path, \
- "dir.up().path %s != expected parent path %s" % \
- (dir.up().get_internal_path(), up_path)
+ "dir.up().path %s != expected parent path %s" % \
+ (dir.up().get_internal_path(), up_path)
save_os_path = os.path
save_os_sep = os.sep
@@ -1616,26 +1655,25 @@ class FSTestCase(_tempdirTestCase):
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('#X:', wp, tmp)
- Dir_test('X:foo', foo, wp)
- Dir_test('X:foo/bar', foo_bar, foo)
- Dir_test('X:/foo', 'X:/foo', 'X:/')
- Dir_test('X:/foo/bar', 'X:/foo/bar/', 'X:/foo/')
- Dir_test('X:..', tmp, parent_tmp)
- Dir_test('X:foo/..', wp, tmp)
- Dir_test('X:../foo', tmp_foo, tmp)
- Dir_test('X:.', wp, tmp)
- Dir_test('X:./.', wp, tmp)
- Dir_test('X:foo/./bar', foo_bar, foo)
- Dir_test('#X:../foo', tmp_foo, tmp)
- Dir_test('#X:/../foo', tmp_foo, tmp)
- Dir_test('#X:foo/bar', foo_bar, foo)
- Dir_test('#X:/foo/bar', foo_bar, foo)
- Dir_test('#X:/', wp, tmp)
+ Dir_test('#X:', wp, tmp)
+ Dir_test('X:foo', foo, wp)
+ Dir_test('X:foo/bar', foo_bar, foo)
+ Dir_test('X:/foo', 'X:/foo', 'X:/')
+ Dir_test('X:/foo/bar', 'X:/foo/bar/', 'X:/foo/')
+ Dir_test('X:..', tmp, parent_tmp)
+ Dir_test('X:foo/..', wp, tmp)
+ Dir_test('X:../foo', tmp_foo, tmp)
+ Dir_test('X:.', wp, tmp)
+ Dir_test('X:./.', wp, tmp)
+ Dir_test('X:foo/./bar', foo_bar, foo)
+ Dir_test('#X:../foo', tmp_foo, tmp)
+ Dir_test('#X:/../foo', tmp_foo, tmp)
+ Dir_test('#X:foo/bar', foo_bar, foo)
+ Dir_test('#X:/foo/bar', foo_bar, foo)
+ Dir_test('#X:/', wp, tmp)
finally:
os.path = save_os_path
os.sep = save_os_sep
@@ -1657,28 +1695,33 @@ class FSTestCase(_tempdirTestCase):
import ntpath
x = test.workpath(*dirs)
drive, path = ntpath.splitdrive(x)
- unc, path = ntpath.splitunc(path)
+ try:
+ unc, path = ntpath.splitunc(path)
+ except AttributeError:
+ # could be python 3.7 or newer, make sure splitdrive can do UNC
+ assert ntpath.splitdrive(r'\\split\drive\test')[0] == r'\\split\drive'
+ pass
path = strip_slash(path)
return '//' + path[1:]
- wp = unc_workpath([''])
+ wp = unc_workpath([''])
if wp[-1] in (os.sep, '/'):
- tmp = os.path.split(wp[:-1])[0]
+ tmp = os.path.split(wp[:-1])[0]
else:
- tmp = os.path.split(wp)[0]
+ tmp = os.path.split(wp)[0]
- parent_tmp = os.path.split(tmp)[0]
+ parent_tmp = os.path.split(tmp)[0]
- tmp_foo = os.path.join(tmp, 'foo')
+ 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', ''])
+ 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', ''])
+ sub_foo = unc_workpath(['sub', 'foo', ''])
fs = SCons.Node.FS.FS()
@@ -1699,22 +1742,22 @@ class FSTestCase(_tempdirTestCase):
name = path.split(os.sep)[-1]
if dir.up() is None:
- dir_up_path = dir.get_internal_path()
+ dir_up_path = dir.get_internal_path()
else:
- dir_up_path = dir.up().get_internal_path()
+ dir_up_path = dir.up().get_internal_path()
assert dir.name == name, \
- "dir.name %s != expected name %s" % \
- (dir.name, name)
+ "dir.name %s != expected name %s" % \
+ (dir.name, name)
assert dir.get_internal_path() == path, \
- "dir.path %s != expected path %s" % \
- (dir.get_internal_path(), path)
+ "dir.path %s != expected path %s" % \
+ (dir.get_internal_path(), path)
assert str(dir) == path, \
- "str(dir) %s != expected path %s" % \
- (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().get_internal_path(), up_path)
+ "dir.up().path %s != expected parent path %s" % \
+ (dir.up().get_internal_path(), up_path)
save_os_path = os.path
save_os_sep = os.sep
@@ -1725,28 +1768,27 @@ class FSTestCase(_tempdirTestCase):
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)
+ 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
@@ -1801,7 +1843,7 @@ class FSTestCase(_tempdirTestCase):
d1 = fs.Dir('d1')
d2 = d1.Dir('d2')
dirs = os.path.normpath(d2.get_abspath()).split(os.sep)
- above_path = os.path.join(*['..']*len(dirs) + ['above'])
+ above_path = os.path.join(*['..'] * len(dirs) + ['above'])
above = d2.Dir(above_path)
def test_lookup_abs(self):
@@ -1819,13 +1861,13 @@ class FSTestCase(_tempdirTestCase):
return
test = self.test
fs = self.fs
- path='//servername/C$/foo'
+ 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)
-
+ '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',):
@@ -1860,56 +1902,56 @@ class FSTestCase(_tempdirTestCase):
d3_d4_f = d3_d4.File('f')
cases = [
- d1, d1, '.',
- d1, d1_f, 'f',
- d1, d1_d2, 'd2',
- d1, d1_d2_f, 'd2/f',
- d1, d3, '../d3',
- d1, d3_f, '../d3/f',
- d1, d3_d4, '../d3/d4',
- d1, d3_d4_f, '../d3/d4/f',
-
- d1_f, d1, '.',
- d1_f, d1_f, 'f',
- d1_f, d1_d2, 'd2',
- d1_f, d1_d2_f, 'd2/f',
- d1_f, d3, '../d3',
- d1_f, d3_f, '../d3/f',
- d1_f, d3_d4, '../d3/d4',
- d1_f, d3_d4_f, '../d3/d4/f',
-
- d1_d2, d1, '..',
- d1_d2, d1_f, '../f',
- d1_d2, d1_d2, '.',
- d1_d2, d1_d2_f, 'f',
- d1_d2, d3, '../../d3',
- d1_d2, d3_f, '../../d3/f',
- d1_d2, d3_d4, '../../d3/d4',
- d1_d2, d3_d4_f, '../../d3/d4/f',
-
- d1_d2_f, d1, '..',
- d1_d2_f, d1_f, '../f',
- d1_d2_f, d1_d2, '.',
- d1_d2_f, d1_d2_f, 'f',
- d1_d2_f, d3, '../../d3',
- d1_d2_f, d3_f, '../../d3/f',
- d1_d2_f, d3_d4, '../../d3/d4',
- d1_d2_f, d3_d4_f, '../../d3/d4/f',
+ d1, d1, '.',
+ d1, d1_f, 'f',
+ d1, d1_d2, 'd2',
+ d1, d1_d2_f, 'd2/f',
+ d1, d3, '../d3',
+ d1, d3_f, '../d3/f',
+ d1, d3_d4, '../d3/d4',
+ d1, d3_d4_f, '../d3/d4/f',
+
+ d1_f, d1, '.',
+ d1_f, d1_f, 'f',
+ d1_f, d1_d2, 'd2',
+ d1_f, d1_d2_f, 'd2/f',
+ d1_f, d3, '../d3',
+ d1_f, d3_f, '../d3/f',
+ d1_f, d3_d4, '../d3/d4',
+ d1_f, d3_d4_f, '../d3/d4/f',
+
+ d1_d2, d1, '..',
+ d1_d2, d1_f, '../f',
+ d1_d2, d1_d2, '.',
+ d1_d2, d1_d2_f, 'f',
+ d1_d2, d3, '../../d3',
+ d1_d2, d3_f, '../../d3/f',
+ d1_d2, d3_d4, '../../d3/d4',
+ d1_d2, d3_d4_f, '../../d3/d4/f',
+
+ d1_d2_f, d1, '..',
+ d1_d2_f, d1_f, '../f',
+ d1_d2_f, d1_d2, '.',
+ d1_d2_f, d1_d2_f, 'f',
+ d1_d2_f, d3, '../../d3',
+ d1_d2_f, d3_f, '../../d3/f',
+ d1_d2_f, d3_d4, '../../d3/d4',
+ d1_d2_f, d3_d4_f, '../../d3/d4/f',
]
if sys.platform in ('win32',):
- x_d1 = fs.Dir(r'X:\d1')
- x_d1_d2 = x_d1.Dir('d2')
- y_d1 = fs.Dir(r'Y:\d1')
- y_d1_d2 = y_d1.Dir('d2')
- y_d2 = fs.Dir(r'Y:\d2')
+ x_d1 = fs.Dir(r'X:\d1')
+ x_d1_d2 = x_d1.Dir('d2')
+ y_d1 = fs.Dir(r'Y:\d1')
+ y_d1_d2 = y_d1.Dir('d2')
+ y_d2 = fs.Dir(r'Y:\d2')
win32_cases = [
- x_d1, x_d1, '.',
- x_d1, x_d1_d2, 'd2',
- x_d1, y_d1, r'Y:\d1',
- x_d1, y_d1_d2, r'Y:\d1\d2',
- x_d1, y_d2, r'Y:\d2',
+ x_d1, x_d1, '.',
+ x_d1, x_d1_d2, 'd2',
+ x_d1, y_d1, r'Y:\d1',
+ x_d1, y_d1_d2, r'Y:\d1\d2',
+ x_d1, y_d2, r'Y:\d2',
]
cases.extend(win32_cases)
@@ -1930,14 +1972,15 @@ class FSTestCase(_tempdirTestCase):
def test_proxy(self):
"""Test a Node.FS object wrapped in a proxy instance"""
f1 = self.fs.File('fff')
+
class MyProxy(SCons.Util.Proxy):
__str__ = SCons.Util.Delegate('__str__')
+
p = MyProxy(f1)
f2 = self.fs.Entry(p)
assert f1 is f2, (f1, str(f1), f2, str(f2))
-
class DirTestCase(_tempdirTestCase):
def test__morph(self):
@@ -1954,8 +1997,10 @@ class DirTestCase(_tempdirTestCase):
def test_subclass(self):
"""Test looking up subclass of Dir nodes"""
+
class DirSubclass(SCons.Node.FS.Dir):
pass
+
sd = self.fs._lookup('special_dir', None, DirSubclass, create=1)
sd.must_be_same(SCons.Node.FS.Dir)
@@ -2002,9 +2047,9 @@ class DirTestCase(_tempdirTestCase):
test.subdir('d')
test.write(['d', 'g'], "67890\n")
test.write(['d', 'f'], "12345\n")
- test.subdir(['d','sub'])
- test.write(['d', 'sub','h'], "abcdef\n")
- test.subdir(['d','empty'])
+ test.subdir(['d', 'sub'])
+ test.write(['d', 'sub', 'h'], "abcdef\n")
+ test.subdir(['d', 'empty'])
d = self.fs.Dir('d')
g = self.fs.File(os.path.join('d', 'g'))
@@ -2017,10 +2062,10 @@ class DirTestCase(_tempdirTestCase):
assert e.get_contents() == '', e.get_contents()
assert e.get_text_contents() == '', e.get_text_contents()
- assert e.get_csig()+" empty" == files[0], files
- assert f.get_csig()+" f" == files[1], files
- assert g.get_csig()+" g" == files[2], files
- assert s.get_csig()+" sub" == files[3], files
+ assert e.get_csig() + " empty" == files[0], files
+ assert f.get_csig() + " f" == files[1], files
+ assert g.get_csig() + " g" == files[2], files
+ assert s.get_csig() + " sub" == files[3], files
def test_implicit_re_scans(self):
"""Test that adding entries causes a directory to be re-scanned
@@ -2078,7 +2123,7 @@ class DirTestCase(_tempdirTestCase):
d = self.fs.Dir('d')
r = self.fs.Dir('r')
d.addRepository(r)
-
+
assert d.rentry_exists_on_disk('exists')
assert d.rentry_exists_on_disk('rexists')
assert not d.rentry_exists_on_disk('does_not_exist')
@@ -2184,7 +2229,7 @@ class DirTestCase(_tempdirTestCase):
SCons.Node._is_derived_map[2] = return_true
SCons.Node._exists_map[5] = return_true
-
+
test.subdir('src0')
test.write(['src0', 'on-disk-f1'], "src0/on-disk-f1\n")
test.write(['src0', 'on-disk-f2'], "src0/on-disk-f2\n")
@@ -2332,6 +2377,7 @@ class DirTestCase(_tempdirTestCase):
r = sub.file_on_disk('dir')
assert not r, r
+
class EntryTestCase(_tempdirTestCase):
def test_runTest(self):
"""Test methods specific to the Entry sub-class.
@@ -2382,16 +2428,20 @@ class EntryTestCase(_tempdirTestCase):
class MyCalc(object):
def __init__(self, val):
self.max_drift = 0
+
class M(object):
def __init__(self, val):
self.val = val
+
def collect(self, args):
result = 0
for a in args:
result += a
return result
+
def signature(self, executor):
return self.val + 222
+
self.module = M(val)
test.subdir('e5d')
@@ -2403,13 +2453,14 @@ class EntryTestCase(_tempdirTestCase):
self.fs.Entry('#topdir/a/b/c')
-
class FileTestCase(_tempdirTestCase):
def test_subclass(self):
"""Test looking up subclass of File nodes"""
+
class FileSubclass(SCons.Node.FS.File):
pass
+
sd = self.fs._lookup('special_file', None, FileSubclass, create=1)
sd.must_be_same(SCons.Node.FS.File)
@@ -2453,8 +2504,144 @@ class FileTestCase(_tempdirTestCase):
build_f1.clear()
build_f1.linked = None
assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1)
- assert not os.path.exists(build_f1.get_abspath()), "%s did not get removed after %s was removed" % (build_f1, src_f1)
+ assert not os.path.exists(build_f1.get_abspath()), "%s did not get removed after %s was removed" % (
+ build_f1, src_f1)
+
+ def test_changed(self):
+ """
+ Verify that changes between BuildInfo's list of souces, depends, and implicit
+ dependencies do not corrupt content signature values written to .SConsign
+ when using CacheDir and Timestamp-MD5 decider.
+ This is for issue #2980
+ """
+
+ # node should have
+ # 1 source (for example main.cpp)
+ # 0 depends
+ # N implicits (for example ['alpha.h', 'beta.h', 'gamma.h', '/usr/bin/g++'])
+
+ class ChangedNode(SCons.Node.FS.File):
+ def __init__(self, name, directory=None, fs=None):
+ SCons.Node.FS.File.__init__(self, name, directory, fs)
+ self.name = name
+ self.Tag('found_includes', [])
+ self.stored_info = None
+ self.build_env = None
+ self.changed_since_last_build = 4
+ self.timestamp = 1
+
+ def get_stored_info(self):
+ return self.stored_info
+
+ def get_build_env(self):
+ return self.build_env
+
+ def get_timestamp(self):
+ """ Fake timestamp so they always match"""
+ return self.timestamp
+ def get_contents(self):
+ return self.name
+
+ def get_ninfo(self):
+ """ mocked to ensure csig will equal the filename"""
+ try:
+ return self.ninfo
+ except AttributeError:
+ self.ninfo = FakeNodeInfo(self.name, self.timestamp)
+ return self.ninfo
+
+ def get_csig(self):
+ ninfo = self.get_ninfo()
+ try:
+ return ninfo.csig
+ except AttributeError:
+ pass
+
+ return "Should Never Happen"
+
+ class ChangedEnvironment(SCons.Environment.Base):
+
+ def __init__(self):
+ SCons.Environment.Base.__init__(self)
+ self.decide_source = self._changed_timestamp_then_content
+
+ class FakeNodeInfo(object):
+ def __init__(self, csig, timestamp):
+ self.csig = csig
+ self.timestamp = timestamp
+
+ # Create nodes
+ fs = SCons.Node.FS.FS()
+ d = self.fs.Dir('.')
+
+ node = ChangedNode('main.o', d, fs) # main.o
+ s1 = ChangedNode('main.cpp', d, fs) # main.cpp
+ s1.timestamp = 2 # this changed
+ i1 = ChangedNode('alpha.h', d, fs) # alpha.h - The bug is caused because the second build adds this file
+ i1.timestamp = 2 # This is the new file.
+ i2 = ChangedNode('beta.h', d, fs) # beta.h
+ i3 = ChangedNode('gamma.h', d, fs) # gamma.h - In the bug beta.h's csig from binfo overwrites this ones
+ i4 = ChangedNode('/usr/bin/g++', d, fs) # /usr/bin/g++
+
+ node.add_source([s1])
+ node.add_dependency([])
+ node.implicit = [i1, i2, i3, i4]
+ node.implicit_set = set()
+ # node._add_child(node.implicit, node.implicit_set, [n7, n8, n9])
+ # node._add_child(node.implicit, node.implicit_set, [n10, n11, n12])
+
+ # Mock out node's scan method
+ # node.scan = lambda *args: None
+
+ # Mock out nodes' children() ?
+ # Should return Node's.
+ # All those nodes should have changed_since_last_build set to match Timestamp-MD5's
+ # decider method...
+
+ # Generate sconsign entry needed
+ sconsign_entry = SCons.SConsign.SConsignEntry()
+ sconsign_entry.binfo = node.new_binfo()
+ sconsign_entry.ninfo = node.new_ninfo()
+
+ # mock out loading info from sconsign
+ # This will cause node.get_stored_info() to return our freshly created sconsign_entry
+ node.stored_info = sconsign_entry
+
+ # binfo = information from previous build (from sconsign)
+ # We'll set the following attributes (which are lists): "bsources", "bsourcesigs",
+ # "bdepends","bdependsigs", "bimplicit", "bimplicitsigs"
+ bi = sconsign_entry.binfo
+ bi.bsources = ['main.cpp']
+ bi.bsourcesigs = [FakeNodeInfo('main.cpp', 1), ]
+
+ bi.bdepends = []
+ bi.bdependsigs = []
+
+ bi.bimplicit = ['beta.h', 'gamma.h']
+ bi.bimplicitsigs = [FakeNodeInfo('beta.h', 1), FakeNodeInfo('gamma.h', 1)]
+
+ ni = sconsign_entry.ninfo
+ # We'll set the following attributes (which are lists): sources, depends, implicit lists
+
+ # Set timestamp-md5
+ # Call changed
+ # Check results
+ node.build_env = ChangedEnvironment()
+
+ changed = node.changed()
+
+ # change to true to debug
+ if False:
+ print("Changed:%s" % changed)
+ print("%15s -> csig:%s" % (s1.name, s1.ninfo.csig))
+ print("%15s -> csig:%s" % (i1.name, i1.ninfo.csig))
+ print("%15s -> csig:%s" % (i2.name, i2.ninfo.csig))
+ print("%15s -> csig:%s" % (i3.name, i3.ninfo.csig))
+ print("%15s -> csig:%s" % (i4.name, i4.ninfo.csig))
+
+ self.assertEqual(i2.name, i2.ninfo.csig,
+ "gamma.h's fake csig should equal gamma.h but equals:%s" % i2.ninfo.csig)
class GlobTestCase(_tempdirTestCase):
@@ -2523,7 +2710,6 @@ class GlobTestCase(_tempdirTestCase):
self.sub_dir3_jjj = self.sub_dir3.File('jjj')
self.sub_dir3_lll = self.sub_dir3.File('lll')
-
def do_cases(self, cases, **kwargs):
# First, execute all of the cases with string=True and verify
@@ -2571,17 +2757,17 @@ class GlobTestCase(_tempdirTestCase):
join = os.path.join
cases = (
- ('ggg', ['ggg'], [self.ggg]),
+ ('ggg', ['ggg'], [self.ggg]),
- ('subdir1', ['subdir1'], [self.subdir1]),
+ ('subdir1', ['subdir1'], [self.subdir1]),
- ('subdir1/jjj', [join('subdir1', 'jjj')], [self.subdir1_jjj]),
+ ('subdir1/jjj', [join('subdir1', 'jjj')], [self.subdir1_jjj]),
- ('disk-aaa', ['disk-aaa'], None),
+ ('disk-aaa', ['disk-aaa'], None),
- ('disk-sub', ['disk-sub'], None),
+ ('disk-sub', ['disk-sub'], None),
- ('both-aaa', ['both-aaa'], []),
+ ('both-aaa', ['both-aaa'], []),
)
self.do_cases(cases)
@@ -2676,8 +2862,8 @@ class GlobTestCase(_tempdirTestCase):
"""Test globbing for things that don't exist"""
cases = (
- ('does_not_exist', [], []),
- ('no_subdir/*', [], []),
+ ('does_not_exist', [], []),
+ ('no_subdir/*', [], []),
('subdir?/no_file', [], []),
)
@@ -2785,7 +2971,7 @@ class GlobTestCase(_tempdirTestCase):
assert g == expect, str(g) + " is not sorted, but should be!"
g = self.fs.Glob('disk-*', strings=True)
- expect = [ 'disk-aaa', 'disk-bbb', 'disk-ccc', 'disk-sub' ]
+ expect = ['disk-aaa', 'disk-bbb', 'disk-ccc', 'disk-sub']
assert g == expect, str(g) + " is not sorted, but should be!"
@@ -2918,10 +3104,13 @@ class RepositoryTestCase(_tempdirTestCase):
def test_rdir(self):
"""Test the Dir.rdir() method"""
+
def return_true(obj):
return 1
+
def return_false(obj):
return 0
+
SCons.Node._exists_map[5] = return_true
SCons.Node._exists_map[6] = return_false
SCons.Node._is_derived_map[2] = return_true
@@ -2971,10 +3160,13 @@ class RepositoryTestCase(_tempdirTestCase):
def test_rfile(self):
"""Test the File.rfile() method"""
+
def return_true(obj):
return 1
+
def return_false(obj):
return 0
+
SCons.Node._exists_map[5] = return_true
SCons.Node._exists_map[6] = return_false
SCons.Node._is_derived_map[2] = return_true
@@ -3113,7 +3305,7 @@ class RepositoryTestCase(_tempdirTestCase):
test.write(["rep3", "contents"], "Con\x1aTents\n")
try:
c = fs.File("contents").get_contents()
- assert c == bytearray("Con\x1aTents\n",'utf-8'), "got '%s'" % c
+ assert c == bytearray("Con\x1aTents\n", 'utf-8'), "got '%s'" % c
finally:
test.unlink(["rep3", "contents"])
@@ -3132,8 +3324,8 @@ class RepositoryTestCase(_tempdirTestCase):
class FakeUnicodeString(collections.UserString):
def encode(self, encoding):
return str(self)
- test_string = FakeUnicodeString("Con\x1aTents\n")
+ test_string = FakeUnicodeString("Con\x1aTents\n")
# Test with ASCII.
test.write(["rep3", "contents"], test_string.encode('ascii'))
@@ -3159,14 +3351,13 @@ class RepositoryTestCase(_tempdirTestCase):
finally:
test.unlink(["rep3", "contents"])
- #def test_is_up_to_date(self):
-
+ # def test_is_up_to_date(self):
class find_fileTestCase(unittest.TestCase):
def runTest(self):
"""Testing find_file function"""
- test = TestCmd(workdir = '')
+ test = TestCmd(workdir='')
test.write('./foo', 'Some file\n')
test.write('./foo2', 'Another file\n')
test.subdir('same')
@@ -3179,9 +3370,9 @@ class find_fileTestCase(unittest.TestCase):
os.chdir(test.workpath(""))
node_derived = fs.File(test.workpath('bar/baz'))
- node_derived.builder_set(1) # Any non-zero value.
+ node_derived.builder_set(1) # Any non-zero value.
node_pseudo = fs.File(test.workpath('pseudo'))
- node_pseudo.set_src_builder(1) # Any non-zero value.
+ node_pseudo.set_src_builder(1) # Any non-zero value.
paths = tuple(map(fs.Dir, ['.', 'same', './bar']))
nodes = [SCons.Node.FS.find_file('foo', paths)]
@@ -3234,12 +3425,13 @@ class find_fileTestCase(unittest.TestCase):
finally:
sys.stdout = save_sys_stdout
+
class StringDirTestCase(unittest.TestCase):
def runTest(self):
"""Test using a string as the second argument of
File() and Dir()"""
- test = TestCmd(workdir = '')
+ test = TestCmd(workdir='')
test.subdir('sub')
fs = SCons.Node.FS.FS(test.workpath(''))
@@ -3250,10 +3442,11 @@ class StringDirTestCase(unittest.TestCase):
assert str(f) == os.path.join('sub', 'file')
assert not f.exists()
+
class stored_infoTestCase(unittest.TestCase):
def runTest(self):
"""Test how we store build information"""
- test = TestCmd(workdir = '')
+ test = TestCmd(workdir='')
test.subdir('sub')
fs = SCons.Node.FS.FS(test.workpath(''))
@@ -3266,9 +3459,10 @@ class stored_infoTestCase(unittest.TestCase):
class Null(object):
def __init__(self):
self.xyzzy = 7
+
def get_entry(self, name):
return self.Null()
-
+
def test_sconsign(node):
return MySConsign()
@@ -3278,10 +3472,11 @@ class stored_infoTestCase(unittest.TestCase):
bi = f.get_stored_info()
assert bi.xyzzy == 7, bi
+
class has_src_builderTestCase(unittest.TestCase):
def runTest(self):
"""Test the has_src_builder() method"""
- test = TestCmd(workdir = '')
+ test = TestCmd(workdir='')
fs = SCons.Node.FS.FS(test.workpath(''))
os.chdir(test.workpath(''))
test.subdir('sub1')
@@ -3300,9 +3495,9 @@ class has_src_builderTestCase(unittest.TestCase):
sub1.set_src_builder(b1)
test.write(['sub1', 'f2'], "sub1/f2\n")
- h = f1.has_src_builder() # cached from previous call
+ h = f1.has_src_builder() # cached from previous call
assert not h, h
- h = f1.has_builder() # cached from previous call
+ h = f1.has_builder() # cached from previous call
assert not h, h
h = f2.has_src_builder()
assert not h, h
@@ -3314,6 +3509,7 @@ class has_src_builderTestCase(unittest.TestCase):
assert h, h
assert f3.builder is b1, f3.builder
+
class prepareTestCase(unittest.TestCase):
def runTest(self):
"""Test the prepare() method"""
@@ -3321,6 +3517,7 @@ class prepareTestCase(unittest.TestCase):
class MyFile(SCons.Node.FS.File):
def _createDir(self, update=None):
raise SCons.Errors.StopError
+
def exists(self):
return None
@@ -3337,6 +3534,7 @@ class prepareTestCase(unittest.TestCase):
class MkdirAction(Action):
def __init__(self, dir_made):
self.dir_made = dir_made
+
def __call__(self, target, source, env, executor=None):
if executor:
target = executor.get_all_targets()
@@ -3361,7 +3559,6 @@ class prepareTestCase(unittest.TestCase):
dir.prepare()
-
class SConstruct_dirTestCase(unittest.TestCase):
def runTest(self):
"""Test setting the SConstruct directory"""
@@ -3371,7 +3568,6 @@ class SConstruct_dirTestCase(unittest.TestCase):
assert fs.SConstruct_dir.get_internal_path() == 'xxx'
-
class CacheDirTestCase(unittest.TestCase):
def test_get_cachedir_csig(self):
@@ -3382,7 +3578,6 @@ class CacheDirTestCase(unittest.TestCase):
assert r == 'd41d8cd98f00b204e9800998ecf8427e', r
-
class clearTestCase(unittest.TestCase):
def runTest(self):
"""Test clearing FS nodes of cached data."""
@@ -3392,11 +3587,11 @@ class clearTestCase(unittest.TestCase):
e = fs.Entry('e')
assert not e.exists()
assert not e.rexists()
- assert str(e) == 'e', str(d)
+ assert str(e) == 'e', str(e)
e.clear()
assert not e.exists()
assert not e.rexists()
- assert str(e) == 'e', str(d)
+ assert str(e) == 'e', str(e)
d = fs.Dir(test.workpath('d'))
test.subdir('d')
@@ -3410,10 +3605,10 @@ class clearTestCase(unittest.TestCase):
assert str(d) == test.workpath('d'), str(d)
# Now verify clear() resets the cache
d.clear()
- assert not d.exists()
+ assert not d.exists()
assert not d.rexists()
assert str(d) == test.workpath('d'), str(d)
-
+
f = fs.File(test.workpath('f'))
test.write(test.workpath('f'), 'file f')
assert f.exists()
@@ -3431,7 +3626,6 @@ class clearTestCase(unittest.TestCase):
assert str(f) == test.workpath('f'), str(f)
-
class disambiguateTestCase(unittest.TestCase):
def runTest(self):
"""Test calling the disambiguate() method."""
@@ -3493,6 +3687,7 @@ class disambiguateTestCase(unittest.TestCase):
f = build_nonexistant.disambiguate()
assert f.__class__ is fff.__class__, f.__class__
+
class postprocessTestCase(unittest.TestCase):
def runTest(self):
"""Test calling the postprocess() method."""
@@ -3508,11 +3703,10 @@ class postprocessTestCase(unittest.TestCase):
f.postprocess()
-
class SpecialAttrTestCase(unittest.TestCase):
def runTest(self):
"""Test special attributes of file nodes."""
- test=TestCmd(workdir='')
+ test = TestCmd(workdir='')
fs = SCons.Node.FS.FS(test.workpath('work'))
f = fs.Entry('foo/bar/baz.blat').get_subst_proxy()
@@ -3667,11 +3861,10 @@ class SpecialAttrTestCase(unittest.TestCase):
assert caught, "did not catch expected AttributeError"
-
class SaveStringsTestCase(unittest.TestCase):
def runTest(self):
"""Test caching string values of nodes."""
- test=TestCmd(workdir='')
+ test = TestCmd(workdir='')
def setup(fs):
fs.Dir('src')
@@ -3725,13 +3918,13 @@ class SaveStringsTestCase(unittest.TestCase):
s = list(map(str, nodes))
expect = list(map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b']))
- assert s == expect, 'node str() not cached: %s'%s
+ assert s == expect, 'node str() not cached: %s' % s
class AbsolutePathTestCase(unittest.TestCase):
def test_root_lookup_equivalence(self):
"""Test looking up /fff vs. fff in the / directory"""
- test=TestCmd(workdir='')
+ test = TestCmd(workdir='')
fs = SCons.Node.FS.FS('/')
@@ -3745,40 +3938,8 @@ class AbsolutePathTestCase(unittest.TestCase):
os.chdir(save_cwd)
-
if __name__ == "__main__":
- suite = unittest.TestSuite()
- suite.addTest(VariantDirTestCase())
- suite.addTest(find_fileTestCase())
- suite.addTest(StringDirTestCase())
- suite.addTest(stored_infoTestCase())
- suite.addTest(has_src_builderTestCase())
- suite.addTest(prepareTestCase())
- suite.addTest(SConstruct_dirTestCase())
- suite.addTest(clearTestCase())
- suite.addTest(disambiguateTestCase())
- suite.addTest(postprocessTestCase())
- suite.addTest(SpecialAttrTestCase())
- suite.addTest(SaveStringsTestCase())
- tclasses = [
- AbsolutePathTestCase,
- BaseTestCase,
- CacheDirTestCase,
- DirTestCase,
- DirBuildInfoTestCase,
- DirNodeInfoTestCase,
- EntryTestCase,
- FileTestCase,
- FileBuildInfoTestCase,
- FileNodeInfoTestCase,
- FSTestCase,
- GlobTestCase,
- RepositoryTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py
index e50616a..ce44b7d 100644
--- a/src/engine/SCons/Node/NodeTests.py
+++ b/src/engine/SCons/Node/NodeTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/NodeTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -30,8 +30,6 @@ import re
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Node
import SCons.Util
@@ -273,7 +271,7 @@ class NodeInfoBaseTestCase(unittest.TestCase):
f = ni1.format()
assert f == ['x', 'y', 'z'], f
-
+
field_list = ['xxx', 'zzz', 'aaa']
f = ni1.format(field_list)
@@ -753,7 +751,7 @@ class NodeTestCase(unittest.TestCase):
e = node.exists()
assert e == 1, e
- def test_exists(self):
+ def test_exists_repo(self):
"""Test evaluating whether a Node exists locally or in a repository.
"""
node = SCons.Node.Node()
@@ -1337,9 +1335,9 @@ class NodeListTestCase(unittest.TestCase):
assert s == "['n3', 'n2', 'n1']", s
r = repr(nl)
- r = re.sub('at (0[xX])?[0-9a-fA-F]+', 'at 0x', r)
+ r = re.sub(r'at (0[xX])?[0-9a-fA-F]+', 'at 0x', r)
# Don't care about ancestry: just leaf value of MyNode
- r = re.sub('<.*?\.MyNode', '<MyNode', r)
+ r = re.sub(r'<.*?\.MyNode', '<MyNode', r)
# New-style classes report as "object"; classic classes report
# as "instance"...
r = re.sub("object", "instance", r)
@@ -1349,15 +1347,8 @@ class NodeListTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ BuildInfoBaseTestCase,
- NodeInfoBaseTestCase,
- NodeTestCase,
- NodeListTestCase ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
+
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
index 06cb93a..d338051 100644
--- a/src/engine/SCons/Node/Python.py
+++ b/src/engine/SCons/Node/Python.py
@@ -5,7 +5,7 @@ Python nodes.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/Python.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Node
@@ -137,6 +137,10 @@ class Value(SCons.Node.Node):
return contents
def get_contents(self):
+ """
+ Get contents for signature calculations.
+ :return: bytes
+ """
text_contents = self.get_text_contents()
try:
return text_contents.encode()
@@ -155,12 +159,17 @@ class Value(SCons.Node.Node):
def get_csig(self, calc=None):
"""Because we're a Python value node and don't have a real
timestamp, we get to ignore the calculator and just use the
- value contents."""
+ value contents.
+
+ Returns string. Ideally string of hex digits. (Not bytes)
+ """
try:
return self.ninfo.csig
except AttributeError:
pass
- contents = self.get_contents()
+
+ contents = self.get_text_contents()
+
self.get_ninfo().csig = contents
return contents
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
index aab7e85..98137c7 100644
--- a/src/engine/SCons/Node/PythonTests.py
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Node/PythonTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/PythonTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Node.Python
@@ -90,15 +88,15 @@ class ValueTestCase(unittest.TestCase):
"""
v1 = SCons.Node.Python.Value('aaa')
csig = v1.get_csig(None)
- assert csig.decode() == 'aaa', csig
+ assert csig == 'aaa', csig
v2 = SCons.Node.Python.Value(7)
csig = v2.get_csig(None)
- assert csig.decode() == '7', csig
+ assert csig == '7', csig
v3 = SCons.Node.Python.Value(None)
csig = v3.get_csig(None)
- assert csig.decode() == 'None', csig
+ assert csig == 'None', csig
class ValueNodeInfoTestCase(unittest.TestCase):
def test___init__(self):
@@ -113,16 +111,7 @@ class ValueBuildInfoTestCase(unittest.TestCase):
bi = SCons.Node.Python.ValueBuildInfo()
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- ValueTestCase,
- ValueBuildInfoTestCase,
- ValueNodeInfoTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py
index 793e101..5455bd6 100644
--- a/src/engine/SCons/Node/__init__.py
+++ b/src/engine/SCons/Node/__init__.py
@@ -22,7 +22,7 @@ be able to depend on any other type of "thing."
from __future__ import print_function
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,12 +43,18 @@ from __future__ import print_function
# 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Node/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import os
import collections
import copy
from itertools import chain
+try:
+ from itertools import zip_longest
+except ImportError:
+ from itertools import izip_longest as zip_longest
+
import SCons.Debug
from SCons.Debug import logInstanceCreation
import SCons.Executor
@@ -102,9 +108,9 @@ implicit_deps_changed = 0
# A variable that can be set to an interface-specific function be called
# to annotate a Node with information about its creation.
-def do_nothing(node): pass
+def do_nothing_node(node): pass
-Annotate = do_nothing
+Annotate = do_nothing_node
# Gets set to 'True' if we're running in interactive mode. Is
# currently used to release parts of a target's info during
@@ -139,6 +145,7 @@ def exists_entry(node):
node.disambiguate()
return _exists_map[node._func_exists](node)
+
def exists_file(node):
# Duplicate from source path if we are set up to do this.
if node.duplicate and not node.is_derived() and not node.linked:
@@ -155,7 +162,7 @@ def exists_file(node):
# 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)
+ print("dup: no src for %s, unlinking old variant copy" % node)
if exists_base(node) or node.islink():
node.fs.unlink(node.get_internal_path())
# Return None explicitly because the Base.exists() call
@@ -249,7 +256,7 @@ _target_from_source_map = {0 : target_from_source_none,
#
# First, the single decider functions
#
-def changed_since_last_build_node(node, target, prev_ni):
+def changed_since_last_build_node(node, target, prev_ni, repo_node=None):
"""
Must be overridden in a specific subclass to return True if this
@@ -269,27 +276,33 @@ def changed_since_last_build_node(node, target, prev_ni):
"""
raise NotImplementedError
-def changed_since_last_build_alias(node, target, prev_ni):
+
+def changed_since_last_build_alias(node, target, prev_ni, repo_node=None):
cur_csig = node.get_csig()
try:
return cur_csig != prev_ni.csig
except AttributeError:
return 1
-def changed_since_last_build_entry(node, target, prev_ni):
+
+def changed_since_last_build_entry(node, target, prev_ni, repo_node=None):
node.disambiguate()
- return _decider_map[node.changed_since_last_build](node, target, prev_ni)
+ return _decider_map[node.changed_since_last_build](node, target, prev_ni, repo_node)
+
-def changed_since_last_build_state_changed(node, target, prev_ni):
- return (node.state != SCons.Node.up_to_date)
+def changed_since_last_build_state_changed(node, target, prev_ni, repo_node=None):
+ return node.state != SCons.Node.up_to_date
-def decide_source(node, target, prev_ni):
- return target.get_build_env().decide_source(node, target, prev_ni)
-def decide_target(node, target, prev_ni):
- return target.get_build_env().decide_target(node, target, prev_ni)
+def decide_source(node, target, prev_ni, repo_node=None):
+ return target.get_build_env().decide_source(node, target, prev_ni, repo_node)
-def changed_since_last_build_python(node, target, prev_ni):
+
+def decide_target(node, target, prev_ni, repo_node=None):
+ return target.get_build_env().decide_target(node, target, prev_ni, repo_node)
+
+
+def changed_since_last_build_python(node, target, prev_ni, repo_node=None):
cur_csig = node.get_csig()
try:
return cur_csig != prev_ni.csig
@@ -380,6 +393,7 @@ class NodeInfoBase(object):
"""
state = other.__getstate__()
self.__setstate__(state)
+
def format(self, field_list=None, names=0):
if field_list is None:
try:
@@ -505,6 +519,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
__slots__ = ['sources',
'sources_set',
+ 'target_peers',
'_specific_sources',
'depends',
'depends_set',
@@ -665,7 +680,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
executor.cleanup()
def reset_executor(self):
- "Remove cached executor; forces recompute when needed."
+ """Remove cached executor; forces recompute when needed."""
try:
delattr(self, 'executor')
except AttributeError:
@@ -760,6 +775,25 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
for parent in self.waiting_parents:
parent.implicit = None
+ # Handle issue where builder emits more than one target and
+ # the source file for the builder is generated.
+ # in that case only the first target was getting it's .implicit
+ # cleared when the source file is built (second scan).
+ # leaving only partial implicits from scan before source file is generated
+ # typically the compiler only. Then scanned files are appended
+ # This is persisted to sconsign and rebuild causes false rebuilds
+ # because the ordering of the implicit list then changes to what it
+ # should have been.
+ # This is at least the following bugs
+ # https://github.com/SCons/scons/issues/2811
+ # https://jira.mongodb.org/browse/SERVER-33111
+ try:
+ for peer in parent.target_peers:
+ peer.implicit = None
+ except AttributeError:
+ pass
+
+
self.clear()
if self.pseudo:
@@ -1136,7 +1170,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
binfo.bactsig = SCons.Util.MD5signature(executor.get_contents())
if self._specific_sources:
- sources = [ s for s in self.sources if not s in ignore_set]
+ sources = [s for s in self.sources if s not in ignore_set]
else:
sources = executor.get_unignored_sources(self, self.ignore)
@@ -1145,13 +1179,17 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
binfo.bsources = [s for s in sources if s not in seen and not seen.add(s)]
binfo.bsourcesigs = [s.get_ninfo() for s in binfo.bsources]
+ binfo.bdepends = [d for d in self.depends if d not in ignore_set]
+ binfo.bdependsigs = [d.get_ninfo() for d in self.depends]
- binfo.bdepends = self.depends
- binfo.bdependsigs = [d.get_ninfo() for d in self.depends if d not in ignore_set]
-
- binfo.bimplicit = self.implicit or []
- binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit if i not in ignore_set]
-
+ # Because self.implicit is initialized to None (and not empty list [])
+ # we have to handle this case
+ if not self.implicit:
+ binfo.bimplicit = []
+ binfo.bimplicitsigs = []
+ else:
+ binfo.bimplicit = [i for i in self.implicit if i not in ignore_set]
+ binfo.bimplicitsigs = [i.get_ninfo() for i in binfo.bimplicit]
return binfo
@@ -1213,7 +1251,7 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
return _exists_map[self._func_exists](self)
def rexists(self):
- """Does this node exist locally or in a repositiory?"""
+ """Does this node exist locally or in a repository?"""
# There are no repositories by default:
return _rexists_map[self._func_rexists](self)
@@ -1452,13 +1490,12 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
result = True
for child, prev_ni in zip(children, then):
- if _decider_map[child.changed_since_last_build](child, self, prev_ni):
+ if _decider_map[child.changed_since_last_build](child, self, prev_ni, node):
if t: Trace(': %s changed' % child)
result = True
- contents = self.get_executor().get_contents()
if self.has_builder():
- import SCons.Util
+ contents = self.get_executor().get_contents()
newsig = SCons.Util.MD5signature(contents)
if bi.bactsig != newsig:
if t: Trace(': bactsig %s != newsig %s' % (bi.bactsig, newsig))
@@ -1607,29 +1644,42 @@ class Node(object, with_metaclass(NoSlotsPyPy)):
# so we only print them after running them through this lambda
# to turn them into the right relative Node and then return
# its string.
- def stringify( s, E=self.dir.Entry ) :
+ def stringify( s, E=self.dir.Entry):
if hasattr( s, 'dir' ) :
return str(E(s))
return str(s)
lines = []
- removed = [x for x in old_bkids if not x in new_bkids]
+ removed = [x for x in old_bkids if x not in new_bkids]
if removed:
- removed = list(map(stringify, removed))
+ removed = [stringify(r) for r in removed]
fmt = "`%s' is no longer a dependency\n"
lines.extend([fmt % s for s in removed])
for k in new_bkids:
- if not k in old_bkids:
+ if k not in old_bkids:
lines.append("`%s' is a new dependency\n" % stringify(k))
- elif _decider_map[k.changed_since_last_build](k, self, osig[k]):
- lines.append("`%s' changed\n" % stringify(k))
+ else:
+ try:
+ changed = _decider_map[k.changed_since_last_build](k, self, osig[k])
+ except DeciderNeedsNode as e:
+ changed = e.decider(self, osig[k], node=self)
+
+ if changed:
+ lines.append("`%s' changed\n" % stringify(k))
if len(lines) == 0 and old_bkids != new_bkids:
- lines.append("the dependency order changed:\n" +
- "%sold: %s\n" % (' '*15, list(map(stringify, old_bkids))) +
- "%snew: %s\n" % (' '*15, list(map(stringify, new_bkids))))
+ lines.append("the dependency order changed:\n")
+ lines.append("->Sources\n")
+ for (o,n) in zip_longest(old.bsources, new.bsources, fillvalue=None):
+ lines.append("Old:%s\tNew:%s\n"%(o,n))
+ lines.append("->Depends\n")
+ for (o,n) in zip_longest(old.bdepends, new.bdepends, fillvalue=None):
+ lines.append("Old:%s\tNew:%s\n"%(o,n))
+ lines.append("->Implicit\n")
+ for (o,n) in zip_longest(old.bimplicit, new.bimplicit, fillvalue=None):
+ lines.append("Old:%s\tNew:%s\n"%(o,n))
if len(lines) == 0:
def fmt_with_title(title, strlines):
@@ -1672,7 +1722,6 @@ class Walker(object):
This is depth-first, children are visited before the parent.
The Walker object can be initialized with any node, and
returns the next node on the descent with each get_next() call.
- 'kids_func' is an optional function that will be called to
get the children of a node instead of calling 'children'.
'cycle_func' is an optional function that will be called
when a cycle is detected.
diff --git a/src/engine/SCons/Options/PackageOption.py b/src/engine/SCons/Options/PackageOption.py
deleted file mode 100644
index 6ebeca2..0000000
--- a/src/engine/SCons/Options/PackageOption.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Copyright (c) 2001 - 2017 The SCons Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "src/engine/SCons/Options/PackageOption.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
-
-warned = False
-
-def PackageOption(*args, **kw):
- global warned
- if not warned:
- msg = "The PackageOption() function is deprecated; use the PackageVariable() function instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
- return SCons.Variables.PackageVariable(*args, **kw)
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Options/PathOption.py b/src/engine/SCons/Options/PathOption.py
deleted file mode 100644
index b177687..0000000
--- a/src/engine/SCons/Options/PathOption.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# Copyright (c) 2001 - 2017 The SCons Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "src/engine/SCons/Options/PathOption.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
-
-warned = False
-
-class _PathOptionClass(object):
- def warn(self):
- global warned
- if not warned:
- msg = "The PathOption() function is deprecated; use the PathVariable() function instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
-
- def __call__(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable(*args, **kw)
-
- def PathAccept(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable.PathAccept(*args, **kw)
-
- def PathIsDir(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable.PathIsDir(*args, **kw)
-
- def PathIsDirCreate(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable.PathIsDirCreate(*args, **kw)
-
- def PathIsFile(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable.PathIsFile(*args, **kw)
-
- def PathExists(self, *args, **kw):
- self.warn()
- return SCons.Variables.PathVariable.PathExists(*args, **kw)
-
-PathOption = _PathOptionClass()
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Options/__init__.py b/src/engine/SCons/Options/__init__.py
deleted file mode 100644
index 8825d10..0000000
--- a/src/engine/SCons/Options/__init__.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Copyright (c) 2001 - 2017 The SCons Foundation
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__revision__ = "src/engine/SCons/Options/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
-
-from .BoolOption import BoolOption # okay
-from .EnumOption import EnumOption # okay
-from .ListOption import ListOption # naja
-from .PackageOption import PackageOption # naja
-from .PathOption import PathOption # okay
-
-warned = False
-
-class Options(SCons.Variables.Variables):
- def __init__(self, *args, **kw):
- global warned
- if not warned:
- msg = "The Options class is deprecated; use the Variables class instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
- SCons.Variables.Variables.__init__(self, *args, **kw)
-
- def AddOptions(self, *args, **kw):
- return SCons.Variables.Variables.AddVariables(self, *args, **kw)
-
- def UnknownOptions(self, *args, **kw):
- return SCons.Variables.Variables.UnknownVariables(self, *args, **kw)
-
- def FormatOptionHelpText(self, *args, **kw):
- return SCons.Variables.Variables.FormatVariableHelpText(self, *args,
- **kw)
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/PathList.py b/src/engine/SCons/PathList.py
index 680b853..d6a01e7 100644
--- a/src/engine/SCons/PathList.py
+++ b/src/engine/SCons/PathList.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/PathList.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """SCons.PathList
diff --git a/src/engine/SCons/PathListTests.py b/src/engine/SCons/PathListTests.py
index 0e5f319..0a18fbe 100644
--- a/src/engine/SCons/PathListTests.py
+++ b/src/engine/SCons/PathListTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/PathListTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
diff --git a/src/engine/SCons/Platform/PlatformTests.py b/src/engine/SCons/Platform/PlatformTests.py
index 686d0d2..7941625 100644
--- a/src/engine/SCons/Platform/PlatformTests.py
+++ b/src/engine/SCons/Platform/PlatformTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,27 +21,28 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/PlatformTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/PlatformTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
import collections
import unittest
-
-import TestUnit
+import os
import SCons.Errors
import SCons.Platform
import SCons.Environment
import SCons.Action
+
class Environment(collections.UserDict):
def Detect(self, cmd):
return cmd
-
+
def AppendENVPath(self, key, value):
pass
+
class PlatformTestCase(unittest.TestCase):
def test_Platform(self):
"""Test the Platform() function"""
@@ -112,13 +113,14 @@ class PlatformTestCase(unittest.TestCase):
p = SCons.Platform.Platform('_does_not_exist_')
except SCons.Errors.UserError:
pass
- else:
+ else: # TODO pylint E0704: bare raise not inside except
raise
env = Environment()
SCons.Platform.Platform()(env)
assert env != {}, env
+
class TempFileMungeTestCase(unittest.TestCase):
def test_MAXLINELENGTH(self):
""" Test different values for MAXLINELENGTH with the same
@@ -140,22 +142,58 @@ class TempFileMungeTestCase(unittest.TestCase):
env['OVERSIMPLIFIED'] = 'command'
expanded_cmd = env.subst(defined_cmd)
# Call the tempfile munger
- cmd = t(None,None,env,0)
+ cmd = t(None, None, env, 0)
assert cmd == defined_cmd, cmd
# Let MAXLINELENGTH equal the string's length
env['MAXLINELENGTH'] = len(expanded_cmd)
- cmd = t(None,None,env,0)
+ cmd = t(None, None, env, 0)
assert cmd == defined_cmd, cmd
# Finally, let the actual tempfile mechanism kick in
# Disable printing of actions...
old_actions = SCons.Action.print_actions
SCons.Action.print_actions = 0
env['MAXLINELENGTH'] = len(expanded_cmd)-1
- cmd = t(None,None,env,0)
+ cmd = t(None, None, env, 0)
# ...and restoring its setting.
SCons.Action.print_actions = old_actions
assert cmd != defined_cmd, cmd
+ def test_TEMPFILEARGJOINBYTE(self):
+ """
+ Test argument join byte TEMPFILEARGJOINBYTE
+ """
+
+ # Init class with cmd, such that the fully expanded
+ # string reads "a test command line".
+ # Note, how we're using a command string here that is
+ # actually longer than the substituted one. This is to ensure
+ # that the TempFileMunge class internally really takes the
+ # length of the expanded string into account.
+ defined_cmd = "a $VERY $OVERSIMPLIFIED line"
+ t = SCons.Platform.TempFileMunge(defined_cmd)
+ env = SCons.Environment.SubstitutionEnvironment(tools=[])
+ # Setting the line length high enough...
+ env['MAXLINELENGTH'] = 1024
+ env['VERY'] = 'test'
+ env['OVERSIMPLIFIED'] = 'command'
+ env['TEMPFILEARGJOINBYTE'] = os.linesep
+ expanded_cmd = env.subst(defined_cmd)
+
+ # For tempfilemunge to operate.
+ old_actions = SCons.Action.print_actions
+ SCons.Action.print_actions = 0
+ env['MAXLINELENGTH'] = len(expanded_cmd)-1
+ cmd = t(None, None, env, 0)
+ # print("CMD is:%s"%cmd)
+
+ with open(cmd[-1],'rb') as f:
+ file_content = f.read()
+ # print("Content is:[%s]"%file_content)
+ # ...and restoring its setting.
+ SCons.Action.print_actions = old_actions
+ assert file_content != env['TEMPFILEARGJOINBYTE'].join(['test','command','line'])
+
+
def test_tempfilecreation_once(self):
# Init class with cmd, such that the fully expanded
# string reads "a test command line".
@@ -175,10 +213,12 @@ class TempFileMungeTestCase(unittest.TestCase):
old_actions = SCons.Action.print_actions
SCons.Action.print_actions = 0
# Create an instance of object derived class to allow setattrb
- class Node(object) :
- class Attrs(object):
+
+ class Node(object):
+ class Attrs(object):
pass
- def __init__(self):
+
+ def __init__(self):
self.attributes = self.Attrs()
target = [Node()]
cmd = t(target, None, env, 0)
@@ -187,6 +227,7 @@ class TempFileMungeTestCase(unittest.TestCase):
assert cmd != defined_cmd, cmd
assert cmd == getattr(target[0].attributes, 'tempfile_cmdlist', None)
+
class PlatformEscapeTestCase(unittest.TestCase):
def test_posix_escape(self):
""" Check that paths with parens are escaped properly
@@ -204,17 +245,8 @@ class PlatformEscapeTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
-
- tclasses = [ PlatformTestCase,
- TempFileMungeTestCase,
- PlatformEscapeTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
-
- TestUnit.run(suite)
+ unittest.main()
+
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Platform/__init__.py b/src/engine/SCons/Platform/__init__.py
index 61a4010..8da1e9d 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 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,11 +43,11 @@ their own platform definition.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Platform/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
-import imp
+import importlib
import os
import sys
import tempfile
@@ -87,6 +87,7 @@ def platform_default():
else:
return sys.platform
+
def platform_module(name = platform_default()):
"""Return the imported module for the platform.
@@ -100,13 +101,8 @@ def platform_module(name = platform_default()):
eval(full_name)
else:
try:
- file, path, desc = imp.find_module(name,
- sys.modules['SCons.Platform'].__path__)
- try:
- mod = imp.load_module(full_name, file, path, desc)
- finally:
- if file:
- file.close()
+ # the specific platform module is a relative import
+ mod = importlib.import_module("." + name, __name__)
except ImportError:
try:
import zipimport
@@ -117,11 +113,13 @@ def platform_module(name = platform_default()):
setattr(SCons.Platform, name, mod)
return sys.modules[full_name]
+
def DefaultToolList(platform, env):
"""Select a default tool list for the specified platform.
"""
return SCons.Tool.tool_list(platform, env)
+
class PlatformSpec(object):
def __init__(self, name, generate):
self.name = name
@@ -133,6 +131,7 @@ class PlatformSpec(object):
def __str__(self):
return self.name
+
class TempFileMunge(object):
"""A callable class. You can set an Environment variable to this,
then call it with a string argument, then it will perform temporary
@@ -140,15 +139,20 @@ class TempFileMunge(object):
line limitation.
Example usage:
- env["TEMPFILE"] = TempFileMunge
- env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
+ env["TEMPFILE"] = TempFileMunge
+ env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
By default, the name of the temporary file used begins with a
- prefix of '@'. This may be configred for other tool chains by
- setting '$TEMPFILEPREFIX'.
-
- env["TEMPFILEPREFIX"] = '-@' # diab compiler
- env["TEMPFILEPREFIX"] = '-via' # arm tool chain
+ prefix of '@'. This may be configured for other tool chains by
+ setting '$TEMPFILEPREFIX':
+ env["TEMPFILEPREFIX"] = '-@' # diab compiler
+ env["TEMPFILEPREFIX"] = '-via' # arm tool chain
+ env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint
+
+ You can configure the extension of the temporary file through the
+ TEMPFILESUFFIX variable, which defaults to '.lnk' (see comments
+ in the code below):
+ env["TEMPFILESUFFIX"] = '.lnt' # PC Lint
"""
def __init__(self, cmd, cmdstr = None):
self.cmd = cmd
@@ -185,21 +189,26 @@ class TempFileMunge(object):
node = target[0] if SCons.Util.is_List(target) else target
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
if node is not None else None
- if cmdlist is not None :
+ if cmdlist is not None:
return cmdlist
# We do a normpath because mktemp() has what appears to be
# a bug in Windows that will use a forward slash as a path
- # delimiter. Windows's link mistakes that for a command line
+ # delimiter. Windows' link mistakes that for a command line
# switch and barfs.
#
- # We use the .lnk suffix for the benefit of the Phar Lap
+ # Default to the .lnk suffix for the benefit of the Phar Lap
# linkloc linker, which likes to append an .lnk suffix if
# none is given.
- (fd, tmp) = tempfile.mkstemp('.lnk', text=True)
+ if env.has_key('TEMPFILESUFFIX'):
+ suffix = env.subst('$TEMPFILESUFFIX')
+ else:
+ suffix = '.lnk'
+
+ fd, tmp = tempfile.mkstemp(suffix, text=True)
native_tmp = SCons.Util.get_native_path(os.path.normpath(tmp))
- if env.get('SHELL',None) == 'sh':
+ if env.get('SHELL', None) == 'sh':
# The sh shell will try to escape the backslashes in the
# path, so unescape them.
native_tmp = native_tmp.replace('\\', r'\\\\')
@@ -217,8 +226,10 @@ class TempFileMunge(object):
prefix = '@'
args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
- os.write(fd, bytearray(" ".join(args) + "\n",'utf-8'))
+ join_char = env.get('TEMPFILEARGJOIN',' ')
+ os.write(fd, bytearray(join_char.join(args) + "\n",'utf-8'))
os.close(fd)
+
# XXX Using the SCons.Action.print_actions value directly
# like this is bogus, but expedient. This class should
# really be rewritten as an Action that defines the
@@ -239,8 +250,9 @@ class TempFileMunge(object):
source) if self.cmdstr is not None else ''
# Print our message only if XXXCOMSTR returns an empty string
if len(cmdstr) == 0 :
- print("Using tempfile "+native_tmp+" for command line:\n"+
- str(cmd[0]) + " " + " ".join(args))
+ cmdstr = ("Using tempfile "+native_tmp+" for command line:\n"+
+ str(cmd[0]) + " " + " ".join(args))
+ self._print_cmd_str(target, source, env, cmdstr)
# Store the temporary file command list into the target Node.attributes
# to avoid creating two temporary files one for print and one for execute.
@@ -252,6 +264,23 @@ class TempFileMunge(object):
pass
return cmdlist
+ def _print_cmd_str(self, target, source, env, cmdstr):
+ # check if the user has specified a cmd line print function
+ print_func = None
+ try:
+ get = env.get
+ except AttributeError:
+ pass
+ else:
+ print_func = get('PRINT_CMD_LINE_FUNC')
+
+ # use the default action cmd line print if user did not supply one
+ if not print_func:
+ action = SCons.Action._ActionAction()
+ action.print_cmd_line(cmdstr, target, source, env)
+ else:
+ print_func(cmdstr, target, source, env)
+
def Platform(name = platform_default()):
"""Select a canned Platform specification.
diff --git a/src/engine/SCons/Platform/__init__.xml b/src/engine/SCons/Platform/__init__.xml
index cb83a9f..d4c2a21 100644
--- a/src/engine/SCons/Platform/__init__.xml
+++ b/src/engine/SCons/Platform/__init__.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -232,13 +232,40 @@ The suffix used for shared object file names.
<summary>
<para>
The prefix for a temporary file used
-to execute lines longer than $MAXLINELENGTH.
-The default is '@'.
-This may be set for toolchains that use other values,
-such as '-@' for the diab compiler
+to store lines lines longer than $MAXLINELENGTH
+as operations which call out to a shell will fail
+if the line is too long, which particularly
+impacts linking.
+The default is '@', which works for the Microsoft
+and GNU toolchains on Windows.
+Set this appropriately for other toolchains,
+for example '-@' for the diab compiler
or '-via' for ARM toolchain.
</para>
</summary>
</cvar>
+<cvar name="TEMPFILESUFFIX">
+<summary>
+<para>
+The suffix used for the temporary file name
+used for long command lines. The name should
+include the dot ('.') if one is wanted as
+it will not be added automatically.
+The default is '.lnk'.
+</para>
+</summary>
+</cvar>
+
+<cvar name="TEMPFILEARGJOIN">
+<summary>
+<para>
+The string (or character) to be used to join the arguments passed to TEMPFILE when command line exceeds the limit set by &cv-MAXLINELENGTH;.
+The default value is a space. However for MSVC, MSLINK the default is a line seperator characters as defined by os.linesep.
+Note this value is used literally and not expanded by the subst logic.
+</para>
+</summary>
+</cvar>
+
+
</sconsdoc>
diff --git a/src/engine/SCons/Platform/aix.py b/src/engine/SCons/Platform/aix.py
index caeb3fb..70fbb35 100644
--- a/src/engine/SCons/Platform/aix.py
+++ b/src/engine/SCons/Platform/aix.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/aix.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/aix.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import subprocess
diff --git a/src/engine/SCons/Platform/cygwin.py b/src/engine/SCons/Platform/cygwin.py
index 0e30b5f..70b6443 100644
--- a/src/engine/SCons/Platform/cygwin.py
+++ b/src/engine/SCons/Platform/cygwin.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,11 +30,20 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/cygwin.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/cygwin.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import sys
from . import posix
from SCons.Platform import TempFileMunge
+CYGWIN_DEFAULT_PATHS = []
+if sys.platform == 'win32':
+ CYGWIN_DEFAULT_PATHS = [
+ r'C:\cygwin64\bin',
+ r'C:\cygwin\bin'
+ ]
+
def generate(env):
posix.generate(env)
diff --git a/src/engine/SCons/Platform/darwin.py b/src/engine/SCons/Platform/darwin.py
index 70ffcf4..d5861d9 100644
--- a/src/engine/SCons/Platform/darwin.py
+++ b/src/engine/SCons/Platform/darwin.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/darwin.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/darwin.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import posix
import os
@@ -56,12 +56,11 @@ def generate(env):
for file in filelist:
if os.path.isfile(file):
- f = open(file, 'r')
- lines = f.readlines()
- for line in lines:
- if line:
- env.AppendENVPath('PATHOSX', line.strip('\n'))
- f.close()
+ with open(file, 'r') as f:
+ lines = f.readlines()
+ for line in lines:
+ if line:
+ env.AppendENVPath('PATHOSX', line.strip('\n'))
# Not sure why this wasn't the case all along?
if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
diff --git a/src/engine/SCons/Platform/hpux.py b/src/engine/SCons/Platform/hpux.py
index 8b34901..6867212 100644
--- a/src/engine/SCons/Platform/hpux.py
+++ b/src/engine/SCons/Platform/hpux.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/hpux.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/hpux.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import posix
diff --git a/src/engine/SCons/Platform/irix.py b/src/engine/SCons/Platform/irix.py
index 1ff4530..a382e71 100644
--- a/src/engine/SCons/Platform/irix.py
+++ b/src/engine/SCons/Platform/irix.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/irix.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/irix.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import posix
diff --git a/src/engine/SCons/Options/ListOption.py b/src/engine/SCons/Platform/mingw.py
index d4e63af..c03c9c8 100644
--- a/src/engine/SCons/Options/ListOption.py
+++ b/src/engine/SCons/Platform/mingw.py
@@ -1,5 +1,11 @@
+"""SCons.Platform.mingw
+
+Platform-specific initialization for the MinGW system.
+
+"""
+
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,30 +27,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Options/ListOption.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
-
-warned = False
+__revision__ = "src/engine/SCons/Platform/mingw.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-def ListOption(*args, **kw):
- global warned
- if not warned:
- msg = "The ListOption() function is deprecated; use the ListVariable() function instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
- return SCons.Variables.ListVariable(*args, **kw)
+import sys
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
+MINGW_DEFAULT_PATHS = []
+if sys.platform == 'win32':
+ MINGW_DEFAULT_PATHS = [
+ r'C:\msys64',
+ r'C:\msys'
+ ] \ No newline at end of file
diff --git a/src/engine/SCons/Platform/os2.py b/src/engine/SCons/Platform/os2.py
index cd1c35c..ebabe3d 100644
--- a/src/engine/SCons/Platform/os2.py
+++ b/src/engine/SCons/Platform/os2.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/os2.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/os2.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import win32
def generate(env):
diff --git a/src/engine/SCons/Platform/posix.py b/src/engine/SCons/Platform/posix.py
index 890a70a..780c764 100644
--- a/src/engine/SCons/Platform/posix.py
+++ b/src/engine/SCons/Platform/posix.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/posix.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/posix.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import errno
import os
@@ -41,6 +41,8 @@ import select
import SCons.Util
from SCons.Platform import TempFileMunge
+from SCons.Platform.virtualenv import ImportVirtualenv
+from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
exitvalmap = {
2 : 127,
@@ -48,7 +50,7 @@ exitvalmap = {
}
def escape(arg):
- "escape shell special characters"
+ """escape shell special characters"""
slash = '\\'
special = '"$'
@@ -119,6 +121,9 @@ def generate(env):
# Must be able to have GCC and DMD work in the same build, so:
env['__DRPATH'] = '$_DRPATH'
+ if enable_virtualenv and not ignore_virtualenv:
+ ImportVirtualenv(env)
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Platform/posix.xml b/src/engine/SCons/Platform/posix.xml
index 00d42ab..a710230 100644
--- a/src/engine/SCons/Platform/posix.xml
+++ b/src/engine/SCons/Platform/posix.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -46,7 +46,7 @@ An automatically-generated construction variable
containing the rpath flags to be used when linking
a program with shared libraries.
The value of &cv-_RPATH; is created
-by appending &cv-RPATHPREFIX; and &cv-RPATHSUFFIX;
+by respectively prepending &cv-RPATHPREFIX; and appending &cv-RPATHSUFFIX;
to the beginning and end
of each directory in &cv-RPATH;.
</para>
@@ -58,7 +58,7 @@ of each directory in &cv-RPATH;.
<para>
The prefix used to specify a directory to be searched for
shared libraries when running programs.
-This will be appended to the beginning of each directory
+This will be prepended to the beginning of each directory
in the &cv-RPATH; construction variable
when the &cv-_RPATH; variable is automatically generated.
</para>
diff --git a/src/engine/SCons/Platform/sunos.py b/src/engine/SCons/Platform/sunos.py
index 3279fb9..6aa54aa 100644
--- a/src/engine/SCons/Platform/sunos.py
+++ b/src/engine/SCons/Platform/sunos.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/sunos.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/sunos.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import posix
diff --git a/src/engine/SCons/Platform/sunos.xml b/src/engine/SCons/Platform/sunos.xml
index 541c862..abab196 100644
--- a/src/engine/SCons/Platform/sunos.xml
+++ b/src/engine/SCons/Platform/sunos.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Platform/virtualenv.py b/src/engine/SCons/Platform/virtualenv.py
new file mode 100644
index 0000000..9fb3e45
--- /dev/null
+++ b/src/engine/SCons/Platform/virtualenv.py
@@ -0,0 +1,120 @@
+"""SCons.Platform.virtualenv
+
+Support for virtualenv.
+"""
+
+#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "src/engine/SCons/Platform/virtualenv.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
+import sys
+import SCons.Util
+
+
+virtualenv_enabled_by_default = False
+
+
+def _enable_virtualenv_default():
+ return SCons.Util.get_os_env_bool('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default)
+
+
+def _ignore_virtualenv_default():
+ return SCons.Util.get_os_env_bool('SCONS_IGNORE_VIRTUALENV', False)
+
+
+enable_virtualenv = _enable_virtualenv_default()
+ignore_virtualenv = _ignore_virtualenv_default()
+virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
+
+
+def _running_in_virtualenv():
+ """Returns True, if scons is executed within a virtualenv"""
+ # see https://stackoverflow.com/a/42580137
+ return (hasattr(sys, 'real_prefix') or
+ (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
+
+
+def _is_path_in(path, base):
+ """Returns true, if **path** is located under the **base** directory."""
+ if not path or not base: # empty path may happen, base too
+ return False
+ rp = os.path.relpath(path, base)
+ return ((not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir))
+
+
+def _inject_venv_variables(env):
+ if 'ENV' not in env:
+ env['ENV'] = {}
+ ENV = env['ENV']
+ for name in virtualenv_variables:
+ try:
+ ENV[name] = os.environ[name]
+ except KeyError:
+ pass
+
+def _inject_venv_path(env, path_list=None):
+ """Modify environment such that SCons will take into account its virtualenv
+ when running external tools."""
+ if path_list is None:
+ path_list = os.getenv('PATH')
+ env.PrependENVPath('PATH', select_paths_in_venv(path_list))
+
+
+def select_paths_in_venv(path_list):
+ """Returns a list of paths from **path_list** which are under virtualenv's
+ home directory."""
+ if SCons.Util.is_String(path_list):
+ path_list = path_list.split(os.path.pathsep)
+ # Find in path_list the paths under the virtualenv's home
+ return [path for path in path_list if IsInVirtualenv(path)]
+
+
+def ImportVirtualenv(env):
+ """Copies virtualenv-related environment variables from OS environment
+ to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``.
+ """
+ _inject_venv_variables(env)
+ _inject_venv_path(env)
+
+
+def Virtualenv():
+ """Returns path to the virtualenv home if scons is executing within a
+ virtualenv or None, if not."""
+ if _running_in_virtualenv():
+ return sys.prefix
+ return None
+
+
+def IsInVirtualenv(path):
+ """Returns True, if **path** is under virtualenv's home directory. If not,
+ or if we don't use virtualenv, returns False."""
+ return _is_path_in(path, Virtualenv())
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Platform/virtualenvTests.py b/src/engine/SCons/Platform/virtualenvTests.py
new file mode 100644
index 0000000..891fdb3
--- /dev/null
+++ b/src/engine/SCons/Platform/virtualenvTests.py
@@ -0,0 +1,243 @@
+#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "src/engine/SCons/Platform/virtualenvTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import SCons.compat
+
+import collections
+import unittest
+import os
+import sys
+
+import SCons.Platform.virtualenv
+import SCons.Util
+
+class Environment(collections.UserDict):
+ def Detect(self, cmd):
+ return cmd
+
+ def AppendENVPath(self, key, value):
+ if SCons.Util.is_List(value):
+ value = os.path.pathsep.join(value)
+ if 'ENV' not in self:
+ self['ENV'] = {}
+ current = self['ENV'].get(key)
+ if not current:
+ self['ENV'][key] = value
+ else:
+ self['ENV'][key] = os.path.pathsep.join([current, value])
+
+ def PrependENVPath(self, key, value):
+ if SCons.Util.is_List(value):
+ value = os.path.pathsep.join(value)
+ if 'ENV' not in self:
+ self['ENV'] = {}
+ current = self['ENV'].get(key)
+ if not current:
+ self['ENV'][key] = value
+ else:
+ self['ENV'][key] = os.path.pathsep.join([value, current])
+
+class SysPrefixes(object):
+ """Used to temporarily mock sys.prefix, sys.real_prefix and sys.base_prefix"""
+ def __init__(self, prefix, real_prefix=None, base_prefix=None):
+ self._prefix = prefix
+ self._real_prefix = real_prefix
+ self._base_prefix = base_prefix
+
+ def start(self):
+ self._store()
+ sys.prefix = self._prefix
+ if self._real_prefix is None:
+ if hasattr(sys, 'real_prefix'):
+ del sys.real_prefix
+ else:
+ sys.real_prefix = self._real_prefix
+ if self._base_prefix is None:
+ if hasattr(sys, 'base_prefix'):
+ del sys.base_prefix
+ else:
+ sys.base_prefix = self._base_prefix
+
+ def stop(self):
+ self._restore()
+
+ def __enter__(self):
+ self.start()
+ attrs = ('prefix', 'real_prefix', 'base_prefix')
+ return {k: getattr(sys, k) for k in attrs if hasattr(sys, k)}
+
+ def __exit__(self, *args):
+ self.stop()
+
+ def _store(self):
+ s = dict()
+ if hasattr(sys, 'real_prefix'):
+ s['real_prefix'] = sys.real_prefix
+ if hasattr(sys, 'base_prefix'):
+ s['base_prefix'] = sys.base_prefix
+ s['prefix'] = sys.prefix
+ self._stored = s
+
+ def _restore(self):
+ s = self._stored
+ if 'real_prefix' in s:
+ sys.real_prefix = s['real_prefix']
+ if 'base_prefix' in s:
+ sys.base_prefix = s['base_prefix']
+ if 'prefix' in s:
+ sys.prefix = s['prefix']
+ del self._stored
+
+def _p(p):
+ """Converts path string **p** from posix format to os-specific format."""
+ drive = []
+ if p.startswith('/') and sys.platform == 'win32':
+ drive = ['C:']
+ pieces = p.split('/')
+ return os.path.sep.join(drive + pieces)
+
+
+class _is_path_in_TestCase(unittest.TestCase):
+ def test_false(self):
+ for args in [ ('',''),
+ ('', _p('/foo/bar')),
+ (_p('/foo/bar'), ''),
+ (_p('/foo/bar'), _p('/foo/bar')),
+ (_p('/foo/bar'), _p('/foo/bar/geez')),
+ (_p('/'), _p('/foo')),
+ (_p('foo'), _p('foo/bar')) ]:
+ assert SCons.Platform.virtualenv._is_path_in(*args) is False, "_is_path_in(%r, %r) should be False" % args
+
+ def test__true(self):
+ for args in [ (_p('/foo'), _p('/')),
+ (_p('/foo/bar'), _p('/foo')),
+ (_p('/foo/bar/geez'), _p('/foo/bar')),
+ (_p('/foo//bar//geez'), _p('/foo/bar')),
+ (_p('/foo/bar/geez'), _p('/foo//bar')),
+ (_p('/foo/bar/geez'), _p('//foo//bar')) ]:
+ assert SCons.Platform.virtualenv._is_path_in(*args) is True, "_is_path_in(%r, %r) should be True" % args
+
+class IsInVirtualenvTestCase(unittest.TestCase):
+ def test_false(self):
+ # "without wirtualenv" - always false
+ with SysPrefixes(_p('/prefix')):
+ for p in [ _p(''),
+ _p('/foo'),
+ _p('/prefix'),
+ _p('/prefix/foo') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ # "with virtualenv"
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ for p in [ _p(''),
+ _p('/real/prefix/foo'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/bar/..'),
+ _p('/virtualenv/prefix/bar/../../bleah'),
+ _p('/virtualenv/bleah') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ # "with venv"
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ for p in [ _p(''),
+ _p('/base/prefix/foo'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/bar/..'),
+ _p('/virtualenv/prefix/bar/../../bleah'),
+ _p('/virtualenv/bleah') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is False, "IsInVirtualenv(%r) should be False" % p
+
+ def test_true(self):
+ # "with virtualenv"
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ for p in [ _p('/virtualenv/prefix/foo'),
+ _p('/virtualenv/prefix/foo/bar') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is True, "IsInVirtualenv(%r) should be True" % p
+
+ # "with venv"
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ for p in [ _p('/virtualenv/prefix/foo'),
+ _p('/virtualenv/prefix/foo/bar') ]:
+ assert SCons.Platform.virtualenv.IsInVirtualenv(p) is True, "IsInVirtualenv(%r) should be True" % p
+
+class _inject_venv_pathTestCase(unittest.TestCase):
+ def path_list(self):
+ return [
+ _p('/virtualenv/prefix/bin'),
+ _p('/virtualenv/prefix'),
+ _p('/virtualenv/prefix/../bar'),
+ _p('/home/user/.local/bin'),
+ _p('/usr/bin'),
+ _p('/opt/bin')
+ ]
+ def test_with_path_string(self):
+ env = Environment()
+ path_string = os.path.pathsep.join(self.path_list())
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ SCons.Platform.virtualenv._inject_venv_path(env, path_string)
+ assert env['ENV']['PATH'] == _p('/virtualenv/prefix/bin'), env['ENV']['PATH']
+
+ def test_with_path_list(self):
+ env = Environment()
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ SCons.Platform.virtualenv._inject_venv_path(env, self.path_list())
+ assert env['ENV']['PATH'] == _p('/virtualenv/prefix/bin'), env['ENV']['PATH']
+
+class VirtualenvTestCase(unittest.TestCase):
+ def test_none(self):
+ def _msg(given):
+ return "Virtualenv() should be None, not %s" % repr(given)
+
+ with SysPrefixes(_p('/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve is None , _msg(ve)
+ with SysPrefixes(_p('/base/prefix'), base_prefix=_p('/base/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve is None, _msg(ve)
+
+ def test_not_none(self):
+ def _msg(expected, given):
+ return "Virtualenv() should == %r, not %s" % (_p(expected), repr(given))
+
+ with SysPrefixes(_p('/virtualenv/prefix'), real_prefix=_p('/real/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/virtualenv/prefix'), _msg('/virtualenv/prefix', ve)
+ with SysPrefixes(_p('/same/prefix'), real_prefix=_p('/same/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/same/prefix'), _msg('/same/prefix', ve)
+ with SysPrefixes(_p('/virtualenv/prefix'), base_prefix=_p('/base/prefix')):
+ ve = SCons.Platform.virtualenv.Virtualenv()
+ assert ve == _p('/virtualenv/prefix'), _msg('/virtualenv/prefix', ve)
+
+
+if __name__ == "__main__":
+ unittest.main()
+
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/src/engine/SCons/Platform/win32.py b/src/engine/SCons/Platform/win32.py
index 79955e7..ea567a2 100644
--- a/src/engine/SCons/Platform/win32.py
+++ b/src/engine/SCons/Platform/win32.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Platform/win32.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Platform/win32.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
@@ -39,8 +39,14 @@ import tempfile
from SCons.Platform.posix import exitvalmap
from SCons.Platform import TempFileMunge
+from SCons.Platform.virtualenv import ImportVirtualenv
+from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
import SCons.Util
+CHOCO_DEFAULT_PATH = [
+ r'C:\ProgramData\chocolatey\bin'
+]
+
try:
import msvcrt
import win32api
@@ -80,16 +86,8 @@ else:
win32con.HANDLE_FLAG_INHERIT, 0)
file = _scons_file
else:
- import io
- for io_class in ['BufferedReader', 'BufferedWriter', 'BufferedRWPair',
- 'BufferedRandom', 'TextIOWrapper']:
- _builtin_file = getattr(io, io_class)
- class _scons_file(_builtin_file):
- def __init__(self, *args, **kw):
- _builtin_file.__init__(self, *args, **kw)
- win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()),
- win32con.HANDLE_FLAG_INHERIT, 0)
- setattr(io, io_class, _scons_file)
+ # No longer needed for python 3.4 and above. Files are opened non sharable
+ pass
@@ -132,7 +130,7 @@ try:
# Without this, python can randomly crash while using -jN.
# See the python bug at http://bugs.python.org/issue6476
# and SCons issue at
- # http://scons.tigris.org/issues/show_bug.cgi?id=2449
+ # https://github.com/SCons/scons/issues/2449
def spawnve(mode, file, args, env):
spawn_lock.acquire()
try:
@@ -195,29 +193,31 @@ def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
# actually do the spawn
try:
- args = [sh, '/C', escape(' '.join(args)) ]
+ args = [sh, '/C', escape(' '.join(args))]
ret = spawnve(os.P_WAIT, sh, args, env)
except OSError as e:
# catch any error
try:
- ret = exitvalmap[e[0]]
+ ret = exitvalmap[e.errno]
except KeyError:
- sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1]))
+ sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror))
if stderr is not None:
- stderr.write("scons: %s: %s\n" % (cmd, e[1]))
+ stderr.write("scons: %s: %s\n" % (cmd, e.strerror))
# copy child output from tempfiles to our streams
# and do clean up stuff
if stdout is not None and stdoutRedirected == 0:
try:
- stdout.write(open( tmpFileStdout, "r" ).read())
- os.remove( tmpFileStdout )
+ with open(tmpFileStdout, "r" ) as tmp:
+ stdout.write(tmp.read())
+ os.remove(tmpFileStdout)
except (IOError, OSError):
pass
if stderr is not None and stderrRedirected == 0:
try:
- stderr.write(open( tmpFileStderr, "r" ).read())
- os.remove( tmpFileStderr )
+ with open(tmpFileStderr, "r" ) as tmp:
+ stderr.write(tmp.read())
+ os.remove(tmpFileStderr)
except (IOError, OSError):
pass
return ret
@@ -436,7 +436,7 @@ def generate(env):
if v:
env['ENV']['COMSPEC'] = v
- env.AppendENVPath('PATH', get_system_root() + '\System32')
+ env.AppendENVPath('PATH', get_system_root() + '\\System32')
env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
env['OBJPREFIX'] = ''
@@ -462,6 +462,9 @@ def generate(env):
env['HOST_OS'] = 'win32'
env['HOST_ARCH'] = get_architecture().arch
+ if enable_virtualenv and not ignore_virtualenv:
+ ImportVirtualenv(env)
+
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Platform/win32.xml b/src/engine/SCons/Platform/win32.xml
index c2b9b01..cc87470 100644
--- a/src/engine/SCons/Platform/win32.xml
+++ b/src/engine/SCons/Platform/win32.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py
index c1ab159..7409c50 100644
--- a/src/engine/SCons/SConf.py
+++ b/src/engine/SCons/SConf.py
@@ -12,7 +12,7 @@ libraries are installed, if some command line options are supported etc.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ libraries are installed, if some command line options are supported etc.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/SConf.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/SConf.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -246,6 +246,7 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
# ConfigureCacheError and if yes, reraise the exception
exc_type = self.exc_info()[0]
if issubclass(exc_type, SConfError):
+ # TODO pylint E0704: bare raise not inside except
raise
elif issubclass(exc_type, SCons.Errors.BuildError):
# we ignore Build Errors (occurs, when a test doesn't pass)
@@ -323,18 +324,6 @@ class SConfBuildTask(SCons.Taskmaster.AlwaysTask):
s = sys.stdout = sys.stderr = Streamer(sys.stdout)
try:
env = self.targets[0].get_build_env()
- if cache_mode == FORCE:
- # Set up the Decider() to force rebuilds by saying
- # that every source has changed. Note that we still
- # call the environment's underlying source decider so
- # that the correct .sconsign info will get calculated
- # and keep the build state consistent.
- def force_build(dependency, target, prev_ni,
- env_decider=env.decide_source):
- env_decider(dependency, target, prev_ni)
- return True
- if env.decide_source.__code__ is not force_build.__code__:
- env.Decider(force_build)
env['PSTDOUT'] = env['PSTDERR'] = s
try:
sconf.cached = 0
@@ -405,12 +394,40 @@ class SConfBase(object):
build tests in the VariantDir, not in the SourceDir)
"""
global SConfFS
+
+ # Now create isolated override so setting source_decider doesn't affect parent Environment
+ if cache_mode == FORCE:
+ self.original_env = env
+ self.env = env.Clone()
+
+ # Set up the Decider() to force rebuilds by saying
+ # that every source has changed. Note that we still
+ # call the environment's underlying source decider so
+ # that the correct .sconsign info will get calculated
+ # and keep the build state consistent.
+ def force_build(dependency, target, prev_ni,
+ repo_node=None,
+ env_decider=env.decide_source):
+ try:
+ env_decider(dependency, target, prev_ni, repo_node)
+ except Exception as e:
+ raise e
+ return True
+
+ if self.env.decide_source.__code__ is not force_build.__code__:
+ self.env.Decider(force_build)
+
+ else:
+ self.env = env
+
+ # print("Override env:%s"%env)
+
if not SConfFS:
SConfFS = SCons.Node.FS.default_fs or \
SCons.Node.FS.FS(env.fs.pathTop)
if sconf_global is not None:
raise SCons.Errors.UserError
- self.env = env
+
if log_file is not None:
log_file = SConfFS.File(env.subst(log_file))
self.logfile = log_file
@@ -449,6 +466,7 @@ class SConfBase(object):
env = sconf.Finish()
"""
self._shutdown()
+
return self.env
def Define(self, name, value = None, comment = None):
@@ -503,6 +521,20 @@ class SConfBase(object):
n.attributes = SCons.Node.Node.Attrs()
n.attributes.keep_targetinfo = 1
+ if True:
+ # Some checkers have intermediate files (for example anything that compiles a c file into a program to run
+ # Those files need to be set to not release their target info, otherwise taskmaster will throw a
+ # Nonetype not callable
+ for c in n.children(scan=False):
+ # Keep debug code here.
+ # print("Checking [%s] for builders and then setting keep_targetinfo"%c)
+ if c.has_builder():
+ n.store_info = 0
+ if not hasattr(c, 'attributes'):
+ c.attributes = SCons.Node.Node.Attrs()
+ c.attributes.keep_targetinfo = 1
+ # pass
+
ret = 1
try:
@@ -609,7 +641,7 @@ class SConfBase(object):
ok = self.TryBuild(self.env.SConfActionBuilder, text, extension)
del self.env['BUILDERS']['SConfActionBuilder']
if ok:
- outputStr = self.lastTarget.get_contents().decode()
+ outputStr = self.lastTarget.get_text_contents()
return (1, outputStr)
return (0, "")
@@ -739,13 +771,21 @@ class SConfBase(object):
self.logstream.write("\n")
self.logstream.close()
self.logstream = None
- # remove the SConfSourceBuilder from the environment
- blds = self.env['BUILDERS']
- del blds['SConfSourceBuilder']
- self.env.Replace( BUILDERS=blds )
+
+ # Now reset the decider if we changed it due to --config=force
+ # We saved original Environment passed in and cloned it to isolate
+ # it from being changed.
+ if cache_mode == FORCE:
+ self.env.Decider(self.original_env.decide_source)
+
+ # remove the SConfSourceBuilder from the environment
+ blds = self.env['BUILDERS']
+ del blds['SConfSourceBuilder']
+ self.env.Replace( BUILDERS=blds )
+
self.active = 0
sconf_global = None
- if not self.config_h is None:
+ if self.config_h is not None:
_ac_config_hs[self.config_h] = self.config_h_text
self.env.fs = self.lastEnvFs
@@ -1000,7 +1040,7 @@ def CheckLib(context, library = None, symbol = "main",
compiles without flags.
"""
- if library == []:
+ if not library:
library = [None]
if not SCons.Util.is_List(library):
diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py
index 36abc7e..bfa4871 100644
--- a/src/engine/SCons/SConfTests.py
+++ b/src/engine/SCons/SConfTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/SConfTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/SConfTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -33,8 +33,6 @@ from types import *
import unittest
import TestCmd
-import TestUnit
-
sys.stdout = io.StringIO()
@@ -115,9 +113,9 @@ class SConfTestCase(unittest.TestCase):
def checks(self, sconf, TryFuncString):
TryFunc = self.SConf.SConfBase.__dict__[TryFuncString]
- res1 = TryFunc( sconf, "int main() { return 0; }\n", ".c" )
+ res1 = TryFunc( sconf, "int main(void) { return 0; }\n", ".c" )
res2 = TryFunc( sconf,
- '#include "no_std_header.h"\nint main() {return 0; }\n',
+ '#include "no_std_header.h"\nint main(void) {return 0; }\n',
'.c' )
return (res1,res2)
@@ -196,7 +194,7 @@ class SConfTestCase(unittest.TestCase):
pass
def add_post_action(self, *actions):
pass
- def children(self):
+ def children(self, scan = 1):
return []
def get_state(self):
return self.state
@@ -254,7 +252,7 @@ class SConfTestCase(unittest.TestCase):
def checks(sconf):
prog = """
#include <stdio.h>
-int main() {
+int main(void) {
printf( "Hello" );
return 0;
}
@@ -300,10 +298,17 @@ int main() {
"""Test SConf.TryAction
"""
def actionOK(target, source, env):
- open(str(target[0]), "w").write( "RUN OK\n" )
+ with open(str(target[0]), "w") as f:
+ f.write("RUN OK\n")
return None
def actionFAIL(target, source, env):
return 1
+ def actionUnicode(target, source, env):
+ with open(str(target[0]), "wb") as f:
+ f.write('2\302\242\n')
+ return None
+
+
self._resetSConfState()
sconf = self.SConf.SConf(self.scons_env,
conf_dir=self.test.workpath('config.tests'),
@@ -313,6 +318,12 @@ int main() {
assert ret and output.encode('utf-8') == bytearray("RUN OK"+os.linesep,'utf-8'), (ret, output)
(ret, output) = sconf.TryAction(action=actionFAIL)
assert not ret and output == "", (ret, output)
+
+ if not TestCmd.IS_PY3:
+ # GH Issue #3141 - unicode text and py2.7 crashes.
+ (ret, output) = sconf.TryAction(action=actionUnicode)
+ assert ret and output == u'2\xa2\n', (ret, output)
+
finally:
sconf.Finish()
@@ -755,7 +766,7 @@ int main() {
prog = """
#include <stdio.h>
-int main() {
+int main(void) {
printf( "Hello" );
return 0;
}
@@ -779,8 +790,7 @@ int main() {
if __name__ == "__main__":
- suite = unittest.makeSuite(SConfTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/SConsign.py b/src/engine/SCons/SConsign.py
index 9d2f69e..e003933 100644
--- a/src/engine/SCons/SConsign.py
+++ b/src/engine/SCons/SConsign.py
@@ -5,7 +5,7 @@ Writing and reading information to the .sconsign file or files.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Writing and reading information to the .sconsign file or files.
from __future__ import print_function
-__revision__ = "src/engine/SCons/SConsign.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/SConsign.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -76,7 +76,8 @@ def Get_DataBase(dir):
except KeyError:
path = d.entry_abspath(DB_Name)
try: db = DataBase[d] = DB_Module.open(path, mode)
- except (IOError, OSError): pass
+ except (IOError, OSError):
+ pass
else:
if mode != "r":
DB_sync_list.append(db)
@@ -334,10 +335,15 @@ class DirFile(Dir):
Dir.__init__(self, fp, dir)
except KeyboardInterrupt:
raise
- except:
+ except Exception:
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
+ try:
+ fp.close()
+ except AttributeError:
+ pass
+
global sig_files
sig_files.append(self)
@@ -394,7 +400,8 @@ class DirFile(Dir):
# here, or in any of the following calls, would get
# raised, indicating something like a potentially
# serious disk or network issue.
- open(self.sconsign, 'wb').write(open(fname, 'rb').read())
+ with open(self.sconsign, 'wb') as f, open(fname, 'rb') as f2:
+ f.write(f2.read())
os.chmod(self.sconsign, mode)
try:
os.unlink(temp)
@@ -416,7 +423,7 @@ def File(name, dbm_module=None):
else:
ForDirectory = DB
DB_Name = name
- if not dbm_module is None:
+ if dbm_module is not None:
DB_Module = dbm_module
# Local Variables:
diff --git a/src/engine/SCons/SConsignTests.py b/src/engine/SCons/SConsignTests.py
index 37e0de9..1ae1f47 100644
--- a/src/engine/SCons/SConsignTests.py
+++ b/src/engine/SCons/SConsignTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/SConsignTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/SConsignTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import sys
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py
index 6cdab4a..206de5f 100644
--- a/src/engine/SCons/Scanner/C.py
+++ b/src/engine/SCons/Scanner/C.py
@@ -5,7 +5,7 @@ This module implements the dependency scanner for C/C++ code.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ This module implements the dependency scanner for C/C++ code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/C.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/C.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Node.FS
import SCons.Scanner
diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py
index f7b2b16..8e1e3b3 100644
--- a/src/engine/SCons/Scanner/CTests.py
+++ b/src/engine/SCons/Scanner/CTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/CTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/CTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -48,7 +48,7 @@ test.write('f1.cpp',"""
#include \"f1.h\"
#include <f2.h>
-int main()
+int main(void)
{
return 0;
}
@@ -60,7 +60,7 @@ test.write('f2.cpp',"""
#include \"f1.h\"
#import <f4.h>
-int main()
+int main(void)
{
return 0;
}
@@ -79,7 +79,7 @@ test.write('f3.cpp',"""
const char* x = "#include <never.h>"
-int main()
+int main(void)
{
return 0;
}
@@ -113,7 +113,7 @@ test.write('fa.cpp',"""
#include \"fa.h\"
#include <fb.h>
-int main()
+int main(void)
{
return 0;
}
@@ -135,7 +135,7 @@ test.write(['work', 'src', 'fff.c'], """
#include <iii.h>
#include <jjj.h>
-int main()
+int main(void)
{
return 0;
}
@@ -144,7 +144,7 @@ int main()
test.write([ 'work', 'src', 'aaa.c'], """
#include "bbb.h"
-int main()
+int main(void)
{
return 0;
}
@@ -155,7 +155,7 @@ test.write([ 'work', 'src', 'bbb.h'], "\n")
test.write([ 'repository', 'src', 'ccc.c'], """
#include "ddd.h"
-int main()
+int main(void)
{
return 0;
}
@@ -218,7 +218,7 @@ def deps_match(self, deps, headers):
global my_normpath
scanned = list(map(my_normpath, list(map(str, deps))))
expect = list(map(my_normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
# define some tests:
diff --git a/src/engine/SCons/Scanner/D.py b/src/engine/SCons/Scanner/D.py
index 3b6f2f9..1ad9e89 100644
--- a/src/engine/SCons/Scanner/D.py
+++ b/src/engine/SCons/Scanner/D.py
@@ -8,7 +8,7 @@ Coded by Andy Friesen
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Coded by Andy Friesen
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/D.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/D.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Scanner
@@ -46,7 +46,7 @@ class D(SCons.Scanner.Classic):
name = "DScanner",
suffixes = '$DSUFFIXES',
path_variable = 'DPATH',
- regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
+ regex = r'(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
)
def find_include(self, include, source_dir, path):
diff --git a/src/engine/SCons/Scanner/DTests.py b/src/engine/SCons/Scanner/DTests.py
index 58fbe76..f115eb0 100644
--- a/src/engine/SCons/Scanner/DTests.py
+++ b/src/engine/SCons/Scanner/DTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,12 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/DTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/DTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
import TestCmd
-import TestUnit
import SCons.Scanner.D
@@ -80,7 +79,7 @@ def deps_match(self, deps, headers):
global my_normpath
scanned = list(map(my_normpath, list(map(str, deps))))
expect = list(map(my_normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
"""
Examples from https://dlang.org/spec/module.html
@@ -266,14 +265,7 @@ class DScannerTestCase(unittest.TestCase):
self.helper('multiline.d', ['A.d'])
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- DScannerTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/Dir.py b/src/engine/SCons/Scanner/Dir.py
index 66d5b6d..be8ae6c 100644
--- a/src/engine/SCons/Scanner/Dir.py
+++ b/src/engine/SCons/Scanner/Dir.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/Dir.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/Dir.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Node.FS
import SCons.Scanner
diff --git a/src/engine/SCons/Scanner/DirTests.py b/src/engine/SCons/Scanner/DirTests.py
index 12f1844..71e527f 100644
--- a/src/engine/SCons/Scanner/DirTests.py
+++ b/src/engine/SCons/Scanner/DirTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,14 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/DirTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/DirTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import sys
import unittest
import TestCmd
-import TestUnit
import SCons.Node.FS
import SCons.Scanner.Dir
@@ -121,14 +120,8 @@ class DirEntryScannerTestCase(DirScannerTestBase):
sss = list(map(str, deps))
assert sss == [], sss
-def suite():
- suite = unittest.TestSuite()
- suite.addTest(DirScannerTestCase())
- suite.addTest(DirEntryScannerTestCase())
- return suite
-
if __name__ == "__main__":
- TestUnit.run(suite())
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/Fortran.py b/src/engine/SCons/Scanner/Fortran.py
index 8a8f3eb..d315bc9 100644
--- a/src/engine/SCons/Scanner/Fortran.py
+++ b/src/engine/SCons/Scanner/Fortran.py
@@ -5,7 +5,7 @@ This module implements the dependency scanner for Fortran code.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ This module implements the dependency scanner for Fortran code.
# 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/Scanner/Fortran.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/Fortran.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import re
@@ -78,7 +78,7 @@ class F90Scanner(SCons.Scanner.Classic):
def scan(self, node, env, path=()):
# cache the includes list in node so we only scan it once:
- if node.includes != None:
+ if node.includes is not None:
mods_and_includes = node.includes
else:
# retrieve all included filenames
@@ -187,7 +187,7 @@ def FortranScan(path_variable="FORTRANPATH"):
# (\w+) : match the module name that is being USE'd
#
#
- use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"
+ use_regex = r"(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"
# The INCLUDE statement regex matches the following:
@@ -275,7 +275,7 @@ def FortranScan(path_variable="FORTRANPATH"):
# set of semicolon-separated INCLUDE statements
# (as allowed by the F2003 standard)
- include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
+ include_regex = r"""(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
# The MODULE statement regex finds module definitions by matching
# the following:
@@ -285,21 +285,29 @@ def FortranScan(path_variable="FORTRANPATH"):
# but *not* the following:
#
# MODULE PROCEDURE procedure_name
+# MODULE SUBROUTINE subroutine_name
+# MODULE FUNCTION function_name
+# MODULE PURE SUBROUTINE|FUNCTION subroutine_name|function_name
+# MODULE ELEMENTAL SUBROUTINE|FUNCTION subroutine_name|function_name
#
# Here is a breakdown of the regex:
#
-# (?i) : regex is case insensitive
-# ^\s* : any amount of white space
-# MODULE : match the string MODULE, case insensitive
-# \s+ : match one or more white space characters
-# (?!PROCEDURE) : but *don't* match if the next word matches
-# PROCEDURE (negative lookahead assertion),
-# case insensitive
-# (\w+) : match one or more alphanumeric characters
-# that make up the defined module name and
-# save it in a group
-
- def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
+# (?i) : regex is case insensitive
+# ^\s* : any amount of white space
+# MODULE : match the string MODULE, case
+# insensitive
+# \s+ : match one or more white space
+# characters
+# (?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)
+# : but *don't* match if the next word
+# matches PROCEDURE, SUBROUTINE,
+# FUNCTION, PURE or ELEMENTAL (negative
+# lookahead assertion), case insensitive
+# (\w+) : match one or more alphanumeric
+# characters that make up the defined
+# module name and save it in a group
+
+ def_regex = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\w+)"""
scanner = F90Scanner("FortranScan",
"$FORTRANSUFFIXES",
diff --git a/src/engine/SCons/Scanner/FortranTests.py b/src/engine/SCons/Scanner/FortranTests.py
index 4194018..5bf4be6 100644
--- a/src/engine/SCons/Scanner/FortranTests.py
+++ b/src/engine/SCons/Scanner/FortranTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,11 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/FortranTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/FortranTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
-import sys
import unittest
import SCons.Scanner.Fortran
@@ -33,17 +32,16 @@ import SCons.Node.FS
import SCons.Warnings
import TestCmd
-import TestUnit
original = os.getcwd()
-test = TestCmd.TestCmd(workdir = '')
+test = TestCmd.TestCmd(workdir='')
os.chdir(test.workpath(''))
# create some source files and headers:
-test.write('fff1.f',"""
+test.write('fff1.f', """
PROGRAM FOO
INCLUDE 'f1.f'
include 'f2.f'
@@ -51,7 +49,7 @@ test.write('fff1.f',"""
END
""")
-test.write('fff2.f',"""
+test.write('fff2.f', """
PROGRAM FOO
INCLUDE 'f2.f'
include 'd1/f2.f'
@@ -60,30 +58,28 @@ test.write('fff2.f',"""
END
""")
-test.write('fff3.f',"""
+test.write('fff3.f', """
PROGRAM FOO
INCLUDE 'f3.f' ; INCLUDE\t'd1/f3.f'
STOP
END
""")
-
# for Emacs -> "
test.subdir('d1', ['d1', 'd2'])
-headers = ['fi.f', 'never.f',
- 'd1/f1.f', 'd1/f2.f', 'd1/f3.f', 'd1/fi.f',
- 'd1/d2/f1.f', 'd1/d2/f2.f', 'd1/d2/f3.f',
- 'd1/d2/f4.f', 'd1/d2/fi.f']
+test_headers = ['fi.f', 'never.f',
+ 'd1/f1.f', 'd1/f2.f', 'd1/f3.f', 'd1/fi.f',
+ 'd1/d2/f1.f', 'd1/d2/f2.f', 'd1/d2/f3.f',
+ 'd1/d2/f4.f', 'd1/d2/fi.f']
-for h in headers:
+for h in test_headers:
test.write(h, "\n")
-
test.subdir('include', 'subdir', ['subdir', 'include'])
-test.write('fff4.f',"""
+test.write('fff4.f', """
PROGRAM FOO
INCLUDE 'f4.f'
STOP
@@ -93,7 +89,7 @@ test.write('fff4.f',"""
test.write('include/f4.f', "\n")
test.write('subdir/include/f4.f', "\n")
-test.write('fff5.f',"""
+test.write('fff5.f', """
PROGRAM FOO
INCLUDE 'f5.f'
INCLUDE 'not_there.f'
@@ -104,7 +100,7 @@ test.write('fff5.f',"""
test.write('f5.f', "\n")
test.subdir('repository', ['repository', 'include'],
- [ 'repository', 'src' ])
+ ['repository', 'src'])
test.subdir('work', ['work', 'src'])
test.write(['repository', 'include', 'iii.f'], "\n")
@@ -117,26 +113,25 @@ test.write(['work', 'src', 'fff.f'], """
END
""")
-test.write([ 'work', 'src', 'aaa.f'], """
+test.write(['work', 'src', 'aaa.f'], """
PROGRAM FOO
INCLUDE 'bbb.f'
STOP
END
""")
-test.write([ 'work', 'src', 'bbb.f'], "\n")
+test.write(['work', 'src', 'bbb.f'], "\n")
-test.write([ 'repository', 'src', 'ccc.f'], """
+test.write(['repository', 'src', 'ccc.f'], """
PROGRAM FOO
INCLUDE 'ddd.f'
STOP
END
""")
-test.write([ 'repository', 'src', 'ddd.f'], "\n")
+test.write(['repository', 'src', 'ddd.f'], "\n")
-
-test.write('fff90a.f90',"""
+test.write('fff90a.f90', """
PROGRAM FOO
! Test comments - these includes should NOT be picked up
@@ -194,18 +189,19 @@ USE mod25 ! Test USE statement at the beginning of line
END
""")
-modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
- 'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
- 'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
- 'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
- 'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod']
+test_modules = ['mod01.mod', 'mod02.mod', 'mod03.mod', 'mod04.mod', 'mod05.mod',
+ 'mod06.mod', 'mod07.mod', 'mod08.mod', 'mod09.mod', 'mod10.mod',
+ 'mod11.mod', 'mod12.mod', 'mod13.mod', 'mod14.mod', 'mod15.mod',
+ 'mod16.mod', 'mod17.mod', 'mod18.mod', 'mod19.mod', 'mod20.mod',
+ 'mod21.mod', 'mod22.mod', 'mod23.mod', 'mod24.mod', 'mod25.mod']
-for m in modules:
+for m in test_modules:
test.write(m, "\n")
test.subdir('modules')
test.write(['modules', 'use.mod'], "\n")
+
# define some helpers:
class DummyEnvironment(object):
@@ -215,7 +211,7 @@ class DummyEnvironment(object):
def Dictionary(self, *args):
if not args:
- return { 'FORTRANPATH': self.path, 'FORTRANMODSUFFIX' : ".mod" }
+ return {'FORTRANPATH': self.path, 'FORTRANMODSUFFIX': ".mod"}
elif len(args) == 1 and args[0] == 'FORTRANPATH':
return self.path
else:
@@ -224,13 +220,13 @@ class DummyEnvironment(object):
def has_key(self, key):
return key in self.Dictionary()
- def __getitem__(self,key):
+ def __getitem__(self, key):
return self.Dictionary()[key]
- def __setitem__(self,key,value):
+ def __setitem__(self, key, value):
self.Dictionary()[key] = value
- def __delitem__(self,key):
+ def __delitem__(self, key):
del self.Dictionary()[key]
def subst(self, arg, target=None, source=None, conv=None):
@@ -255,10 +251,12 @@ class DummyEnvironment(object):
def File(self, filename):
return self.fs.File(filename)
+
def deps_match(self, deps, headers):
scanned = list(map(os.path.normpath, list(map(str, deps))))
expect = list(map(os.path.normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+
# define some tests:
@@ -275,6 +273,7 @@ class FortranScannerTestCase1(unittest.TestCase):
test.unlink('f1.f')
test.unlink('f2.f')
+
class FortranScannerTestCase2(unittest.TestCase):
def runTest(self):
test.write('f1.f', "\n")
@@ -288,6 +287,7 @@ class FortranScannerTestCase2(unittest.TestCase):
test.unlink('f1.f')
test.unlink('f2.f')
+
class FortranScannerTestCase3(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
@@ -297,6 +297,7 @@ class FortranScannerTestCase3(unittest.TestCase):
headers = ['d1/f1.f', 'd1/f2.f']
deps_match(self, deps, headers)
+
class FortranScannerTestCase4(unittest.TestCase):
def runTest(self):
test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
@@ -308,6 +309,7 @@ class FortranScannerTestCase4(unittest.TestCase):
deps_match(self, deps, headers)
test.write(['d1', 'f2.f'], "\n")
+
class FortranScannerTestCase5(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1")])
@@ -317,6 +319,7 @@ class FortranScannerTestCase5(unittest.TestCase):
headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/f2.f']
deps_match(self, deps, headers)
+
class FortranScannerTestCase6(unittest.TestCase):
def runTest(self):
test.write('f2.f', "\n")
@@ -324,19 +327,21 @@ class FortranScannerTestCase6(unittest.TestCase):
s = SCons.Scanner.Fortran.FortranScan()
path = s.path(env)
deps = s(env.File('fff2.f'), env, path)
- headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
+ headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
deps_match(self, deps, headers)
test.unlink('f2.f')
+
class FortranScannerTestCase7(unittest.TestCase):
def runTest(self):
env = DummyEnvironment([test.workpath("d1/d2"), test.workpath("d1")])
s = SCons.Scanner.Fortran.FortranScan()
path = s.path(env)
deps = s(env.File('fff2.f'), env, path)
- headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/d2/f2.f']
+ headers = ['d1/f2.f', 'd1/d2/f2.f', 'd1/d2/f2.f']
deps_match(self, deps, headers)
+
class FortranScannerTestCase8(unittest.TestCase):
def runTest(self):
test.write('f2.f', "\n")
@@ -344,10 +349,11 @@ class FortranScannerTestCase8(unittest.TestCase):
s = SCons.Scanner.Fortran.FortranScan()
path = s.path(env)
deps = s(env.File('fff2.f'), env, path)
- headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
+ headers = ['d1/f2.f', 'd1/d2/f2.f', 'f2.f']
deps_match(self, deps, headers)
test.unlink('f2.f')
+
class FortranScannerTestCase9(unittest.TestCase):
def runTest(self):
test.write('f3.f', "\n")
@@ -356,9 +362,11 @@ class FortranScannerTestCase9(unittest.TestCase):
path = s.path(env)
n = env.File('fff3.f')
+
def my_rexists(s):
s.Tag('rexists_called', 1)
return SCons.Node._rexists_map[s.GetTag('old_rexists')](s)
+
n.Tag('old_rexists', n._func_rexists)
SCons.Node._rexists_map[3] = my_rexists
n._func_rexists = 3
@@ -369,10 +377,11 @@ class FortranScannerTestCase9(unittest.TestCase):
# scanned, essential for cooperation with VariantDir functionality.
assert n.GetTag('rexists_called')
- headers = ['d1/f3.f', 'f3.f']
+ headers = ['d1/f3.f', 'f3.f']
deps_match(self, deps, headers)
test.unlink('f3.f')
+
class FortranScannerTestCase10(unittest.TestCase):
def runTest(self):
env = DummyEnvironment(["include"])
@@ -380,18 +389,20 @@ class FortranScannerTestCase10(unittest.TestCase):
path = s.path(env)
deps1 = s(env.File('fff4.f'), env, path)
env.fs.chdir(env.Dir('subdir'))
- dir = env.fs.getcwd()
+ test_dir = env.fs.getcwd()
env.fs.chdir(env.Dir(''))
- path = s.path(env, dir)
+ path = s.path(env, test_dir)
deps2 = s(env.File('#fff4.f'), env, path)
- headers1 = list(map(test.workpath, ['include/f4.f']))
- headers2 = ['include/f4.f']
+ headers1 = [test.workpath(f) for f in ['include/f4.f']]
+ headers2 = ['include/f4.f']
deps_match(self, deps1, headers1)
deps_match(self, deps2, headers2)
+
class FortranScannerTestCase11(unittest.TestCase):
def runTest(self):
SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning)
+
class TestOut(object):
def __call__(self, x):
self.out = x
@@ -407,7 +418,8 @@ class FortranScannerTestCase11(unittest.TestCase):
# Did we catch the warning from not finding not_there.f?
assert to.out
- deps_match(self, deps, [ 'f5.f' ])
+ deps_match(self, deps, ['f5.f'])
+
class FortranScannerTestCase12(unittest.TestCase):
def runTest(self):
@@ -421,6 +433,7 @@ class FortranScannerTestCase12(unittest.TestCase):
deps_match(self, deps, ['f4.f'])
test.unlink('include/fff4.f')
+
class FortranScannerTestCase13(unittest.TestCase):
def runTest(self):
os.chdir(test.workpath('work'))
@@ -429,9 +442,9 @@ class FortranScannerTestCase13(unittest.TestCase):
# Create a derived file in a directory that does not exist yet.
# This was a bug at one time.
- f1=fs.File('include2/jjj.f')
- f1.builder=1
- env = DummyEnvironment(['include','include2'])
+ f1 = fs.File('include2/jjj.f')
+ f1.builder = 1
+ env = DummyEnvironment(['include', 'include2'])
env.fs = fs
s = SCons.Scanner.Fortran.FortranScan()
path = s.path(env)
@@ -439,6 +452,7 @@ class FortranScannerTestCase13(unittest.TestCase):
deps_match(self, deps, [test.workpath('repository/include/iii.f'), 'include2/jjj.f'])
os.chdir(test.workpath(''))
+
class FortranScannerTestCase14(unittest.TestCase):
def runTest(self):
os.chdir(test.workpath('work'))
@@ -451,15 +465,16 @@ class FortranScannerTestCase14(unittest.TestCase):
s = SCons.Scanner.Fortran.FortranScan()
path = s.path(env)
deps1 = s(fs.File('build1/aaa.f'), env, path)
- deps_match(self, deps1, [ 'build1/bbb.f' ])
+ deps_match(self, deps1, ['build1/bbb.f'])
deps2 = s(fs.File('build2/aaa.f'), env, path)
- deps_match(self, deps2, [ 'src/bbb.f' ])
+ deps_match(self, deps2, ['src/bbb.f'])
deps3 = s(fs.File('build1/ccc.f'), env, path)
- deps_match(self, deps3, [ 'build1/ddd.f' ])
+ deps_match(self, deps3, ['build1/ddd.f'])
deps4 = s(fs.File('build2/ccc.f'), env, path)
- deps_match(self, deps4, [ test.workpath('repository/src/ddd.f') ])
+ deps_match(self, deps4, [test.workpath('repository/src/ddd.f')])
os.chdir(test.workpath(''))
+
class FortranScannerTestCase15(unittest.TestCase):
def runTest(self):
class SubstEnvironment(DummyEnvironment):
@@ -468,6 +483,7 @@ class FortranScannerTestCase15(unittest.TestCase):
return test.workpath("d1")
else:
return arg
+
test.write(['d1', 'f2.f'], " INCLUDE 'fi.f'\n")
env = SubstEnvironment(["$junk"])
s = SCons.Scanner.Fortran.FortranScan()
@@ -477,6 +493,7 @@ class FortranScannerTestCase15(unittest.TestCase):
deps_match(self, deps, headers)
test.write(['d1', 'f2.f'], "\n")
+
class FortranScannerTestCase16(unittest.TestCase):
def runTest(self):
test.write('f1.f', "\n")
@@ -512,28 +529,10 @@ class FortranScannerTestCase16(unittest.TestCase):
test.unlink('f9.f')
test.unlink('f10.f')
-def suite():
- suite = unittest.TestSuite()
- suite.addTest(FortranScannerTestCase1())
- suite.addTest(FortranScannerTestCase2())
- suite.addTest(FortranScannerTestCase3())
- suite.addTest(FortranScannerTestCase4())
- suite.addTest(FortranScannerTestCase5())
- suite.addTest(FortranScannerTestCase6())
- suite.addTest(FortranScannerTestCase7())
- suite.addTest(FortranScannerTestCase8())
- suite.addTest(FortranScannerTestCase9())
- suite.addTest(FortranScannerTestCase10())
- suite.addTest(FortranScannerTestCase11())
- suite.addTest(FortranScannerTestCase12())
- suite.addTest(FortranScannerTestCase13())
- suite.addTest(FortranScannerTestCase14())
- suite.addTest(FortranScannerTestCase15())
- suite.addTest(FortranScannerTestCase16())
- return suite
+
if __name__ == "__main__":
- TestUnit.run(suite())
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/IDL.py b/src/engine/SCons/Scanner/IDL.py
index 706ff41..88226e6 100644
--- a/src/engine/SCons/Scanner/IDL.py
+++ b/src/engine/SCons/Scanner/IDL.py
@@ -6,7 +6,7 @@ Definition Language) files.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Definition Language) files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/IDL.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/IDL.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Node.FS
import SCons.Scanner
diff --git a/src/engine/SCons/Scanner/IDLTests.py b/src/engine/SCons/Scanner/IDLTests.py
index f1b64c0..9bc4e5a 100644
--- a/src/engine/SCons/Scanner/IDLTests.py
+++ b/src/engine/SCons/Scanner/IDLTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/IDLTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/IDLTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
import sys
@@ -159,7 +159,7 @@ test.write(['work', 'src', 'fff.c'], """
#include <iii.idl>
#include <jjj.idl>
-int main()
+int main(void)
{
return 0;
}
@@ -168,7 +168,7 @@ int main()
test.write([ 'work', 'src', 'aaa.c'], """
#include "bbb.idl"
-int main()
+int main(void)
{
return 0;
}
@@ -179,7 +179,7 @@ test.write([ 'work', 'src', 'bbb.idl'], "\n")
test.write([ 'repository', 'src', 'ccc.c'], """
#include "ddd.idl"
-int main()
+int main(void)
{
return 0;
}
@@ -243,7 +243,7 @@ if os.path.normcase('foo') == os.path.normcase('FOO'):
def deps_match(self, deps, headers):
scanned = list(map(my_normpath, list(map(str, deps))))
expect = list(map(my_normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
# define some tests:
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py
index 69154bd..8afe5b0 100644
--- a/src/engine/SCons/Scanner/LaTeX.py
+++ b/src/engine/SCons/Scanner/LaTeX.py
@@ -5,7 +5,7 @@ This module implements the dependency scanner for LaTeX code.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ This module implements the dependency scanner for LaTeX code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/LaTeX.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/LaTeX.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import re
@@ -128,8 +128,8 @@ class LaTeX(SCons.Scanner.Base):
Unlike most scanners, which use regular expressions that just
return the included file name, this returns a tuple consisting
of the keyword for the inclusion ("include", "includegraphics",
- "input", or "bibliography"), and then the file name itself.
- Based on a quick look at LaTeX documentation, it seems that we
+ "input", or "bibliography"), and then the file name itself.
+ Based on a quick look at LaTeX documentation, it seems that we
should append .tex suffix for the "include" keywords, append .tex if
there is no extension for the "input" keyword, and need to add .bib
for the "bibliography" keyword that does not accept extensions by itself.
@@ -137,7 +137,7 @@ class LaTeX(SCons.Scanner.Base):
Finally, if there is no extension for an "includegraphics" keyword
latex will append .ps or .eps to find the file, while pdftex may use .pdf,
.jpg, .tif, .mps, or .png.
-
+
The actual subset and search order may be altered by
DeclareGraphicsExtensions command. This complication is ignored.
The default order corresponds to experimentation with teTeX::
@@ -179,15 +179,7 @@ class LaTeX(SCons.Scanner.Base):
'inputfrom', 'subinputfrom']
def __init__(self, name, suffixes, graphics_extensions, *args, **kw):
-
- # We have to include \n with the % we exclude from the first part
- # part of the regex because the expression is compiled with re.M.
- # Without the \n, the ^ could match the beginning of a *previous*
- # line followed by one or more newline characters (i.e. blank
- # lines), interfering with a match on the next line.
- # add option for whitespace before the '[options]' or the '{filename}'
regex = r'''
- ^[^%\n]*
\\(
include
| includegraphics(?:\s*\[[^\]]+\])?
@@ -333,7 +325,7 @@ class LaTeX(SCons.Scanner.Base):
line_continues_a_comment = False
for line in text.splitlines():
line,comment = self.comment_re.findall(line)[0]
- if line_continues_a_comment == True:
+ if line_continues_a_comment:
out[-1] = out[-1] + line.lstrip()
else:
out.append(line)
@@ -348,8 +340,8 @@ class LaTeX(SCons.Scanner.Base):
# Cache the includes list in node so we only scan it once:
# path_dict = dict(list(path))
# add option for whitespace (\s) before the '['
- noopt_cre = re.compile('\s*\[.*$')
- if node.includes != None:
+ noopt_cre = re.compile(r'\s*\[.*$')
+ if node.includes is not None:
includes = node.includes
else:
text = self.canonical_text(node.get_text_contents())
@@ -372,9 +364,9 @@ class LaTeX(SCons.Scanner.Base):
inc_list = include[2].split(',')
else:
inc_list = include[1].split(',')
- for j in range(len(inc_list)):
- split_includes.append( (inc_type, inc_subdir, inc_list[j]) )
- #
+ for inc in inc_list:
+ split_includes.append((inc_type, inc_subdir, inc))
+
includes = split_includes
node.includes = includes
@@ -386,8 +378,8 @@ class LaTeX(SCons.Scanner.Base):
directory of the main file just as latex does"""
path_dict = dict(list(path))
-
- queue = []
+
+ queue = []
queue.extend( self.scan(node) )
seen = {}
@@ -402,7 +394,7 @@ class LaTeX(SCons.Scanner.Base):
source_dir = node.get_dir()
#for include in includes:
while queue:
-
+
include = queue.pop()
inc_type, inc_subdir, inc_filename = include
diff --git a/src/engine/SCons/Scanner/LaTeXTests.py b/src/engine/SCons/Scanner/LaTeXTests.py
index 93729d4..8750000 100644
--- a/src/engine/SCons/Scanner/LaTeXTests.py
+++ b/src/engine/SCons/Scanner/LaTeXTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/LaTeXTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/LaTeXTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -31,14 +31,13 @@ import sys
import unittest
import TestCmd
-import TestUnit
import SCons.Node.FS
import SCons.Scanner.LaTeX
test = TestCmd.TestCmd(workdir = '')
-test.write('test1.latex',"""
+test.write('test1.latex',r"""
\include{inc1}
\input{inc2}
include{incNO}
@@ -52,16 +51,22 @@ xyzzy \include{inc6}
\subinputfrom{subdir}{inc3e}
""")
-test.write('test2.latex',"""
+test.write('test2.latex',r"""
\include{inc1}
\include{inc3}
""")
-test.write('test3.latex',"""
+test.write('test3.latex',r"""
\includegraphics{inc4.eps}
\includegraphics[width=60mm]{inc5.xyz}
""")
+test.write('test4.latex',r"""
+\include{inc1}\include{inc2}
+\only<1>{\includegraphics{inc5.xyz}}%
+\only<2>{\includegraphics{inc7.png}}
+""")
+
test.subdir('subdir')
test.write('inc1.tex',"\n")
@@ -74,6 +79,7 @@ test.write(['subdir', 'inc3c.tex'], "\n")
test.write(['subdir', 'inc4.eps'], "\n")
test.write('inc5.xyz', "\n")
test.write('inc6.tex', "\n")
+test.write('inc7.png', "\n")
test.write('incNO.tex', "\n")
# define some helpers:
@@ -123,7 +129,7 @@ def deps_match(self, deps, headers):
global my_normpath
scanned = list(map(my_normpath, list(map(str, deps))))
expect = list(map(my_normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
class LaTeXScannerTestCase1(unittest.TestCase):
@@ -156,16 +162,17 @@ class LaTeXScannerTestCase3(unittest.TestCase):
files = ['inc5.xyz', 'subdir/inc4.eps']
deps_match(self, deps, files)
-
-def suite():
- suite = unittest.TestSuite()
- suite.addTest(LaTeXScannerTestCase1())
- suite.addTest(LaTeXScannerTestCase2())
- suite.addTest(LaTeXScannerTestCase3())
- return suite
+class LaTeXScannerTestCase4(unittest.TestCase):
+ def runTest(self):
+ env = DummyEnvironment(TEXINPUTS=[test.workpath("subdir")],LATEXSUFFIXES = [".tex", ".ltx", ".latex"])
+ s = SCons.Scanner.LaTeX.LaTeXScanner()
+ path = s.path(env)
+ deps = s(env.File('test4.latex'), env, path)
+ files = ['inc1.tex', 'inc2.tex', 'inc5.xyz', 'inc7.png']
+ deps_match(self, deps, files)
if __name__ == "__main__":
- TestUnit.run(suite())
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/Prog.py b/src/engine/SCons/Scanner/Prog.py
index 63d5a38..2ae3c68 100644
--- a/src/engine/SCons/Scanner/Prog.py
+++ b/src/engine/SCons/Scanner/Prog.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/Prog.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/Prog.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Node
import SCons.Node.FS
diff --git a/src/engine/SCons/Scanner/ProgTests.py b/src/engine/SCons/Scanner/ProgTests.py
index 1f4dfb5..7dae37c 100644
--- a/src/engine/SCons/Scanner/ProgTests.py
+++ b/src/engine/SCons/Scanner/ProgTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,14 +21,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/ProgTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/ProgTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import sys
import unittest
import TestCmd
-import TestUnit
import SCons.Node.FS
import SCons.Scanner.Prog
@@ -274,7 +273,7 @@ def suite():
return suite
if __name__ == "__main__":
- TestUnit.run(suite())
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/RC.py b/src/engine/SCons/Scanner/RC.py
index 4202362..4f0cee2 100644
--- a/src/engine/SCons/Scanner/RC.py
+++ b/src/engine/SCons/Scanner/RC.py
@@ -6,7 +6,7 @@ Definition Language) files.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Definition Language) files.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/RC.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/RC.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import re
@@ -48,9 +48,9 @@ def RCScan():
"""Return a prototype Scanner instance for scanning RC source files"""
res_re= r'^(?:\s*#\s*(?:include)|' \
- '.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
- '\s*.*?)' \
- '\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
+ r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
+ r'\s*.*?)' \
+ r'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
"$RCSUFFIXES",
"CPPPATH",
diff --git a/src/engine/SCons/Scanner/RCTests.py b/src/engine/SCons/Scanner/RCTests.py
index fa0a9b4..2915985 100644
--- a/src/engine/SCons/Scanner/RCTests.py
+++ b/src/engine/SCons/Scanner/RCTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/RCTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/RCTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
import sys
@@ -29,7 +29,6 @@ import collections
import os
import TestCmd
-import TestUnit
import SCons.Scanner.RC
import SCons.Node.FS
@@ -117,7 +116,7 @@ if os.path.normcase('foo') == os.path.normcase('FOO'):
def deps_match(self, deps, headers):
scanned = sorted(map(my_normpath, list(map(str, deps))))
expect = sorted(map(my_normpath, headers))
- self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
+ self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
# define some tests:
@@ -167,7 +166,7 @@ def suite():
return suite
if __name__ == "__main__":
- TestUnit.run(suite())
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Scanner/SWIG.py b/src/engine/SCons/Scanner/SWIG.py
index 048574c..5f2a3e3 100644
--- a/src/engine/SCons/Scanner/SWIG.py
+++ b/src/engine/SCons/Scanner/SWIG.py
@@ -5,7 +5,7 @@ This module implements the dependency scanner for SWIG code.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,14 +27,14 @@ This module implements the dependency scanner for SWIG code.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/SWIG.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/SWIG.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Scanner
SWIGSuffixes = [ '.i' ]
def SWIGScanner():
- expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)'
+ expr = r'^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)'
scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr)
return scanner
diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py
index a962a4c..64842d4 100644
--- a/src/engine/SCons/Scanner/ScannerTests.py
+++ b/src/engine/SCons/Scanner/ScannerTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Scanner/ScannerTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/ScannerTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -132,16 +132,16 @@ class BaseTestCase(unittest.TestCase):
scanned = scanner(filename, env, path)
scanned_strs = [str(x) for x in scanned]
- self.failUnless(self.filename == filename, "the filename was passed incorrectly")
- self.failUnless(self.env == env, "the environment was passed incorrectly")
- self.failUnless(scanned_strs == deps, "the dependencies were returned incorrectly")
+ self.assertTrue(self.filename == filename, "the filename was passed incorrectly")
+ self.assertTrue(self.env == env, "the environment was passed incorrectly")
+ self.assertTrue(scanned_strs == deps, "the dependencies were returned incorrectly")
for d in scanned:
- self.failUnless(not isinstance(d, str), "got a string in the dependencies")
+ self.assertTrue(not isinstance(d, str), "got a string in the dependencies")
if len(args) > 0:
- self.failUnless(self.arg == args[0], "the argument was passed incorrectly")
+ self.assertTrue(self.arg == args[0], "the argument was passed incorrectly")
else:
- self.failIf(hasattr(self, "arg"), "an argument was given when it shouldn't have been")
+ self.assertFalse(hasattr(self, "arg"), "an argument was given when it shouldn't have been")
def test___call__dict(self):
"""Test calling Scanner.Base objects with a dictionary"""
@@ -245,7 +245,7 @@ class BaseTestCase(unittest.TestCase):
dict[s] = 777
i = hash(id(s))
h = hash(list(dict.keys())[0])
- self.failUnless(h == i,
+ self.assertTrue(h == i,
"hash Scanner base class expected %s, got %s" % (i, h))
def test_scan_check(self):
@@ -260,7 +260,7 @@ class BaseTestCase(unittest.TestCase):
self.checked = {}
path = s.path(env)
scanned = s(DummyNode('x'), env, path)
- self.failUnless(self.checked['x'] == 1,
+ self.assertTrue(self.checked['x'] == 1,
"did not call check function")
def test_recursive(self):
@@ -269,42 +269,42 @@ class BaseTestCase(unittest.TestCase):
s = SCons.Scanner.Base(function = self.func)
n = s.recurse_nodes(nodes)
- self.failUnless(n == [],
+ self.assertTrue(n == [],
"default behavior returned nodes: %s" % n)
s = SCons.Scanner.Base(function = self.func, recursive = None)
n = s.recurse_nodes(nodes)
- self.failUnless(n == [],
+ self.assertTrue(n == [],
"recursive = None returned nodes: %s" % n)
s = SCons.Scanner.Base(function = self.func, recursive = 1)
n = s.recurse_nodes(nodes)
- self.failUnless(n == n,
+ self.assertTrue(n == n,
"recursive = 1 didn't return all nodes: %s" % n)
def odd_only(nodes):
return [n for n in nodes if n % 2]
s = SCons.Scanner.Base(function = self.func, recursive = odd_only)
n = s.recurse_nodes(nodes)
- self.failUnless(n == [1, 3],
+ self.assertTrue(n == [1, 3],
"recursive = 1 didn't return all nodes: %s" % n)
def test_get_skeys(self):
"""Test the Scanner.Base get_skeys() method"""
s = SCons.Scanner.Base(function = self.func)
sk = s.get_skeys()
- self.failUnless(sk == [],
+ self.assertTrue(sk == [],
"did not initialize to expected []")
s = SCons.Scanner.Base(function = self.func, skeys = ['.1', '.2'])
sk = s.get_skeys()
- self.failUnless(sk == ['.1', '.2'],
+ self.assertTrue(sk == ['.1', '.2'],
"sk was %s, not ['.1', '.2']")
s = SCons.Scanner.Base(function = self.func, skeys = '$LIST')
env = DummyEnvironment(LIST = ['.3', '.4'])
sk = s.get_skeys(env)
- self.failUnless(sk == ['.3', '.4'],
+ self.assertTrue(sk == ['.3', '.4'],
"sk was %s, not ['.3', '.4']")
def test_select(self):
@@ -432,19 +432,19 @@ class CurrentTestCase(unittest.TestCase):
path = s.path(env)
hnb = HasNoBuilder()
s(hnb, env, path)
- self.failUnless(hnb.called_has_builder, "did not call has_builder()")
- self.failUnless(not hnb.called_is_up_to_date, "did call is_up_to_date()")
- self.failUnless(hnb.func_called, "did not call func()")
+ self.assertTrue(hnb.called_has_builder, "did not call has_builder()")
+ self.assertTrue(not hnb.called_is_up_to_date, "did call is_up_to_date()")
+ self.assertTrue(hnb.func_called, "did not call func()")
inc = IsNotCurrent()
s(inc, env, path)
- self.failUnless(inc.called_has_builder, "did not call has_builder()")
- self.failUnless(inc.called_is_up_to_date, "did not call is_up_to_date()")
- self.failUnless(not inc.func_called, "did call func()")
+ self.assertTrue(inc.called_has_builder, "did not call has_builder()")
+ self.assertTrue(inc.called_is_up_to_date, "did not call is_up_to_date()")
+ self.assertTrue(not inc.func_called, "did call func()")
ic = IsCurrent()
s(ic, env, path)
- self.failUnless(ic.called_has_builder, "did not call has_builder()")
- self.failUnless(ic.called_is_up_to_date, "did not call is_up_to_date()")
- self.failUnless(ic.func_called, "did not call func()")
+ self.assertTrue(ic.called_has_builder, "did not call has_builder()")
+ self.assertTrue(ic.called_is_up_to_date, "did not call is_up_to_date()")
+ self.assertTrue(ic.func_called, "did not call func()")
class ClassicTestCase(unittest.TestCase):
@@ -461,7 +461,7 @@ class ClassicTestCase(unittest.TestCase):
def test_find_include(self):
"""Test the Scanner.Classic find_include() method"""
env = DummyEnvironment()
- s = SCons.Scanner.Classic("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
+ s = SCons.Scanner.Classic("t", ['.suf'], 'MYPATH', r'^my_inc (\S+)')
def _find_file(filename, paths):
return paths[0]+'/'+filename
@@ -479,7 +479,7 @@ class ClassicTestCase(unittest.TestCase):
def test_name(self):
"""Test setting the Scanner.Classic name"""
- s = SCons.Scanner.Classic("my_name", ['.s'], 'MYPATH', '^my_inc (\S+)')
+ s = SCons.Scanner.Classic("my_name", ['.s'], 'MYPATH', r'^my_inc (\S+)')
assert s.name == "my_name", s.name
def test_scan(self):
@@ -505,7 +505,7 @@ class ClassicTestCase(unittest.TestCase):
return include, include
env = DummyEnvironment()
- s = MyScanner("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
+ s = MyScanner("t", ['.suf'], 'MYPATH', r'^my_inc (\S+)')
# This set of tests is intended to test the scanning operation
# of the Classic scanner.
@@ -566,7 +566,7 @@ class ClassicTestCase(unittest.TestCase):
s = SCons.Scanner.Classic("Test", [], None, "", function=self.func, recursive=1)
n = s.recurse_nodes(nodes)
- self.failUnless(n == n,
+ self.assertTrue(n == n,
"recursive = 1 didn't return all nodes: %s" % n)
def odd_only(nodes):
@@ -574,7 +574,7 @@ class ClassicTestCase(unittest.TestCase):
s = SCons.Scanner.Classic("Test", [], None, "", function=self.func, recursive=odd_only)
n = s.recurse_nodes(nodes)
- self.failUnless(n == [1, 3],
+ self.assertTrue(n == [1, 3],
"recursive = 1 didn't return all nodes: %s" % n)
diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py
index 73e8c09..feff12a 100644
--- a/src/engine/SCons/Scanner/__init__.py
+++ b/src/engine/SCons/Scanner/__init__.py
@@ -5,7 +5,7 @@ The Scanner package for the SCons software construction utility.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The Scanner package for the SCons software construction utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Scanner/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Scanner/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import re
@@ -207,7 +207,7 @@ class Base(object):
self = self.select(node)
- if not self.argument is _null:
+ if self.argument is not _null:
node_list = self.function(node, env, path, self.argument)
else:
node_list = self.function(node, env, path)
diff --git a/src/engine/SCons/Scanner/__init__.xml b/src/engine/SCons/Scanner/__init__.xml
index db2d14b..436d806 100644
--- a/src/engine/SCons/Scanner/__init__.xml
+++ b/src/engine/SCons/Scanner/__init__.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Script/Interactive.py b/src/engine/SCons/Script/Interactive.py
index dee770c..3d70728 100644
--- a/src/engine/SCons/Script/Interactive.py
+++ b/src/engine/SCons/Script/Interactive.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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.
from __future__ import print_function
-__revision__ = "src/engine/SCons/Script/Interactive.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/Interactive.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """
SCons interactive mode
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index 076c30b..878f824 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -17,7 +17,7 @@ unsupported_python_version = (2, 6, 0)
deprecated_python_version = (2, 7, 0)
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -38,7 +38,7 @@ deprecated_python_version = (2, 7, 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/Main.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -48,6 +48,7 @@ import sys
import time
import traceback
import sysconfig
+import platform
import SCons.CacheDir
import SCons.Debug
@@ -58,6 +59,7 @@ import SCons.Job
import SCons.Node
import SCons.Node.FS
import SCons.Platform
+import SCons.Platform.virtualenv
import SCons.SConf
import SCons.Script
import SCons.Taskmaster
@@ -66,6 +68,20 @@ import SCons.Warnings
import SCons.Script.Interactive
+# Global variables
+first_command_start = None
+last_command_end = None
+print_objects = 0
+print_memoizer = 0
+print_stacktrace = 0
+print_time = 0
+sconscript_time = 0
+cumulative_command_time = 0
+exit_status = 0 # final exit status, assume success by default
+this_build_status = 0 # "exit status" of an individual build
+num_jobs = None
+delayed_warnings = []
+
def fetch_win32_parallel_msg():
# A subsidiary function that exists solely to isolate this import
@@ -85,15 +101,14 @@ def revert_io():
sys.stderr = sys.__stderr__
sys.stdout = sys.__stdout__
+
class SConsPrintHelpException(Exception):
pass
+
display = SCons.Util.display
progress_display = SCons.Util.DisplayEngine()
-first_command_start = None
-last_command_end = None
-
class Progressor(object):
prev = ''
@@ -441,19 +456,6 @@ def python_version_deprecated(version=sys.version_info):
return version < deprecated_python_version
-# Global variables
-
-print_objects = 0
-print_memoizer = 0
-print_stacktrace = 0
-print_time = 0
-sconscript_time = 0
-cumulative_command_time = 0
-exit_status = 0 # final exit status, assume success by default
-this_build_status = 0 # "exit status" of an individual build
-num_jobs = None
-delayed_warnings = []
-
class FakeOptionParser(object):
"""
A do-nothing option parser, used for the initial OptionsParser variable.
@@ -622,7 +624,7 @@ def _SConstruct_exists(dirname='', repositories=[], filelist=None):
current directory.
"""
if not filelist:
- filelist = ['SConstruct', 'Sconstruct', 'sconstruct']
+ filelist = ['SConstruct', 'Sconstruct', 'sconstruct', 'SConstruct.py', 'Sconstruct.py', 'sconstruct.py']
for file in filelist:
sfile = os.path.join(dirname, file)
if os.path.isfile(sfile):
@@ -862,6 +864,13 @@ def _main(parser):
for warning_type, message in delayed_warnings:
SCons.Warnings.warn(warning_type, message)
+ if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ if options.enable_virtualenv:
+ SCons.Platform.virtualenv.enable_virtualenv = True
+
+ if options.ignore_virtualenv:
+ SCons.Platform.virtualenv.ignore_virtualenv = True
+
if options.diskcheck:
SCons.Node.FS.set_diskcheck(options.diskcheck)
@@ -1161,7 +1170,7 @@ def _build_targets(fs, options, targets, target_top):
# -U, local SConscript Default() targets
target_top = fs.Dir(target_top)
def check_dir(x, target_top=target_top):
- if hasattr(x, 'cwd') and not x.cwd is None:
+ if hasattr(x, 'cwd') and x.cwd is not None:
cwd = x.cwd.srcnode()
return cwd == target_top
else:
@@ -1253,7 +1262,11 @@ def _build_targets(fs, options, targets, target_top):
BuildTask.options = options
- python_has_threads = sysconfig.get_config_var('WITH_THREAD')
+ is_pypy = platform.python_implementation() == 'PyPy'
+ # As of 3.7, python removed support for threadless platforms.
+ # See https://www.python.org/dev/peps/pep-0011/
+ is_37_or_later = sys.version_info >= (3, 7)
+ python_has_threads = sysconfig.get_config_var('WITH_THREAD') or is_pypy or is_37_or_later
# to check if python configured with threads.
global num_jobs
num_jobs = options.num_jobs
@@ -1347,7 +1360,7 @@ def main():
pass
parts.append(version_string("engine", SCons))
parts.append(path_string("engine", SCons))
- parts.append("Copyright (c) 2001 - 2017 The SCons Foundation")
+ parts.append("Copyright (c) 2001 - 2019 The SCons Foundation")
version = ''.join(parts)
from . import SConsOptions
@@ -1363,7 +1376,7 @@ def main():
revert_io()
except SystemExit as s:
if s:
- exit_status = s
+ exit_status = s.code
except KeyboardInterrupt:
print("scons: Build interrupted.")
sys.exit(2)
diff --git a/src/engine/SCons/Script/Main.xml b/src/engine/SCons/Script/Main.xml
index 73db83e..c1c4bde 100644
--- a/src/engine/SCons/Script/Main.xml
+++ b/src/engine/SCons/Script/Main.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Script/MainTests.py b/src/engine/SCons/Script/MainTests.py
index f5660b0..752ea0a 100644
--- a/src/engine/SCons/Script/MainTests.py
+++ b/src/engine/SCons/Script/MainTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,12 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Script/MainTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/MainTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Script.Main
@@ -41,12 +39,7 @@ import SCons.Script.Main
# of private functionality.
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = []
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Script/SConsOptions.py b/src/engine/SCons/Script/SConsOptions.py
index 5515c7d..5651c96 100644
--- a/src/engine/SCons/Script/SConsOptions.py
+++ b/src/engine/SCons/Script/SConsOptions.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/SConsOptions.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import optparse
import re
@@ -38,6 +38,7 @@ except ImportError:
_ = gettext
import SCons.Node.FS
+import SCons.Platform.virtualenv
import SCons.Warnings
OptionValueError = optparse.OptionValueError
@@ -146,7 +147,7 @@ class SConsValues(optparse.Values):
"""
Sets an option from an SConscript file.
"""
- if not name in self.settable:
+ if name not in self.settable:
raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name)
if name == 'num_jobs':
@@ -166,7 +167,7 @@ class SConsValues(optparse.Values):
value = str(value)
except ValueError:
raise SCons.Errors.UserError("A string is required: %s"%repr(value))
- if not value in SCons.Node.FS.Valid_Duplicates:
+ if value not in SCons.Node.FS.Valid_Duplicates:
raise SCons.Errors.UserError("Not a valid duplication style: %s" % value)
# Set the duplicate style right away so it can affect linking
# of SConscript files.
@@ -225,39 +226,8 @@ class SConsOption(optparse.Option):
fmt = "option %s: nargs='?' is incompatible with short options"
raise SCons.Errors.UserError(fmt % self._short_opts[0])
- try:
- _orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS
-
- _orig_CHECK_METHODS = optparse.Option.CHECK_METHODS
-
- except AttributeError:
- # optparse.Option had no CONST_ACTIONS before Python 2.5.
-
- _orig_CONST_ACTIONS = ("store_const",)
-
- def _check_const(self):
- if self.action not in self.CONST_ACTIONS and self.const is not None:
- raise OptionError(
- "'const' must not be supplied for action %r" % self.action,
- self)
-
- # optparse.Option collects its list of unbound check functions
- # up front. This sucks because it means we can't just override
- # the _check_const() function like a normal method, we have to
- # actually replace it in the list. This seems to be the most
- # straightforward way to do that.
-
- _orig_CHECK_METHODS = [optparse.Option._check_action,
- optparse.Option._check_type,
- optparse.Option._check_choice,
- optparse.Option._check_dest,
- _check_const,
- optparse.Option._check_nargs,
- optparse.Option._check_callback]
-
- CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional]
-
- CONST_ACTIONS = _orig_CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
+ CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_nargs_optional]
+ CONST_ACTIONS = optparse.Option.CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
class SConsOptionGroup(optparse.OptionGroup):
"""
@@ -363,7 +333,7 @@ class SConsOptionParser(optparse.OptionParser):
in self.largs, so that any value overridden on the
command line is immediately available if the user turns
around and does a GetOption() right away.
-
+
We mimic the processing of the single args
in the original OptionParser._process_args(), but here we
allow exact matches for long-opts only (no partial
@@ -374,7 +344,7 @@ class SConsOptionParser(optparse.OptionParser):
command-line arguments that
1. haven't been processed so far (self.largs), but
2. are possibly not added to the list of options yet.
-
+
So, when we only have a value for "--myargument" yet,
a command-line argument of "--myarg=test" would set it.
Responsible for this behaviour is the method
@@ -383,7 +353,7 @@ class SConsOptionParser(optparse.OptionParser):
be unique.
This would lead to further confusion, because we might want
to add another option "--myarg" later on (see issue #2929).
-
+
"""
rargs = []
largs_restore = []
@@ -400,7 +370,7 @@ class SConsOptionParser(optparse.OptionParser):
if "=" in l:
# Split into option and value
lopt = l.split("=", 1)
-
+
if lopt[0] in self._long_opt:
# Argument is already known
rargs.append('='.join(lopt))
@@ -415,7 +385,7 @@ class SConsOptionParser(optparse.OptionParser):
skip = True
else:
rargs.append(l)
-
+
# Parse the filtered list
self.parse_args(rargs, self.values)
# Restore the list of remaining arguments for the
@@ -689,7 +659,7 @@ def Parser(version):
metavar="TYPE")
def opt_duplicate(option, opt, value, parser):
- if not value in SCons.Node.FS.Valid_Duplicates:
+ if value not in SCons.Node.FS.Valid_Duplicates:
raise OptionValueError(opt_invalid('duplication', value,
SCons.Node.FS.Valid_Duplicates))
setattr(parser.values, option.dest, value)
@@ -706,6 +676,12 @@ def Parser(version):
action="callback", callback=opt_duplicate,
help=opt_duplicate_help)
+ if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
+ op.add_option('--enable-virtualenv',
+ dest="enable_virtualenv",
+ action="store_true",
+ help="Import certain virtualenv variables to SCons")
+
op.add_option('-f', '--file', '--makefile', '--sconstruct',
nargs=1, type="string",
dest="file", default=[],
@@ -733,6 +709,11 @@ def Parser(version):
help="Search DIR for imported Python modules.",
metavar="DIR")
+ op.add_option('--ignore-virtualenv',
+ dest="ignore_virtualenv",
+ action="store_true",
+ help="Do not import virtualenv variables to SCons")
+
op.add_option('--implicit-cache',
dest='implicit_cache', default=False,
action="store_true",
@@ -906,6 +887,7 @@ def Parser(version):
action="append",
help="Search REPOSITORY for source and target files.")
+
# Options from Make and Cons classic that we do not yet support,
# but which we may support someday and whose (potential) meanings
# we don't want to change. These all get a "the -X option is not
@@ -978,7 +960,6 @@ def Parser(version):
action="callback", callback=opt_not_yet,
# help="Warn when an undefined variable is referenced."
help=SUPPRESS_HELP)
-
return op
# Local Variables:
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 350772e..9687c29 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -5,10 +5,8 @@ files.
"""
-from __future__ import print_function
-
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 +27,7 @@ from __future__ import print_function
# 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/SConscript.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/SConscript.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons
import SCons.Action
@@ -46,12 +44,15 @@ import SCons.Script.Main
import SCons.Tool
import SCons.Util
+from . import Main
+
import collections
import os
import os.path
import re
import sys
import traceback
+import time
class SConscriptReturn(Exception):
pass
@@ -152,6 +153,35 @@ def Return(*vars, **kw):
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
+def handle_missing_SConscript(f, must_exist=None):
+ """Take appropriate action on missing file in SConscript() call.
+
+ Print a warning or raise an exception on missing file.
+ On first warning, print a deprecation message.
+
+ Args:
+ f (str): path of missing configuration file
+ must_exist (bool): raise exception if file does not exist
+
+ Raises:
+ UserError if 'must_exist' is True or if global
+ SCons.Script._no_missing_sconscript is True.
+ """
+
+ if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False):
+ msg = "Fatal: missing SConscript '%s'" % f.get_internal_path()
+ raise SCons.Errors.UserError(msg)
+
+ if SCons.Script._warn_missing_sconscript_deprecated:
+ msg = "Calling missing SConscript without error is deprecated.\n" + \
+ "Transition by adding must_exist=0 to SConscript calls.\n" + \
+ "Missing SConscript '%s'" % f.get_internal_path()
+ SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
+ SCons.Script._warn_missing_sconscript_deprecated = False
+ else:
+ msg = "Ignoring missing SConscript '%s'" % f.get_internal_path()
+ SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
+
def _SConscript(fs, *files, **kw):
top = fs.Top
sd = fs.SConstruct_dir.rdir()
@@ -248,17 +278,23 @@ def _SConscript(fs, *files, **kw):
pass
try:
try:
-# _file_ = SCons.Util.to_str(_file_)
- exec(compile(_file_.read(), _file_.name, 'exec'),
- call_stack[-1].globals)
+ if Main.print_time:
+ time1 = time.time()
+ scriptdata = _file_.read()
+ scriptname = _file_.name
+ _file_.close()
+ exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
except SConscriptReturn:
pass
finally:
+ if Main.print_time:
+ time2 = time.time()
+ print('SConscript:%s took %0.3f ms' % (f.get_abspath(), (time2 - time1) * 1000.0))
+
if old_file is not None:
call_stack[-1].globals.update({__file__:old_file})
else:
- SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning,
- "Ignoring missing SConscript '%s'" % f.get_internal_path())
+ handle_missing_SConscript(f, kw.get('must_exist', None))
finally:
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
@@ -362,9 +398,9 @@ class SConsEnvironment(SCons.Environment.Base):
something like 3.2b1."""
version = version_string.split(' ')[0].split('.')
v_major = int(version[0])
- v_minor = int(re.match('\d+', version[1]).group())
+ v_minor = int(re.match(r'\d+', version[1]).group())
if len(version) >= 3:
- v_revision = int(re.match('\d+', version[2]).group())
+ v_revision = int(re.match(r'\d+', version[2]).group())
else:
v_revision = 0
return v_major, v_minor, v_revision
@@ -516,6 +552,31 @@ class SConsEnvironment(SCons.Environment.Base):
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
def SConscript(self, *ls, **kw):
+ """Execute SCons configuration files.
+
+ Parameters:
+ *ls (str or list): configuration file(s) to execute.
+
+ Keyword arguments:
+ dirs (list): execute SConscript in each listed directory.
+ name (str): execute script 'name' (used only with 'dirs').
+ exports (list or dict): locally export variables the
+ called script(s) can import.
+ variant_dir (str): mirror sources needed for the build in
+ a variant directory to allow building in it.
+ duplicate (bool): physically duplicate sources instead of just
+ adjusting paths of derived files (used only with 'variant_dir')
+ (default is True).
+ must_exist (bool): fail if a requested script is missing
+ (default is False, default is deprecated).
+
+ Returns:
+ list of variables returned by the called script
+
+ Raises:
+ UserError: a script is not found and such exceptions are enabled.
+ """
+
if 'build_dir' in kw:
msg = """The build_dir keyword has been deprecated; use the variant_dir keyword instead."""
SCons.Warnings.warn(SCons.Warnings.DeprecatedBuildDirWarning, msg)
diff --git a/src/engine/SCons/Script/SConscript.xml b/src/engine/SCons/Script/SConscript.xml
index e6be6d2..2d77aa3 100644
--- a/src/engine/SCons/Script/SConscript.xml
+++ b/src/engine/SCons/Script/SConscript.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -38,6 +38,10 @@ Multiple calls to
&f-Default;
are legal,
and add to the list of default targets.
+As noted above, both forms of this call affect the
+same global list of default targets; the
+construction environment method applies
+construction variable expansion to the targets.
</para>
<para>
@@ -357,12 +361,12 @@ Return('val1 val2')
<scons_function name="SConscript">
<arguments>
-(scripts, [exports, variant_dir, duplicate])
-<!-- (scripts, [exports, variant_dir, src_dir, duplicate]) -->
+(scripts, [exports, variant_dir, duplicate, must_exist])
+<!-- (scripts, [exports, variant_dir, src_dir, duplicate, must_exist]) -->
</arguments>
<arguments>
-(dirs=subdirs, [name=script, exports, variant_dir, duplicate])
-<!-- (dirs=subdirs, [name=script, exports, variant_dir, src_dir, duplicate]) -->
+(dirs=subdirs, [name=script, exports, variant_dir, duplicate, must_exist])
+<!-- (dirs=subdirs, [name=script, exports, variant_dir, src_dir, duplicate, must_exist]) -->
</arguments>
<summary>
<para>
@@ -564,6 +568,17 @@ TODO??? SConscript('build/SConscript', src_dir='src')
</para>
<para>
+The optional
+<varname>must_exist</varname>
+argument, if true, causes an exception to be raised if a requested
+&SConscript; file is not found. The current default is false,
+causing only a warning to be omitted, but this behavior is deprecated.
+For scripts which truly intend to be optional, transition to
+explicty supplying
+<literal>must_exist=False</literal> to the call.
+</para>
+
+<para>
Here are some composite examples:
</para>
diff --git a/src/engine/SCons/Script/SConscriptTests.py b/src/engine/SCons/Script/SConscriptTests.py
index 2b10446..c1232e8 100644
--- a/src/engine/SCons/Script/SConscriptTests.py
+++ b/src/engine/SCons/Script/SConscriptTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/SConscriptTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Script.SConscript
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index ffafadf..cf2e472 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 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Script/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import time
start_time = time.time()
@@ -81,8 +81,8 @@ import SCons.Action
import SCons.Builder
import SCons.Environment
import SCons.Node.FS
-import SCons.Options
import SCons.Platform
+import SCons.Platform.virtualenv
import SCons.Scanner
import SCons.SConf
import SCons.Subst
@@ -150,6 +150,7 @@ Environment = SCons.Environment.Environment
#OptParser = SCons.SConsOptions.OptParser
FindPathDirs = SCons.Scanner.FindPathDirs
Platform = SCons.Platform.Platform
+Virtualenv = SCons.Platform.virtualenv.Virtualenv
Return = _SConscript.Return
Scanner = SCons.Scanner.Base
Tool = SCons.Tool.Tool
@@ -162,12 +163,6 @@ ListVariable = SCons.Variables.ListVariable
PackageVariable = SCons.Variables.PackageVariable
PathVariable = SCons.Variables.PathVariable
-# Deprecated names that will go away some day.
-BoolOption = SCons.Options.BoolOption
-EnumOption = SCons.Options.EnumOption
-ListOption = SCons.Options.ListOption
-PackageOption = SCons.Options.PackageOption
-PathOption = SCons.Options.PathOption
# Action factories.
Chmod = SCons.Defaults.Chmod
@@ -283,12 +278,20 @@ def HelpFunction(text, append=False):
# Will be non-zero if we are reading an SConscript file.
sconscript_reading = 0
+_no_missing_sconscript = False
+_warn_missing_sconscript_deprecated = True
+
+def set_missing_sconscript_error(flag=1):
+ """Set behavior on missing file in SConscript() call. Returns previous value"""
+ global _no_missing_sconscript
+ old = _no_missing_sconscript
+ _no_missing_sconscript = flag
+ return old
+
#
def Variables(files=[], args=ARGUMENTS):
return SCons.Variables.Variables(files, args)
-def Options(files=[], args=ARGUMENTS):
- return SCons.Options.Options(files, args)
# The list of global functions to add to the SConscript name space
# that end up calling corresponding methods or Builders in the
@@ -374,7 +377,9 @@ GlobalDefaultBuilders = [
'SharedObject',
'StaticLibrary',
'StaticObject',
+ 'Substfile',
'Tar',
+ 'Textfile',
'TypeLibrary',
'Zip',
'Package',
diff --git a/src/engine/SCons/Subst.py b/src/engine/SCons/Subst.py
index 90c12a0..1e0d423 100644
--- a/src/engine/SCons/Subst.py
+++ b/src/engine/SCons/Subst.py
@@ -5,7 +5,7 @@ SCons string substitution.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Subst.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import collections
import re
@@ -86,6 +86,9 @@ class Literal(object):
def __neq__(self, other):
return not self.__eq__(other)
+ def __hash__(self):
+ return hash(self.lstr)
+
class SpecialAttrWrapper(object):
"""This is a wrapper for what we call a 'Node special attribute.'
This is any of the attributes of a Node that we can reference from
@@ -338,13 +341,16 @@ SUBST_RAW = 1
SUBST_SIG = 2
_rm = re.compile(r'\$[()]')
-_rm_split = re.compile(r'(\$[()])')
+
+# Note the pattern below only matches $( or $) when there is no
+# preceeding $. (Thus the (?<!\$))
+_rm_split = re.compile(r'(?<!\$)(\$[()])')
# Indexed by the SUBST_* constants above.
_regex_remove = [ _rm, None, _rm_split ]
def _rm_list(list):
- return [l for l in list if not l in ('$(', '$)')]
+ return [l for l in list if l not in ('$(', '$)')]
def _remove_list(list):
result = []
@@ -437,7 +443,11 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
if s0 != '$':
return s
if s1 == '$':
- return '$'
+ # In this case keep the double $'s which we'll later
+ # swap for a single dollar sign as we need to retain
+ # this information to properly avoid matching "$("" when
+ # the actual text was "$$("" (or "$)"" when "$$)"" )
+ return '$$'
elif s1 in '()':
return s
else:
@@ -458,7 +468,7 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
s = lvars[key]
elif key in self.gvars:
s = self.gvars[key]
- elif not NameError in AllowableExceptions:
+ elif NameError not in AllowableExceptions:
raise_exception(NameError(key), lvars['TARGETS'], s)
else:
return ''
@@ -583,6 +593,12 @@ def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={
# Compress strings of white space characters into
# a single space.
result = _space_sep.sub(' ', result).strip()
+
+ # Now replace escaped $'s currently "$$"
+ # This is needed because we now retain $$ instead of
+ # replacing them during substition to avoid
+ # improperly trying to escape "$$(" as being "$("
+ result = result.replace('$$','$')
elif is_Sequence(result):
remove = _list_remove[mode]
if remove:
@@ -674,7 +690,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gv
s = lvars[key]
elif key in self.gvars:
s = self.gvars[key]
- elif not NameError in AllowableExceptions:
+ elif NameError not in AllowableExceptions:
raise_exception(NameError(), lvars['TARGETS'], s)
else:
return
diff --git a/src/engine/SCons/Subst.xml b/src/engine/SCons/Subst.xml
index a75003f..858ff40 100644
--- a/src/engine/SCons/Subst.xml
+++ b/src/engine/SCons/Subst.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py
index 5a85b6c..49a9a2f 100644
--- a/src/engine/SCons/SubstTests.py
+++ b/src/engine/SCons/SubstTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 print_function
-__revision__ = "src/engine/SCons/SubstTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/SubstTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -32,8 +32,6 @@ import unittest
from collections import UserDict
-import TestUnit
-
import SCons.Errors
from SCons.Subst import *
@@ -134,6 +132,7 @@ class SubstTestCase(unittest.TestCase):
def __str__(self):
return self.value
+ # only use of this is currently commented out below
def function_foo(arg):
pass
@@ -336,6 +335,10 @@ class scons_subst_TestCase(SubstTestCase):
# Test double-dollar-sign behavior.
"$$FFF$HHH", "$FFFIII",
+ # Test double-dollar-sign before open paren. It's not meant
+ # to be signature escaping
+ 'echo $$(pwd) > XYZ', 'echo $(pwd) > XYZ',
+
# Test that a Literal will stop dollar-sign substitution.
"$XXX $LITERAL $FFF", "GGG $XXX GGG",
@@ -1044,7 +1047,7 @@ class scons_subst_list_TestCase(SubstTestCase):
node = scons_subst_list("$NODE", env, mode=SUBST_SIG, conv=s, gvars=gvars)
assert node == [[n1]], node
- def test_subst_list_overriding_gvars(self):
+ def test_subst_list_overriding_gvars2(self):
"""Test scons_subst_list(): supplying an overriding gvars dictionary"""
env = DummyEnv({'XXX' : 'xxx'})
result = scons_subst_list('$XXX', env, gvars=env.Dictionary())
@@ -1239,21 +1242,7 @@ class subst_dict_TestCase(unittest.TestCase):
assert SOURCES == ['s3', 'v-rstr-s4', 'v-s5'], SOURCES
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [
- CLVar_TestCase,
- LiteralTestCase,
- SpecialAttrWrapperTestCase,
- quote_spaces_TestCase,
- scons_subst_TestCase,
- scons_subst_list_TestCase,
- scons_subst_once_TestCase,
- subst_dict_TestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index 8fca4a9..29e48ac 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,10 +27,10 @@ import sys
__doc__ = """
Generic Taskmaster module for the SCons build engine.
=====================================================
-
+
This module contains the primary interface(s) between a wrapping user
interface and the SCons build engine. There are two key classes here:
-
+
Taskmaster
----------
This is the main engine for walking the dependency graph and
@@ -54,7 +54,7 @@ __doc__ = """
target(s) that it decides need to be evaluated and/or built.
"""
-__revision__ = "src/engine/SCons/Taskmaster.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Taskmaster.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from itertools import chain
import operator
@@ -470,14 +470,23 @@ class Task(object):
pending_children.discard(t)
for p in t.waiting_parents:
parents[p] = parents.get(p, 0) + 1
+ t.waiting_parents = set()
for t in targets:
if t.side_effects is not None:
for s in t.side_effects:
if s.get_state() == NODE_EXECUTING:
s.set_state(NODE_NO_STATE)
+
+ # The side-effects may have been transferred to
+ # NODE_NO_STATE by executed_with{,out}_callbacks, but was
+ # not taken out of the waiting parents/pending children
+ # data structures. Check for that now.
+ if s.get_state() == NODE_NO_STATE and s.waiting_parents:
+ pending_children.discard(s)
for p in s.waiting_parents:
parents[p] = parents.get(p, 0) + 1
+ s.waiting_parents = set()
for p in s.waiting_s_e:
if p.ref_count == 0:
self.tm.candidates.append(p)
@@ -542,7 +551,7 @@ class Task(object):
try:
exc_type, exc_value, exc_traceback = exc
except ValueError:
- exc_type, exc_value = exc
+ exc_type, exc_value = exc # pylint: disable=unbalanced-tuple-unpacking
exc_traceback = None
# raise exc_type(exc_value).with_traceback(exc_traceback)
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index fab54cf..218870e 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/TaskmasterTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -30,7 +30,6 @@ import copy
import sys
import unittest
-import TestUnit
import SCons.Taskmaster
import SCons.Errors
@@ -1086,6 +1085,7 @@ class TaskmasterTestCase(unittest.TestCase):
exception_values = [
"integer division or modulo",
"integer division or modulo by zero",
+ "integer division by zero", # PyPy2
]
assert str(exc_value) in exception_values, exc_value
@@ -1239,8 +1239,7 @@ Taskmaster: No candidate anymore.
if __name__ == "__main__":
- suite = unittest.makeSuite(TaskmasterTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/386asm.py b/src/engine/SCons/Tool/386asm.py
index b318c4b..1121c3d 100644
--- a/src/engine/SCons/Tool/386asm.py
+++ b/src/engine/SCons/Tool/386asm.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/386asm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 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 80a2cd6..fe819d2 100644
--- a/src/engine/SCons/Tool/386asm.xml
+++ b/src/engine/SCons/Tool/386asm.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/DCommon.py b/src/engine/SCons/Tool/DCommon.py
index 8973853..f6b6000 100644
--- a/src/engine/SCons/Tool/DCommon.py
+++ b/src/engine/SCons/Tool/DCommon.py
@@ -9,7 +9,7 @@ Coded by Russel Winder (russel@winder.org.uk)
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Coded by Russel Winder (russel@winder.org.uk)
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/DCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/DCommon.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/DCommon.xml b/src/engine/SCons/Tool/DCommon.xml
index b1deb82..5103ca1 100644
--- a/src/engine/SCons/Tool/DCommon.xml
+++ b/src/engine/SCons/Tool/DCommon.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/FortranCommon.py b/src/engine/SCons/Tool/FortranCommon.py
index d2126a4..11f1eb7 100644
--- a/src/engine/SCons/Tool/FortranCommon.py
+++ b/src/engine/SCons/Tool/FortranCommon.py
@@ -5,7 +5,7 @@ Stuff for processing Fortran, common to all fortran dialects.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Stuff for processing Fortran, common to all fortran dialects.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/FortranCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/FortranCommon.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import re
import os.path
@@ -64,7 +64,8 @@ def _fortranEmitter(target, source, env):
if not node.exists() and not node.is_derived():
print("Could not locate " + str(node.name))
return ([], [])
- mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
+ # This has to match the def_regex in the Fortran scanner
+ mod_regex = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\w+)"""
cre = re.compile(mod_regex,re.M)
# Retrieve all USE'd module names
modules = cre.findall(node.get_text_contents())
diff --git a/src/engine/SCons/Tool/FortranCommonTests.py b/src/engine/SCons/Tool/FortranCommonTests.py
new file mode 100644
index 0000000..9cca9b0
--- /dev/null
+++ b/src/engine/SCons/Tool/FortranCommonTests.py
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# from typing import Dict, Any
+
+__revision__ = "src/engine/SCons/Tool/FortranCommonTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
+import os.path
+import unittest
+
+import SCons.Node.FS
+import SCons.Warnings
+import SCons.Tool.FortranCommon
+
+import TestCmd
+
+original = os.getcwd()
+
+test = TestCmd.TestCmd(workdir='')
+
+os.chdir(test.workpath(''))
+
+
+class DummyEnvironment(object):
+ dictionary = None # type: Dict[Any, Any]
+
+ def __init__(self, list_cpp_path):
+ self.path = list_cpp_path
+ self.fs = SCons.Node.FS.FS(test.workpath(''))
+ self.dictionary = {}
+
+ def has_key(self, key):
+ return key in self.dictionary
+
+ def __getitem__(self, key):
+ return self.dictionary[key]
+
+ def __setitem__(self, key, value):
+ self.dictionary[key] = value
+
+ def __delitem__(self, key):
+ del self.dictionary[key]
+
+ def subst(self, arg, target=None, source=None, conv=None):
+ if arg[0] == '$':
+ return self[arg[1:]]
+ return arg
+
+ def subst_path(self, path, target=None, source=None, conv=None):
+ if not isinstance(path, list):
+ path = [path]
+ return list(map(self.subst, path))
+
+ def get_calculator(self):
+ return None
+
+ def get_factory(self, factory):
+ return factory or self.fs.File
+
+ def Dir(self, filename):
+ return self.fs.Dir(filename)
+
+ def File(self, filename):
+ return self.fs.File(filename)
+
+
+class FortranScannerSubmodulesTestCase(unittest.TestCase):
+ def runTest(self):
+ """
+ Check that test_1.f90 and test_2.f90 which have interface specifications
+ Don't generate targets for those modules listed in the interface section
+ """
+
+ test.dir_fixture('fortran_unittests')
+ env = DummyEnvironment([test.workpath('modules')])
+ env['FORTRANMODDIR'] = 'modules'
+ env['FORTRANMODSUFFIX'] = '.mod'
+ emitter = SCons.Tool.FortranCommon._fortranEmitter
+ # path = s.path(env)
+
+ for fort in ['test_1.f90', 'test_2.f90']:
+ file_base, _ = os.path.splitext(fort)
+ file_mod = '%s.mod' % file_base
+ f = env.File(fort)
+ (target, source) = emitter([], [f, ], env)
+
+ # print("Targets:%s\nSources:%s"%([str(a) for a in target], [str(a) for a in source]))
+
+ # should only be 1 target and 1 source
+ self.assertEqual(len(target), 1,
+ msg="More than 1 target: %d [%s]" % (len(target), [str(t) for t in target]))
+ self.assertEqual(len(source), 1,
+ msg="More than 1 source: %d [%s]" % (len(source), [str(t) for t in source]))
+
+ # target should be file_base.mod
+ self.assertEqual(str(target[0]).endswith(file_mod), True,
+ msg="Target[0]=%s doesn't end with '%s'" % (str(target[0]), file_mod))
+
+ # source should be file_base .f90
+ self.assertEqual(str(source[0]).endswith(fort), True,
+ msg="Source[0]=%s doesn't end with '%s'" % (str(source[0]), fort))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/src/engine/SCons/Tool/GettextCommon.py b/src/engine/SCons/Tool/GettextCommon.py
index b475d8f..79912b6 100644
--- a/src/engine/SCons/Tool/GettextCommon.py
+++ b/src/engine/SCons/Tool/GettextCommon.py
@@ -3,8 +3,8 @@
Used by several tools of `gettext` toolset.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
-#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -12,10 +12,10 @@ Used by several tools of `gettext` toolset.
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
-#
+#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
-#
+#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -24,7 +24,7 @@ Used by several tools of `gettext` toolset.
# 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/GettextCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/GettextCommon.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Warnings
import re
@@ -71,7 +71,7 @@ SCons.Warnings.enableWarningClass(MsgfmtNotFound)
#############################################################################
class _POTargetFactory(object):
""" A factory of `PO` target files.
-
+
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
(this is required by builders and actions gettext) and `noclean` flags by
default for all produced nodes.
@@ -80,9 +80,9 @@ class _POTargetFactory(object):
def __init__(self, env, nodefault=True, alias=None, precious=True
, noclean=True):
""" Object constructor.
-
+
**Arguments**
-
+
- *env* (`SCons.Environment.Environment`)
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
from default target `'.'`
@@ -160,13 +160,13 @@ from SCons.Builder import BuilderBase
#############################################################################
class _POFileBuilder(BuilderBase):
""" `PO` file builder.
-
+
This is multi-target single-source builder. In typical situation the source
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
targets to be updated from this `POT`. We must run
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
dependencies separatelly for each target file.
-
+
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
with target being list of all targets, all targets would be rebuilt each time
one of the targets from this list is missing. This would happen, for example,
@@ -198,29 +198,29 @@ class _POFileBuilder(BuilderBase):
# After that it calls emitter (which is quite too late). The emitter is
# also called in each iteration, what makes things yet worse.
def __init__(self, env, **kw):
- if not 'suffix' in kw:
+ if 'suffix' not in kw:
kw['suffix'] = '$POSUFFIX'
- if not 'src_suffix' in kw:
+ if 'src_suffix' not in kw:
kw['src_suffix'] = '$POTSUFFIX'
- if not 'src_builder' in kw:
+ if 'src_builder' not in kw:
kw['src_builder'] = '_POTUpdateBuilder'
- if not 'single_source' in kw:
+ if 'single_source' not in kw:
kw['single_source'] = True
alias = None
if 'target_alias' in kw:
alias = kw['target_alias']
del kw['target_alias']
- if not 'target_factory' in kw:
+ if 'target_factory' not in kw:
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
BuilderBase.__init__(self, **kw)
def _execute(self, env, target, source, *args, **kw):
""" Execute builder's actions.
-
- Here we append to `target` the languages read from `$LINGUAS_FILE` and
+
+ Here we append to `target` the languages read from `$LINGUAS_FILE` and
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
The arguments and return value are same as for
- `SCons.Builder.BuilderBase._execute()`.
+ `SCons.Builder.BuilderBase._execute()`.
"""
import SCons.Util
import SCons.Node
@@ -272,7 +272,7 @@ def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
class RPaths(object):
""" Callable object, which returns pathnames relative to SCons current
working directory.
-
+
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
for nodes that are outside of current working directory (`env.fs.getcwd()`).
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
@@ -285,17 +285,17 @@ class RPaths(object):
the references would be correct only on the machine, where `POT` file was
recently re-created. For such reason, we need a function, which always
returns relative paths. This is the purpose of `RPaths` callable object.
-
+
The `__call__` method returns paths relative to current working directory, but
we assume, that *xgettext(1)* is run from the directory, where target file is
going to be created.
-
+
Note, that this may not work for files distributed over several hosts or
across different drives on windows. We assume here, that single local
filesystem holds both source files and target `POT` templates.
-
+
Intended use of `RPaths` - in `xgettext.py`::
-
+
def generate(env):
from GettextCommon import RPaths
...
@@ -318,9 +318,9 @@ class RPaths(object):
def __init__(self, env):
""" Initialize `RPaths` callable object.
-
+
**Arguments**:
-
+
- *env* - a `SCons.Environment.Environment` object, defines *current
working dir*.
"""
@@ -329,16 +329,16 @@ class RPaths(object):
# FIXME: I'm not sure, how it should be implemented (what the *args are in
# general, what is **kw).
def __call__(self, nodes, *args, **kw):
- """ Return nodes' paths (strings) relative to current working directory.
-
+ """ Return nodes' paths (strings) relative to current working directory.
+
**Arguments**:
-
+
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
- *args* - currently unused.
- *kw* - currently unused.
-
+
**Returns**:
-
+
- Tuple of strings, which represent paths relative to current working
directory (for given environment).
"""
@@ -390,7 +390,7 @@ def _detect_xgettext(env):
""" Detects *xgettext(1)* binary """
if 'XGETTEXT' in env:
return env['XGETTEXT']
- xgettext = env.Detect('xgettext');
+ xgettext = env.Detect('xgettext')
if xgettext:
return xgettext
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
@@ -409,7 +409,7 @@ def _detect_msginit(env):
""" Detects *msginit(1)* program. """
if 'MSGINIT' in env:
return env['MSGINIT']
- msginit = env.Detect('msginit');
+ msginit = env.Detect('msginit')
if msginit:
return msginit
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
@@ -428,7 +428,7 @@ def _detect_msgmerge(env):
""" Detects *msgmerge(1)* program. """
if 'MSGMERGE' in env:
return env['MSGMERGE']
- msgmerge = env.Detect('msgmerge');
+ msgmerge = env.Detect('msgmerge')
if msgmerge:
return msgmerge
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
@@ -447,7 +447,7 @@ def _detect_msgfmt(env):
""" Detects *msgmfmt(1)* program. """
if 'MSGFMT' in env:
return env['MSGFMT']
- msgfmt = env.Detect('msgfmt');
+ msgfmt = env.Detect('msgfmt')
if msgfmt:
return msgfmt
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py
index 5c2507d..1e58af6 100644
--- a/src/engine/SCons/Tool/JavaCommon.py
+++ b/src/engine/SCons/Tool/JavaCommon.py
@@ -5,7 +5,7 @@ Stuff for processing Java.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,16 +27,48 @@ Stuff for processing Java.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/JavaCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/JavaCommon.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
import re
+import glob
java_parsing = 1
default_java_version = '1.4'
+# a switch for which jdk versions to use the Scope state for smarter
+# anonymous inner class parsing.
+scopeStateVersions = ('1.8')
+
+# Glob patterns for use in finding where the JDK is.
+# These are pairs, *dir_glob used in the general case,
+# *version_dir_glob if matching only a specific version.
+# For now only used for Windows.
+java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin'
+# On windows, since Java 9, there is a dash between 'jdk' and the version
+# string that wasn't there before. this glob should catch either way.
+java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk*%s*/bin'
+
+# Glob patterns for use in finding where the JDK headers are.
+# These are pairs, *dir_glob used in the general case,
+# *version_dir_glob if matching only a specific version.
+java_macos_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Headers/'
+java_macos_version_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/'
+
+java_linux_include_dirs_glob = [
+ '/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/java-*/include'
+]
+# Need to match path like below (from Centos 7)
+# /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/
+java_linux_version_include_dirs_glob = [
+ '/usr/lib/jvm/java-*-sun-%s*/include',
+ '/usr/lib/jvm/java-%s*-openjdk*/include',
+ '/usr/java/jdk%s*/include'
+]
+
if java_parsing:
# Parse Java files for class names.
#
@@ -59,13 +91,15 @@ if java_parsing:
r'\d*\.\d*|[A-Za-z_][\w\$\.]*|<[A-Za-z_]\w+>|' +
r'/\*|\*/|\[\])')
+
class OuterState(object):
"""The initial state for parsing a Java file for classes,
interfaces, and anonymous inner classes."""
+
def __init__(self, version=default_java_version):
- if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '1.7',
- '1.8', '5', '6'):
+ if version not in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7',
+ '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
msg = "Java version %s not supported" % version
raise NotImplementedError(msg)
@@ -115,8 +149,8 @@ if java_parsing:
ret = SkipState(1, self)
self.skipState = ret
return ret
-
- def __getAnonStack(self):
+
+ def _getAnonStack(self):
return self.anonStacksStack[-1]
def openBracket(self):
@@ -125,15 +159,16 @@ if java_parsing:
def closeBracket(self):
self.brackets = self.brackets - 1
if len(self.stackBrackets) and \
- self.brackets == self.stackBrackets[-1]:
+ self.brackets == self.stackBrackets[-1]:
self.listOutputs.append('$'.join(self.listClasses))
self.localClasses.pop()
self.listClasses.pop()
self.anonStacksStack.pop()
self.stackBrackets.pop()
if len(self.stackAnonClassBrackets) and \
- self.brackets == self.stackAnonClassBrackets[-1]:
- self.__getAnonStack().pop()
+ self.brackets == self.stackAnonClassBrackets[-1] and \
+ self.version not in scopeStateVersions:
+ self._getAnonStack().pop()
self.stackAnonClassBrackets.pop()
def parseToken(self, token):
@@ -145,13 +180,13 @@ if java_parsing:
self.openBracket()
elif token == '}':
self.closeBracket()
- elif token in [ '"', "'" ]:
+ elif token in ['"', "'"]:
return IgnoreState(token, self)
elif token == "new":
# anonymous inner class
if len(self.listClasses) > 0:
return self.__getAnonClassState()
- return self.__getSkipState() # Skip the class name
+ return self.__getSkipState() # Skip the class name
elif token in ['class', 'interface', 'enum']:
if len(self.listClasses) == 0:
self.nextAnon = 1
@@ -171,28 +206,99 @@ if java_parsing:
if self.version in ('1.1', '1.2', '1.3', '1.4'):
clazz = self.listClasses[0]
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
- elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6'):
+ elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
self.stackAnonClassBrackets.append(self.brackets)
className = []
className.extend(self.listClasses)
- self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1
- for anon in self.__getAnonStack():
+ self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1
+ for anon in self._getAnonStack():
className.append(str(anon))
self.listOutputs.append('$'.join(className))
self.nextAnon = self.nextAnon + 1
- self.__getAnonStack().append(0)
+ self._getAnonStack().append(0)
def setPackage(self, package):
self.package = package
+
+ class ScopeState(object):
+ """
+ A state that parses code within a scope normally,
+ within the confines of a scope.
+ """
+
+ def __init__(self, old_state):
+ self.outer_state = old_state.outer_state
+ self.old_state = old_state
+ self.brackets = 0
+
+ def __getClassState(self):
+ try:
+ return self.classState
+ except AttributeError:
+ ret = ClassState(self)
+ self.classState = ret
+ return ret
+
+ def __getAnonClassState(self):
+ try:
+ return self.anonState
+ except AttributeError:
+ ret = SkipState(1, AnonClassState(self))
+ self.anonState = ret
+ return ret
+
+ def __getSkipState(self):
+ try:
+ return self.skipState
+ except AttributeError:
+ ret = SkipState(1, self)
+ self.skipState = ret
+ return ret
+
+ def openBracket(self):
+ self.brackets = self.brackets + 1
+
+ def closeBracket(self):
+ self.brackets = self.brackets - 1
+
+ def parseToken(self, token):
+ # if self.brackets == 0:
+ # return self.old_state.parseToken(token)
+ if token[:2] == '//':
+ return IgnoreState('\n', self)
+ elif token == '/*':
+ return IgnoreState('*/', self)
+ elif token == '{':
+ self.openBracket()
+ elif token == '}':
+ self.closeBracket()
+ if self.brackets == 0:
+ self.outer_state._getAnonStack().pop()
+ return self.old_state
+ elif token in ['"', "'"]:
+ return IgnoreState(token, self)
+ elif token == "new":
+ # anonymous inner class
+ return self.__getAnonClassState()
+ elif token == '.':
+ # Skip the attribute, it might be named "class", in which
+ # case we don't want to treat the following token as
+ # an inner class name...
+ return self.__getSkipState()
+ return self
+
+
class AnonClassState(object):
"""A state that looks for anonymous inner classes."""
+
def __init__(self, old_state):
# outer_state is always an instance of OuterState
self.outer_state = old_state.outer_state
self.old_state = old_state
self.brace_level = 0
+
def parseToken(self, token):
# This is an anonymous class if and only if the next
# non-whitespace token is a bracket. Everything between
@@ -212,32 +318,40 @@ if java_parsing:
if token == 'new':
# look further for anonymous inner class
return SkipState(1, AnonClassState(self))
- elif token in [ '"', "'" ]:
+ elif token in ['"', "'"]:
return IgnoreState(token, self)
elif token == ')':
self.brace_level = self.brace_level - 1
return self
if token == '{':
self.outer_state.addAnonClass()
+ if self.outer_state.version in scopeStateVersions:
+ return ScopeState(old_state=self.old_state).parseToken(token)
return self.old_state.parseToken(token)
+
class SkipState(object):
"""A state that will skip a specified number of tokens before
reverting to the previous state."""
+
def __init__(self, tokens_to_skip, old_state):
self.tokens_to_skip = tokens_to_skip
self.old_state = old_state
+
def parseToken(self, token):
self.tokens_to_skip = self.tokens_to_skip - 1
if self.tokens_to_skip < 1:
return self.old_state
return self
+
class ClassState(object):
"""A state we go into when we hit a class or interface keyword."""
+
def __init__(self, outer_state):
# outer_state is always an instance of OuterState
self.outer_state = outer_state
+
def parseToken(self, token):
# the next non-whitespace token should be the name of the class
if token == '\n':
@@ -245,14 +359,14 @@ if java_parsing:
# If that's an inner class which is declared in a method, it
# requires an index prepended to the class-name, e.g.
# 'Foo$1Inner'
- # http://scons.tigris.org/issues/show_bug.cgi?id=2087
+ # https://github.com/SCons/scons/issues/2087
if self.outer_state.localClasses and \
- self.outer_state.stackBrackets[-1] > \
- self.outer_state.stackBrackets[-2]+1:
+ self.outer_state.stackBrackets[-1] > \
+ self.outer_state.stackBrackets[-2] + 1:
locals = self.outer_state.localClasses[-1]
try:
idx = locals[token]
- locals[token] = locals[token]+1
+ locals[token] = locals[token] + 1
except KeyError:
locals[token] = 1
token = str(locals[token]) + token
@@ -261,29 +375,39 @@ if java_parsing:
self.outer_state.anonStacksStack.append([0])
return self.outer_state
+
class IgnoreState(object):
"""A state that will ignore all tokens until it gets to a
specified token."""
+
def __init__(self, ignore_until, old_state):
self.ignore_until = ignore_until
self.old_state = old_state
+
def parseToken(self, token):
if self.ignore_until == token:
return self.old_state
return self
+
class PackageState(object):
"""The state we enter when we encounter the package keyword.
We assume the next token will be the package name."""
+
def __init__(self, outer_state):
# outer_state is always an instance of OuterState
self.outer_state = outer_state
+
def parseToken(self, token):
self.outer_state.setPackage(token)
return self.outer_state
+
def parse_java_file(fn, version=default_java_version):
- return parse_java(open(fn, 'r').read(), version)
+ with open(fn, 'r') as f:
+ data = f.read()
+ return parse_java(data, version)
+
def parse_java(contents, version=default_java_version, trace=None):
"""Parse a .java file and return a double of package directory,
@@ -315,7 +439,71 @@ else:
is that the file name matches the public class name, and that
the path to the file is the same as the package name.
"""
- return os.path.split(file)
+ return os.path.split(fn)
+
+
+def get_java_install_dirs(platform, version=None):
+ """
+ Find the java jdk installation directories.
+
+ This list is intended to supply as "default paths" for use when looking
+ up actual java binaries.
+
+ :param platform: selector for search algorithm.
+ :param version: If specified, only look for java sdk's of this version
+ :return: list of default paths for java.
+ """
+
+ paths = []
+ if platform == 'win32':
+ if version:
+ paths = glob.glob(java_win32_version_dir_glob % version)
+ else:
+ paths = glob.glob(java_win32_dir_glob)
+ else:
+ # other platforms, do nothing for now
+ pass
+
+ return sorted(paths)
+
+
+def get_java_include_paths(env, javac, version):
+ """
+ Find java include paths for JNI building.
+
+ :param env: construction environment, used to extract platform.
+ :param javac: path to detected javac.
+ :return: list of paths.
+ """
+
+ paths = []
+ if not javac:
+ # there are no paths if we've not detected javac.
+ pass
+ elif env['PLATFORM'] == 'win32':
+ # on Windows, we have the right path to javac, so look locally
+ javac_bin_dir = os.path.dirname(javac)
+ java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include'))
+ paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')]
+ elif env['PLATFORM'] == 'darwin':
+ if not version:
+ paths = [java_macos_include_dir_glob]
+ else:
+ paths = sorted(glob.glob(java_macos_version_include_dir_glob % version))
+ else:
+ base_paths = []
+ if not version:
+ for p in java_linux_include_dirs_glob:
+ base_paths.extend(glob.glob(p))
+ else:
+ for p in java_linux_version_include_dirs_glob:
+ base_paths.extend(glob.glob(p % version))
+
+ for p in base_paths:
+ paths.extend([p, os.path.join(p, 'linux')])
+
+ # print("PATHS:%s"%paths)
+ return paths
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py
index da405f0..45a8a0b 100644
--- a/src/engine/SCons/Tool/JavaCommonTests.py
+++ b/src/engine/SCons/Tool/JavaCommonTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,17 +21,17 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/JavaCommonTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/JavaCommonTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import sys
import unittest
-
-import TestUnit
+import fnmatch
import SCons.Scanner.IDL
import SCons.Tool.JavaCommon
+import TestSCons
# Adding trace=trace to any of the parse_jave() calls below will cause
# the parser to spit out trace messages of the tokens it sees and the
@@ -566,14 +566,122 @@ public class Foo
assert expect == classes, (expect, classes)
+ def test_in_function_class_declaration(self):
+ """
+ Test that implementing a class in a function call doesn't confuse SCons.
+ """
+
+ input = """
+package com.Matthew;
+
+public class AnonDemo {
+
+ public static void main(String[] args) {
+ new AnonDemo().execute();
+ }
+
+ public void execute() {
+ Foo bar = new Foo(new Foo() {
+ @Override
+ public int getX() { return this.x; }
+ }) {
+ @Override
+ public int getX() { return this.x; }
+ };
+ }
+
+ public abstract class Foo {
+ public int x;
+ public abstract int getX();
+
+ public Foo(Foo f) {
+ this.x = f.x;
+ }
+
+ public Foo() {}
+ }
+}
+"""
+ expect = ['AnonDemo$1',
+ 'AnonDemo$2',
+ 'AnonDemo$Foo',
+ 'AnonDemo']
+ pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.8')
+ assert expect == classes, (expect, classes)
+
+ def test_jdk_globs(self):
+ """
+ Verify that the java path globs work with specific examples.
+ :return:
+ """
+ from SCons.Tool.JavaCommon import java_linux_include_dirs_glob, java_linux_version_include_dirs_glob, java_win32_dir_glob, java_win32_version_dir_glob, java_macos_include_dir_glob, java_macos_version_include_dir_glob
+
+ # Test windows globs
+ win_java_dirs = [
+ ('C:/Program Files/Java/jdk1.8.0_201/bin', '1.8.0'),
+ ('C:/Program Files/Java/jdk-11.0.2/bin', '11.0.2'),
+ ('C:/Program Files/Java/jdk1.7.0_80/bin', '1.7.0')
+ ]
+
+ for (wjd, version) in win_java_dirs:
+ if not fnmatch.fnmatch(wjd, java_win32_dir_glob):
+ self.fail("Didn't properly match %s with pattern %s" % (wjd, java_win32_dir_glob))
+ if not fnmatch.fnmatch(wjd, java_win32_version_dir_glob % version):
+ self.fail("Didn't properly match %s with version (%s) specific pattern %s" % (
+ wjd, version, java_win32_version_dir_glob % version))
+
+ non_win_java_include_dirs = [
+ ('/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include', '1.8.0'),
+ ('/usr/lib/jvm/java-1.8.0-openjdk-amd64/include', '1.8.0'),
+ ('/usr/lib/jvm/java-8-openjdk-amd64/include', '8'),
+ ]
+
+ # Test non-windows/non-macos globs
+ for (wjd, version) in non_win_java_include_dirs:
+ match = False
+ globs_tried =[]
+ for jlig in java_linux_include_dirs_glob:
+ globs_tried.append(jlig)
+
+ if fnmatch.fnmatch(wjd, jlig):
+ match = True
+ break
+
+ if not match:
+ self.fail("Didn't properly match %s with pattern %s" % (wjd, globs_tried))
+
+ match = False
+ globs_tried = []
+ for jlvig in java_linux_version_include_dirs_glob:
+ globs_tried.append(jlvig%version)
+ if fnmatch.fnmatch(wjd, jlvig % version):
+ match = True
+ break
+
+ if not match:
+ self.fail("Didn't properly match %s with version (%s) specific pattern %s" % (
+ wjd, version, globs_tried))
+
+ # Test macos globs
+ # Test windows globs
+ macos_java_dirs = [
+ # ('/System/Library/Frameworks/JavaVM.framework/Headers/', None),
+ ('/System/Library/Frameworks/JavaVM.framework/Versions/11.0.2/Headers/', '11.0.2'),
+ ]
+
+ if not fnmatch.fnmatch('/System/Library/Frameworks/JavaVM.framework/Headers/', java_macos_include_dir_glob):
+ self.fail("Didn't properly match %s with pattern %s" % ('/System/Library/Frameworks/JavaVM.framework/Headers/', java_macos_include_dir_glob))
+
+ for (wjd, version) in macos_java_dirs:
+ if not fnmatch.fnmatch(wjd, java_macos_version_include_dir_glob % version):
+ self.fail("Didn't properly match %s with version (%s) specific pattern %s" % (
+ wjd, version, java_macos_version_include_dir_glob % version))
+
+
+
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ parse_javaTestCase ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/MSCommon/__init__.py b/src/engine/SCons/Tool/MSCommon/__init__.py
index 989ab08..e3c4471 100644
--- a/src/engine/SCons/Tool/MSCommon/__init__.py
+++ b/src/engine/SCons/Tool/MSCommon/__init__.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/MSCommon/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """
Common functions for Microsoft Visual Studio and Visual C/C++.
diff --git a/src/engine/SCons/Tool/MSCommon/arch.py b/src/engine/SCons/Tool/MSCommon/arch.py
index 96f05a8..6312541 100644
--- a/src/engine/SCons/Tool/MSCommon/arch.py
+++ b/src/engine/SCons/Tool/MSCommon/arch.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/MSCommon/arch.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/arch.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """Module to define supported Windows chip architectures.
"""
@@ -37,22 +37,22 @@ class ArchDefinition(object):
self.synonyms = synonyms
SupportedArchitectureList = [
- ArchitectureDefinition(
+ ArchDefinition(
'x86',
['i386', 'i486', 'i586', 'i686'],
),
- ArchitectureDefinition(
+ ArchDefinition(
'x86_64',
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
),
- ArchitectureDefinition(
+ ArchDefinition(
'ia64',
['IA64'],
),
- ArchitectureDefinition(
+ ArchDefinition(
'arm',
['ARM'],
),
diff --git a/src/engine/SCons/Tool/MSCommon/common.py b/src/engine/SCons/Tool/MSCommon/common.py
index fcf623f..8353944 100644
--- a/src/engine/SCons/Tool/MSCommon/common.py
+++ b/src/engine/SCons/Tool/MSCommon/common.py
@@ -2,7 +2,7 @@
Common helper functions for working with the Microsoft tool chain.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@ Common helper functions for working with the Microsoft tool chain.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/MSCommon/common.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/common.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import copy
import os
@@ -34,7 +34,6 @@ import re
import SCons.Util
-
LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG')
if LOGFILE == '-':
def debug(message):
@@ -46,7 +45,7 @@ elif LOGFILE:
debug = lambda message: open(LOGFILE, 'a').write(message + '\n')
else:
logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
- debug = logging.debug
+ debug = logging.getLogger(name=__name__).debug
else:
debug = lambda x: None
@@ -117,7 +116,7 @@ def normalize_env(env, keys, force=False):
normenv[k] = copy.deepcopy(env[k])
for k in keys:
- if k in os.environ and (force or not k in normenv):
+ if k in os.environ and (force or k not in normenv):
normenv[k] = os.environ[k]
# This shouldn't be necessary, since the default environment should include system32,
@@ -188,8 +187,10 @@ def get_output(vcbat, args = None, env = None):
# Use the .stdout and .stderr attributes directly because the
# .communicate() method uses the threading module on Windows
# and won't work under Pythons not built with threading.
- stdout = popen.stdout.read()
- stderr = popen.stderr.read()
+ with popen.stdout:
+ stdout = popen.stdout.read()
+ with popen.stderr:
+ stderr = popen.stderr.read()
# Extra debug logic, uncomment if necessary
# debug('get_output():stdout:%s'%stdout)
@@ -206,7 +207,7 @@ def get_output(vcbat, args = None, env = None):
output = stdout.decode("mbcs")
return output
-def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH")):
+def parse_output(output, keep=("INCLUDE", "LIB", "LIBPATH", "PATH", 'VSCMD_ARG_app_plat')):
"""
Parse output from running visual c++/studios vcvarsall.bat and running set
To capture the values listed in keep
diff --git a/src/engine/SCons/Tool/MSCommon/netframework.py b/src/engine/SCons/Tool/MSCommon/netframework.py
index b769c44..edd9fd9 100644
--- a/src/engine/SCons/Tool/MSCommon/netframework.py
+++ b/src/engine/SCons/Tool/MSCommon/netframework.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Tool/MSCommon/netframework.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/netframework.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """
"""
@@ -68,7 +68,7 @@ def query_versions():
# sequence comparison in python is lexicographical
# which is exactly what we want.
# Note we sort backwards so the highest version is first.
- return cmp(bbl,aal)
+ return (aal > bbl) - (aal < bbl)
versions.sort(versrt)
else:
diff --git a/src/engine/SCons/Tool/MSCommon/sdk.py b/src/engine/SCons/Tool/MSCommon/sdk.py
index 8bc9830..e664a30 100644
--- a/src/engine/SCons/Tool/MSCommon/sdk.py
+++ b/src/engine/SCons/Tool/MSCommon/sdk.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/MSCommon/sdk.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/sdk.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """Module to detect the Platform/Windows SDK
@@ -178,6 +178,16 @@ SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
#
# If you update this list, update the documentation in Tool/mssdk.xml.
SupportedSDKList = [
+ WindowsSDK('10.0A',
+ sanity_check_file=r'bin\SetEnv.Cmd',
+ include_subdir='include',
+ lib_subdir={
+ 'x86' : ['lib'],
+ 'x86_64' : [r'lib\x64'],
+ 'ia64' : [r'lib\ia64'],
+ },
+ vc_setup_scripts = SDK70VCSetupScripts,
+ ),
WindowsSDK('10.0',
sanity_check_file=r'bin\SetEnv.Cmd',
include_subdir='include',
diff --git a/src/engine/SCons/Tool/MSCommon/vc.py b/src/engine/SCons/Tool/MSCommon/vc.py
index fba86af..fa7be96 100644
--- a/src/engine/SCons/Tool/MSCommon/vc.py
+++ b/src/engine/SCons/Tool/MSCommon/vc.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@
# * test on 64 bits XP + VS 2005 (and VS 6 if possible)
# * SDK
# * Assembly
-__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """Module for Visual C/C++ detection and configuration.
"""
@@ -43,6 +43,7 @@ import platform
from string import digits as string_digits
import SCons.Warnings
+from SCons.Tool import find_program_path
from . import common
@@ -59,7 +60,10 @@ class VisualCException(Exception):
class UnsupportedVersion(VisualCException):
pass
-class UnsupportedArch(VisualCException):
+class MSVCUnsupportedHostArch(VisualCException):
+ pass
+
+class MSVCUnsupportedTargetArch(VisualCException):
pass
class MissingConfiguration(VisualCException):
@@ -79,15 +83,41 @@ _ARCH_TO_CANONICAL = {
"i486" : "x86",
"i586" : "x86",
"i686" : "x86",
- "ia64" : "ia64",
- "itanium" : "ia64",
+ "ia64" : "ia64", # deprecated
+ "itanium" : "ia64", # deprecated
"x86" : "x86",
"x86_64" : "amd64",
- "x86_amd64" : "x86_amd64", # Cross compile to 64 bit from 32bits
+ "arm" : "arm",
+ "arm64" : "arm64",
+ "aarch64" : "arm64",
+}
+
+_HOST_TARGET_TO_CL_DIR_GREATER_THAN_14 = {
+ ("amd64","amd64") : ("Hostx64","x64"),
+ ("amd64","x86") : ("Hostx64","x86"),
+ ("amd64","arm") : ("Hostx64","arm"),
+ ("amd64","arm64") : ("Hostx64","arm64"),
+ ("x86","amd64") : ("Hostx86","x64"),
+ ("x86","x86") : ("Hostx86","x86"),
+ ("x86","arm") : ("Hostx86","arm"),
+ ("x86","arm64") : ("Hostx86","arm64"),
}
-# Given a (host, target) tuple, return the argument for the bat file. Both host
-# and targets should be canonalized.
+# get path to the cl.exe dir for older VS versions
+# based off a tuple of (host, target) platforms
+_HOST_TARGET_TO_CL_DIR = {
+ ("amd64","amd64") : "amd64",
+ ("amd64","x86") : "amd64_x86",
+ ("amd64","arm") : "amd64_arm",
+ ("amd64","arm64") : "amd64_arm64",
+ ("x86","amd64") : "x86_amd64",
+ ("x86","x86") : "",
+ ("x86","arm") : "x86_arm",
+ ("x86","arm64") : "x86_arm64",
+}
+
+# Given a (host, target) tuple, return the argument for the bat file.
+# Both host and targets should be canonalized.
_HOST_TARGET_ARCH_TO_BAT_ARCH = {
("x86", "x86"): "x86",
("x86", "amd64"): "x86_amd64",
@@ -95,9 +125,32 @@ _HOST_TARGET_ARCH_TO_BAT_ARCH = {
("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express
("amd64", "amd64"): "amd64",
("amd64", "x86"): "x86",
- ("x86", "ia64"): "x86_ia64"
+ ("x86", "ia64"): "x86_ia64", # gone since 14.0
+ ("arm", "arm"): "arm", # since 14.0, maybe gone 14.1?
+ ("x86", "arm"): "x86_arm", # since 14.0
+ ("x86", "arm64"): "x86_arm64", # since 14.1
+ ("amd64", "arm"): "amd64_arm", # since 14.0
+ ("amd64", "arm64"): "amd64_arm64", # since 14.1
}
+_CL_EXE_NAME = 'cl.exe'
+
+def get_msvc_version_numeric(msvc_version):
+ """Get the raw version numbers from a MSVC_VERSION string, so it
+ could be cast to float or other numeric values. For example, '14.0Exp'
+ would get converted to '14.0'.
+
+ Args:
+ msvc_version: str
+ string representing the version number, could contain non
+ digit characters
+
+ Returns:
+ str: the value converted to a numeric only string
+
+ """
+ return ''.join([x for x in msvc_version if x in string_digits + '.'])
+
def get_host_target(env):
debug('vc.py:get_host_target()')
@@ -122,25 +175,33 @@ def get_host_target(env):
try:
host = _ARCH_TO_CANONICAL[host_platform.lower()]
- except KeyError as e:
+ except KeyError:
msg = "Unrecognized host architecture %s"
- raise ValueError(msg % repr(host_platform))
+ raise MSVCUnsupportedHostArch(msg % repr(host_platform))
try:
target = _ARCH_TO_CANONICAL[target_platform.lower()]
- except KeyError as e:
+ except KeyError:
all_archs = str(list(_ARCH_TO_CANONICAL.keys()))
- raise ValueError("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
+ raise MSVCUnsupportedTargetArch("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
return (host, target,req_target_platform)
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
# MSVC_VERSION documentation in Tool/msvc.xml.
-_VCVER = ["14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
+_VCVER = ["14.2", "14.1", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
+
+# if using vswhere, a further mapping is needed
+_VCVER_TO_VSWHERE_VER = {
+ '14.2' : '[16.0, 17.0)',
+ '14.1' : '[15.0, 16.0)',
+}
_VCVER_TO_PRODUCT_DIR = {
+ '14.2' : [
+ (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # VS 2019 doesn't set this key
'14.1' : [
- (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # Visual Studio 2017 doesn't set this registry key anymore
+ (SCons.Util.HKEY_LOCAL_MACHINE, r'')], # VS 2017 doesn't set this key
'14.0' : [
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
'14.0Exp' : [
@@ -188,7 +249,7 @@ _VCVER_TO_PRODUCT_DIR = {
}
def msvc_version_to_maj_min(msvc_version):
- msvc_version_numeric = ''.join([x for x in msvc_version if x in string_digits + '.'])
+ msvc_version_numeric = get_msvc_version_numeric(msvc_version)
t = msvc_version_numeric.split(".")
if not len(t) == 2:
@@ -201,53 +262,73 @@ def msvc_version_to_maj_min(msvc_version):
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
def is_host_target_supported(host_target, msvc_version):
- """Return True if the given (host, target) tuple is supported given the
- msvc version.
-
- Parameters
- ----------
- host_target: tuple
- tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
- compilation from 32 bits windows to 64 bits.
- msvc_version: str
- msvc version (major.minor, e.g. 10.0)
-
- Note
- ----
- This only check whether a given version *may* support the given (host,
- target), not that the toolchain is actually present on the machine.
+ """Check if (host, target) pair is supported for a VC version.
+
+ :note: only checks whether a given version *may* support the given (host,
+ target), not that the toolchain is actually present on the machine.
+ :param tuple host_target: canonalized host-targets pair, e.g.
+ ("x86", "amd64") for cross compilation from 32 bit Windows to 64 bits.
+ :param str msvc_version: Visual C++ version (major.minor), e.g. "10.0"
+ :returns: True or False
"""
# We assume that any Visual Studio version supports x86 as a target
if host_target[1] != "x86":
maj, min = msvc_version_to_maj_min(msvc_version)
if maj < 8:
return False
-
return True
def find_vc_pdir_vswhere(msvc_version):
"""
- Find the MSVC product directory using vswhere.exe .
- Run it asking for specified version and get MSVS install location
- :param msvc_version:
- :return: MSVC install dir
+ Find the MSVC product directory using the vswhere program.
+
+ :param msvc_version: MSVC version to search for
+ :return: MSVC install dir or None
+ :raises UnsupportedVersion: if the version is not known by this file
"""
- vswhere_path = os.path.join(
- 'C:\\',
- 'Program Files (x86)',
- 'Microsoft Visual Studio',
- 'Installer',
- 'vswhere.exe'
- )
- vswhere_cmd = [vswhere_path, '-version', msvc_version, '-property', 'installationPath']
-
- if os.path.exists(vswhere_path):
- sp = subprocess.Popen(vswhere_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- vsdir, err = sp.communicate()
- vsdir = vsdir.decode("mbcs")
- vsdir = vsdir.rstrip()
- vc_pdir = os.path.join(vsdir, 'VC')
+
+ try:
+ vswhere_version = _VCVER_TO_VSWHERE_VER[msvc_version]
+ except KeyError:
+ debug("Unknown version of MSVC: %s" % msvc_version)
+ raise UnsupportedVersion("Unknown version %s" % msvc_version)
+
+ # For bug 3333 - support default location of vswhere for both 64 and 32 bit windows
+ # installs.
+ for pf in ['Program Files (x86)', 'Program Files']:
+ vswhere_path = os.path.join(
+ 'C:\\',
+ pf,
+ 'Microsoft Visual Studio',
+ 'Installer',
+ 'vswhere.exe'
+ )
+ if os.path.exists(vswhere_path):
+ # If we found vswhere, then use it.
+ break
+ else:
+ # No vswhere on system, no install info available
+ return None
+
+ vswhere_cmd = [vswhere_path,
+ '-products', '*',
+ '-version', vswhere_version,
+ '-property', 'installationPath']
+
+ #TODO PY27 cannot use Popen as context manager
+ # try putting it back to the old way for now
+ sp = subprocess.Popen(vswhere_cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ vsdir, err = sp.communicate()
+ if vsdir:
+ vsdir = vsdir.decode("mbcs").splitlines()
+ # vswhere could easily return multiple lines
+ # we could define a way to pick the one we prefer, but since
+ # this data is currently only used to make a check for existence,
+ # returning the first hit should be good enough for now.
+ vc_pdir = os.path.join(vsdir[0], 'VC')
return vc_pdir
else:
# No vswhere on system, no install info available
@@ -255,13 +336,25 @@ def find_vc_pdir_vswhere(msvc_version):
def find_vc_pdir(msvc_version):
- """Try to find the product directory for the given
- version.
+ """Find the MSVC product directory for the given version.
+
+ Tries to look up the path using a registry key from the table
+ _VCVER_TO_PRODUCT_DIR; if there is no key, calls find_vc_pdir_wshere
+ for help instead.
- Note
- ----
- If for some reason the requested version could not be found, an
- exception which inherits from VisualCException will be raised."""
+ Args:
+ msvc_version: str
+ msvc version (major.minor, e.g. 10.0)
+
+ Returns:
+ str: Path found in registry, or None
+
+ Raises:
+ UnsupportedVersion: if the version is not known by this file.
+ MissingConfiguration: found version but the directory is missing.
+
+ Both exceptions inherit from VisualCException.
+ """
root = 'Software\\'
try:
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
@@ -275,8 +368,10 @@ def find_vc_pdir(msvc_version):
if not key:
comps = find_vc_pdir_vswhere(msvc_version)
if not comps:
- debug('find_vc_dir(): no VC found via vswhere for version {}'.format(repr(key)))
+ debug('find_vc_pdir_vswhere(): no VC found for version {}'.format(repr(msvc_version)))
raise SCons.Util.WinError
+ debug('find_vc_pdir_vswhere(): VC found: {}'.format(repr(msvc_version)))
+ return comps
else:
if common.is_win64():
try:
@@ -308,10 +403,10 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
if pdir is None:
raise NoVersionFound("No version of Visual Studio found")
- debug('vc.py: find_batch_file() pdir:{}'.format(pdir))
+ debug('vc.py: find_batch_file() in {}'.format(pdir))
# filter out e.g. "Exp" from the version name
- msvc_ver_numeric = ''.join([x for x in msvc_version if x in string_digits + "."])
+ msvc_ver_numeric = get_msvc_version_numeric(msvc_version)
vernum = float(msvc_ver_numeric)
if 7 <= vernum < 8:
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
@@ -342,26 +437,146 @@ def find_batch_file(env,msvc_version,host_arch,target_arch):
__INSTALLED_VCS_RUN = None
+_VC_TOOLS_VERSION_FILE_PATH = ['Auxiliary', 'Build', 'Microsoft.VCToolsVersion.default.txt']
+_VC_TOOLS_VERSION_FILE = os.sep.join(_VC_TOOLS_VERSION_FILE_PATH)
+
+def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version):
+ """Find the cl.exe on the filesystem in the vc_dir depending on
+ TARGET_ARCH, HOST_ARCH and the msvc version. TARGET_ARCH and
+ HOST_ARCH can be extracted from the passed env, unless its None,
+ which then the native platform is assumed the host and target.
+
+ Args:
+ env: Environment
+ a construction environment, usually if this is passed its
+ because there is a desired TARGET_ARCH to be used when searching
+ for a cl.exe
+ vc_dir: str
+ the path to the VC dir in the MSVC installation
+ msvc_version: str
+ msvc version (major.minor, e.g. 10.0)
+
+ Returns:
+ bool:
+
+ """
-def cached_get_installed_vcs():
+ # determine if there is a specific target platform we want to build for and
+ # use that to find a list of valid VCs, default is host platform == target platform
+ # and same for if no env is specified to extract target platform from
+ if env:
+ (host_platform, target_platform, req_target_platform) = get_host_target(env)
+ else:
+ host_platform = platform.machine().lower()
+ target_platform = host_platform
+
+ host_platform = _ARCH_TO_CANONICAL[host_platform]
+ target_platform = _ARCH_TO_CANONICAL[target_platform]
+
+ debug('_check_cl_exists_in_vc_dir(): host platform %s, target platform %s for version %s' % (host_platform, target_platform, msvc_version))
+
+ ver_num = float(get_msvc_version_numeric(msvc_version))
+
+ # make sure the cl.exe exists meaning the tool is installed
+ if ver_num > 14:
+ # 2017 and newer allowed multiple versions of the VC toolset to be installed at the same time.
+ # Just get the default tool version for now
+ #TODO: support setting a specific minor VC version
+ default_toolset_file = os.path.join(vc_dir, _VC_TOOLS_VERSION_FILE)
+ try:
+ with open(default_toolset_file) as f:
+ vc_specific_version = f.readlines()[0].strip()
+ except IOError:
+ debug('_check_cl_exists_in_vc_dir(): failed to read ' + default_toolset_file)
+ return False
+ except IndexError:
+ debug('_check_cl_exists_in_vc_dir(): failed to find MSVC version in ' + default_toolset_file)
+ return False
+
+ host_trgt_dir = _HOST_TARGET_TO_CL_DIR_GREATER_THAN_14.get((host_platform, target_platform), None)
+ if host_trgt_dir is None:
+ debug('_check_cl_exists_in_vc_dir(): unsupported host/target platform combo: (%s,%s)'%(host_platform, target_platform))
+ return False
+
+ cl_path = os.path.join(vc_dir, 'Tools','MSVC', vc_specific_version, 'bin', host_trgt_dir[0], host_trgt_dir[1], _CL_EXE_NAME)
+ debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
+ if os.path.exists(cl_path):
+ debug('_check_cl_exists_in_vc_dir(): found ' + _CL_EXE_NAME + '!')
+ return True
+
+ elif ver_num <= 14 and ver_num >= 8:
+
+ # Set default value to be -1 as "" which is the value for x86/x86 yields true when tested
+ # if not host_trgt_dir
+ host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get((host_platform, target_platform), None)
+ if host_trgt_dir is None:
+ debug('_check_cl_exists_in_vc_dir(): unsupported host/target platform combo')
+ return False
+
+ cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
+ debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
+
+ cl_path_exists = os.path.exists(cl_path)
+ if not cl_path_exists and host_platform == 'amd64':
+ # older versions of visual studio only had x86 binaries,
+ # so if the host platform is amd64, we need to check cross
+ # compile options (x86 binary compiles some other target on a 64 bit os)
+
+ # Set default value to be -1 as "" which is the value for x86/x86 yields true when tested
+ # if not host_trgt_dir
+ host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get(('x86', target_platform), None)
+ if host_trgt_dir is None:
+ return False
+
+ cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
+ debug('_check_cl_exists_in_vc_dir(): checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
+ cl_path_exists = os.path.exists(cl_path)
+
+ if cl_path_exists:
+ debug('_check_cl_exists_in_vc_dir(): found ' + _CL_EXE_NAME + '!')
+ return True
+
+ elif ver_num < 8 and ver_num >= 6:
+ # not sure about these versions so if a walk the VC dir (could be slow)
+ for root, _, files in os.walk(vc_dir):
+ if _CL_EXE_NAME in files:
+ debug('get_installed_vcs ' + _CL_EXE_NAME + ' found %s' % os.path.join(root, _CL_EXE_NAME))
+ return True
+ return False
+ else:
+ # version not support return false
+ debug('_check_cl_exists_in_vc_dir(): unsupported MSVC version: ' + str(ver_num))
+
+ return False
+
+def cached_get_installed_vcs(env=None):
global __INSTALLED_VCS_RUN
if __INSTALLED_VCS_RUN is None:
- ret = get_installed_vcs()
+ ret = get_installed_vcs(env)
__INSTALLED_VCS_RUN = ret
return __INSTALLED_VCS_RUN
-def get_installed_vcs():
+def get_installed_vcs(env=None):
installed_versions = []
+
for ver in _VCVER:
debug('trying to find VC %s' % ver)
try:
- if find_vc_pdir(ver):
+ VC_DIR = find_vc_pdir(ver)
+ if VC_DIR:
debug('found VC %s' % ver)
- installed_versions.append(ver)
+ if _check_cl_exists_in_vc_dir(env, VC_DIR, ver):
+ installed_versions.append(ver)
+ else:
+ debug('find_vc_pdir no compiler found %s' % ver)
else:
debug('find_vc_pdir return None for ver %s' % ver)
+ except (MSVCUnsupportedTargetArch, MSVCUnsupportedHostArch):
+ # Allow this exception to propagate further as it should cause
+ # SCons to exit with an error code
+ raise
except VisualCException as e:
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
return installed_versions
@@ -416,7 +631,7 @@ def get_default_version(env):
% (msvc_version, msvs_version))
return msvs_version
if not msvc_version:
- installed_vcs = cached_get_installed_vcs()
+ installed_vcs = cached_get_installed_vcs(env)
debug('installed_vcs:%s' % installed_vcs)
if not installed_vcs:
#msg = 'No installed VCs'
@@ -443,16 +658,17 @@ def msvc_find_valid_batch_script(env,version):
debug('vc.py:msvc_find_valid_batch_script()')
# Find the host platform, target platform, and if present the requested
# target platform
- (host_platform, target_platform,req_target_platform) = get_host_target(env)
+ platforms = get_host_target(env)
+ debug("vc.py: msvs_find_valid_batch_script(): host_platform %s, target_platform %s req_target_platform:%s" % platforms)
+ host_platform, target_platform, req_target_platform = platforms
try_target_archs = [target_platform]
- debug("msvs_find_valid_batch_script(): req_target_platform %s target_platform:%s"%(req_target_platform,target_platform))
# VS2012 has a "cross compile" environment to build 64 bit
# with x86_amd64 as the argument to the batch setup script
- if req_target_platform in ('amd64','x86_64'):
+ if req_target_platform in ('amd64', 'x86_64'):
try_target_archs.append('x86_amd64')
- elif not req_target_platform and target_platform in ['amd64','x86_64']:
+ elif not req_target_platform and target_platform in ['amd64', 'x86_64']:
# There may not be "native" amd64, but maybe "cross" x86_amd64 tools
try_target_archs.append('x86_amd64')
# If the user hasn't specifically requested a TARGET_ARCH, and
@@ -474,7 +690,7 @@ def msvc_find_valid_batch_script(env,version):
(host_target, version)
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
-
+
# Get just version numbers
maj, min = msvc_version_to_maj_min(version)
# VS2015+
@@ -493,15 +709,17 @@ def msvc_find_valid_batch_script(env,version):
warn_msg = "VC version %s not installed. " + \
"C/C++ compilers are most likely not set correctly.\n" + \
" Installed versions are: %s"
- warn_msg = warn_msg % (version, cached_get_installed_vcs())
+ warn_msg = warn_msg % (version, cached_get_installed_vcs(env))
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
continue
# Try to use the located batch file for this host/target platform combo
debug('vc.py:msvc_find_valid_batch_script() use_script 2 %s, args:%s\n' % (repr(vc_script), arg))
+ found = None
if vc_script:
try:
d = script_env(vc_script, args=arg)
+ found = vc_script
except BatchFileExecutionError as e:
debug('vc.py:msvc_find_valid_batch_script() use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
vc_script=None
@@ -510,6 +728,7 @@ def msvc_find_valid_batch_script(env,version):
debug('vc.py:msvc_find_valid_batch_script() use_script 4: trying sdk script: %s'%(sdk_script))
try:
d = script_env(sdk_script)
+ found = sdk_script
except BatchFileExecutionError as e:
debug('vc.py:msvc_find_valid_batch_script() use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script),e))
continue
@@ -517,7 +736,7 @@ def msvc_find_valid_batch_script(env,version):
debug('vc.py:msvc_find_valid_batch_script() use_script 6: Neither VC script nor SDK script found')
continue
- debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s %s"%(repr(sdk_script),arg))
+ debug("vc.py:msvc_find_valid_batch_script() Found a working script/target: %s/%s"%(repr(found),arg))
break # We've found a working target_platform, so stop looking
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
@@ -566,8 +785,14 @@ def msvc_setup_env(env):
debug('vc.py:msvc_setup_env() env:%s -> %s'%(k,v))
env.PrependENVPath(k, v, delete_existing=True)
-def msvc_exists(version=None):
- vcs = cached_get_installed_vcs()
+ # final check to issue a warning if the compiler is not present
+ msvc_cl = find_program_path(env, 'cl')
+ if not msvc_cl:
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning,
+ "Could not find MSVC compiler 'cl', it may need to be installed separately with Visual Studio")
+
+def msvc_exists(env=None, version=None):
+ vcs = cached_get_installed_vcs(env)
if version is None:
return len(vcs) > 0
return version in vcs
diff --git a/src/engine/SCons/Tool/MSCommon/vcTests.py b/src/engine/SCons/Tool/MSCommon/vcTests.py
new file mode 100644
index 0000000..25537f3
--- /dev/null
+++ b/src/engine/SCons/Tool/MSCommon/vcTests.py
@@ -0,0 +1,180 @@
+#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# from typing import Dict, Any
+
+__revision__ = "src/engine/SCons/Tool/MSCommon/vcTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
+import os.path
+import unittest
+
+import SCons.Node.FS
+import SCons.Warnings
+import SCons.Tool.MSCommon.vc
+
+import TestCmd
+
+original = os.getcwd()
+
+test = TestCmd.TestCmd(workdir='')
+
+os.chdir(test.workpath(''))
+
+MSVCUnsupportedHostArch = SCons.Tool.MSCommon.vc.MSVCUnsupportedHostArch
+MSVCUnsupportedTargetArch = SCons.Tool.MSCommon.vc.MSVCUnsupportedTargetArch
+
+MS_TOOLS_VERSION='1.1.1'
+
+class MSVcTestCase(unittest.TestCase):
+
+ @staticmethod
+ def _createDummyCl(path, add_bin=True):
+ """
+ Creates a dummy cl.ex in the correct directory.
+ It will create all missing parent directories as well
+
+ Args:
+ path: Relative path to cl.exe for the version about to be tested.
+ """
+
+ # print("PATH:%s"%path)
+
+ path = path.replace('\\', os.sep)
+ if add_bin:
+ create_path = os.path.join(path,'bin')
+ else:
+ create_path = path
+ if create_path and not os.path.isdir(create_path):
+ os.makedirs(create_path)
+
+ create_this = os.path.join(create_path,'cl.exe')
+
+ # print("Creating: %s"%create_this)
+ with open(create_this,'w') as ct:
+ ct.write('created')
+
+
+
+
+ def runTest(self):
+ """
+ Check that all proper HOST_PLATFORM and TARGET_PLATFORM are handled.
+ Verify that improper HOST_PLATFORM and/or TARGET_PLATFORM are properly handled.
+ by SCons.Tool.MSCommon.vc._check_cl_exists_in_vc_dir()
+ """
+
+ check = SCons.Tool.MSCommon.vc._check_cl_exists_in_vc_dir
+
+ env={'TARGET_ARCH':'x86'}
+ p = SCons.Tool.MSCommon.vc._HOST_TARGET_TO_CL_DIR[('x86','x86')]
+ MSVcTestCase._createDummyCl(p)
+
+ # print("retval:%s"%check(env, '.', '8.0'))
+
+
+ # Setup for VC 14+ tests
+
+ # Create the VC minor/major version file
+ tools_version_file = SCons.Tool.MSCommon.vc._VC_TOOLS_VERSION_FILE
+ tools_dir = os.path.dirname(tools_version_file)
+ if not os.path.isdir(tools_dir):
+ os.makedirs(tools_dir)
+ try:
+ with open(tools_version_file, 'w') as tf:
+ tf.write(MS_TOOLS_VERSION)
+ except IOError as e:
+ print("Failed trying to write :%s :%s"%(tools_version_file, e))
+
+
+ # Now walk all the valid combinations of host/target for VC 14 +
+ vc_gt_14_map = SCons.Tool.MSCommon.vc._HOST_TARGET_TO_CL_DIR_GREATER_THAN_14
+
+ for key, value in vc_gt_14_map.items():
+ # print("GT 14 Got: %s -> %s"%(key,value))
+
+ env={'TARGET_ARCH':key[1], 'HOST_ARCH':key[0]}
+ path = os.path.join('.','Tools','MSVC', MS_TOOLS_VERSION, 'bin', value[0], value[1])
+ MSVcTestCase._createDummyCl(path, add_bin=False)
+ result=check(env, '.', '14.1')
+ # print("for:%s got :%s"%(key[1], result))
+ self.assertTrue(result, "Checking host: %s target: %s"%(value[0], value[1]))
+
+ # Now test bogus value for HOST_ARCH
+ env={'TARGET_ARCH':'x86', 'HOST_ARCH':'GARBAGE'}
+ try:
+ result=check(env, '.', '14.1')
+ # print("for:%s got :%s"%(env, result))
+ self.assertFalse(result, "Did not fail with bogus HOST_ARCH host: %s target: %s"%(value[0], value[1]))
+ except MSVCUnsupportedHostArch:
+ pass
+ else:
+ self.fail('Did not fail when HOST_ARCH specified as: %s'%env['HOST_ARCH'])
+
+ # Now test bogus value for TARGET_ARCH
+ env={'TARGET_ARCH':'GARBAGE', 'HOST_ARCH':'x86'}
+ try:
+ result=check(env, '.', '14.1')
+ # print("for:%s got :%s"%(env, result))
+ self.assertFalse(result, "Did not fail with bogus TARGET_ARCH host: %s target: %s"%(value[0], value[1]))
+ except MSVCUnsupportedTargetArch:
+ pass
+ else:
+ self.fail('Did not fail when HOST_ARCH specified as: %s'%env['TARGET_ARCH'])
+
+ # Test >8 < 14 VC versions
+ vc_map = SCons.Tool.MSCommon.vc._HOST_TARGET_TO_CL_DIR
+ for key,value in vc_map.items():
+ # print("LT 14 Got: %s -> %s"%(key,value))
+ env={'TARGET_ARCH':key[1], 'HOST_ARCH':key[0]}
+ path = os.path.join('.', 'bin', value )
+ MSVcTestCase._createDummyCl(path, add_bin=False)
+ result=check(env, '.', '9.0')
+ # print("for:%s got :%s"%(key[1], result))
+ self.assertTrue(result, "Checking host: %s target: %s"%(key[0], key[1]))
+
+ # Now test bogus value for HOST_ARCH
+ env={'TARGET_ARCH':'x86', 'HOST_ARCH':'GARBAGE'}
+ try:
+ result=check(env, '.', '9.0')
+ # print("for:%s got :%s"%(env, result))
+ self.assertFalse(result, "Did not fail with bogus HOST_ARCH host: %s target: %s"%(env['HOST_ARCH'], env['TARGET_ARCH']))
+ except MSVCUnsupportedHostArch:
+ pass
+ else:
+ self.fail('Did not fail when HOST_ARCH specified as: %s'%env['HOST_ARCH'])
+
+ # Now test bogus value for TARGET_ARCH
+ env={'TARGET_ARCH':'GARBAGE', 'HOST_ARCH':'x86'}
+ try:
+ result=check(env, '.', '9.0')
+ # print("for:%s got :%s"%(env, result))
+ self.assertFalse(result, "Did not fail with bogus TARGET_ARCH host: %s target: %s"%(env['HOST_ARCH'], env['TARGET_ARCH']))
+ except MSVCUnsupportedTargetArch:
+ pass
+ else:
+ self.fail('Did not fail when HOST_ARCH specified as: %s'%env['TARGET_ARCH'])
+
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/src/engine/SCons/Tool/MSCommon/vs.py b/src/engine/SCons/Tool/MSCommon/vs.py
index dafdbaf..731f328 100644
--- a/src/engine/SCons/Tool/MSCommon/vs.py
+++ b/src/engine/SCons/Tool/MSCommon/vs.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/MSCommon/vs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/MSCommon/vs.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """Module to detect Visual Studio and/or Visual C/C++
"""
@@ -68,9 +68,9 @@ class VisualStudio(object):
SCons.Tool.MSCommon.vc.get_installed_vcs()
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version)
if not dir:
- debug('find_vs_dir(): no installed VC %s' % self.vc_version)
+ debug('find_vs_dir_by_vc(): no installed VC %s' % self.vc_version)
return None
- return dir
+ return os.path.abspath(os.path.join(dir, os.pardir))
def find_vs_dir_by_reg(self):
root = 'Software\\'
@@ -95,12 +95,11 @@ class VisualStudio(object):
First try to find by registry, and if that fails find via VC dir
"""
-
- if True:
- vs_dir=self.find_vs_dir_by_reg()
- return vs_dir
- else:
- return self.find_vs_dir_by_vc()
+ vs_dir=self.find_vs_dir_by_reg()
+ if not vs_dir:
+ vs_dir = self.find_vs_dir_by_vc()
+ debug('find_vs_dir(): found VS in ' + str(vs_dir ))
+ return vs_dir
def find_executable(self):
vs_dir = self.get_vs_dir()
@@ -199,6 +198,17 @@ class VisualStudio(object):
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
SupportedVSList = [
+ # Visual Studio 2019
+ VisualStudio('14.2',
+ vc_version='14.2',
+ sdk_version='10.0A',
+ hkeys=[],
+ common_tools_var='VS160COMNTOOLS',
+ executable_path=r'Common7\IDE\devenv.com',
+ batch_file_path=r'VC\Auxiliary\Build\vsvars32.bat',
+ supported_arch=['x86', 'amd64', "arm"],
+ ),
+
# Visual Studio 2017
VisualStudio('14.1',
vc_version='14.1',
@@ -521,7 +531,7 @@ def get_default_arch(env):
if not msvs:
arch = 'x86'
- elif not arch in msvs.get_supported_arch():
+ elif arch not in msvs.get_supported_arch():
fmt = "Visual Studio version %s does not support architecture %s"
raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
diff --git a/src/engine/SCons/Tool/PharLapCommon.py b/src/engine/SCons/Tool/PharLapCommon.py
index c45c6d3..623f2a8 100644
--- a/src/engine/SCons/Tool/PharLapCommon.py
+++ b/src/engine/SCons/Tool/PharLapCommon.py
@@ -7,7 +7,7 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Phar Lap ETS tool chain. Right now, this is linkloc and
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/PharLapCommon.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/PharLapCommon.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
@@ -79,7 +79,8 @@ def getPharLapVersion():
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
if not os.path.exists(include_path):
raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?")
- mo = REGEX_ETS_VER.search(open(include_path, 'r').read())
+ with open(include_path, 'r') as f:
+ mo = REGEX_ETS_VER.search(f.read())
if mo:
return int(mo.group(1))
# Default return for Phar Lap 9.1
diff --git a/src/engine/SCons/Tool/ToolTests.py b/src/engine/SCons/Tool/ToolTests.py
index f5678c1..25e9b2d 100644
--- a/src/engine/SCons/Tool/ToolTests.py
+++ b/src/engine/SCons/Tool/ToolTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,8 +21,9 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/ToolTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ToolTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import os
import sys
import unittest
@@ -31,29 +32,49 @@ import TestUnit
import SCons.Errors
import SCons.Tool
+
+class DummyEnvironment(object):
+ def __init__(self):
+ self.dict = {}
+ def Detect(self, progs):
+ if not SCons.Util.is_List(progs):
+ progs = [ progs ]
+ return progs[0]
+ def Append(self, **kw):
+ self.dict.update(kw)
+ def __getitem__(self, key):
+ return self.dict[key]
+ def __setitem__(self, key, val):
+ self.dict[key] = val
+ def __contains__(self, key):
+ return self.dict.__contains__(key)
+ def has_key(self, key):
+ return key in self.dict
+ def subst(self, string, *args, **kwargs):
+ return string
+
+ PHONY_PATH = "/usr/phony/bin"
+ def WhereIs(self, key_program):
+ # for pathfind test for Issue #3336:
+ # need to fake the case where extra paths are searched, and
+ # if one has a "hit" after some fails, the fails are left in
+ # the environment's PATH. So construct a positive answer if
+ # we see a magic known path component in PATH; answer in
+ # the negative otherwise.
+ paths = self['ENV']['PATH']
+ if self.PHONY_PATH in paths:
+ return os.path.join(self.PHONY_PATH, key_program)
+ return None
+ def AppendENVPath(self, pathvar, path):
+ # signature matches how called from find_program_path()
+ self['ENV'][pathvar] = self['ENV'][pathvar] + os.pathsep + path
+
+
class ToolTestCase(unittest.TestCase):
def test_Tool(self):
"""Test the Tool() function"""
- class Environment(object):
- def __init__(self):
- self.dict = {}
- def Detect(self, progs):
- if not SCons.Util.is_List(progs):
- progs = [ progs ]
- return progs[0]
- def Append(self, **kw):
- self.dict.update(kw)
- def __getitem__(self, key):
- return self.dict[key]
- def __setitem__(self, key, val):
- self.dict[key] = val
- def __contains__(self, key):
- return self.dict.__contains__(key)
- def has_key(self, key):
- return key in self.dict
- def subst(self, string, *args, **kwargs):
- return string
- env = Environment()
+
+ env = DummyEnvironment()
env['BUILDERS'] = {}
env['ENV'] = {}
env['PLATFORM'] = 'test'
@@ -67,17 +88,34 @@ class ToolTestCase(unittest.TestCase):
SCons.Tool.Tool()
except TypeError:
pass
- else:
+ else: # TODO pylint E0704: bare raise not inside except
raise
try:
p = SCons.Tool.Tool('_does_not_exist_')
- except SCons.Errors.EnvironmentError:
+ except SCons.Errors.SConsEnvironmentError:
pass
- else:
+ else: # TODO pylint E0704: bare raise not inside except
raise
+ def test_pathfind(self):
+ """Test that find_program_path() does not alter PATH"""
+
+ env = DummyEnvironment()
+ PHONY_PATHS = [
+ r'C:\cygwin64\bin',
+ r'C:\cygwin\bin',
+ '/usr/local/dummy/bin',
+ env.PHONY_PATH, # will be recognized by dummy WhereIs
+ ]
+ env['ENV'] = {}
+ env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin'
+ pre_path = env['ENV']['PATH']
+ _ = SCons.Tool.find_program_path(env, 'no_tool', default_paths=PHONY_PATHS)
+ assert env['ENV']['PATH'] == pre_path, env['ENV']['PATH']
+
+
if __name__ == "__main__":
suite = unittest.makeSuite(ToolTestCase, 'test_')
TestUnit.run(suite)
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 9265b81..271f214 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -14,7 +14,7 @@ tool definition.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,16 +35,13 @@ 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-import imp
-import importlib
import sys
import re
import os
import shutil
-
import SCons.Builder
import SCons.Errors
import SCons.Node.FS
@@ -54,9 +51,14 @@ import SCons.Scanner.D
import SCons.Scanner.LaTeX
import SCons.Scanner.Prog
import SCons.Scanner.SWIG
-import collections
+try:
+ # Python 3
+ from collections.abc import Callable
+except ImportError:
+ # Python 2.7
+ from collections import Callable
-DefaultToolpath=[]
+DefaultToolpath = []
CScanner = SCons.Scanner.C.CScanner()
DScanner = SCons.Scanner.D.DScanner()
@@ -97,20 +99,22 @@ for suffix in LaTeXSuffixes:
SourceFileScanner.add_scanner(suffix, LaTeXScanner)
SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner)
-
# Tool aliases are needed for those tools whos module names also
# occur in the python standard library. This causes module shadowing and
# can break using python library functions under python3
TOOL_ALIASES = {
- 'gettext':'gettext_tool',
+ 'gettext': 'gettext_tool',
'clang++': 'clangxx',
}
+
class Tool(object):
- def __init__(self, name, toolpath=[], **kw):
+ def __init__(self, name, toolpath=None, **kw):
+ if toolpath is None:
+ toolpath = []
# Rename if there's a TOOL_ALIAS for this tool
- self.name = TOOL_ALIASES.get(name,name)
+ self.name = TOOL_ALIASES.get(name, name)
self.toolpath = toolpath + DefaultToolpath
# remember these so we can merge them into the call
self.init_kw = kw
@@ -122,6 +126,8 @@ class Tool(object):
self.options = module.options
def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None):
+ import imp
+
splitname = short_name.split('.')
index = 0
srchpths = searchpaths
@@ -136,7 +142,7 @@ class Tool(object):
sys.path = self.toolpath + sys.path
# sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path))
- if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
+ if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0, 1, 2, 3, 4)):
# Py 2 code
try:
try:
@@ -149,8 +155,8 @@ class Tool(object):
file.close()
except ImportError as e:
splitname = self.name.split('.')
- if str(e)!="No module named %s"%splitname[0]:
- raise SCons.Errors.EnvironmentError(e)
+ if str(e) != "No module named %s" % splitname[0]:
+ raise SCons.Errors.SConsEnvironmentError(e)
try:
import zipimport
except ImportError:
@@ -184,46 +190,48 @@ class Tool(object):
add_to_scons_tools_namespace = False
for path in self.toolpath:
sepname = self.name.replace('.', os.path.sep)
- file_path = os.path.join(path, "%s.py"%sepname)
+ file_path = os.path.join(path, "%s.py" % sepname)
file_package = os.path.join(path, sepname)
- if debug: sys.stderr.write("Trying:%s %s\n"%(file_path, file_package))
+ if debug: sys.stderr.write("Trying:%s %s\n" % (file_path, file_package))
if os.path.isfile(file_path):
spec = importlib.util.spec_from_file_location(self.name, file_path)
- if debug: print("file_Path:%s FOUND"%file_path)
+ if debug: print("file_Path:%s FOUND" % file_path)
break
elif os.path.isdir(file_package):
file_package = os.path.join(file_package, '__init__.py')
spec = importlib.util.spec_from_file_location(self.name, file_package)
- if debug: print("PACKAGE:%s Found"%file_package)
+ if debug: print("PACKAGE:%s Found" % file_package)
break
else:
continue
if spec is None:
- if debug: sys.stderr.write("NO SPEC :%s\n"%self.name)
- spec = importlib.util.find_spec("."+self.name, package='SCons.Tool')
+ if debug: sys.stderr.write("NO SPEC :%s\n" % self.name)
+ spec = importlib.util.find_spec("." + self.name, package='SCons.Tool')
if spec:
- found_name = 'SCons.Tool.'+self.name
+ found_name = 'SCons.Tool.' + self.name
add_to_scons_tools_namespace = True
- if debug: sys.stderr.write("Spec Found? .%s :%s\n"%(self.name, spec))
+ if debug: sys.stderr.write("Spec Found? .%s :%s\n" % (self.name, spec))
if spec is None:
- error_string = "No module named %s"%self.name
- raise SCons.Errors.EnvironmentError(error_string)
+ error_string = "No module named %s" % self.name
+ raise SCons.Errors.SConsEnvironmentError(error_string)
module = importlib.util.module_from_spec(spec)
if module is None:
- if debug: print("MODULE IS NONE:%s"%self.name)
- error_string = "No module named %s"%self.name
- raise SCons.Errors.EnvironmentError(error_string)
+ if debug: print("MODULE IS NONE:%s" % self.name)
+ error_string = "No module named %s" % self.name
+ raise SCons.Errors.SConsEnvironmentError(error_string)
# Don't reload a tool we already loaded.
- sys_modules_value = sys.modules.get(found_name,False)
+ sys_modules_value = sys.modules.get(found_name, False)
+
+ found_module = None
if sys_modules_value and sys_modules_value.__file__ == spec.origin:
- return sys.modules[found_name]
+ found_module = sys.modules[found_name]
else:
# Not sure what to do in the case that there already
# exists sys.modules[self.name] but the source file is
@@ -235,8 +243,11 @@ class Tool(object):
# If we found it in SCons.Tool, then add it to the module
setattr(SCons.Tool, self.name, module)
- return module
+ found_module = module
+ if found_module is not None:
+ sys.path = oldpythonpath
+ return found_module
sys.path = oldpythonpath
@@ -253,20 +264,20 @@ class Tool(object):
file.close()
return module
except ImportError as e:
- if str(e)!="No module named %s"%self.name:
- raise SCons.Errors.EnvironmentError(e)
+ if str(e) != "No module named %s" % self.name:
+ raise SCons.Errors.SConsEnvironmentError(e)
try:
import zipimport
- importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] )
+ importer = zipimport.zipimporter(sys.modules['SCons.Tool'].__path__[0])
module = importer.load_module(full_name)
setattr(SCons.Tool, self.name, module)
return module
except ImportError as e:
m = "No tool named '%s': %s" % (self.name, e)
- raise SCons.Errors.EnvironmentError(m)
+ raise SCons.Errors.SConsEnvironmentError(m)
except ImportError as e:
m = "No tool named '%s': %s" % (self.name, e)
- raise SCons.Errors.EnvironmentError(m)
+ raise SCons.Errors.SConsEnvironmentError(m)
def __call__(self, env, *args, **kw):
if self.init_kw is not None:
@@ -278,13 +289,13 @@ class Tool(object):
kw.update(call_kw)
else:
kw = self.init_kw
- env.Append(TOOLS = [ self.name ])
+ env.Append(TOOLS=[self.name])
if hasattr(self, 'options'):
import SCons.Variables
if 'options' not in env:
from SCons.Script import ARGUMENTS
- env['options']=SCons.Variables.Variables(args=ARGUMENTS)
- opts=env['options']
+ env['options'] = SCons.Variables.Variables(args=ARGUMENTS)
+ opts = env['options']
self.options(opts)
opts.Update(env)
@@ -294,6 +305,7 @@ class Tool(object):
def __str__(self):
return self.name
+
##########################################################################
# Create common executable program / library / object builders
@@ -308,13 +320,13 @@ def createProgBuilder(env):
program = env['BUILDERS']['Program']
except KeyError:
import SCons.Defaults
- program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction,
- emitter = '$PROGEMITTER',
- prefix = '$PROGPREFIX',
- suffix = '$PROGSUFFIX',
- src_suffix = '$OBJSUFFIX',
- src_builder = 'Object',
- target_scanner = ProgramScanner)
+ program = SCons.Builder.Builder(action=SCons.Defaults.LinkAction,
+ emitter='$PROGEMITTER',
+ prefix='$PROGPREFIX',
+ suffix='$PROGSUFFIX',
+ src_suffix='$OBJSUFFIX',
+ src_builder='Object',
+ target_scanner=ProgramScanner)
env['BUILDERS']['Program'] = program
return program
@@ -330,23 +342,24 @@ def createStaticLibBuilder(env):
try:
static_lib = env['BUILDERS']['StaticLibrary']
except KeyError:
- action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
- if env.get('RANLIB',False) or env.Detect('ranlib'):
+ action_list = [SCons.Action.Action("$ARCOM", "$ARCOMSTR")]
+ if env.get('RANLIB', False) or env.Detect('ranlib'):
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
action_list.append(ranlib_action)
- static_lib = SCons.Builder.Builder(action = action_list,
- emitter = '$LIBEMITTER',
- prefix = '$LIBPREFIX',
- suffix = '$LIBSUFFIX',
- src_suffix = '$OBJSUFFIX',
- src_builder = 'StaticObject')
+ static_lib = SCons.Builder.Builder(action=action_list,
+ emitter='$LIBEMITTER',
+ prefix='$LIBPREFIX',
+ suffix='$LIBSUFFIX',
+ src_suffix='$OBJSUFFIX',
+ src_builder='StaticObject')
env['BUILDERS']['StaticLibrary'] = static_lib
env['BUILDERS']['Library'] = static_lib
return static_lib
-def _call_linker_cb(env, callback, args, result = None):
+
+def _call_linker_cb(env, callback, args, result=None):
"""Returns the result of env['LINKCALLBACKS'][callback](*args)
if env['LINKCALLBACKS'] is a dictionary and env['LINKCALLBACKS'][callback]
is callable. If these conditions are not met, return the value provided as
@@ -370,136 +383,163 @@ def _call_linker_cb(env, callback, args, result = None):
if Verbose:
print('_call_linker_cb: env["LINKCALLBACKS"][%r] found' % callback)
print('_call_linker_cb: env["LINKCALLBACKS"][%r]=%r' % (callback, cbfun))
- if(isinstance(cbfun, collections.Callable)):
+ if isinstance(cbfun, Callable):
if Verbose:
print('_call_linker_cb: env["LINKCALLBACKS"][%r] is callable' % callback)
result = cbfun(env, *args)
return result
+
def _call_env_subst(env, string, *args, **kw):
kw2 = {}
for k in ('raw', 'target', 'source', 'conv', 'executor'):
- try: kw2[k] = kw[k]
- except KeyError: pass
+ try:
+ kw2[k] = kw[k]
+ except KeyError:
+ pass
return env.subst(string, *args, **kw2)
+
class _ShLibInfoSupport(object):
- def get_libtype(self):
+ @property
+ def libtype(self):
return 'ShLib'
+
def get_lib_prefix(self, env, *args, **kw):
- return _call_env_subst(env,'$SHLIBPREFIX', *args, **kw)
+ return _call_env_subst(env, '$SHLIBPREFIX', *args, **kw)
+
def get_lib_suffix(self, env, *args, **kw):
- return _call_env_subst(env,'$SHLIBSUFFIX', *args, **kw)
+ return _call_env_subst(env, '$SHLIBSUFFIX', *args, **kw)
+
def get_lib_version(self, env, *args, **kw):
- return _call_env_subst(env,'$SHLIBVERSION', *args, **kw)
+ return _call_env_subst(env, '$SHLIBVERSION', *args, **kw)
+
def get_lib_noversionsymlinks(self, env, *args, **kw):
- return _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw)
+ return _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw)
+
class _LdModInfoSupport(object):
- def get_libtype(self):
+ @property
+ def libtype(self):
return 'LdMod'
+
def get_lib_prefix(self, env, *args, **kw):
- return _call_env_subst(env,'$LDMODULEPREFIX', *args, **kw)
+ return _call_env_subst(env, '$LDMODULEPREFIX', *args, **kw)
+
def get_lib_suffix(self, env, *args, **kw):
- return _call_env_subst(env,'$LDMODULESUFFIX', *args, **kw)
+ return _call_env_subst(env, '$LDMODULESUFFIX', *args, **kw)
+
def get_lib_version(self, env, *args, **kw):
- return _call_env_subst(env,'$LDMODULEVERSION', *args, **kw)
+ return _call_env_subst(env, '$LDMODULEVERSION', *args, **kw)
+
def get_lib_noversionsymlinks(self, env, *args, **kw):
- return _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw)
+ return _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw)
+
class _ImpLibInfoSupport(object):
- def get_libtype(self):
+ @property
+ def libtype(self):
return 'ImpLib'
+
def get_lib_prefix(self, env, *args, **kw):
- return _call_env_subst(env,'$IMPLIBPREFIX', *args, **kw)
+ return _call_env_subst(env, '$IMPLIBPREFIX', *args, **kw)
+
def get_lib_suffix(self, env, *args, **kw):
- return _call_env_subst(env,'$IMPLIBSUFFIX', *args, **kw)
+ return _call_env_subst(env, '$IMPLIBSUFFIX', *args, **kw)
+
def get_lib_version(self, env, *args, **kw):
- version = _call_env_subst(env,'$IMPLIBVERSION', *args, **kw)
+ version = _call_env_subst(env, '$IMPLIBVERSION', *args, **kw)
if not version:
- try: lt = kw['implib_libtype']
- except KeyError: pass
+ try:
+ lt = kw['implib_libtype']
+ except KeyError:
+ pass
else:
if lt == 'ShLib':
- version = _call_env_subst(env,'$SHLIBVERSION', *args, **kw)
+ version = _call_env_subst(env, '$SHLIBVERSION', *args, **kw)
elif lt == 'LdMod':
- version = _call_env_subst(env,'$LDMODULEVERSION', *args, **kw)
+ version = _call_env_subst(env, '$LDMODULEVERSION', *args, **kw)
return version
+
def get_lib_noversionsymlinks(self, env, *args, **kw):
disable = None
- try: env['IMPLIBNOVERSIONSYMLINKS']
+ try:
+ env['IMPLIBNOVERSIONSYMLINKS']
except KeyError:
- try: lt = kw['implib_libtype']
- except KeyError: pass
+ try:
+ lt = kw['implib_libtype']
+ except KeyError:
+ pass
else:
if lt == 'ShLib':
- disable = _call_env_subst(env,'$SHLIBNOVERSIONSYMLINKS', *args, **kw)
+ disable = _call_env_subst(env, '$SHLIBNOVERSIONSYMLINKS', *args, **kw)
elif lt == 'LdMod':
- disable = _call_env_subst(env,'$LDMODULENOVERSIONSYMLINKS', *args, **kw)
+ disable = _call_env_subst(env, '$LDMODULENOVERSIONSYMLINKS', *args, **kw)
else:
- disable = _call_env_subst(env,'$IMPLIBNOVERSIONSYMLINKS', *args, **kw)
+ disable = _call_env_subst(env, '$IMPLIBNOVERSIONSYMLINKS', *args, **kw)
return disable
+
class _LibInfoGeneratorBase(object):
"""Generator base class for library-related info such as suffixes for
versioned libraries, symlink maps, sonames etc. It handles commonities
of SharedLibrary and LoadableModule
"""
- _support_classes = { 'ShLib' : _ShLibInfoSupport,
- 'LdMod' : _LdModInfoSupport,
- 'ImpLib' : _ImpLibInfoSupport }
+ _support_classes = {'ShLib': _ShLibInfoSupport,
+ 'LdMod': _LdModInfoSupport,
+ 'ImpLib': _ImpLibInfoSupport}
+
def __init__(self, libtype, infoname):
- self.set_libtype(libtype)
- self.set_infoname(infoname)
+ self.libtype = libtype
+ self.infoname = infoname
+
+ @property
+ def libtype(self):
+ return self._support.libtype
- def set_libtype(self, libtype):
+ @libtype.setter
+ def libtype(self, libtype):
try:
support_class = self._support_classes[libtype]
except KeyError:
raise ValueError('unsupported libtype %r' % libtype)
self._support = support_class()
- def get_libtype(self):
- return self._support.get_libtype()
-
- def set_infoname(self, infoname):
- self.infoname = infoname
-
- def get_infoname(self):
- return self.infoname
-
def get_lib_prefix(self, env, *args, **kw):
- return self._support.get_lib_prefix(env,*args,**kw)
+ return self._support.get_lib_prefix(env, *args, **kw)
def get_lib_suffix(self, env, *args, **kw):
- return self._support.get_lib_suffix(env,*args,**kw)
+ return self._support.get_lib_suffix(env, *args, **kw)
def get_lib_version(self, env, *args, **kw):
- return self._support.get_lib_version(env,*args,**kw)
+ return self._support.get_lib_version(env, *args, **kw)
def get_lib_noversionsymlinks(self, env, *args, **kw):
- return self._support.get_lib_noversionsymlinks(env,*args,**kw)
+ return self._support.get_lib_noversionsymlinks(env, *args, **kw)
# Returns name of generator linker callback that shall be used to generate
# our info for a versioned library. For example, if our libtype is 'ShLib'
# and infoname is 'Prefix', it would return 'VersionedShLibPrefix'.
def get_versioned_lib_info_generator(self, **kw):
- try: libtype = kw['generator_libtype']
- except KeyError: libtype = self.get_libtype()
- infoname = self.get_infoname()
- return 'Versioned%s%s' % (libtype, infoname)
+ try:
+ libtype = kw['generator_libtype']
+ except KeyError:
+ libtype = self.libtype
+ return 'Versioned%s%s' % (libtype, self.infoname)
- def generate_versioned_lib_info(self, env, args, result = None, **kw):
+ def generate_versioned_lib_info(self, env, args, result=None, **kw):
callback = self.get_versioned_lib_info_generator(**kw)
return _call_linker_cb(env, callback, args, result)
+
class _LibPrefixGenerator(_LibInfoGeneratorBase):
"""Library prefix generator, used as target_prefix in SharedLibrary and
LoadableModule builders"""
+
def __init__(self, libtype):
super(_LibPrefixGenerator, self).__init__(libtype, 'Prefix')
- def __call__(self, env, sources = None, **kw):
+ def __call__(self, env, sources=None, **kw):
Verbose = False
if sources and 'source' not in kw:
@@ -508,7 +548,7 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase):
else:
kw2 = kw
- prefix = self.get_lib_prefix(env,**kw2)
+ prefix = self.get_lib_prefix(env, **kw2)
if Verbose:
print("_LibPrefixGenerator: input prefix=%r" % prefix)
@@ -523,17 +563,20 @@ class _LibPrefixGenerator(_LibInfoGeneratorBase):
print("_LibPrefixGenerator: return prefix=%r" % prefix)
return prefix
-ShLibPrefixGenerator = _LibPrefixGenerator('ShLib')
-LdModPrefixGenerator = _LibPrefixGenerator('LdMod')
+
+ShLibPrefixGenerator = _LibPrefixGenerator('ShLib')
+LdModPrefixGenerator = _LibPrefixGenerator('LdMod')
ImpLibPrefixGenerator = _LibPrefixGenerator('ImpLib')
+
class _LibSuffixGenerator(_LibInfoGeneratorBase):
"""Library suffix generator, used as target_suffix in SharedLibrary and
LoadableModule builders"""
+
def __init__(self, libtype):
super(_LibSuffixGenerator, self).__init__(libtype, 'Suffix')
- def __call__(self, env, sources = None, **kw):
+ def __call__(self, env, sources=None, **kw):
Verbose = False
if sources and 'source' not in kw:
@@ -557,13 +600,16 @@ class _LibSuffixGenerator(_LibInfoGeneratorBase):
print("_LibSuffixGenerator: return suffix=%r" % suffix)
return suffix
-ShLibSuffixGenerator = _LibSuffixGenerator('ShLib')
-LdModSuffixGenerator = _LibSuffixGenerator('LdMod')
+
+ShLibSuffixGenerator = _LibSuffixGenerator('ShLib')
+LdModSuffixGenerator = _LibSuffixGenerator('LdMod')
ImpLibSuffixGenerator = _LibSuffixGenerator('ImpLib')
+
class _LibSymlinkGenerator(_LibInfoGeneratorBase):
"""Library symlink map generator. It generates a list of symlinks that
should be created by SharedLibrary or LoadableModule builders"""
+
def __init__(self, libtype):
super(_LibSymlinkGenerator, self).__init__(libtype, 'Symlinks')
@@ -588,18 +634,20 @@ class _LibSymlinkGenerator(_LibInfoGeneratorBase):
print('_LibSymlinkGenerator: disable=%r' % disable)
if version and not disable:
- prefix = self.get_lib_prefix(env,**kw2)
- suffix = self.get_lib_suffix(env,**kw2)
+ prefix = self.get_lib_prefix(env, **kw2)
+ suffix = self.get_lib_suffix(env, **kw2)
symlinks = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2)
if Verbose:
print('_LibSymlinkGenerator: return symlinks=%r' % StringizeLibSymlinks(symlinks))
return symlinks
-ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib')
-LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod')
+
+ShLibSymlinkGenerator = _LibSymlinkGenerator('ShLib')
+LdModSymlinkGenerator = _LibSymlinkGenerator('LdMod')
ImpLibSymlinkGenerator = _LibSymlinkGenerator('ImpLib')
+
class _LibNameGenerator(_LibInfoGeneratorBase):
"""Generates "unmangled" library name from a library file node.
@@ -614,6 +662,7 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
the _LibNameGenerator shall return "libfoo.so". Other link tools may
implement it's own way of library name unmangling.
"""
+
def __init__(self, libtype):
super(_LibNameGenerator, self).__init__(libtype, 'Name')
@@ -636,8 +685,8 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
name = None
if version:
- prefix = self.get_lib_prefix(env,**kw2)
- suffix = self.get_lib_suffix(env,**kw2)
+ prefix = self.get_lib_prefix(env, **kw2)
+ suffix = self.get_lib_suffix(env, **kw2)
name = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2)
if not name:
@@ -648,13 +697,16 @@ class _LibNameGenerator(_LibInfoGeneratorBase):
return name
-ShLibNameGenerator = _LibNameGenerator('ShLib')
-LdModNameGenerator = _LibNameGenerator('LdMod')
+
+ShLibNameGenerator = _LibNameGenerator('ShLib')
+LdModNameGenerator = _LibNameGenerator('LdMod')
ImpLibNameGenerator = _LibNameGenerator('ImpLib')
+
class _LibSonameGenerator(_LibInfoGeneratorBase):
"""Library soname generator. Returns library soname (e.g. libfoo.so.0) for
a given node (e.g. /foo/bar/libfoo.so.0.1.2)"""
+
def __init__(self, libtype):
super(_LibSonameGenerator, self).__init__(libtype, 'Soname')
@@ -673,17 +725,17 @@ class _LibSonameGenerator(_LibInfoGeneratorBase):
soname = _call_env_subst(env, '$SONAME', **kw2)
if not soname:
- version = self.get_lib_version(env,**kw2)
+ version = self.get_lib_version(env, **kw2)
if Verbose:
print("_LibSonameGenerator: version=%r" % version)
if version:
- prefix = self.get_lib_prefix(env,**kw2)
- suffix = self.get_lib_suffix(env,**kw2)
+ prefix = self.get_lib_prefix(env, **kw2)
+ suffix = self.get_lib_suffix(env, **kw2)
soname = self.generate_versioned_lib_info(env, [libnode, version, prefix, suffix], **kw2)
if not soname:
# fallback to library name (as returned by appropriate _LibNameGenerator)
- soname = _LibNameGenerator(self.get_libtype())(env, libnode)
+ soname = _LibNameGenerator(self.libtype)(env, libnode)
if Verbose:
print("_LibSonameGenerator: FALLBACK: soname=%r" % soname)
@@ -692,40 +744,44 @@ class _LibSonameGenerator(_LibInfoGeneratorBase):
return soname
-ShLibSonameGenerator = _LibSonameGenerator('ShLib')
-LdModSonameGenerator = _LibSonameGenerator('LdMod')
+
+ShLibSonameGenerator = _LibSonameGenerator('ShLib')
+LdModSonameGenerator = _LibSonameGenerator('LdMod')
+
def StringizeLibSymlinks(symlinks):
"""Converts list with pairs of nodes to list with pairs of node paths
(strings). Used mainly for debugging."""
if SCons.Util.is_List(symlinks):
try:
- return [ (k.get_path(), v.get_path()) for k,v in symlinks ]
+ return [(k.get_path(), v.get_path()) for k, v in symlinks]
except (TypeError, ValueError):
return symlinks
else:
return symlinks
+
def EmitLibSymlinks(env, symlinks, libnode, **kw):
"""Used by emitters to handle (shared/versioned) library symlinks"""
Verbose = False
# nodes involved in process... all symlinks + library
- nodes = list(set([ x for x,y in symlinks ] + [libnode]))
+ nodes = list(set([x for x, y in symlinks] + [libnode]))
clean_targets = kw.get('clean_targets', [])
if not SCons.Util.is_List(clean_targets):
- clean_targets = [ clean_targets ]
+ clean_targets = [clean_targets]
for link, linktgt in symlinks:
env.SideEffect(link, linktgt)
- if(Verbose):
+ if (Verbose):
print("EmitLibSymlinks: SideEffect(%r,%r)" % (link.get_path(), linktgt.get_path()))
clean_list = [x for x in nodes if x != linktgt]
env.Clean(list(set([linktgt] + clean_targets)), clean_list)
- if(Verbose):
+ if (Verbose):
print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt.get_path(), [x.get_path() for x in clean_list]))
+
def CreateLibSymlinks(env, symlinks):
"""Physically creates symlinks. The symlinks argument must be a list in
form [ (link, linktarget), ... ], where link and linktarget are SCons
@@ -736,38 +792,40 @@ def CreateLibSymlinks(env, symlinks):
for link, linktgt in symlinks:
linktgt = link.get_dir().rel_path(linktgt)
link = link.get_path()
- if(Verbose):
+ if (Verbose):
print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link, linktgt))
# Delete the (previously created) symlink if exists. Let only symlinks
# to be deleted to prevent accidental deletion of source files...
if env.fs.islink(link):
env.fs.unlink(link)
- if(Verbose):
+ if (Verbose):
print("CreateLibSymlinks: removed old symlink %r" % link)
# If a file or directory exists with the same name as link, an OSError
# will be thrown, which should be enough, I think.
env.fs.symlink(linktgt, link)
- if(Verbose):
+ if (Verbose):
print("CreateLibSymlinks: add symlink %r -> %r" % (link, linktgt))
return 0
+
def LibSymlinksActionFunction(target, source, env):
for tgt in target:
- symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None)
+ symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None)
if symlinks:
CreateLibSymlinks(env, symlinks)
return 0
+
def LibSymlinksStrFun(target, source, env, *args):
cmd = None
for tgt in target:
- symlinks = getattr(getattr(tgt,'attributes', None), 'shliblinks', None)
+ symlinks = getattr(getattr(tgt, 'attributes', None), 'shliblinks', None)
if symlinks:
if cmd is None: cmd = ""
if cmd: cmd += "\n"
cmd += "Create symlinks for: %r" % tgt.get_path()
try:
- linkstr = ', '.join([ "%r->%r" %(k,v) for k,v in StringizeLibSymlinks(symlinks)])
+ linkstr = ', '.join(["%r->%r" % (k, v) for k, v in StringizeLibSymlinks(symlinks)])
except (KeyError, ValueError):
pass
else:
@@ -789,20 +847,21 @@ def createSharedLibBuilder(env):
shared_lib = env['BUILDERS']['SharedLibrary']
except KeyError:
import SCons.Defaults
- action_list = [ SCons.Defaults.SharedCheck,
- SCons.Defaults.ShLinkAction,
- LibSymlinksAction ]
- shared_lib = SCons.Builder.Builder(action = action_list,
- emitter = "$SHLIBEMITTER",
- prefix = ShLibPrefixGenerator,
- suffix = ShLibSuffixGenerator,
- target_scanner = ProgramScanner,
- src_suffix = '$SHOBJSUFFIX',
- src_builder = 'SharedObject')
+ action_list = [SCons.Defaults.SharedCheck,
+ SCons.Defaults.ShLinkAction,
+ LibSymlinksAction]
+ shared_lib = SCons.Builder.Builder(action=action_list,
+ emitter="$SHLIBEMITTER",
+ prefix=ShLibPrefixGenerator,
+ suffix=ShLibSuffixGenerator,
+ target_scanner=ProgramScanner,
+ src_suffix='$SHOBJSUFFIX',
+ src_builder='SharedObject')
env['BUILDERS']['SharedLibrary'] = shared_lib
return shared_lib
+
def createLoadableModuleBuilder(env):
"""This is a utility function that creates the LoadableModule
Builder in an Environment if it is not there already.
@@ -814,20 +873,21 @@ def createLoadableModuleBuilder(env):
ld_module = env['BUILDERS']['LoadableModule']
except KeyError:
import SCons.Defaults
- action_list = [ SCons.Defaults.SharedCheck,
- SCons.Defaults.LdModuleLinkAction,
- LibSymlinksAction ]
- ld_module = SCons.Builder.Builder(action = action_list,
- emitter = "$LDMODULEEMITTER",
- prefix = LdModPrefixGenerator,
- suffix = LdModSuffixGenerator,
- target_scanner = ProgramScanner,
- src_suffix = '$SHOBJSUFFIX',
- src_builder = 'SharedObject')
+ action_list = [SCons.Defaults.SharedCheck,
+ SCons.Defaults.LdModuleLinkAction,
+ LibSymlinksAction]
+ ld_module = SCons.Builder.Builder(action=action_list,
+ emitter="$LDMODULEEMITTER",
+ prefix=LdModPrefixGenerator,
+ suffix=LdModSuffixGenerator,
+ target_scanner=ProgramScanner,
+ src_suffix='$SHOBJSUFFIX',
+ src_builder='SharedObject')
env['BUILDERS']['LoadableModule'] = ld_module
return ld_module
+
def createObjBuilders(env):
"""This is a utility function that creates the StaticObject
and SharedObject Builders in an Environment if they
@@ -841,34 +901,34 @@ def createObjBuilders(env):
The return is a 2-tuple of (StaticObject, SharedObject)
"""
-
try:
static_obj = env['BUILDERS']['StaticObject']
except KeyError:
- static_obj = SCons.Builder.Builder(action = {},
- emitter = {},
- prefix = '$OBJPREFIX',
- suffix = '$OBJSUFFIX',
- src_builder = ['CFile', 'CXXFile'],
- source_scanner = SourceFileScanner,
- single_source = 1)
+ static_obj = SCons.Builder.Builder(action={},
+ emitter={},
+ prefix='$OBJPREFIX',
+ suffix='$OBJSUFFIX',
+ src_builder=['CFile', 'CXXFile'],
+ source_scanner=SourceFileScanner,
+ single_source=1)
env['BUILDERS']['StaticObject'] = static_obj
env['BUILDERS']['Object'] = static_obj
try:
shared_obj = env['BUILDERS']['SharedObject']
except KeyError:
- shared_obj = SCons.Builder.Builder(action = {},
- emitter = {},
- prefix = '$SHOBJPREFIX',
- suffix = '$SHOBJSUFFIX',
- src_builder = ['CFile', 'CXXFile'],
- source_scanner = SourceFileScanner,
- single_source = 1)
+ shared_obj = SCons.Builder.Builder(action={},
+ emitter={},
+ prefix='$SHOBJPREFIX',
+ suffix='$SHOBJSUFFIX',
+ src_builder=['CFile', 'CXXFile'],
+ source_scanner=SourceFileScanner,
+ single_source=1)
env['BUILDERS']['SharedObject'] = shared_obj
return (static_obj, shared_obj)
+
def createCFileBuilders(env):
"""This is a utility function that creates the CFile/CXXFile
Builders in an Environment if they
@@ -885,95 +945,109 @@ def createCFileBuilders(env):
try:
c_file = env['BUILDERS']['CFile']
except KeyError:
- c_file = SCons.Builder.Builder(action = {},
- emitter = {},
- suffix = {None:'$CFILESUFFIX'})
+ c_file = SCons.Builder.Builder(action={},
+ emitter={},
+ suffix={None: '$CFILESUFFIX'})
env['BUILDERS']['CFile'] = c_file
- env.SetDefault(CFILESUFFIX = '.c')
+ env.SetDefault(CFILESUFFIX='.c')
try:
cxx_file = env['BUILDERS']['CXXFile']
except KeyError:
- cxx_file = SCons.Builder.Builder(action = {},
- emitter = {},
- suffix = {None:'$CXXFILESUFFIX'})
+ cxx_file = SCons.Builder.Builder(action={},
+ emitter={},
+ suffix={None: '$CXXFILESUFFIX'})
env['BUILDERS']['CXXFile'] = cxx_file
- env.SetDefault(CXXFILESUFFIX = '.cc')
+ env.SetDefault(CXXFILESUFFIX='.cc')
return (c_file, cxx_file)
+
##########################################################################
# Create common Java builders
def CreateJarBuilder(env):
+ """The Jar builder expects a list of class files
+ which it can package into a jar file.
+
+ The jar tool provides an interface for passing other types
+ of java files such as .java, directories or swig interfaces
+ and will build them to class files in which it can package
+ into the jar.
+ """
try:
- java_jar = env['BUILDERS']['Jar']
+ java_jar = env['BUILDERS']['JarFile']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR')
- java_jar = SCons.Builder.Builder(action = jar_com,
- suffix = '$JARSUFFIX',
- src_suffix = '$JAVACLASSSUFFIX',
- src_builder = 'JavaClassFile',
- source_factory = fs.Entry)
- env['BUILDERS']['Jar'] = java_jar
+ java_jar = SCons.Builder.Builder(action=jar_com,
+ suffix='$JARSUFFIX',
+ src_suffix='$JAVACLASSSUFFIX',
+ src_builder='JavaClassFile',
+ source_factory=fs.Entry)
+ env['BUILDERS']['JarFile'] = java_jar
return java_jar
+
def CreateJavaHBuilder(env):
try:
java_javah = env['BUILDERS']['JavaH']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR')
- java_javah = SCons.Builder.Builder(action = java_javah_com,
- src_suffix = '$JAVACLASSSUFFIX',
- target_factory = fs.Entry,
- source_factory = fs.File,
- src_builder = 'JavaClassFile')
+ java_javah = SCons.Builder.Builder(action=java_javah_com,
+ src_suffix='$JAVACLASSSUFFIX',
+ target_factory=fs.Entry,
+ source_factory=fs.File,
+ src_builder='JavaClassFile')
env['BUILDERS']['JavaH'] = java_javah
return java_javah
+
def CreateJavaClassFileBuilder(env):
try:
java_class_file = env['BUILDERS']['JavaClassFile']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
- java_class_file = SCons.Builder.Builder(action = javac_com,
- emitter = {},
- #suffix = '$JAVACLASSSUFFIX',
- src_suffix = '$JAVASUFFIX',
- src_builder = ['JavaFile'],
- target_factory = fs.Entry,
- source_factory = fs.File)
+ java_class_file = SCons.Builder.Builder(action=javac_com,
+ emitter={},
+ # suffix = '$JAVACLASSSUFFIX',
+ src_suffix='$JAVASUFFIX',
+ src_builder=['JavaFile'],
+ target_factory=fs.Entry,
+ source_factory=fs.File)
env['BUILDERS']['JavaClassFile'] = java_class_file
return java_class_file
+
def CreateJavaClassDirBuilder(env):
try:
java_class_dir = env['BUILDERS']['JavaClassDir']
except KeyError:
fs = SCons.Node.FS.get_default_fs()
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR')
- java_class_dir = SCons.Builder.Builder(action = javac_com,
- emitter = {},
- target_factory = fs.Dir,
- source_factory = fs.Dir)
+ java_class_dir = SCons.Builder.Builder(action=javac_com,
+ emitter={},
+ target_factory=fs.Dir,
+ source_factory=fs.Dir)
env['BUILDERS']['JavaClassDir'] = java_class_dir
return java_class_dir
+
def CreateJavaFileBuilder(env):
try:
java_file = env['BUILDERS']['JavaFile']
except KeyError:
- java_file = SCons.Builder.Builder(action = {},
- emitter = {},
- suffix = {None:'$JAVASUFFIX'})
+ java_file = SCons.Builder.Builder(action={},
+ emitter={},
+ suffix={None: '$JAVASUFFIX'})
env['BUILDERS']['JavaFile'] = java_file
env['JAVASUFFIX'] = '.java'
return java_file
+
class ToolInitializerMethod(object):
"""
This is added to a construction environment in place of a
@@ -984,6 +1058,7 @@ class ToolInitializerMethod(object):
whatever builder was (presumably) added to the construction
environment in place of this particular instance.
"""
+
def __init__(self, name, initializer):
"""
Note: we store the tool name as __name__ so it can be used by
@@ -1022,6 +1097,7 @@ class ToolInitializerMethod(object):
return [], []
return builder(*args, **kw)
+
class ToolInitializer(object):
"""
A class for delayed initialization of Tools modules.
@@ -1033,6 +1109,7 @@ class ToolInitializer(object):
ToolInitializerMethod objects for the various Builder methods
that we want to use to delay Tool searches until necessary.
"""
+
def __init__(self, env, tools, names):
if not SCons.Util.is_List(tools):
tools = [tools]
@@ -1067,24 +1144,30 @@ class ToolInitializer(object):
env.Tool(tool)
return
- # If we fall through here, there was no tool module found.
- # This is where we can put an informative error message
- # about the inability to find the tool. We'll start doing
- # this as we cut over more pre-defined Builder+Tools to use
- # the ToolInitializer class.
+ # If we fall through here, there was no tool module found.
+ # This is where we can put an informative error message
+ # about the inability to find the tool. We'll start doing
+ # this as we cut over more pre-defined Builder+Tools to use
+ # the ToolInitializer class.
+
def Initializers(env):
ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs', '_InternalInstallVersionedLib'])
+
def Install(self, *args, **kw):
return self._InternalInstall(*args, **kw)
+
def InstallAs(self, *args, **kw):
return self._InternalInstallAs(*args, **kw)
+
def InstallVersionedLib(self, *args, **kw):
return self._InternalInstallVersionedLib(*args, **kw)
+
env.AddMethod(Install)
env.AddMethod(InstallAs)
env.AddMethod(InstallVersionedLib)
+
def FindTool(tools, env):
for tool in tools:
t = Tool(tool)
@@ -1092,14 +1175,16 @@ def FindTool(tools, env):
return tool
return None
+
def FindAllTools(tools, env):
def ToolExists(tool, env=env):
return Tool(tool).exists(env)
- return list(filter (ToolExists, tools))
-def tool_list(platform, env):
+ return list(filter(ToolExists, tools))
- other_plat_tools=[]
+
+def tool_list(platform, env):
+ other_plat_tools = []
# XXX this logic about what tool to prefer on which platform
# should be moved into either the platform files or
# the tool files themselves.
@@ -1107,21 +1192,21 @@ def tool_list(platform, env):
# change these search orders, update the man page as well.
if str(platform) == 'win32':
"prefer Microsoft tools on Windows"
- linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ]
- c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ]
- cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32' ]
- assemblers = ['masm', 'nasm', 'gas', '386asm' ]
+ linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32']
+ c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32']
+ cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'cxx', 'bcc32']
+ assemblers = ['masm', 'nasm', 'gas', '386asm']
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
ars = ['mslib', 'ar', 'tlib']
other_plat_tools = ['msvs', 'midl']
elif str(platform) == 'os2':
"prefer IBM tools on OS/2"
- linkers = ['ilink', 'gnulink', ]#'mslink']
- c_compilers = ['icc', 'gcc',]# 'msvc', 'cc']
- cxx_compilers = ['icc', 'g++',]# 'msvc', 'cxx']
- assemblers = ['nasm',]# 'masm', 'gas']
+ linkers = ['ilink', 'gnulink', ] # 'mslink']
+ c_compilers = ['icc', 'gcc', ] # 'msvc', 'cc']
+ cxx_compilers = ['icc', 'g++', ] # 'msvc', 'cxx']
+ assemblers = ['nasm', ] # 'masm', 'gas']
fortran_compilers = ['ifl', 'g77']
- ars = ['ar',]# 'mslib']
+ ars = ['ar', ] # 'mslib']
elif str(platform) == 'irix':
"prefer MIPSPro on IRIX"
linkers = ['sgilink', 'gnulink']
@@ -1174,11 +1259,11 @@ def tool_list(platform, env):
else:
"prefer GNU tools on all other platforms"
linkers = ['gnulink', 'ilink']
- c_compilers = ['gcc', 'intelc', 'icc', 'cc']
+ c_compilers = ['gcc', 'intelc', 'icc', 'cc']
cxx_compilers = ['g++', 'intelc', 'icc', 'cxx']
assemblers = ['gas', 'nasm', 'masm']
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77']
- ars = ['ar',]
+ ars = ['ar', ]
if not str(platform) == 'win32':
other_plat_tools += ['m4', 'rpm']
@@ -1210,22 +1295,24 @@ def tool_list(platform, env):
d_compiler = FindTool(d_compilers, env) or d_compilers[0]
other_tools = FindAllTools(other_plat_tools + [
- #TODO: merge 'install' into 'filesystem' and
- # make 'filesystem' the default
- 'filesystem',
- 'wix', #'midl', 'msvs',
- # Parser generators
- 'lex', 'yacc',
- # Foreign function interface
- 'rpcgen', 'swig',
- # Java
- 'jar', 'javac', 'javah', 'rmic',
- # TeX
- 'dvipdf', 'dvips', 'gs',
- 'tex', 'latex', 'pdflatex', 'pdftex',
- # Archivers
- 'tar', 'zip',
- ], env)
+ # TODO: merge 'install' into 'filesystem' and
+ # make 'filesystem' the default
+ 'filesystem',
+ 'wix', # 'midl', 'msvs',
+ # Parser generators
+ 'lex', 'yacc',
+ # Foreign function interface
+ 'rpcgen', 'swig',
+ # Java
+ 'jar', 'javac', 'javah', 'rmic',
+ # TeX
+ 'dvipdf', 'dvips', 'gs',
+ 'tex', 'latex', 'pdflatex', 'pdftex',
+ # Archivers
+ 'tar', 'zip',
+ # File builders (text)
+ 'textfile',
+ ], env)
tools = ([linker, c_compiler, cxx_compiler,
fortran_compiler, assembler, ar, d_compiler]
@@ -1233,6 +1320,38 @@ def tool_list(platform, env):
return [x for x in tools if x]
+
+def find_program_path(env, key_program, default_paths=None):
+ """
+ Find the location of a tool using various means.
+
+ Mainly for windows where tools aren't all installed in /usr/bin, etc.
+
+ :param env: Current Construction Environment.
+ :param key_program: Tool to locate.
+ :param default_paths: List of additional paths this tool might be found in.
+ """
+ # First search in the SCons path
+ path = env.WhereIs(key_program)
+ if path:
+ return path
+
+ # Then in the OS path
+ path = SCons.Util.WhereIs(key_program)
+ if path:
+ return path
+
+ # Finally, add the defaults and check again. Do not change
+ # ['ENV']['PATH'] permananetly, the caller can do that if needed.
+ if default_paths is None:
+ return path
+ save_path = env['ENV']['PATH']
+ for p in default_paths:
+ env.AppendENVPath('PATH', p)
+ path = env.WhereIs(key_program)
+ env['ENV']['PATH'] = save_path
+ return path
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/Tool/__init__.xml b/src/engine/SCons/Tool/__init__.xml
index 32b8ce6..80fd2f6 100644
--- a/src/engine/SCons/Tool/__init__.xml
+++ b/src/engine/SCons/Tool/__init__.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/aixc++.py b/src/engine/SCons/Tool/aixc++.py
index 0a2465d..bafaea4 100644
--- a/src/engine/SCons/Tool/aixc++.py
+++ b/src/engine/SCons/Tool/aixc++.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/aixc++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/aixc++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
from SCons.Tool.aixcxx import *
diff --git a/src/engine/SCons/Tool/aixc++.xml b/src/engine/SCons/Tool/aixc++.xml
index 04a27f6..0d50ae9 100644
--- a/src/engine/SCons/Tool/aixc++.xml
+++ b/src/engine/SCons/Tool/aixc++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/aixcc.py b/src/engine/SCons/Tool/aixcc.py
index aa351cd..349a40a 100644
--- a/src/engine/SCons/Tool/aixcc.py
+++ b/src/engine/SCons/Tool/aixcc.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/aixcc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/aixcc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/aixcc.xml b/src/engine/SCons/Tool/aixcc.xml
index 44ee0bc..aa0e604 100644
--- a/src/engine/SCons/Tool/aixcc.xml
+++ b/src/engine/SCons/Tool/aixcc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/aixcxx.py b/src/engine/SCons/Tool/aixcxx.py
index 97bd8a6..0830e33 100644
--- a/src/engine/SCons/Tool/aixcxx.py
+++ b/src/engine/SCons/Tool/aixcxx.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/aixcxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/aixcxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/aixf77.py b/src/engine/SCons/Tool/aixf77.py
index c72346c..d2c619a 100644
--- a/src/engine/SCons/Tool/aixf77.py
+++ b/src/engine/SCons/Tool/aixf77.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/aixf77.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/aixf77.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/aixf77.xml b/src/engine/SCons/Tool/aixf77.xml
index 69f4d92..ee4d232 100644
--- a/src/engine/SCons/Tool/aixf77.xml
+++ b/src/engine/SCons/Tool/aixf77.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/aixlink.py b/src/engine/SCons/Tool/aixlink.py
index fd67d66..ea2949f 100644
--- a/src/engine/SCons/Tool/aixlink.py
+++ b/src/engine/SCons/Tool/aixlink.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/aixlink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/aixlink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
diff --git a/src/engine/SCons/Tool/aixlink.xml b/src/engine/SCons/Tool/aixlink.xml
index d5438ef..0f7fc62 100644
--- a/src/engine/SCons/Tool/aixlink.xml
+++ b/src/engine/SCons/Tool/aixlink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/applelink.py b/src/engine/SCons/Tool/applelink.py
index 45f524c..011b29d 100644
--- a/src/engine/SCons/Tool/applelink.py
+++ b/src/engine/SCons/Tool/applelink.py
@@ -1,6 +1,6 @@
"""SCons.Tool.applelink
-Tool-specific initialization for the Apple gnu-like linker.
+Tool-specific initialization for Apple's gnu-like linker.
There normally shouldn't be any need to import this module directly.
It will usually be imported through the generic SCons.Tool.Tool()
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/applelink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/applelink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
@@ -39,25 +39,162 @@ import SCons.Util
# the -rpath option, so we use the "link" tool instead of "gnulink".
from . import link
+
+class AppleLinkInvalidCurrentVersionException(Exception):
+ pass
+
+class AppleLinkInvalidCompatibilityVersionException(Exception):
+ pass
+
+
+def _applelib_versioned_lib_suffix(env, suffix, version):
+ """For suffix='.dylib' and version='0.1.2' it returns '.0.1.2.dylib'"""
+ Verbose = False
+ if Verbose:
+ print("_applelib_versioned_lib_suffix: suffix={!r}".format(suffix))
+ print("_applelib_versioned_lib_suffix: version={!r}".format(version))
+ if version not in suffix:
+ suffix = "." + version + suffix
+ if Verbose:
+ print("_applelib_versioned_lib_suffix: return suffix={!r}".format(suffix))
+ return suffix
+
+
+def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
+ """For libnode='/optional/dir/libfoo.X.Y.Z.dylib' it returns 'libfoo.X.dylib'"""
+ Verbose = False
+ if Verbose:
+ print("_applelib_versioned_lib_soname: version={!r}".format(version))
+ name = name_func(env, libnode, version, prefix, suffix)
+ if Verbose:
+ print("_applelib_versioned_lib_soname: name={!r}".format(name))
+ major = version.split('.')[0]
+ (libname,_suffix) = name.split('.')
+ soname = '.'.join([libname, major, _suffix])
+ if Verbose:
+ print("_applelib_versioned_lib_soname: soname={!r}".format(soname))
+ return soname
+
+def _applelib_versioned_shlib_soname(env, libnode, version, prefix, suffix):
+ return _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name)
+
+
+# User programmatically describes how SHLIBVERSION maps to values for compat/current.
+_applelib_max_version_values = (65535, 255, 255)
+def _applelib_check_valid_version(version_string):
+ """
+ Check that the version # is valid.
+ X[.Y[.Z]]
+ where X 0-65535
+ where Y either not specified or 0-255
+ where Z either not specified or 0-255
+ :param version_string:
+ :return:
+ """
+ parts = version_string.split('.')
+ if len(parts) > 3:
+ return False, "Version string has too many periods [%s]"%version_string
+ if len(parts) <= 0:
+ return False, "Version string unspecified [%s]"%version_string
+
+ for (i, p) in enumerate(parts):
+ try:
+ p_i = int(p)
+ except ValueError:
+ return False, "Version component %s (from %s) is not a number"%(p, version_string)
+ if p_i < 0 or p_i > _applelib_max_version_values[i]:
+ return False, "Version component %s (from %s) is not valid value should be between 0 and %d"%(p, version_string, _applelib_max_version_values[i])
+
+ return True, ""
+
+
+def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
+ """
+ A generator function to create the -Wl,-current_version flag if needed.
+ If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
+ Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
+ will be used.
+
+ :param source:
+ :param target:
+ :param env:
+ :param for_signature:
+ :return: A string providing the flag to specify the current_version of the shared library
+ """
+ if env.get('APPLELINK_NO_CURRENT_VERSION', False):
+ return ""
+ elif env.get('APPLELINK_CURRENT_VERSION', False):
+ version_string = env['APPLELINK_CURRENT_VERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = env['SHLIBVERSION']
+ else:
+ return ""
+
+ version_string = ".".join(version_string.split('.')[:3])
+
+ valid, reason = _applelib_check_valid_version(version_string)
+ if not valid:
+ raise AppleLinkInvalidCurrentVersionException(reason)
+
+ return "-Wl,-current_version,%s" % version_string
+
+
+def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
+ """
+ A generator function to create the -Wl,-compatibility_version flag if needed.
+ If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
+ Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
+ the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
+
+ :param source:
+ :param target:
+ :param env:
+ :param for_signature:
+ :return: A string providing the flag to specify the compatibility_version of the shared library
+ """
+ if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
+ return ""
+ elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
+ version_string = env['APPLELINK_COMPATIBILITY_VERSION']
+ elif env.get('SHLIBVERSION', False):
+ version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
+ else:
+ return ""
+
+ if version_string is None:
+ return ""
+
+ valid, reason = _applelib_check_valid_version(version_string)
+ if not valid:
+ raise AppleLinkInvalidCompatibilityVersionException(reason)
+
+ return "-Wl,-compatibility_version,%s" % version_string
+
+
def generate(env):
"""Add Builders and construction variables for applelink to an
Environment."""
link.generate(env)
env['FRAMEWORKPATHPREFIX'] = '-F'
- env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__)}'
+ env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
+
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
- # TODO: Work needed to generate versioned shared libraries
- # Leaving this commented out, and also going to disable versioned library checking for now
# see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming
- #link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
- #env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
+ link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
+ env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
+ env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix
+ env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname
+ env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
+ env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
+ env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
+ env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
# override the default for loadable modules, which are different
# on OS X than dynamic shared libs. echoing what XCode does for
@@ -67,6 +204,8 @@ def generate(env):
env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
+ env['__SHLIBVERSIONFLAGS'] = '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}'
+
def exists(env):
diff --git a/src/engine/SCons/Tool/applelink.xml b/src/engine/SCons/Tool/applelink.xml
index 699abf0..c7209fa 100644
--- a/src/engine/SCons/Tool/applelink.xml
+++ b/src/engine/SCons/Tool/applelink.xml
@@ -1,155 +1,254 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
-->
<!DOCTYPE sconsdoc [
-<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
-%scons;
-<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
-%builders-mod;
-<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
-%functions-mod;
-<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
-%tools-mod;
-<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
-%variables-mod;
-]>
+ <!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+ %scons;
+ <!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+ %builders-mod;
+ <!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+ %functions-mod;
+ <!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+ %tools-mod;
+ <!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+ %variables-mod;
+ ]>
<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
-<tool name="applelink">
-<summary>
-<para>
-Sets construction variables for the Apple linker
-(similar to the GNU linker).
-</para>
-</summary>
-<sets>
-<item>FRAMEWORKPATHPREFIX</item>
-<item>_FRAMEWORKPATH</item>
-<item>_FRAMEWORKS</item>
-<item>LINKCOM</item>
-<item>SHLINKFLAGS</item>
-<item>SHLINKCOM</item>
-<item>LDMODULEPREFIX</item>
-<item>LDMODULESUFFIX</item>
-<item>LDMODULEFLAGS</item>
-<item>LDMODULECOM</item>
-</sets>
-<uses>
-<item>FRAMEWORKSFLAGS</item>
-</uses>
-</tool>
-
-<cvar name="FRAMEWORKSFLAGS">">
-<summary>
-<para>
-On Mac OS X with gcc,
-general user-supplied frameworks options to be added at
-the end of a command
-line building a loadable module.
-(This has been largely superseded by
-the &cv-link-FRAMEWORKPATH;, &cv-link-FRAMEWORKPATHPREFIX;,
-&cv-link-FRAMEWORKPREFIX; and &cv-link-FRAMEWORKS; variables
-described above.)
-</para>
-</summary>
-</cvar>
-
-<cvar name="FRAMEWORKS">
-<summary>
-<para>
-On Mac OS X with gcc, a list of the framework names to be linked into a
-program or shared library or bundle.
-The default value is the empty list.
-For example:
-</para>
-
-<example_commands>
- env.AppendUnique(FRAMEWORKS=Split('System Cocoa SystemConfiguration'))
-</example_commands>
-
-</summary>
-</cvar>
-
-<cvar name="FRAMEWORKPREFIX">
-<summary>
-<para>
-On Mac OS X with gcc,
-the prefix to be used for linking in frameworks
-(see &cv-link-FRAMEWORKS;).
-The default value is
-<option>-framework</option>.
-</para>
-</summary>
-</cvar>
-
-<cvar name="_FRAMEWORKS">
-<summary>
-<para>
-On Mac OS X with gcc,
-an automatically-generated construction variable
-containing the linker command-line options
-for linking with FRAMEWORKS.
-</para>
-</summary>
-</cvar>
-
-<cvar name="FRAMEWORKPATH">
-<summary>
-<para>
-On Mac OS X with gcc,
-a list containing the paths to search for frameworks.
-Used by the compiler to find framework-style includes like
-#include &lt;Fmwk/Header.h&gt;.
-Used by the linker to find user-specified frameworks when linking (see
-&cv-link-FRAMEWORKS;).
-For example:
-</para>
-
-<example_commands>
- env.AppendUnique(FRAMEWORKPATH='#myframeworkdir')
-</example_commands>
-
-<para>
-will add
-</para>
-
-<example_commands>
- ... -Fmyframeworkdir
-</example_commands>
-
-<para>
-to the compiler and linker command lines.
-</para>
-</summary>
-</cvar>
-
-<cvar name="FRAMEWORKPATHPREFIX">
-<summary>
-<para>
-On Mac OS X with gcc, the prefix to be used for the FRAMEWORKPATH entries.
-(see &cv-link-FRAMEWORKPATH;).
-The default value is
-<option>-F</option>.
-</para>
-</summary>
-</cvar>
-
-<cvar name="_FRAMEWORKPATH">
-<summary>
-<para>
-On Mac OS X with gcc, an automatically-generated construction variable
-containing the linker command-line options corresponding to
-&cv-link-FRAMEWORKPATH;.
-</para>
-</summary>
-</cvar>
+ <tool name="applelink">
+ <summary>
+ <para>
+ Sets construction variables for the Apple linker
+ (similar to the GNU linker).
+ </para>
+ </summary>
+ <sets>
+ <item>FRAMEWORKPATHPREFIX</item>
+ <item>_FRAMEWORKPATH</item>
+ <item>_FRAMEWORKS</item>
+ <item>LINKCOM</item>
+ <item>SHLINKFLAGS</item>
+ <item>SHLINKCOM</item>
+ <item>LDMODULEPREFIX</item>
+ <item>LDMODULESUFFIX</item>
+ <item>LDMODULEFLAGS</item>
+ <item>LDMODULECOM</item>
+ <item>APPLELINK_CURRENT_VERSION</item>
+ <item>APPLELINK_COMPATIBILITY_VERSION</item>
+ <item>APPLELINK_NO_CURRENT_VERSION</item>
+ <item>APPLELINK_NO_COMPATIBILITY_VERSION</item>
+ <item>_APPLELINK_CURRENT_VERSION</item>
+ <item>_APPLELINK_COMPATIBILITY_VERSION</item>
+ </sets>
+ <uses>
+ <item>FRAMEWORKSFLAGS</item>
+ </uses>
+ </tool>
+
+
+ <cvar name="APPLELINK_COMPATIBILITY_VERSION">
+ <summary>
+ <para>
+ On Mac OS X this is used to set the linker flag:
+
+ -compatibility_version
+ </para>
+ <para>
+ The value is specified as X[.Y[.Z]] where X is between 1 and 65535, Y can be omitted or between 1 and
+ 255, Z can be omitted or between 1 and 255. This value will be derived from &cv-link-SHLIBVERSION; if
+ not
+ specified. The lowest digit will be dropped and replaced by a 0.
+ </para>
+ <para>
+ If the &cv-link-APPLELINK_NO_COMPATIBILITY_VERSION; is set then no -compatibility_version will be
+ output.
+ </para>
+ <para>See MacOS's ld manpage for more details</para>
+ </summary>
+ </cvar>
+
+ <cvar name="APPLELINK_NO_COMPATIBILITY_VERSION">
+ <summary>
+ <para>
+ Set this to any True (1|True|non-empty string) value to disable adding -compatibility_version flag when
+ generating versioned shared libraries.
+ </para>
+ <para>
+ This overrides &cv-link-APPLELINK_COMPATIBILITY_VERSION;.
+ </para>
+ </summary>
+ </cvar>
+
+
+ <cvar name="_APPLELINK_COMPATIBILITY_VERSION">
+ <summary>
+ <para>
+ A macro (by default a generator function) used to create the linker flags to specify
+ apple's linker's -compatibility_version flag.
+ The default generator uses &cv-link-APPLELINK_COMPATIBILITY_VERSION;
+ and &cv-link-APPLELINK_NO_COMPATIBILITY_VERSION; and &cv-link-SHLIBVERSION;
+ to determine the correct flag.
+ </para>
+ </summary>
+ </cvar>
+
+
+ <cvar name="APPLELINK_CURRENT_VERSION">
+ <summary>
+ <para>
+ On Mac OS X this is used to set the linker flag:
+
+ -current_version
+ </para>
+ <para>
+ The value is specified as X[.Y[.Z]] where X is between 1 and 65535, Y can be omitted or between 1 and
+ 255, Z can be omitted or between 1 and 255. This value will be set to &cv-link-SHLIBVERSION; if not
+ specified.
+ </para>
+ <para>
+ If the &cv-link-APPLELINK_NO_CURRENT_VERSION; is set then no -current_version will be
+ output.
+ </para>
+ <para>See MacOS's ld manpage for more details</para>
+
+ </summary>
+ </cvar>
+
+
+ <cvar name="APPLELINK_NO_CURRENT_VERSION">
+ <summary>
+ <para>
+ Set this to any True (1|True|non-empty string) value to disable adding -current_version flag when
+ generating versioned shared libraries.
+ </para>
+ <para>
+ This overrides &cv-link-APPLELINK_CURRENT_VERSION;.
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="_APPLELINK_CURRENT_VERSION">
+ <summary>
+ <para>
+ A macro (by default a generator function) used to create the linker flags to specify apple's linker's
+ -current_version flag. The default generator uses &cv-link-APPLELINK_CURRENT_VERSION; and
+ &cv-link-APPLELINK_NO_CURRENT_VERSION; and &cv-link-SHLIBVERSION; to determine the correct flag.
+ </para>
+ </summary>
+ </cvar>
+
+
+ <cvar name="FRAMEWORKSFLAGS">">
+ <summary>
+ <para>
+ On Mac OS X with gcc,
+ general user-supplied frameworks options to be added at
+ the end of a command
+ line building a loadable module.
+ (This has been largely superseded by
+ the &cv-link-FRAMEWORKPATH;, &cv-link-FRAMEWORKPATHPREFIX;,
+ &cv-link-FRAMEWORKPREFIX; and &cv-link-FRAMEWORKS; variables
+ described above.)
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="FRAMEWORKS">
+ <summary>
+ <para>
+ On Mac OS X with gcc, a list of the framework names to be linked into a
+ program or shared library or bundle.
+ The default value is the empty list.
+ For example:
+ </para>
+
+ <example_commands>
+ env.AppendUnique(FRAMEWORKS=Split('System Cocoa SystemConfiguration'))
+ </example_commands>
+
+ </summary>
+ </cvar>
+
+ <cvar name="FRAMEWORKPREFIX">
+ <summary>
+ <para>
+ On Mac OS X with gcc,
+ the prefix to be used for linking in frameworks
+ (see &cv-link-FRAMEWORKS;).
+ The default value is
+ <option>-framework</option>.
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="_FRAMEWORKS">
+ <summary>
+ <para>
+ On Mac OS X with gcc,
+ an automatically-generated construction variable
+ containing the linker command-line options
+ for linking with FRAMEWORKS.
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="FRAMEWORKPATH">
+ <summary>
+ <para>
+ On Mac OS X with gcc,
+ a list containing the paths to search for frameworks.
+ Used by the compiler to find framework-style includes like
+ #include &lt;Fmwk/Header.h&gt;.
+ Used by the linker to find user-specified frameworks when linking (see
+ &cv-link-FRAMEWORKS;).
+ For example:
+ </para>
+
+ <example_commands>
+ env.AppendUnique(FRAMEWORKPATH='#myframeworkdir')
+ </example_commands>
+
+ <para>
+ will add
+ </para>
+
+ <example_commands>
+ ... -Fmyframeworkdir
+ </example_commands>
+
+ <para>
+ to the compiler and linker command lines.
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="FRAMEWORKPATHPREFIX">
+ <summary>
+ <para>
+ On Mac OS X with gcc, the prefix to be used for the FRAMEWORKPATH entries.
+ (see &cv-link-FRAMEWORKPATH;).
+ The default value is
+ <option>-F</option>.
+ </para>
+ </summary>
+ </cvar>
+
+ <cvar name="_FRAMEWORKPATH">
+ <summary>
+ <para>
+ On Mac OS X with gcc, an automatically-generated construction variable
+ containing the linker command-line options corresponding to
+ &cv-link-FRAMEWORKPATH;.
+ </para>
+ </summary>
+ </cvar>
</sconsdoc>
diff --git a/src/engine/SCons/Tool/ar.py b/src/engine/SCons/Tool/ar.py
index 4d2a005..459fb55 100644
--- a/src/engine/SCons/Tool/ar.py
+++ b/src/engine/SCons/Tool/ar.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/ar.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ar.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/ar.xml b/src/engine/SCons/Tool/ar.xml
index 9b9e0a0..573c80b 100644
--- a/src/engine/SCons/Tool/ar.xml
+++ b/src/engine/SCons/Tool/ar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/as.py b/src/engine/SCons/Tool/as.py
index ab81b89..02139c5 100644
--- a/src/engine/SCons/Tool/as.py
+++ b/src/engine/SCons/Tool/as.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/as.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/as.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/as.xml b/src/engine/SCons/Tool/as.xml
index f4d886d..c2d1814 100644
--- a/src/engine/SCons/Tool/as.xml
+++ b/src/engine/SCons/Tool/as.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/bcc32.py b/src/engine/SCons/Tool/bcc32.py
index bf0a5dd..e8ffbbf 100644
--- a/src/engine/SCons/Tool/bcc32.py
+++ b/src/engine/SCons/Tool/bcc32.py
@@ -5,7 +5,7 @@ XXX
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/bcc32.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/bcc32.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
diff --git a/src/engine/SCons/Tool/bcc32.xml b/src/engine/SCons/Tool/bcc32.xml
index 6163016..b2d8394 100644
--- a/src/engine/SCons/Tool/bcc32.xml
+++ b/src/engine/SCons/Tool/bcc32.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/c++.py b/src/engine/SCons/Tool/c++.py
index ebfe0a4..8819f82 100644
--- a/src/engine/SCons/Tool/c++.py
+++ b/src/engine/SCons/Tool/c++.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/c++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/c++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
diff --git a/src/engine/SCons/Tool/c++.xml b/src/engine/SCons/Tool/c++.xml
index e2021fc..c10438a 100644
--- a/src/engine/SCons/Tool/c++.xml
+++ b/src/engine/SCons/Tool/c++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/cc.py b/src/engine/SCons/Tool/cc.py
index 31e7b2b..698d725 100644
--- a/src/engine/SCons/Tool/cc.py
+++ b/src/engine/SCons/Tool/cc.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/cc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/cc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool
import SCons.Defaults
diff --git a/src/engine/SCons/Tool/cc.xml b/src/engine/SCons/Tool/cc.xml
index 1ec3084..735f700 100644
--- a/src/engine/SCons/Tool/cc.xml
+++ b/src/engine/SCons/Tool/cc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/clang.py b/src/engine/SCons/Tool/clang.py
index 1271378..f48afbf 100644
--- a/src/engine/SCons/Tool/clang.py
+++ b/src/engine/SCons/Tool/clang.py
@@ -11,7 +11,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-# __revision__ = "src/engine/SCons/Tool/clang.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+# __revision__ = "src/engine/SCons/Tool/clang.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
# Brought into the SCons mainline by Russel Winder 2017.
@@ -45,6 +45,8 @@ import sys
import SCons.Util
import SCons.Tool.cc
+from SCons.Tool.clangCommon import get_clang_install_dirs
+
compilers = ['clang']
@@ -52,11 +54,20 @@ def generate(env):
"""Add Builders and construction variables for clang to an Environment."""
SCons.Tool.cc.generate(env)
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for clang
+ clang = SCons.Tool.find_program_path(env, compilers[0],
+ default_paths=get_clang_install_dirs(env['PLATFORM']))
+ if clang:
+ clang_bin_dir = os.path.dirname(clang)
+ env.AppendENVPath('PATH', clang_bin_dir)
+
env['CC'] = env.Detect(compilers) or 'clang'
if env['PLATFORM'] in ['cygwin', 'win32']:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
else:
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
+
# determine compiler version
if env['CC']:
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
@@ -66,7 +77,8 @@ def generate(env):
stdout=subprocess.PIPE)
if pipe.wait() != 0: return
# clang -dumpversion is of no use
- line = pipe.stdout.readline()
+ with pipe.stdout:
+ line = pipe.stdout.readline()
if sys.version_info[0] > 2:
line = line.decode()
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
diff --git a/src/engine/SCons/Tool/clang.xml b/src/engine/SCons/Tool/clang.xml
index 3086a51..a546946 100644
--- a/src/engine/SCons/Tool/clang.xml
+++ b/src/engine/SCons/Tool/clang.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/clangCommon/__init__.py b/src/engine/SCons/Tool/clangCommon/__init__.py
new file mode 100644
index 0000000..37efbf6
--- /dev/null
+++ b/src/engine/SCons/Tool/clangCommon/__init__.py
@@ -0,0 +1,17 @@
+"""
+Common routines and data for clang tools
+"""
+
+clang_win32_dirs = [
+ r'C:\Program Files\LLVM\bin',
+ r'C:\cygwin64\bin',
+ r'C:\msys64',
+ r'C:\cygwin\bin',
+ r'C:\msys',
+]
+
+def get_clang_install_dirs(platform):
+ if platform == 'win32':
+ return clang_win32_dirs
+ else:
+ return [] \ No newline at end of file
diff --git a/src/engine/SCons/Tool/clangxx.py b/src/engine/SCons/Tool/clangxx.py
index f56c9e5..d88874e 100644
--- a/src/engine/SCons/Tool/clangxx.py
+++ b/src/engine/SCons/Tool/clangxx.py
@@ -11,7 +11,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-# __revision__ = "src/engine/SCons/Tool/clangxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+# __revision__ = "src/engine/SCons/Tool/clangxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
# Brought into the SCons mainline by Russel Winder 2017.
@@ -46,6 +46,8 @@ import sys
import SCons.Tool
import SCons.Util
import SCons.Tool.cxx
+from SCons.Tool.clangCommon import get_clang_install_dirs
+
compilers = ['clang++']
@@ -66,15 +68,25 @@ def generate(env):
env['SHOBJSUFFIX'] = '.pic.o'
elif env['PLATFORM'] == 'sunos':
env['SHOBJSUFFIX'] = '.pic.o'
+ elif env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for clang++
+ clangxx = SCons.Tool.find_program_path(env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM']))
+ if clangxx:
+ clangxx_bin_dir = os.path.dirname(clangxx)
+ env.AppendENVPath('PATH', clangxx_bin_dir)
+
# determine compiler version
if env['CXX']:
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
stdin='devnull',
stderr='devnull',
stdout=subprocess.PIPE)
- if pipe.wait() != 0: return
+ if pipe.wait() != 0:
+ return
+
# clang -dumpversion is of no use
- line = pipe.stdout.readline()
+ with pipe.stdout:
+ line = pipe.stdout.readline()
if sys.version_info[0] > 2:
line = line.decode()
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
diff --git a/src/engine/SCons/Tool/clangxx.xml b/src/engine/SCons/Tool/clangxx.xml
index 309bb63..7372389 100644
--- a/src/engine/SCons/Tool/clangxx.xml
+++ b/src/engine/SCons/Tool/clangxx.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/cvf.py b/src/engine/SCons/Tool/cvf.py
index a785471..aa24d69 100644
--- a/src/engine/SCons/Tool/cvf.py
+++ b/src/engine/SCons/Tool/cvf.py
@@ -5,7 +5,7 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Tool-specific initialization for the Compaq Visual Fortran compiler.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/cvf.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/cvf.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import fortran
diff --git a/src/engine/SCons/Tool/cvf.xml b/src/engine/SCons/Tool/cvf.xml
index 1b2c447..b56c23c 100644
--- a/src/engine/SCons/Tool/cvf.xml
+++ b/src/engine/SCons/Tool/cvf.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/cxx.py b/src/engine/SCons/Tool/cxx.py
index 236730f..2ac278e 100644
--- a/src/engine/SCons/Tool/cxx.py
+++ b/src/engine/SCons/Tool/cxx.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/cxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/cxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/cyglink.py b/src/engine/SCons/Tool/cyglink.py
index f69b886..c3d78de 100644
--- a/src/engine/SCons/Tool/cyglink.py
+++ b/src/engine/SCons/Tool/cyglink.py
@@ -133,7 +133,7 @@ def _versioned_lib_suffix(env, suffix, version):
if Verbose:
print("_versioned_lib_suffix: suffix= ", suffix)
print("_versioned_lib_suffix: version= ", version)
- cygversion = re.sub('\.', '-', version)
+ cygversion = re.sub(r'\.', '-', version)
if not suffix.startswith('-' + cygversion):
suffix = '-' + cygversion + suffix
if Verbose:
diff --git a/src/engine/SCons/Tool/cyglink.xml b/src/engine/SCons/Tool/cyglink.xml
index 13556e8..a0aefac 100644
--- a/src/engine/SCons/Tool/cyglink.xml
+++ b/src/engine/SCons/Tool/cyglink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/default.py b/src/engine/SCons/Tool/default.py
index 72d3399..866b823 100644
--- a/src/engine/SCons/Tool/default.py
+++ b/src/engine/SCons/Tool/default.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/default.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/default.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool
diff --git a/src/engine/SCons/Tool/default.xml b/src/engine/SCons/Tool/default.xml
index 3683a10..8e1ed21 100644
--- a/src/engine/SCons/Tool/default.xml
+++ b/src/engine/SCons/Tool/default.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/dmd.py b/src/engine/SCons/Tool/dmd.py
index 1dfb5d7..befcd22 100644
--- a/src/engine/SCons/Tool/dmd.py
+++ b/src/engine/SCons/Tool/dmd.py
@@ -31,7 +31,7 @@ Lib tool variables:
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -53,7 +53,7 @@ Lib tool variables:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/dmd.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/dmd.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import subprocess
diff --git a/src/engine/SCons/Tool/dmd.xml b/src/engine/SCons/Tool/dmd.xml
index a06db10..5149503 100644
--- a/src/engine/SCons/Tool/dmd.xml
+++ b/src/engine/SCons/Tool/dmd.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/docbook/__init__.py b/src/engine/SCons/Tool/docbook/__init__.py
index ed63784..147556d 100644
--- a/src/engine/SCons/Tool/docbook/__init__.py
+++ b/src/engine/SCons/Tool/docbook/__init__.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -84,7 +84,7 @@ def __extend_targets_sources(target, source):
source = [source]
if len(target) < len(source):
target.extend(source[len(target):])
-
+
return target, source
def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
@@ -94,12 +94,12 @@ def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
path_args = [scriptpath, db_xsl_folder] + default_path
xsl_style = os.path.join(*path_args)
kw['DOCBOOK_XSL'] = xsl_style
-
+
def __select_builder(lxml_builder, libxml2_builder, cmdline_builder):
""" Selects a builder, based on which Python modules are present. """
if prefer_xsltproc:
return cmdline_builder
-
+
if not has_libxml2:
# At the moment we prefer libxml2 over lxml, the latter can lead
# to conflicts when installed together with libxml2.
@@ -115,7 +115,7 @@ def __ensure_suffix(t, suffix):
tpath = str(t)
if not tpath.endswith(suffix):
return tpath+suffix
-
+
return t
def __ensure_suffix_stem(t, suffix):
@@ -124,11 +124,11 @@ def __ensure_suffix_stem(t, suffix):
if not tpath.endswith(suffix):
stem = tpath
tpath += suffix
-
+
return tpath, stem
else:
stem, ext = os.path.splitext(tpath)
-
+
return t, stem
def __get_xml_text(root):
@@ -151,7 +151,7 @@ def __create_output_dir(base_dir):
else:
if base_dir.endswith('/'):
dir = base_dir
-
+
if dir and not os.path.isdir(dir):
os.makedirs(dir)
@@ -166,6 +166,8 @@ xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan']
# see: http://saxon.sourceforge.net/
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
+ # Note if saxon-xslt is version 5.5 the proper arguments are: (swap order of docbook_xsl and source)
+ # 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $SOURCE $DOCBOOK_XSL $DOCBOOK_XSLTPROCPARAMS',
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'}
xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'}
@@ -201,10 +203,10 @@ def _detect(env):
the requested output formats.
"""
global prefer_xsltproc
-
+
if env.get('DOCBOOK_PREFER_XSLTPROC',''):
prefer_xsltproc = True
-
+
if ((not has_libxml2 and not has_lxml) or (prefer_xsltproc)):
# Try to find the XSLT processors
__detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority)
@@ -217,15 +219,15 @@ def _detect(env):
#
include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']')
sentity_re = re.compile('<!ENTITY\\s+%*\\s*[^\\s]+\\s+SYSTEM\\s+["|\']([^\\n]*)["|\']>')
-
+
def __xml_scan(node, env, path, arg):
""" Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """
# Does the node exist yet?
if not os.path.isfile(str(node)):
return []
-
+
if env.get('DOCBOOK_SCANENT',''):
- # Use simple pattern matching for system entities..., no support
+ # Use simple pattern matching for system entities..., no support
# for recursion yet.
contents = node.get_text_contents()
return sentity_re.findall(contents)
@@ -233,9 +235,9 @@ def __xml_scan(node, env, path, arg):
xsl_file = os.path.join(scriptpath,'utils','xmldepend.xsl')
if not has_libxml2 or prefer_xsltproc:
if has_lxml and not prefer_xsltproc:
-
+
from lxml import etree
-
+
xsl_tree = etree.parse(xsl_file)
doc = etree.parse(str(node))
result = doc.xslt(xsl_tree)
@@ -264,7 +266,7 @@ def __xml_scan(node, env, path, arg):
for x in str(result).splitlines():
if x.strip() != "" and not x.startswith("<?xml "):
depfiles.extend(x.strip().split())
-
+
style.freeStylesheet()
doc.freeDoc()
result.freeDoc()
@@ -280,7 +282,7 @@ docbook_xml_scanner = SCons.Script.Scanner(function = __xml_scan,
# Action generators
#
def __generate_xsltproc_action(source, target, env, for_signature):
- cmd = env['DOCBOOK_XSLTPROCCOM']
+ cmd = env['DOCBOOK_XSLTPROCCOM']
# Does the environment have a base_dir defined?
base_dir = env.subst('$base_dir')
if base_dir:
@@ -298,7 +300,7 @@ def __emit_xsl_basedir(target, source, env):
if base_dir:
# Yes, so prepend it to each target
return [os.path.join(base_dir, str(t)) for t in target], source
-
+
# No, so simply pass target and source names through
return target, source
@@ -332,11 +334,11 @@ def __build_lxml(target, source, env):
General XSLT builder (HTML/FO), using the lxml module.
"""
from lxml import etree
-
- xslt_ac = etree.XSLTAccessControl(read_file=True,
- write_file=True,
- create_dir=True,
- read_network=False,
+
+ xslt_ac = etree.XSLTAccessControl(read_file=True,
+ write_file=True,
+ create_dir=True,
+ read_network=False,
write_network=False)
xsl_style = env.subst('$DOCBOOK_XSL')
xsl_tree = etree.parse(xsl_style)
@@ -348,11 +350,10 @@ def __build_lxml(target, source, env):
result = transform(doc, **parampass)
else:
result = transform(doc)
-
+
try:
- of = open(str(target[0]), "wb")
- of.write(of.write(etree.tostring(result, pretty_print=True)))
- of.close()
+ with open(str(target[0]), "wb") as of:
+ of.write(etree.tostring(result, pretty_print=True))
except:
pass
@@ -374,11 +375,11 @@ def __xinclude_lxml(target, source, env):
Resolving XIncludes, using the lxml module.
"""
from lxml import etree
-
+
doc = etree.parse(str(source[0]))
doc.xinclude()
try:
- doc.write(str(target[0]), xml_declaration=True,
+ doc.write(str(target[0]), xml_declaration=True,
encoding="UTF-8", pretty_print=True)
except:
pass
@@ -430,33 +431,31 @@ def DocbookEpub(env, target, source=None, *args, **kw):
"""
import zipfile
import shutil
-
+
def build_open_container(target, source, env):
"""Generate the *.epub file from intermediate outputs
- Constructs the epub file according to the Open Container Format. This
+ Constructs the epub file according to the Open Container Format. This
function could be replaced by a call to the SCons Zip builder if support
was added for different compression formats for separate source nodes.
"""
- zf = zipfile.ZipFile(str(target[0]), 'w')
- mime_file = open('mimetype', 'w')
- mime_file.write('application/epub+zip')
- mime_file.close()
- zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
- for s in source:
- if os.path.isfile(str(s)):
- head, tail = os.path.split(str(s))
- if not head:
- continue
- s = head
- for dirpath, dirnames, filenames in os.walk(str(s)):
- for fname in filenames:
- path = os.path.join(dirpath, fname)
- if os.path.isfile(path):
- zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
- zipfile.ZIP_DEFLATED)
- zf.close()
-
+ with zipfile.ZipFile(str(target[0]), 'w') as zf:
+ with open('mimetype', 'w') as mime_file:
+ mime_file.write('application/epub+zip')
+ zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
+ for s in source:
+ if os.path.isfile(str(s)):
+ head, tail = os.path.split(str(s))
+ if not head:
+ continue
+ s = head
+ for dirpath, dirnames, filenames in os.walk(str(s)):
+ for fname in filenames:
+ path = os.path.join(dirpath, fname)
+ if os.path.isfile(path):
+ zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
+ zipfile.ZIP_DEFLATED)
+
def add_resources(target, source, env):
"""Add missing resources to the OEBPS directory
@@ -466,7 +465,7 @@ def DocbookEpub(env, target, source=None, *args, **kw):
content_file = os.path.join(source[0].get_abspath(), 'content.opf')
if not os.path.isfile(content_file):
return
-
+
hrefs = []
if has_libxml2:
nsmap = {'opf' : 'http://www.idpf.org/2007/opf'}
@@ -493,51 +492,51 @@ def DocbookEpub(env, target, source=None, *args, **kw):
hrefs.append(item.attrib['href'])
doc.freeDoc()
- xpath_context.xpathFreeContext()
+ xpath_context.xpathFreeContext()
elif has_lxml:
from lxml import etree
-
+
opf = etree.parse(content_file)
# All the opf:item elements are resources
- for item in opf.xpath('//opf:item',
+ for item in opf.xpath('//opf:item',
namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):
hrefs.append(item.attrib['href'])
-
+
for href in hrefs:
- # If the resource was not already created by DocBook XSL itself,
+ # If the resource was not already created by DocBook XSL itself,
# copy it into the OEBPS folder
referenced_file = os.path.join(source[0].get_abspath(), href)
if not os.path.exists(referenced_file):
shutil.copy(href, os.path.join(source[0].get_abspath(), href))
-
+
# Init list of targets/sources
target, source = __extend_targets_sources(target, source)
-
+
# Init XSL stylesheet
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_EPUB', ['epub','docbook.xsl'])
# Setup builder
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
-
+
# Create targets
result = []
- if not env.GetOption('clean'):
+ if not env.GetOption('clean'):
# Ensure that the folders OEBPS and META-INF exist
__create_output_dir('OEBPS/')
__create_output_dir('META-INF/')
dirs = env.Dir(['OEBPS', 'META-INF'])
-
+
# Set the fixed base_dir
kw['base_dir'] = 'OEBPS/'
tocncx = __builder.__call__(env, 'toc.ncx', source[0], **kw)
cxml = env.File('META-INF/container.xml')
env.SideEffect(cxml, tocncx)
-
+
env.Depends(tocncx, kw['DOCBOOK_XSL'])
result.extend(tocncx+[cxml])
- container = env.Command(__ensure_suffix(str(target[0]), '.epub'),
- tocncx+[cxml], [add_resources, build_open_container])
+ container = env.Command(__ensure_suffix(str(target[0]), '.epub'),
+ tocncx+[cxml], [add_resources, build_open_container])
mimetype = env.File('mimetype')
env.SideEffect(mimetype, container)
@@ -553,13 +552,13 @@ def DocbookHtml(env, target, source=None, *args, **kw):
"""
# Init list of targets/sources
target, source = __extend_targets_sources(target, source)
-
+
# Init XSL stylesheet
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTML', ['html','docbook.xsl'])
# Setup builder
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
-
+
# Create targets
result = []
for t,s in zip(target,source):
@@ -581,18 +580,18 @@ def DocbookHtmlChunked(env, target, source=None, *args, **kw):
target = ['index.html']
elif not SCons.Util.is_List(source):
source = [source]
-
+
# Init XSL stylesheet
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED', ['html','chunkfast.xsl'])
# Setup builder
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
-
+
# Detect base dir
base_dir = kw.get('base_dir', '')
if base_dir:
__create_output_dir(base_dir)
-
+
# Create targets
result = []
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
@@ -615,8 +614,8 @@ def DocbookHtmlhelp(env, target, source=None, *args, **kw):
source = target
target = ['index.html']
elif not SCons.Util.is_List(source):
- source = [source]
-
+ source = [source]
+
# Init XSL stylesheet
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLHELP', ['htmlhelp','htmlhelp.xsl'])
@@ -627,7 +626,7 @@ def DocbookHtmlhelp(env, target, source=None, *args, **kw):
base_dir = kw.get('base_dir', '')
if base_dir:
__create_output_dir(base_dir)
-
+
# Create targets
result = []
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
@@ -685,30 +684,29 @@ def DocbookMan(env, target, source=None, *args, **kw):
if os.path.isfile(srcfile):
try:
import xml.dom.minidom
-
+
dom = xml.dom.minidom.parse(__ensure_suffix(str(s),'.xml'))
# Extract volume number, default is 1
for node in dom.getElementsByTagName('refmeta'):
for vol in node.getElementsByTagName('manvolnum'):
volnum = __get_xml_text(vol)
-
+
# Extract output filenames
for node in dom.getElementsByTagName('refnamediv'):
for ref in node.getElementsByTagName('refname'):
outfiles.append(__get_xml_text(ref)+'.'+volnum)
-
+
except:
- # Use simple regex parsing
- f = open(__ensure_suffix(str(s),'.xml'), 'r')
- content = f.read()
- f.close()
-
+ # Use simple regex parsing
+ with open(__ensure_suffix(str(s),'.xml'), 'r') as f:
+ content = f.read()
+
for m in re_manvolnum.finditer(content):
volnum = m.group(1)
-
+
for m in re_refname.finditer(content):
outfiles.append(m.group(1)+'.'+volnum)
-
+
if not outfiles:
# Use stem of the source file
spath = str(s)
@@ -720,14 +718,14 @@ def DocbookMan(env, target, source=None, *args, **kw):
else:
# We have to completely rely on the given target name
outfiles.append(t)
-
+
__builder.__call__(env, outfiles[0], s, **kw)
env.Depends(outfiles[0], kw['DOCBOOK_XSL'])
result.append(outfiles[0])
if len(outfiles) > 1:
env.Clean(outfiles[0], outfiles[1:])
-
+
return result
def DocbookSlidesPdf(env, target, source=None, *args, **kw):
@@ -748,7 +746,7 @@ def DocbookSlidesPdf(env, target, source=None, *args, **kw):
for t,s in zip(target,source):
t, stem = __ensure_suffix_stem(t, '.pdf')
xsl = __builder.__call__(env, stem+'.fo', s, **kw)
- env.Depends(xsl, kw['DOCBOOK_XSL'])
+ env.Depends(xsl, kw['DOCBOOK_XSL'])
result.extend(xsl)
result.extend(__fop_builder.__call__(env, t, xsl, **kw))
@@ -765,7 +763,7 @@ def DocbookSlidesHtml(env, target, source=None, *args, **kw):
source = target
target = ['index.html']
elif not SCons.Util.is_List(source):
- source = [source]
+ source = [source]
# Init XSL stylesheet
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESHTML', ['slides','html','plain.xsl'])
@@ -798,12 +796,12 @@ def DocbookXInclude(env, target, source, *args, **kw):
# Setup builder
__builder = __select_builder(__xinclude_lxml_builder,__xinclude_libxml2_builder,__xmllint_builder)
-
+
# Create targets
result = []
for t,s in zip(target,source):
result.extend(__builder.__call__(env, t, s, **kw))
-
+
return result
def DocbookXslt(env, target, source=None, *args, **kw):
@@ -812,13 +810,13 @@ def DocbookXslt(env, target, source=None, *args, **kw):
"""
# Init list of targets/sources
target, source = __extend_targets_sources(target, source)
-
+
# Init XSL stylesheet
kw['DOCBOOK_XSL'] = kw.get('xsl', 'transform.xsl')
# Setup builder
__builder = __select_builder(__lxml_builder, __libxml2_builder, __xsltproc_builder)
-
+
# Create targets
result = []
for t,s in zip(target,source):
@@ -842,18 +840,18 @@ def generate(env):
DOCBOOK_DEFAULT_XSL_MAN = '',
DOCBOOK_DEFAULT_XSL_SLIDESPDF = '',
DOCBOOK_DEFAULT_XSL_SLIDESHTML = '',
-
+
# Paths to the detected executables
DOCBOOK_XSLTPROC = '',
DOCBOOK_XMLLINT = '',
DOCBOOK_FOP = '',
-
+
# Additional flags for the text processors
DOCBOOK_XSLTPROCFLAGS = SCons.Util.CLVar(''),
DOCBOOK_XMLLINTFLAGS = SCons.Util.CLVar(''),
DOCBOOK_FOPFLAGS = SCons.Util.CLVar(''),
DOCBOOK_XSLTPROCPARAMS = SCons.Util.CLVar(''),
-
+
# Default command lines for the detected executables
DOCBOOK_XSLTPROCCOM = xsltproc_com['xsltproc'],
DOCBOOK_XMLLINTCOM = xmllint_com['xmllint'],
@@ -863,7 +861,7 @@ def generate(env):
DOCBOOK_XSLTPROCCOMSTR = None,
DOCBOOK_XMLLINTCOMSTR = None,
DOCBOOK_FOPCOMSTR = None,
-
+
)
_detect(env)
diff --git a/src/engine/SCons/Tool/docbook/__init__.xml b/src/engine/SCons/Tool/docbook/__init__.xml
index 1994392..3110649 100644
--- a/src/engine/SCons/Tool/docbook/__init__.xml
+++ b/src/engine/SCons/Tool/docbook/__init__.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/docbook/docs/manual.xml b/src/engine/SCons/Tool/docbook/docs/manual.xml
index c129753..64ee925 100644
--- a/src/engine/SCons/Tool/docbook/docs/manual.xml
+++ b/src/engine/SCons/Tool/docbook/docs/manual.xml
@@ -67,7 +67,7 @@ package's <literal>docbook</literal> folder to
<itemizedlist><listitem><para>the SCons User's Guide, chap. 19.7 "Where to put your custom Builders and Tools" and
</para>
</listitem>
-<listitem><para>the SCons Tools Wiki page at <ulink url="http://scons.org/wiki/ToolsIndex">http://scons.org/wiki/ToolsIndex</ulink>.
+<listitem><para>the SCons Tools Wiki page at <ulink url="https://github.com/SCons/scons/wiki/ToolsIndex">http://github.com/SCons/scons/wiki/ToolsIndex</ulink>.
</para>
</listitem>
</itemizedlist>
diff --git a/src/engine/SCons/Tool/dvi.py b/src/engine/SCons/Tool/dvi.py
index 9ec1563..5cd85ed 100644
--- a/src/engine/SCons/Tool/dvi.py
+++ b/src/engine/SCons/Tool/dvi.py
@@ -5,7 +5,7 @@ Common DVI Builder definition for various other Tool modules that use it.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Common DVI Builder definition for various other Tool modules that use it.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/dvi.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/dvi.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Builder
import SCons.Tool
diff --git a/src/engine/SCons/Tool/dvi.xml b/src/engine/SCons/Tool/dvi.xml
index 1ec2ef0..82ff01b 100644
--- a/src/engine/SCons/Tool/dvi.xml
+++ b/src/engine/SCons/Tool/dvi.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/dvipdf.py b/src/engine/SCons/Tool/dvipdf.py
index 339155d..32f57e6 100644
--- a/src/engine/SCons/Tool/dvipdf.py
+++ b/src/engine/SCons/Tool/dvipdf.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# 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/dvipdf.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/dvipdf.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Defaults
diff --git a/src/engine/SCons/Tool/dvipdf.xml b/src/engine/SCons/Tool/dvipdf.xml
index a5d2018..683ca72 100644
--- a/src/engine/SCons/Tool/dvipdf.xml
+++ b/src/engine/SCons/Tool/dvipdf.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/dvips.py b/src/engine/SCons/Tool/dvips.py
index 95641d6..988ecd3 100644
--- a/src/engine/SCons/Tool/dvips.py
+++ b/src/engine/SCons/Tool/dvips.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/dvips.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/dvips.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Builder
diff --git a/src/engine/SCons/Tool/dvips.xml b/src/engine/SCons/Tool/dvips.xml
index 7f47592..9838db1 100644
--- a/src/engine/SCons/Tool/dvips.xml
+++ b/src/engine/SCons/Tool/dvips.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/f03.py b/src/engine/SCons/Tool/f03.py
index a9f91a8..541ec88 100644
--- a/src/engine/SCons/Tool/f03.py
+++ b/src/engine/SCons/Tool/f03.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/f03.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/f03.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/f03.xml b/src/engine/SCons/Tool/f03.xml
index e486acf..af9da30 100644
--- a/src/engine/SCons/Tool/f03.xml
+++ b/src/engine/SCons/Tool/f03.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/f08.py b/src/engine/SCons/Tool/f08.py
index eb44487..5dc49da 100644
--- a/src/engine/SCons/Tool/f08.py
+++ b/src/engine/SCons/Tool/f08.py
@@ -11,7 +11,7 @@ selection method.
from __future__ import absolute_import
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ from __future__ import absolute_import
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/f08.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/f08.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/f08.xml b/src/engine/SCons/Tool/f08.xml
index aac7b66..4c07890 100644
--- a/src/engine/SCons/Tool/f08.xml
+++ b/src/engine/SCons/Tool/f08.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/f77.py b/src/engine/SCons/Tool/f77.py
index afa9a7b..6d60edf 100644
--- a/src/engine/SCons/Tool/f77.py
+++ b/src/engine/SCons/Tool/f77.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/f77.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 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 210c646..7ce1159 100644
--- a/src/engine/SCons/Tool/f77.xml
+++ b/src/engine/SCons/Tool/f77.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/f90.py b/src/engine/SCons/Tool/f90.py
index f66ed47..e0b5fae 100644
--- a/src/engine/SCons/Tool/f90.py
+++ b/src/engine/SCons/Tool/f90.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/f90.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/f90.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Scanner.Fortran
diff --git a/src/engine/SCons/Tool/f90.xml b/src/engine/SCons/Tool/f90.xml
index b5f7f13..f8c1854 100644
--- a/src/engine/SCons/Tool/f90.xml
+++ b/src/engine/SCons/Tool/f90.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/f95.py b/src/engine/SCons/Tool/f95.py
index bc5439f..9a1afdf 100644
--- a/src/engine/SCons/Tool/f95.py
+++ b/src/engine/SCons/Tool/f95.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/f95.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/f95.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/f95.xml b/src/engine/SCons/Tool/f95.xml
index f1cb7c2..a575ad0 100644
--- a/src/engine/SCons/Tool/f95.xml
+++ b/src/engine/SCons/Tool/f95.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/filesystem.py b/src/engine/SCons/Tool/filesystem.py
index 6615c31..a625714 100644
--- a/src/engine/SCons/Tool/filesystem.py
+++ b/src/engine/SCons/Tool/filesystem.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/filesystem.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/filesystem.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons
from SCons.Tool.install import copyFunc
diff --git a/src/engine/SCons/Tool/fortran.py b/src/engine/SCons/Tool/fortran.py
index b99b5e6..1b09880 100644
--- a/src/engine/SCons/Tool/fortran.py
+++ b/src/engine/SCons/Tool/fortran.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/fortran.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/fortran.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import re
diff --git a/src/engine/SCons/Tool/fortran.xml b/src/engine/SCons/Tool/fortran.xml
index 3907ce2..0fde8f1 100644
--- a/src/engine/SCons/Tool/fortran.xml
+++ b/src/engine/SCons/Tool/fortran.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -125,7 +125,8 @@ containing the Fortran compiler command-line options
for specifying directories to be searched for include
files and module files.
The value of &cv-link-_FORTRANINCFLAGS; is created
-by prepending/appending &cv-link-INCPREFIX; and &cv-link-INCSUFFIX;
+by respectively prepending and appending
+&cv-link-INCPREFIX; and &cv-link-INCSUFFIX;
to the beginning and end
of each directory in &cv-link-FORTRANPATH;.
</para>
@@ -148,7 +149,7 @@ for module files, as well.
<para>
The prefix used to specify a module directory on the Fortran compiler command
line.
-This will be appended to the beginning of the directory
+This will be prepended to the beginning of the directory
in the &cv-link-FORTRANMODDIR; construction variables
when the &cv-link-_FORTRANMODFLAG; variables is automatically generated.
</para>
@@ -160,7 +161,7 @@ when the &cv-link-_FORTRANMODFLAG; variables is automatically generated.
<para>
The suffix used to specify a module directory on the Fortran compiler command
line.
-This will be appended to the beginning of the directory
+This will be appended to the end of the directory
in the &cv-link-FORTRANMODDIR; construction variables
when the &cv-link-_FORTRANMODFLAG; variables is automatically generated.
</para>
@@ -176,8 +177,8 @@ for specifying the directory location where the Fortran
compiler should place any module files that happen to get
generated during compilation.
The value of &cv-link-_FORTRANMODFLAG; is created
-by prepending/appending &cv-link-FORTRANMODDIRPREFIX; and
-&cv-link-FORTRANMODDIRSUFFIX;
+by respectively prepending and appending
+&cv-link-FORTRANMODDIRPREFIX; and &cv-link-FORTRANMODDIRSUFFIX;
to the beginning and end of the directory in &cv-link-FORTRANMODDIR;.
</para>
</summary>
@@ -250,7 +251,7 @@ through the automatically-generated
&cv-link-_FORTRANINCFLAGS;
construction variable,
which is constructed by
-appending the values of the
+respectively prepending and appending the values of the
&cv-link-INCPREFIX; and &cv-link-INCSUFFIX;
construction variables
to the beginning and end
diff --git a/src/engine/SCons/Tool/g++.py b/src/engine/SCons/Tool/g++.py
index 468fa87..8cf881f 100644
--- a/src/engine/SCons/Tool/g++.py
+++ b/src/engine/SCons/Tool/g++.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/g++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/g++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
diff --git a/src/engine/SCons/Tool/g++.xml b/src/engine/SCons/Tool/g++.xml
index 6698869..f997540 100644
--- a/src/engine/SCons/Tool/g++.xml
+++ b/src/engine/SCons/Tool/g++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/g77.py b/src/engine/SCons/Tool/g77.py
index 36b3c43..fc0bcba 100644
--- a/src/engine/SCons/Tool/g77.py
+++ b/src/engine/SCons/Tool/g77.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/g77.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/g77.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env
diff --git a/src/engine/SCons/Tool/g77.xml b/src/engine/SCons/Tool/g77.xml
index ae57994..519dfaf 100644
--- a/src/engine/SCons/Tool/g77.xml
+++ b/src/engine/SCons/Tool/g77.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gas.py b/src/engine/SCons/Tool/gas.py
index 75e5456..c104e34 100644
--- a/src/engine/SCons/Tool/gas.py
+++ b/src/engine/SCons/Tool/gas.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gas.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gas.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
try:
as_module = __import__('as', globals(), locals(), [])
diff --git a/src/engine/SCons/Tool/gas.xml b/src/engine/SCons/Tool/gas.xml
index 95ccf27..9cfe0de 100644
--- a/src/engine/SCons/Tool/gas.xml
+++ b/src/engine/SCons/Tool/gas.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gcc.py b/src/engine/SCons/Tool/gcc.py
index f241c7b..2532427 100644
--- a/src/engine/SCons/Tool/gcc.py
+++ b/src/engine/SCons/Tool/gcc.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gcc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gcc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import cc
import os
@@ -42,6 +42,7 @@ import SCons.Util
compilers = ['gcc', 'cc']
+
def generate(env):
"""Add Builders and construction variables for gcc to an Environment."""
@@ -59,38 +60,48 @@ def generate(env):
if version:
env['CCVERSION'] = version
+
def exists(env):
# is executable, and is a GNU compiler (or accepts '--version' at least)
return detect_version(env, env.Detect(env.get('CC', compilers)))
+
def detect_version(env, cc):
"""Return the version of the GNU compiler, or None if it is not a GNU compiler."""
+ version = None
cc = env.subst(cc)
if not cc:
- return None
- version = None
- #pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'],
- pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['--version'],
- stdin = 'devnull',
- stderr = 'devnull',
- stdout = subprocess.PIPE)
+ return version
+
# -dumpversion was added in GCC 3.0. As long as we're supporting
# GCC versions older than that, we should use --version and a
# regular expression.
- #line = pipe.stdout.read().strip()
- #if line:
- # version = line
- line = SCons.Util.to_str(pipe.stdout.readline())
+ # pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'],
+ pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['--version'],
+ stdin='devnull',
+ stderr='devnull',
+ stdout=subprocess.PIPE)
+ if pipe.wait() != 0:
+ return version
+
+ with pipe.stdout:
+ # -dumpversion variant:
+ # line = pipe.stdout.read().strip()
+ # --version variant:
+ line = SCons.Util.to_str(pipe.stdout.readline())
+ # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer:
+ # So continue with reading to let the child process actually terminate.
+ while SCons.Util.to_str(pipe.stdout.readline()):
+ pass
+
+ # -dumpversion variant:
+ # if line:
+ # version = line
+ # --version variant:
match = re.search(r'[0-9]+(\.[0-9]+)+', line)
if match:
version = match.group(0)
- # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer:
- # So continue with reading to let the child process actually terminate.
- while SCons.Util.to_str(pipe.stdout.readline()):
- pass
- ret = pipe.wait()
- if ret != 0:
- return None
+
return version
# Local Variables:
diff --git a/src/engine/SCons/Tool/gcc.xml b/src/engine/SCons/Tool/gcc.xml
index 17fe2a1..8c29e9d 100644
--- a/src/engine/SCons/Tool/gcc.xml
+++ b/src/engine/SCons/Tool/gcc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gdc.py b/src/engine/SCons/Tool/gdc.py
index f98fabc..46a910c 100644
--- a/src/engine/SCons/Tool/gdc.py
+++ b/src/engine/SCons/Tool/gdc.py
@@ -26,7 +26,7 @@ Lib tool variables:
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -48,7 +48,7 @@ Lib tool variables:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/gdc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gdc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Defaults
diff --git a/src/engine/SCons/Tool/gdc.xml b/src/engine/SCons/Tool/gdc.xml
index 8f71b5d..ea31215 100644
--- a/src/engine/SCons/Tool/gdc.xml
+++ b/src/engine/SCons/Tool/gdc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gettext.xml b/src/engine/SCons/Tool/gettext.xml
index 299184a..fc3af69 100644
--- a/src/engine/SCons/Tool/gettext.xml
+++ b/src/engine/SCons/Tool/gettext.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gettext_tool.py b/src/engine/SCons/Tool/gettext_tool.py
index e500a18..5fc0158 100644
--- a/src/engine/SCons/Tool/gettext_tool.py
+++ b/src/engine/SCons/Tool/gettext_tool.py
@@ -2,7 +2,7 @@
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,14 +23,26 @@
# 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/gettext_tool.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gettext_tool.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#############################################################################
def generate(env,**kw):
+ import sys
+ import os
import SCons.Tool
+ from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+ from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+
from SCons.Tool.GettextCommon \
import _translate, tool_list
for t in tool_list(env['PLATFORM'], env):
+ if sys.platform == 'win32':
+ tool = SCons.Tool.find_program_path(env, t, default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if tool:
+ tool_bin_dir = os.path.dirname(tool)
+ env.AppendENVPath('PATH', tool_bin_dir)
+ else:
+ SCons.Warnings.Warning(t + ' tool requested, but binary not found in ENV PATH')
env.Tool(t)
env.AddMethod(_translate, 'Translate')
#############################################################################
diff --git a/src/engine/SCons/Tool/gfortran.py b/src/engine/SCons/Tool/gfortran.py
index 730ad55..8d02daa 100644
--- a/src/engine/SCons/Tool/gfortran.py
+++ b/src/engine/SCons/Tool/gfortran.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gfortran.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gfortran.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
@@ -54,6 +54,8 @@ def generate(env):
env['INC%sPREFIX' % dialect] = "-I"
env['INC%sSUFFIX' % dialect] = ""
+ env['FORTRANMODDIRPREFIX'] = "-J"
+
def exists(env):
return env.Detect('gfortran')
diff --git a/src/engine/SCons/Tool/gfortran.xml b/src/engine/SCons/Tool/gfortran.xml
index 926a2c8..4e78495 100644
--- a/src/engine/SCons/Tool/gfortran.xml
+++ b/src/engine/SCons/Tool/gfortran.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gnulink.py b/src/engine/SCons/Tool/gnulink.py
index 56bae9a..53f5081 100644
--- a/src/engine/SCons/Tool/gnulink.py
+++ b/src/engine/SCons/Tool/gnulink.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gnulink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gnulink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
import SCons.Tool
diff --git a/src/engine/SCons/Tool/gnulink.xml b/src/engine/SCons/Tool/gnulink.xml
index fce7a55..5ef80eb 100644
--- a/src/engine/SCons/Tool/gnulink.xml
+++ b/src/engine/SCons/Tool/gnulink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gs.py b/src/engine/SCons/Tool/gs.py
index ec5ab27..371b810 100644
--- a/src/engine/SCons/Tool/gs.py
+++ b/src/engine/SCons/Tool/gs.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gs.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Builder
diff --git a/src/engine/SCons/Tool/gs.xml b/src/engine/SCons/Tool/gs.xml
index 40e6f06..185f1b4 100644
--- a/src/engine/SCons/Tool/gs.xml
+++ b/src/engine/SCons/Tool/gs.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/gxx.py b/src/engine/SCons/Tool/gxx.py
index 709f72b..d956c9f 100644
--- a/src/engine/SCons/Tool/gxx.py
+++ b/src/engine/SCons/Tool/gxx.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/gxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/gxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import re
@@ -45,12 +45,13 @@ from . import cxx
compilers = ['g++']
+
def generate(env):
"""Add Builders and construction variables for g++ to an Environment."""
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
if 'CXX' not in env:
- env['CXX'] = env.Detect(compilers) or compilers[0]
+ env['CXX'] = env.Detect(compilers) or compilers[0]
cxx.generate(env)
@@ -68,6 +69,7 @@ def generate(env):
if version:
env['CXXVERSION'] = version
+
def exists(env):
# is executable, and is a GNU compiler (or accepts '--version' at least)
return gcc.detect_version(env, env.Detect(env.get('CXX', compilers)))
diff --git a/src/engine/SCons/Tool/hpc++.py b/src/engine/SCons/Tool/hpc++.py
index 9471ef5..4ec2fe3 100644
--- a/src/engine/SCons/Tool/hpc++.py
+++ b/src/engine/SCons/Tool/hpc++.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/hpc++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/hpc++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
diff --git a/src/engine/SCons/Tool/hpc++.xml b/src/engine/SCons/Tool/hpc++.xml
index d3d11c4..8bb4a65 100644
--- a/src/engine/SCons/Tool/hpc++.xml
+++ b/src/engine/SCons/Tool/hpc++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/hpcc.py b/src/engine/SCons/Tool/hpcc.py
index 0f6a5b4..6a564b9 100644
--- a/src/engine/SCons/Tool/hpcc.py
+++ b/src/engine/SCons/Tool/hpcc.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/hpcc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/hpcc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/hpcc.xml b/src/engine/SCons/Tool/hpcc.xml
index 765860f..f8bece8 100644
--- a/src/engine/SCons/Tool/hpcc.xml
+++ b/src/engine/SCons/Tool/hpcc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/hpcxx.py b/src/engine/SCons/Tool/hpcxx.py
index 847eaca..8ee888f 100644
--- a/src/engine/SCons/Tool/hpcxx.py
+++ b/src/engine/SCons/Tool/hpcxx.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/hpcxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/hpcxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
@@ -68,7 +68,8 @@ def generate(env):
env['CXX'] = acc or 'aCC'
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z')
# determine version of aCC
- line = os.popen(acc + ' -V 2>&1').readline().rstrip()
+ with os.popen(acc + ' -V 2>&1') as p:
+ line = p.readline().rstrip()
if line.find('aCC: HP ANSI C++') == 0:
env['CXXVERSION'] = line.split()[-1]
diff --git a/src/engine/SCons/Tool/hplink.py b/src/engine/SCons/Tool/hplink.py
index 2329282..1afa95e 100644
--- a/src/engine/SCons/Tool/hplink.py
+++ b/src/engine/SCons/Tool/hplink.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/hplink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/hplink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
diff --git a/src/engine/SCons/Tool/hplink.xml b/src/engine/SCons/Tool/hplink.xml
index ffa6c0d..f2b923b 100644
--- a/src/engine/SCons/Tool/hplink.xml
+++ b/src/engine/SCons/Tool/hplink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/icc.py b/src/engine/SCons/Tool/icc.py
index 1f9e8cf..8110a60 100644
--- a/src/engine/SCons/Tool/icc.py
+++ b/src/engine/SCons/Tool/icc.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/icc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/icc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import cc
diff --git a/src/engine/SCons/Tool/icc.xml b/src/engine/SCons/Tool/icc.xml
index b0af318..8492fce 100644
--- a/src/engine/SCons/Tool/icc.xml
+++ b/src/engine/SCons/Tool/icc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/icl.py b/src/engine/SCons/Tool/icl.py
index 99410cd..29d5862 100644
--- a/src/engine/SCons/Tool/icl.py
+++ b/src/engine/SCons/Tool/icl.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/icl.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/icl.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool.intelc
diff --git a/src/engine/SCons/Tool/icl.xml b/src/engine/SCons/Tool/icl.xml
index 035a3a9..31e0bcc 100644
--- a/src/engine/SCons/Tool/icl.xml
+++ b/src/engine/SCons/Tool/icl.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ifl.py b/src/engine/SCons/Tool/ifl.py
index 116c9ac..0eb7cda 100644
--- a/src/engine/SCons/Tool/ifl.py
+++ b/src/engine/SCons/Tool/ifl.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/ifl.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ifl.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
from SCons.Scanner.Fortran import FortranScan
diff --git a/src/engine/SCons/Tool/ifl.xml b/src/engine/SCons/Tool/ifl.xml
index d693ef6..f78c9fd 100644
--- a/src/engine/SCons/Tool/ifl.xml
+++ b/src/engine/SCons/Tool/ifl.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ifort.py b/src/engine/SCons/Tool/ifort.py
index 8e88946..730e778 100644
--- a/src/engine/SCons/Tool/ifort.py
+++ b/src/engine/SCons/Tool/ifort.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/ifort.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ifort.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
from SCons.Scanner.Fortran import FortranScan
diff --git a/src/engine/SCons/Tool/ifort.xml b/src/engine/SCons/Tool/ifort.xml
index 26d4ca9..47a55e3 100644
--- a/src/engine/SCons/Tool/ifort.xml
+++ b/src/engine/SCons/Tool/ifort.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ilink.py b/src/engine/SCons/Tool/ilink.py
index 577e54b..7c69e72 100644
--- a/src/engine/SCons/Tool/ilink.py
+++ b/src/engine/SCons/Tool/ilink.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/ilink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ilink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/ilink.xml b/src/engine/SCons/Tool/ilink.xml
index 941db53..731bdfb 100644
--- a/src/engine/SCons/Tool/ilink.xml
+++ b/src/engine/SCons/Tool/ilink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ilink32.py b/src/engine/SCons/Tool/ilink32.py
index 3e8e095..a1e12a6 100644
--- a/src/engine/SCons/Tool/ilink32.py
+++ b/src/engine/SCons/Tool/ilink32.py
@@ -5,7 +5,7 @@ XXX
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/ilink32.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ilink32.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool
import SCons.Tool.bcc32
diff --git a/src/engine/SCons/Tool/ilink32.xml b/src/engine/SCons/Tool/ilink32.xml
index 02343d9..3f273a8 100644
--- a/src/engine/SCons/Tool/ilink32.xml
+++ b/src/engine/SCons/Tool/ilink32.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/install.py b/src/engine/SCons/Tool/install.py
index 12dcf8f..c0a8917 100644
--- a/src/engine/SCons/Tool/install.py
+++ b/src/engine/SCons/Tool/install.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/install.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/install.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import re
diff --git a/src/engine/SCons/Tool/install.xml b/src/engine/SCons/Tool/install.xml
index 139cd1e..da2d4a0 100644
--- a/src/engine/SCons/Tool/install.xml
+++ b/src/engine/SCons/Tool/install.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/intelc.py b/src/engine/SCons/Tool/intelc.py
index 425f221..fdd9730 100644
--- a/src/engine/SCons/Tool/intelc.py
+++ b/src/engine/SCons/Tool/intelc.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,12 +32,12 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import division, print_function
-__revision__ = "src/engine/SCons/Tool/intelc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/intelc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import math, sys, os.path, glob, string, re
is_windows = sys.platform == 'win32'
-is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or
+is_win64 = is_windows and (os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' or
('PROCESSOR_ARCHITEW6432' in os.environ and
os.environ['PROCESSOR_ARCHITEW6432'] == 'AMD64'))
is_linux = sys.platform.startswith('linux')
@@ -73,7 +73,7 @@ def linux_ver_normalize(vstr):
m = re.match(r'([0-9]+)\.([0-9]+)\.([0-9]+)', vstr)
if m:
vmaj,vmin,build = m.groups()
- return float(vmaj) * 10. + float(vmin) + float(build) / 1000.;
+ return float(vmaj) * 10. + float(vmin) + float(build) / 1000.
else:
f = float(vstr)
if is_windows:
@@ -113,11 +113,6 @@ def check_abi(abi):
(abi, list(valid_abis.keys())))
return abi
-def vercmp(a, b):
- """Compare strings as floats,
- but Intel changed Linux naming convention at 9.0"""
- return cmp(linux_ver_normalize(b), linux_ver_normalize(a))
-
def get_version_from_list(v, vlist):
"""See if we can match v (string) in vlist (list of strings)
Linux has to match in a fuzzy way."""
@@ -221,7 +216,7 @@ def get_all_compiler_versions():
versions = []
try:
while i < 100:
- subkey = SCons.Util.RegEnumKey(k, i) # raises EnvironmentError
+ subkey = SCons.Util.RegEnumKey(k, i) # raises SConsEnvironmentError
# Check that this refers to an existing dir.
# This is not 100% perfect but should catch common
# installation issues like when the compiler was installed
@@ -293,7 +288,7 @@ def get_all_compiler_versions():
m = re.search(r'([0-9]{0,4})(?:_sp\d*)?\.([0-9][0-9.]*)$', d)
if m:
versions.append("%s.%s"%(m.group(1), m.group(2)))
-
+
def keyfunc(str):
"""Given a dot-separated version string, return a tuple of ints representing it."""
return [int(x) for x in str.split('.')]
@@ -383,7 +378,7 @@ def get_intel_compiler_top(version, abi):
top = d
break
return top
-
+
top = find_in_2016style_dir(version) or find_in_2011style_dir(version) or find_in_2010style_dir(version) or find_in_2008style_dir(version)
# print "INTELC: top=",top
if not top:
diff --git a/src/engine/SCons/Tool/intelc.xml b/src/engine/SCons/Tool/intelc.xml
index 3ec9ddd..af77186 100644
--- a/src/engine/SCons/Tool/intelc.xml
+++ b/src/engine/SCons/Tool/intelc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ipkg.py b/src/engine/SCons/Tool/ipkg.py
index 4ad53c9..664c3a6 100644
--- a/src/engine/SCons/Tool/ipkg.py
+++ b/src/engine/SCons/Tool/ipkg.py
@@ -11,7 +11,7 @@ packages fake_root.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ packages fake_root.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/ipkg.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ipkg.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
@@ -55,8 +55,10 @@ def generate(env):
env['IPKGCOM'] = '$IPKG $IPKGFLAGS ${SOURCE}'
if env.WhereIs('id'):
- env['IPKGUSER'] = os.popen('id -un').read().strip()
- env['IPKGGROUP'] = os.popen('id -gn').read().strip()
+ with os.popen('id -un') as p:
+ env['IPKGUSER'] = p.read().strip()
+ with os.popen('id -gn') as p:
+ env['IPKGGROUP'] = p.read().strip()
env['IPKGFLAGS'] = SCons.Util.CLVar('-o $IPKGUSER -g $IPKGGROUP')
env['IPKGSUFFIX'] = '.ipk'
diff --git a/src/engine/SCons/Tool/jar.py b/src/engine/SCons/Tool/jar.py
index a56dd70..98be08f 100644
--- a/src/engine/SCons/Tool/jar.py
+++ b/src/engine/SCons/Tool/jar.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,10 +31,14 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/jar.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/jar.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import os
import SCons.Subst
import SCons.Util
+from SCons.Node.FS import _my_normcase
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
def jarSources(target, source, env, for_signature):
"""Only include sources that are not a manifest file."""
@@ -50,7 +54,7 @@ def jarSources(target, source, env, for_signature):
result = []
for src in source:
contents = src.get_text_contents()
- if contents[:16] != "Manifest-Version":
+ if not contents.startswith("Manifest-Version"):
if jarchdir_set:
_chdir = jarchdir
else:
@@ -71,7 +75,7 @@ def jarManifest(target, source, env, for_signature):
"""Look in sources for a manifest file, if any."""
for src in source:
contents = src.get_text_contents()
- if contents[:16] == "Manifest-Version":
+ if contents.startswith("Manifest-Version"):
return src
return ''
@@ -81,16 +85,137 @@ def jarFlags(target, source, env, for_signature):
jarflags = env.subst('$JARFLAGS', target=target, source=source)
for src in source:
contents = src.get_text_contents()
- if contents[:16] == "Manifest-Version":
- if not 'm' in jarflags:
+ if contents.startswith("Manifest-Version"):
+ if 'm' not in jarflags:
return jarflags + 'm'
break
return jarflags
+def Jar(env, target = None, source = [], *args, **kw):
+ """
+ A pseudo-Builder wrapper around the separate Jar sources{File,Dir}
+ Builders.
+ """
+
+ # jar target should not be a list so assume they passed
+ # no target and want implicit target to be made and the arg
+ # was actaully the list of sources
+ if SCons.Util.is_List(target) and source == []:
+ SCons.Warnings.Warning("Making implicit target jar file, " +
+ "and treating the list as sources")
+ source = target
+ target = None
+
+ # mutiple targets pass so build each target the same from the
+ # same source
+ #TODO Maybe this should only be done once, and the result copied
+ # for each target since it should result in the same?
+ if SCons.Util.is_List(target) and SCons.Util.is_List(source):
+ jars = []
+ for single_target in target:
+ jars += env.Jar( target = single_target, source = source, *args, **kw)
+ return jars
+
+ # they passed no target so make a target implicitly
+ if target is None:
+ try:
+ # make target from the first source file
+ target = os.path.splitext(str(source[0]))[0] + env.subst('$JARSUFFIX')
+ except:
+ # something strange is happening but attempt anyways
+ SCons.Warnings.Warning("Could not make implicit target from sources, using directory")
+ target = os.path.basename(str(env.Dir('.'))) + env.subst('$JARSUFFIX')
+
+ # make lists out of our target and sources
+ if not SCons.Util.is_List(target):
+ target = [target]
+ if not SCons.Util.is_List(source):
+ source = [source]
+
+ # setup for checking through all the sources and handle accordingly
+ java_class_suffix = env.subst('$JAVACLASSSUFFIX')
+ java_suffix = env.subst('$JAVASUFFIX')
+ target_nodes = []
+
+ # function for determining what to do with a file and not a directory
+ # if its already a class file then it can be used as a
+ # source for jar, otherwise turn it into a class file then
+ # return the source
+ def file_to_class(s):
+ if _my_normcase(str(s)).endswith(java_suffix):
+ return env.JavaClassFile(source = s, *args, **kw)
+ else:
+ return [env.fs.File(s)]
+
+ # function for calling the JavaClassDir builder if a directory is
+ # passed as a source to Jar builder. The JavaClassDir builder will
+ # return an empty list if there were not target classes built from
+ # the directory, in this case assume the user wanted the directory
+ # copied into the jar as is (it contains other files such as
+ # resources or class files compiled from proir commands)
+ # TODO: investigate the expexcted behavior for directories that
+ # have mixed content, such as Java files along side other files
+ # files.
+ def dir_to_class(s):
+ dir_targets = env.JavaClassDir(source = s, *args, **kw)
+ if(dir_targets == []):
+ # no classes files could be built from the source dir
+ # so pass the dir as is.
+ return [env.fs.Dir(s)]
+ else:
+ return dir_targets
+
+ # loop through the sources and handle each accordingly
+ # the goal here is to get all the source files into a class
+ # file or a directory that contains class files
+ for s in SCons.Util.flatten(source):
+ s = env.subst(s)
+ if isinstance(s, SCons.Node.FS.Base):
+ if isinstance(s, SCons.Node.FS.File):
+ # found a file so make sure its a class file
+ target_nodes.extend(file_to_class(s))
+ else:
+ # found a dir so get the class files out of it
+ target_nodes.extend(dir_to_class(s))
+ else:
+ try:
+ # source is string try to convert it to file
+ target_nodes.extend(file_to_class(env.fs.File(s)))
+ continue
+ except:
+ pass
+
+ try:
+ # source is string try to covnert it to dir
+ target_nodes.extend(dir_to_class(env.fs.Dir(s)))
+ continue
+ except:
+ pass
+
+ SCons.Warnings.Warning("File: " + str(s) + " could not be identified as File or Directory, skipping.")
+
+ # at this point all our sources have been converted to classes or directories of class
+ # so pass it to the Jar builder
+ return env.JarFile(target = target, source = target_nodes, *args, **kw)
+
def generate(env):
"""Add Builders and construction variables for jar to an Environment."""
SCons.Tool.CreateJarBuilder(env)
+ SCons.Tool.CreateJavaFileBuilder(env)
+ SCons.Tool.CreateJavaClassFileBuilder(env)
+ SCons.Tool.CreateJavaClassDirBuilder(env)
+
+ env.AddMethod(Jar)
+
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for jar
+ paths = get_java_install_dirs('win32')
+ jar = SCons.Tool.find_program_path(env, 'jar', default_paths=paths)
+ if jar:
+ jar_bin_dir = os.path.dirname(jar)
+ env.AppendENVPath('PATH', jar_bin_dir)
+
env['JAR'] = 'jar'
env['JARFLAGS'] = SCons.Util.CLVar('cf')
env['_JARFLAGS'] = jarFlags
diff --git a/src/engine/SCons/Tool/jar.xml b/src/engine/SCons/Tool/jar.xml
index e18207e..73f6bcb 100644
--- a/src/engine/SCons/Tool/jar.xml
+++ b/src/engine/SCons/Tool/jar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/javac.py b/src/engine/SCons/Tool/javac.py
index f3cabf3..387afdb 100644
--- a/src/engine/SCons/Tool/javac.py
+++ b/src/engine/SCons/Tool/javac.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,15 +30,16 @@ selection method.
# 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/javac.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/javac.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
+from collections import OrderedDict
import SCons.Action
import SCons.Builder
from SCons.Node.FS import _my_normcase
-from SCons.Tool.JavaCommon import parse_java_file
+from SCons.Tool.JavaCommon import parse_java_file, get_java_install_dirs, get_java_include_paths
import SCons.Util
def classname(path):
@@ -70,7 +71,7 @@ def emit_java_classes(target, source, env):
if isinstance(entry, SCons.Node.FS.File):
slist.append(entry)
elif isinstance(entry, SCons.Node.FS.Dir):
- result = SCons.Util.OrderedDict()
+ result = OrderedDict()
dirnode = entry.rdir()
def find_java_files(arg, dirpath, filenames):
java_files = sorted([n for n in filenames
@@ -207,6 +208,21 @@ def generate(env):
env.AddMethod(Java)
+ version = env.get('JAVAVERSION', None)
+
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for javac
+ paths = get_java_install_dirs('win32', version=version)
+ javac = SCons.Tool.find_program_path(env, 'javac', default_paths=paths)
+ if javac:
+ javac_bin_dir = os.path.dirname(javac)
+ env.AppendENVPath('PATH', javac_bin_dir)
+ else:
+ javac = SCons.Tool.find_program_path(env, 'javac')
+
+ env['JAVAINCLUDES'] = get_java_include_paths(env, javac, version)
+
+
env['JAVAC'] = 'javac'
env['JAVACFLAGS'] = SCons.Util.CLVar('')
env['JAVABOOTCLASSPATH'] = []
diff --git a/src/engine/SCons/Tool/javac.xml b/src/engine/SCons/Tool/javac.xml
index be478ba..dc72f75 100644
--- a/src/engine/SCons/Tool/javac.xml
+++ b/src/engine/SCons/Tool/javac.xml
@@ -1,285 +1,304 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
-->
<!DOCTYPE sconsdoc [
-<!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
-%scons;
-<!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
-%builders-mod;
-<!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
-%functions-mod;
-<!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
-%tools-mod;
-<!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
-%variables-mod;
-]>
+ <!ENTITY % scons SYSTEM '../../../../doc/scons.mod'>
+ %scons;
+ <!ENTITY % builders-mod SYSTEM '../../../../doc/generated/builders.mod'>
+ %builders-mod;
+ <!ENTITY % functions-mod SYSTEM '../../../../doc/generated/functions.mod'>
+ %functions-mod;
+ <!ENTITY % tools-mod SYSTEM '../../../../doc/generated/tools.mod'>
+ %tools-mod;
+ <!ENTITY % variables-mod SYSTEM '../../../../doc/generated/variables.mod'>
+ %variables-mod;
+ ]>
<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
-<tool name="javac">
-<summary>
-<para>
-Sets construction variables for the &javac; compiler.
-</para>
-</summary>
-<sets>
-<item>JAVAC</item>
-<item>JAVACFLAGS</item>
-<item>JAVACCOM</item>
-<item>JAVACLASSSUFFIX</item>
-<item>JAVASUFFIX</item>
-<item>JAVABOOTCLASSPATH</item>
-<item>JAVACLASSPATH</item>
-<item>JAVASOURCEPATH</item>
-</sets>
-<uses>
-<item>JAVACCOMSTR</item>
-</uses>
-</tool>
+ <tool name="javac">
+ <summary>
+ <para>
+ Sets construction variables for the &javac; compiler.
+ </para>
+ </summary>
+ <sets>
+ <item>JAVAC</item>
+ <item>JAVACFLAGS</item>
+ <item>JAVACCOM</item>
+ <item>JAVACLASSSUFFIX</item>
+ <item>JAVAINCLUDES</item>
+ <item>JAVASUFFIX</item>
+ <item>JAVABOOTCLASSPATH</item>
+ <item>JAVACLASSPATH</item>
+ <item>JAVASOURCEPATH</item>
+ </sets>
+ <uses>
+ <item>JAVACCOMSTR</item>
+ </uses>
+ </tool>
-<builder name="Java">
-<summary>
-<para>
-Builds one or more Java class files.
-The sources may be any combination of explicit
-<filename>.java</filename> files,
-or directory trees which will be scanned
-for <filename>.java</filename> files.
-</para>
+ <builder name="Java">
+ <summary>
+ <para>
+ Builds one or more Java class files.
+ The sources may be any combination of explicit
+ <filename>.java</filename>
+ files,
+ or directory trees which will be scanned
+ for <filename>.java</filename> files.
+ </para>
-<para>
-SCons will parse each source <filename>.java</filename> file
-to find the classes
-(including inner classes)
-defined within that file,
-and from that figure out the
-target <filename>.class</filename> files that will be created.
-The class files will be placed underneath
-the specified target directory.
-</para>
+ <para>
+ SCons will parse each source <filename>.java</filename> file
+ to find the classes
+ (including inner classes)
+ defined within that file,
+ and from that figure out the
+ target <filename>.class</filename> files that will be created.
+ The class files will be placed underneath
+ the specified target directory.
+ </para>
-<para>
-SCons will also search each Java file
-for the Java package name,
-which it assumes can be found on a line
-beginning with the string
-<literal>package</literal>
-in the first column;
-the resulting <filename>.class</filename> files
-will be placed in a directory reflecting
-the specified package name.
-For example,
-the file
-<filename>Foo.java</filename>
-defining a single public
-<classname>Foo</classname>
-class and
-containing a package name of
-<classname>sub.dir</classname>
-will generate a corresponding
-<filename>sub/dir/Foo.class</filename>
-class file.
-</para>
+ <para>
+ SCons will also search each Java file
+ for the Java package name,
+ which it assumes can be found on a line
+ beginning with the string
+ <literal>package</literal>
+ in the first column;
+ the resulting <filename>.class</filename> files
+ will be placed in a directory reflecting
+ the specified package name.
+ For example,
+ the file
+ <filename>Foo.java</filename>
+ defining a single public
+ <classname>Foo</classname>
+ class and
+ containing a package name of
+ <classname>sub.dir</classname>
+ will generate a corresponding
+ <filename>sub/dir/Foo.class</filename>
+ class file.
+ </para>
-<para>
-Examples:
-</para>
+ <para>
+ Examples:
+ </para>
-<example_commands>
-env.Java(target = 'classes', source = 'src')
-env.Java(target = 'classes', source = ['src1', 'src2'])
-env.Java(target = 'classes', source = ['File1.java', 'File2.java'])
-</example_commands>
+ <example_commands>
+ env.Java(target = 'classes', source = 'src')
+ env.Java(target = 'classes', source = ['src1', 'src2'])
+ env.Java(target = 'classes', source = ['File1.java', 'File2.java'])
+ </example_commands>
-<para>
-Java source files can use the native encoding for the underlying OS.
-Since SCons compiles in simple ASCII mode by default,
-the compiler will generate warnings about unmappable characters,
-which may lead to errors as the file is processed further.
-In this case, the user must specify the <literal>LANG</literal>
-environment variable to tell the compiler what encoding is used.
-For portibility, it's best if the encoding is hard-coded
-so that the compile will work if it is done on a system
-with a different encoding.
-</para>
+ <para>
+ Java source files can use the native encoding for the underlying OS.
+ Since SCons compiles in simple ASCII mode by default,
+ the compiler will generate warnings about unmappable characters,
+ which may lead to errors as the file is processed further.
+ In this case, the user must specify the
+ <literal>LANG</literal>
+ environment variable to tell the compiler what encoding is used.
+ For portibility, it's best if the encoding is hard-coded
+ so that the compile will work if it is done on a system
+ with a different encoding.
+ </para>
-<example_commands>
-env = Environment()
-env['ENV']['LANG'] = 'en_GB.UTF-8'
-</example_commands>
-</summary>
-</builder>
+ <example_commands>
+ env = Environment()
+ env['ENV']['LANG'] = 'en_GB.UTF-8'
+ </example_commands>
+ </summary>
+ </builder>
-<cvar name="JAVABOOTCLASSPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be added to the
-&javac; command line
-via the <option>-bootclasspath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVABOOTCLASSPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be added to the
+ &javac; command line
+ via the <option>-bootclasspath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVAC">
-<summary>
-<para>
-The Java compiler.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAINCLUDES">
+ <summary>
+ <para>
+ Include path for Java header files (such as jni.h)
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACCOM">
-<summary>
-<para>
-The command line used to compile a directory tree containing
-Java source files to
-corresponding Java class files.
-Any options specified in the &cv-link-JAVACFLAGS; construction variable
-are included on this command line.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAC">
+ <summary>
+ <para>
+ The Java compiler.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACCOMSTR">
-<summary>
-<para>
-The string displayed when compiling
-a directory tree of Java source files to
-corresponding Java class files.
-If this is not set, then &cv-link-JAVACCOM; (the command line) is displayed.
-</para>
+ <cvar name="JAVACCOM">
+ <summary>
+ <para>
+ The command line used to compile a directory tree containing
+ Java source files to
+ corresponding Java class files.
+ Any options specified in the &cv-link-JAVACFLAGS; construction variable
+ are included on this command line.
+ </para>
+ </summary>
+ </cvar>
-<example_commands>
-env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
-</example_commands>
-</summary>
-</cvar>
+ <cvar name="JAVACCOMSTR">
+ <summary>
+ <para>
+ The string displayed when compiling
+ a directory tree of Java source files to
+ corresponding Java class files.
+ If this is not set, then &cv-link-JAVACCOM; (the command line) is displayed.
+ </para>
-<cvar name="JAVACFLAGS">
-<summary>
-<para>
-General options that are passed to the Java compiler.
-</para>
-</summary>
-</cvar>
+ <example_commands>
+ env = Environment(JAVACCOMSTR = "Compiling class files $TARGETS from $SOURCES")
+ </example_commands>
+ </summary>
+ </cvar>
-<cvar name="JAVACLASSDIR">
-<summary>
-<para>
-The directory in which Java class files may be found.
-This is stripped from the beginning of any Java .class
-file names supplied to the
-<literal>JavaH</literal>
-builder.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVACFLAGS">
+ <summary>
+ <para>
+ General options that are passed to the Java compiler.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVACLASSPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be searched for Java
-<filename>.class</filename> file.
-The directories in this list will be added to the
-&javac; and &javah; command lines
-via the <option>-classpath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <cvar name="JAVACLASSDIR">
+ <summary>
+ <para>
+ The directory in which Java class files may be found.
+ This is stripped from the beginning of any Java .class
+ file names supplied to the
+ <literal>JavaH</literal>
+ builder.
+ </para>
+ </summary>
+ </cvar>
-<para>
-Note that this currently just adds the specified
-directory via the <option>-classpath</option> option.
-&SCons; does not currently search the
-&cv-JAVACLASSPATH; directories for dependency
-<filename>.class</filename> files.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVACLASSPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be searched for Java
+ <filename>.class</filename>
+ file.
+ The directories in this list will be added to the
+ &javac; and &javah; command lines
+ via the <option>-classpath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<cvar name="JAVACLASSSUFFIX">
-<summary>
-<para>
-The suffix for Java class files;
-<filename>.class</filename>
-by default.
-</para>
-</summary>
-</cvar>
+ <para>
+ Note that this currently just adds the specified
+ directory via the <option>-classpath</option> option.
+ &SCons; does not currently search the
+ &cv-JAVACLASSPATH; directories for dependency
+ <filename>.class</filename>
+ files.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVASOURCEPATH">
-<summary>
-<para>
-Specifies the list of directories that
-will be searched for input
-<filename>.java</filename> file.
-The directories in this list will be added to the
-&javac; command line
-via the <option>-sourcepath</option> option.
-The individual directory names will be
-separated by the operating system's path separate character
-(<filename>:</filename> on UNIX/Linux/POSIX,
-<filename>;</filename> on Windows).
-</para>
+ <cvar name="JAVACLASSSUFFIX">
+ <summary>
+ <para>
+ The suffix for Java class files;
+ <filename>.class</filename>
+ by default.
+ </para>
+ </summary>
+ </cvar>
-<para>
-Note that this currently just adds the specified
-directory via the <option>-sourcepath</option> option.
-&SCons; does not currently search the
-&cv-JAVASOURCEPATH; directories for dependency
-<filename>.java</filename> files.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVASOURCEPATH">
+ <summary>
+ <para>
+ Specifies the list of directories that
+ will be searched for input
+ <filename>.java</filename>
+ file.
+ The directories in this list will be added to the
+ &javac; command line
+ via the <option>-sourcepath</option> option.
+ The individual directory names will be
+ separated by the operating system's path separate character
+ (<filename>:</filename> on UNIX/Linux/POSIX,
+ <filename>;</filename>
+ on Windows).
+ </para>
-<cvar name="JAVASUFFIX">
-<summary>
-<para>
-The suffix for Java files;
-<filename>.java</filename>
-by default.
-</para>
-</summary>
-</cvar>
+ <para>
+ Note that this currently just adds the specified
+ directory via the <option>-sourcepath</option> option.
+ &SCons; does not currently search the
+ &cv-JAVASOURCEPATH; directories for dependency
+ <filename>.java</filename>
+ files.
+ </para>
+ </summary>
+ </cvar>
-<cvar name="JAVAVERSION">
-<summary>
-<para>
-Specifies the Java version being used by the &b-Java; builder.
-This is <emphasis>not</emphasis> currently used to select one
-version of the Java compiler vs. another.
-Instead, you should set this to specify the version of Java
-supported by your &javac; compiler.
-The default is <literal>1.4</literal>.
-</para>
+ <cvar name="JAVASUFFIX">
+ <summary>
+ <para>
+ The suffix for Java files;
+ <filename>.java</filename>
+ by default.
+ </para>
+ </summary>
+ </cvar>
-<para>
-This is sometimes necessary because
-Java 1.5 changed the file names that are created
-for nested anonymous inner classes,
-which can cause a mismatch with the files
-that &SCons; expects will be generated by the &javac; compiler.
-Setting &cv-JAVAVERSION; to <literal>1.5</literal>
-(or <literal>1.6</literal>, as appropriate)
-can make &SCons; realize that a Java 1.5 or 1.6
-build is actually up to date.
-</para>
-</summary>
-</cvar>
+ <cvar name="JAVAVERSION">
+ <summary>
+ <para>
+ Specifies the Java version being used by the &b-Java; builder.
+ This is <emphasis>not</emphasis> currently used to select one
+ version of the Java compiler vs. another.
+ Instead, you should set this to specify the version of Java
+ supported by your &javac; compiler.
+ The default is <literal>1.4</literal>.
+ </para>
+
+ <para>
+ This is sometimes necessary because
+ Java 1.5 changed the file names that are created
+ for nested anonymous inner classes,
+ which can cause a mismatch with the files
+ that &SCons; expects will be generated by the &javac; compiler.
+ Setting &cv-JAVAVERSION; to
+ <literal>1.5</literal>
+ (or <literal>1.6</literal>, as appropriate)
+ can make &SCons; realize that a Java 1.5 or 1.6
+ build is actually up to date.
+ </para>
+ </summary>
+ </cvar>
</sconsdoc>
diff --git a/src/engine/SCons/Tool/javacTests.py b/src/engine/SCons/Tool/javacTests.py
index 0debbb6..067ff3e 100644
--- a/src/engine/SCons/Tool/javacTests.py
+++ b/src/engine/SCons/Tool/javacTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,8 +24,6 @@
import os
import unittest
-import TestUnit
-
import SCons.Tool.javac
class DummyNode(object):
@@ -40,14 +38,14 @@ class pathoptTestCase(unittest.TestCase):
popt = SCons.Tool.javac.pathopt('-foopath', 'FOOPATH')
env = {'FOOPATH': path}
actual = popt(None, None, env, None)
- self.assertEquals(expect, actual)
+ self.assertEqual(expect, actual)
def assert_pathopt_default(self, expect, path, default):
popt = SCons.Tool.javac.pathopt('-foopath', 'FOOPATH', default='DPATH')
env = {'FOOPATH': path,
'DPATH': default}
actual = popt(None, None, env, None)
- self.assertEquals(expect, actual)
+ self.assertEqual(expect, actual)
def test_unset(self):
self.assert_pathopt([], None)
@@ -101,5 +99,4 @@ class pathoptTestCase(unittest.TestCase):
'')
if __name__ == "__main__":
- suite = unittest.makeSuite(pathoptTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
diff --git a/src/engine/SCons/Tool/javah.py b/src/engine/SCons/Tool/javah.py
index 0e1885c..251778d 100644
--- a/src/engine/SCons/Tool/javah.py
+++ b/src/engine/SCons/Tool/javah.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/javah.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/javah.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
@@ -40,6 +40,8 @@ import SCons.Builder
import SCons.Node.FS
import SCons.Tool.javac
import SCons.Util
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
def emit_java_headers(target, source, env):
"""Create and return lists of Java stub header files that will
@@ -120,6 +122,14 @@ def generate(env):
java_javah = SCons.Tool.CreateJavaHBuilder(env)
java_javah.emitter = emit_java_headers
+ if env['PLATFORM'] == 'win32':
+ # Ensure that we have a proper path for javah
+ paths = get_java_install_dirs('win32')
+ javah = SCons.Tool.find_program_path(env, 'javah', default_paths=paths)
+ if javah:
+ javah_bin_dir = os.path.dirname(javah)
+ env.AppendENVPath('PATH', javah_bin_dir)
+
env['_JAVAHOUTFLAG'] = JavaHOutFlagGenerator
env['JAVAH'] = 'javah'
env['JAVAHFLAGS'] = SCons.Util.CLVar('')
diff --git a/src/engine/SCons/Tool/javah.xml b/src/engine/SCons/Tool/javah.xml
index f362e3e..f72a6cd 100644
--- a/src/engine/SCons/Tool/javah.xml
+++ b/src/engine/SCons/Tool/javah.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/latex.py b/src/engine/SCons/Tool/latex.py
index aa7ea15..3f1af08 100644
--- a/src/engine/SCons/Tool/latex.py
+++ b/src/engine/SCons/Tool/latex.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/latex.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/latex.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Defaults
diff --git a/src/engine/SCons/Tool/latex.xml b/src/engine/SCons/Tool/latex.xml
index bb0816d..b4eb45a 100644
--- a/src/engine/SCons/Tool/latex.xml
+++ b/src/engine/SCons/Tool/latex.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/ldc.py b/src/engine/SCons/Tool/ldc.py
index 5bb04ff..dda1a5e 100644
--- a/src/engine/SCons/Tool/ldc.py
+++ b/src/engine/SCons/Tool/ldc.py
@@ -26,7 +26,7 @@ Lib tool variables:
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -48,7 +48,7 @@ Lib tool variables:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/ldc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/ldc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import subprocess
diff --git a/src/engine/SCons/Tool/ldc.xml b/src/engine/SCons/Tool/ldc.xml
index 1479867..691145a 100644
--- a/src/engine/SCons/Tool/ldc.xml
+++ b/src/engine/SCons/Tool/ldc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/lex.py b/src/engine/SCons/Tool/lex.py
index e185b93..4831776 100644
--- a/src/engine/SCons/Tool/lex.py
+++ b/src/engine/SCons/Tool/lex.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,16 +31,25 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/lex.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/lex.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
+import sys
import SCons.Action
import SCons.Tool
import SCons.Util
+from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+from SCons.Platform.win32 import CHOCO_DEFAULT_PATH
LexAction = SCons.Action.Action("$LEXCOM", "$LEXCOMSTR")
+if sys.platform == 'win32':
+ BINS = ['flex', 'lex', 'win_flex']
+else:
+ BINS = ["flex", "lex"]
+
def lexEmitter(target, source, env):
sourceBase, sourceExt = os.path.splitext(SCons.Util.to_String(source[0]))
@@ -64,6 +73,29 @@ def lexEmitter(target, source, env):
target.append(fileName)
return (target, source)
+def get_lex_path(env, append_paths=False):
+ """
+ Find the path to the lex tool, searching several possible names
+
+ Only called in the Windows case, so the default_path
+ can be Windows-specific
+
+ :param env: current construction environment
+ :param append_paths: if set, add the path to the tool to PATH
+ :return: path to lex tool, if found
+ """
+ for prog in BINS:
+ bin_path = SCons.Tool.find_program_path(
+ env,
+ prog,
+ default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if bin_path:
+ if append_paths:
+ env.AppendENVPath('PATH', os.path.dirname(bin_path))
+ return bin_path
+ SCons.Warnings.Warning('lex tool requested, but lex or flex binary not found in ENV PATH')
+
+
def generate(env):
"""Add Builders and construction variables for lex to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
@@ -83,12 +115,24 @@ def generate(env):
cxx_file.add_action(".ll", LexAction)
cxx_file.add_emitter(".ll", lexEmitter)
- env["LEX"] = env.Detect("flex") or "lex"
env["LEXFLAGS"] = SCons.Util.CLVar("")
- env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
+
+ if sys.platform == 'win32':
+ # ignore the return - we do not need the full path here
+ _ = get_lex_path(env, append_paths=True)
+ env["LEX"] = env.Detect(BINS)
+ if not env.get("LEXUNISTD"):
+ env["LEXUNISTD"] = SCons.Util.CLVar("")
+ env["LEXCOM"] = "$LEX $LEXUNISTD $LEXFLAGS -t $SOURCES > $TARGET"
+ else:
+ env["LEX"] = env.Detect(BINS)
+ env["LEXCOM"] = "$LEX $LEXFLAGS -t $SOURCES > $TARGET"
def exists(env):
- return env.Detect(["flex", "lex"])
+ if sys.platform == 'win32':
+ return get_lex_path(env)
+ else:
+ return env.Detect(BINS)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/lex.xml b/src/engine/SCons/Tool/lex.xml
index e178308..0d044b8 100644
--- a/src/engine/SCons/Tool/lex.xml
+++ b/src/engine/SCons/Tool/lex.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -33,6 +33,7 @@ Sets construction variables for the &lex; lexical analyser.
<item>LEX</item>
<item>LEXFLAGS</item>
<item>LEXCOM</item>
+<item>LEXUNISTD</item>
</sets>
<uses>
<item>LEXCOMSTR</item>
@@ -78,4 +79,12 @@ General options passed to the lexical analyzer generator.
</summary>
</cvar>
+<cvar name="LEXUNISTD">
+<summary>
+<para>
+Used only on windows environments to set a lex flag to prevent 'unistd.h' from being included. The default value is '--nounistd'.
+</para>
+</summary>
+</cvar>
+
</sconsdoc>
diff --git a/src/engine/SCons/Tool/link.py b/src/engine/SCons/Tool/link.py
index e8c11ed..dcaf91f 100644
--- a/src/engine/SCons/Tool/link.py
+++ b/src/engine/SCons/Tool/link.py
@@ -1,4 +1,3 @@
-
"""SCons.Tool.link
Tool-specific initialization for the generic Posix linker.
@@ -10,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +32,7 @@ selection method.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/link.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/link.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import re
@@ -47,22 +46,21 @@ from SCons.Tool.FortranCommon import isfortran
from SCons.Tool.DCommon import isD
-import SCons.Tool.cxx
-cplusplus = SCons.Tool.cxx
-# cplusplus = __import__(__package__+'.cxx', globals(), locals(), ['*'])
+from SCons.Tool.cxx import iscplusplus
issued_mixed_link_warning = False
+
def smart_link(source, target, env, for_signature):
- has_cplusplus = cplusplus.iscplusplus(source)
+ has_cplusplus = iscplusplus(source)
has_fortran = isfortran(env, source)
has_d = isD(env, source)
if has_cplusplus and has_fortran and not has_d:
global issued_mixed_link_warning
if not issued_mixed_link_warning:
msg = "Using $CXX to link Fortran and C++ code together.\n\t" + \
- "This may generate a buggy executable if the '%s'\n\t" + \
- "compiler does not know how to deal with Fortran runtimes."
+ "This may generate a buggy executable if the '%s'\n\t" + \
+ "compiler does not know how to deal with Fortran runtimes."
SCons.Warnings.warn(SCons.Warnings.FortranCxxMixWarning,
msg % env.subst('$CXX'))
issued_mixed_link_warning = True
@@ -77,11 +75,14 @@ def smart_link(source, target, env, for_signature):
return '$CXX'
return '$CC'
+
def _lib_emitter(target, source, env, **kw):
Verbose = False
if Verbose:
- print("_lib_emitter: target[0]={:r}".format(target[0].get_path()))
+ print("_lib_emitter: target[0]={!r}".format(target[0].get_path()))
for tgt in target:
+ if SCons.Util.is_String(tgt):
+ tgt = env.File(tgt)
tgt.attributes.shared = 1
try:
@@ -90,21 +91,24 @@ def _lib_emitter(target, source, env, **kw):
pass
else:
if Verbose:
- print("_lib_emitter: symlink_generator={:r}".format(symlink_generator))
+ print("_lib_emitter: symlink_generator={!r}".format(symlink_generator))
symlinks = symlink_generator(env, target[0])
if Verbose:
- print("_lib_emitter: symlinks={:r}".format(symlinks))
+ print("_lib_emitter: symlinks={!r}".format(symlinks))
if symlinks:
SCons.Tool.EmitLibSymlinks(env, symlinks, target[0])
target[0].attributes.shliblinks = symlinks
return (target, source)
+
def shlib_emitter(target, source, env):
- return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.ShLibSymlinkGenerator)
+ return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.ShLibSymlinkGenerator)
+
def ldmod_emitter(target, source, env):
- return _lib_emitter(target, source, env, symlink_generator = SCons.Tool.LdModSymlinkGenerator)
+ return _lib_emitter(target, source, env, symlink_generator=SCons.Tool.LdModSymlinkGenerator)
+
# This is generic enough to be included here...
def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw):
@@ -112,98 +116,107 @@ def _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator,
Verbose = False
if Verbose:
- print("_versioned_lib_name: libnode={:r}".format(libnode.get_path()))
- print("_versioned_lib_name: version={:r}".format(version))
- print("_versioned_lib_name: prefix={:r}".format(prefix))
- print("_versioned_lib_name: suffix={:r}".format(suffix))
- print("_versioned_lib_name: suffix_generator={:r}".format(suffix_generator))
+ print("_versioned_lib_name: libnode={!r}".format(libnode.get_path()))
+ print("_versioned_lib_name: version={!r}".format(version))
+ print("_versioned_lib_name: prefix={!r}".format(prefix))
+ print("_versioned_lib_name: suffix={!r}".format(suffix))
+ print("_versioned_lib_name: suffix_generator={!r}".format(suffix_generator))
versioned_name = os.path.basename(libnode.get_path())
if Verbose:
- print("_versioned_lib_name: versioned_name={:r}".format(versioned_name))
+ print("_versioned_lib_name: versioned_name={!r}".format(versioned_name))
versioned_prefix = prefix_generator(env, **kw)
versioned_suffix = suffix_generator(env, **kw)
if Verbose:
- print("_versioned_lib_name: versioned_prefix={:r}".format(versioned_prefix))
- print("_versioned_lib_name: versioned_suffix={:r}".format(versioned_suffix))
+ print("_versioned_lib_name: versioned_prefix={!r}".format(versioned_prefix))
+ print("_versioned_lib_name: versioned_suffix={!r}".format(versioned_suffix))
versioned_prefix_re = '^' + re.escape(versioned_prefix)
versioned_suffix_re = re.escape(versioned_suffix) + '$'
name = re.sub(versioned_prefix_re, prefix, versioned_name)
name = re.sub(versioned_suffix_re, suffix, name)
if Verbose:
- print("_versioned_lib_name: name={:r}".format(name))
+ print("_versioned_lib_name: name={!r}".format(name))
return name
+
def _versioned_shlib_name(env, libnode, version, prefix, suffix, **kw):
- pg = SCons.Tool.ShLibPrefixGenerator
- sg = SCons.Tool.ShLibSuffixGenerator
- return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
+ prefix_generator = SCons.Tool.ShLibPrefixGenerator
+ suffix_generator = SCons.Tool.ShLibSuffixGenerator
+ return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw)
+
def _versioned_ldmod_name(env, libnode, version, prefix, suffix, **kw):
- pg = SCons.Tool.LdModPrefixGenerator
- sg = SCons.Tool.LdModSuffixGenerator
- return _versioned_lib_name(env, libnode, version, prefix, suffix, pg, sg, **kw)
+ prefix_generator = SCons.Tool.LdModPrefixGenerator
+ suffix_generator = SCons.Tool.LdModSuffixGenerator
+ return _versioned_lib_name(env, libnode, version, prefix, suffix, prefix_generator, suffix_generator, **kw)
+
def _versioned_lib_suffix(env, suffix, version):
"""For suffix='.so' and version='0.1.2' it returns '.so.0.1.2'"""
Verbose = False
if Verbose:
- print("_versioned_lib_suffix: suffix={:r}".format(suffix))
- print("_versioned_lib_suffix: version={:r}".format(version))
+ print("_versioned_lib_suffix: suffix={!r}".format(suffix))
+ print("_versioned_lib_suffix: version={!r}".format(version))
if not suffix.endswith(version):
suffix = suffix + '.' + version
if Verbose:
- print("_versioned_lib_suffix: return suffix={:r}".format(suffix))
+ print("_versioned_lib_suffix: return suffix={!r}".format(suffix))
return suffix
+
def _versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
"""For libnode='/optional/dir/libfoo.so.X.Y.Z' it returns 'libfoo.so.X'"""
Verbose = False
if Verbose:
- print("_versioned_lib_soname: version={:r}".format(version))
+ print("_versioned_lib_soname: version={!r}".format(version))
name = name_func(env, libnode, version, prefix, suffix)
if Verbose:
- print("_versioned_lib_soname: name={:r}".format(name))
+ print("_versioned_lib_soname: name={!r}".format(name))
major = version.split('.')[0]
soname = name + '.' + major
if Verbose:
- print("_versioned_lib_soname: soname={:r}".format(soname))
+ print("_versioned_lib_soname: soname={!r}".format(soname))
return soname
+
def _versioned_shlib_soname(env, libnode, version, prefix, suffix):
return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_shlib_name)
+
def _versioned_ldmod_soname(env, libnode, version, prefix, suffix):
return _versioned_lib_soname(env, libnode, version, prefix, suffix, _versioned_ldmod_name)
+
def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func):
- """Generate link names that should be created for a versioned shared lirbrary.
+ """Generate link names that should be created for a versioned shared library.
Returns a dictionary in the form { linkname : linktarget }
"""
Verbose = False
if Verbose:
- print("_versioned_lib_symlinks: libnode={:r}".format(libnode.get_path()))
- print("_versioned_lib_symlinks: version={:r}".format(version))
+ print("_versioned_lib_symlinks: libnode={!r}".format(libnode.get_path()))
+ print("_versioned_lib_symlinks: version={!r}".format(version))
if sys.platform.startswith('openbsd'):
# OpenBSD uses x.y shared library versioning numbering convention
# and doesn't use symlinks to backwards-compatible libraries
if Verbose:
- print("_versioned_lib_symlinks: return symlinks={:r}".format(None))
+ print("_versioned_lib_symlinks: return symlinks={!r}".format(None))
return None
linkdir = libnode.get_dir()
if Verbose:
- print("_versioned_lib_symlinks: linkdir={:r}".format(linkdir.get_path()))
+ print("_versioned_lib_symlinks: linkdir={!r}".format(linkdir.get_path()))
name = name_func(env, libnode, version, prefix, suffix)
if Verbose:
- print("_versioned_lib_symlinks: name={:r}".format(name))
+ print("_versioned_lib_symlinks: name={!r}".format(name))
soname = soname_func(env, libnode, version, prefix, suffix)
+ if Verbose:
+ print("_versioned_lib_symlinks: soname={!r}".format(soname))
link0 = env.fs.File(soname, linkdir)
link1 = env.fs.File(name, linkdir)
@@ -211,50 +224,63 @@ def _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, so
# We create direct symlinks, not daisy-chained.
if link0 == libnode:
# This enables SHLIBVERSION without periods (e.g. SHLIBVERSION=1)
- symlinks = [ (link1, libnode) ]
+ symlinks = [(link1, libnode)]
else:
# This handles usual SHLIBVERSION, i.e. '1.2', '1.2.3', etc.
- symlinks = [ (link0, libnode), (link1, libnode) ]
+ symlinks = [(link0, libnode), (link1, libnode)]
if Verbose:
- print("_versioned_lib_symlinks: return symlinks={:r}".format(SCons.Tool.StringizeLibSymlinks(symlinks)))
+ print("_versioned_lib_symlinks: return symlinks={!r}".format(SCons.Tool.StringizeLibSymlinks(symlinks)))
return symlinks
+
def _versioned_shlib_symlinks(env, libnode, version, prefix, suffix):
- nf = _versioned_shlib_name
- sf = _versioned_shlib_soname
- return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf)
+ name_func = env['LINKCALLBACKS']['VersionedShLibName']
+ soname_func = env['LINKCALLBACKS']['VersionedShLibSoname']
+
+ return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func)
+
def _versioned_ldmod_symlinks(env, libnode, version, prefix, suffix):
- nf = _versioned_ldmod_name
- sf = _versioned_ldmod_soname
- return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, nf, sf)
+ name_func = _versioned_ldmod_name
+ soname_func = _versioned_ldmod_soname
+
+ name_func = env['LINKCALLBACKS']['VersionedLdModName']
+ soname_func = env['LINKCALLBACKS']['VersionedLdModSoname']
+
+ return _versioned_lib_symlinks(env, libnode, version, prefix, suffix, name_func, soname_func)
+
def _versioned_lib_callbacks():
return {
- 'VersionedShLibSuffix' : _versioned_lib_suffix,
- 'VersionedLdModSuffix' : _versioned_lib_suffix,
- 'VersionedShLibSymlinks' : _versioned_shlib_symlinks,
- 'VersionedLdModSymlinks' : _versioned_ldmod_symlinks,
- 'VersionedShLibName' : _versioned_shlib_name,
- 'VersionedLdModName' : _versioned_ldmod_name,
- 'VersionedShLibSoname' : _versioned_shlib_soname,
- 'VersionedLdModSoname' : _versioned_ldmod_soname,
+ 'VersionedShLibSuffix': _versioned_lib_suffix,
+ 'VersionedLdModSuffix': _versioned_lib_suffix,
+ 'VersionedShLibSymlinks': _versioned_shlib_symlinks,
+ 'VersionedLdModSymlinks': _versioned_ldmod_symlinks,
+ 'VersionedShLibName': _versioned_shlib_name,
+ 'VersionedLdModName': _versioned_ldmod_name,
+ 'VersionedShLibSoname': _versioned_shlib_soname,
+ 'VersionedLdModSoname': _versioned_ldmod_soname,
}.copy()
+
def _setup_versioned_lib_variables(env, **kw):
"""
Setup all variables required by the versioning machinery
"""
tool = None
- try: tool = kw['tool']
- except KeyError: pass
+ try:
+ tool = kw['tool']
+ except KeyError:
+ pass
use_soname = False
- try: use_soname = kw['use_soname']
- except KeyError: pass
+ try:
+ use_soname = kw['use_soname']
+ except KeyError:
+ pass
# The $_SHLIBVERSIONFLAGS define extra commandline flags used when
# building VERSIONED shared libraries. It's always set, but used only
@@ -284,22 +310,25 @@ def generate(env):
SCons.Tool.createSharedLibBuilder(env)
SCons.Tool.createProgBuilder(env)
- env['SHLINK'] = '$LINK'
+ env['SHLINK'] = '$LINK'
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
- env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
- # don't set up the emitter, cause AppendUnique will generate a list
+ env['SHLINKCOM'] = '$SHLINK -o $TARGET $SHLINKFLAGS $__SHLIBVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+
+ # don't set up the emitter, because AppendUnique will generate a list
# starting with None :-(
- env.Append(SHLIBEMITTER = [shlib_emitter])
- env['SMARTLINK'] = smart_link
- env['LINK'] = "$SMARTLINK"
- env['LINKFLAGS'] = SCons.Util.CLVar('')
+ env.Append(SHLIBEMITTER=[shlib_emitter])
+
+ env['SMARTLINK'] = smart_link
+ env['LINK'] = "$SMARTLINK"
+ env['LINKFLAGS'] = SCons.Util.CLVar('')
+
# __RPATH is only set to something ($_RPATH typically) on platforms that support it.
- env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
- env['LIBDIRPREFIX']='-L'
- env['LIBDIRSUFFIX']=''
- env['_LIBFLAGS']='${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
- env['LIBLINKPREFIX']='-l'
- env['LIBLINKSUFFIX']=''
+ env['LINKCOM'] = '$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+ env['LIBDIRPREFIX'] = '-L'
+ env['LIBDIRSUFFIX'] = ''
+ env['_LIBFLAGS'] = '${_stripixes(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
+ env['LIBLINKPREFIX'] = '-l'
+ env['LIBLINKSUFFIX'] = ''
if env['PLATFORM'] == 'hpux':
env['SHLIBSUFFIX'] = '.sl'
@@ -311,14 +340,16 @@ def generate(env):
# setting them the same means that LoadableModule works everywhere.
SCons.Tool.createLoadableModuleBuilder(env)
env['LDMODULE'] = '$SHLINK'
- env.Append(LDMODULEEMITTER = [ldmod_emitter])
+ env.Append(LDMODULEEMITTER=[ldmod_emitter])
env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
- env['LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
+ env[
+ 'LDMODULECOM'] = '$LDMODULE -o $TARGET $LDMODULEFLAGS $__LDMODULEVERSIONFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS'
env['LDMODULEVERSION'] = '$SHLIBVERSION'
env['LDMODULENOVERSIONSYMLINKS'] = '$SHLIBNOVERSIONSYMLINKS'
+
def exists(env):
# This module isn't really a Tool on its own, it's common logic for
# other linkers.
diff --git a/src/engine/SCons/Tool/link.xml b/src/engine/SCons/Tool/link.xml
index 669a020..a8b6954 100644
--- a/src/engine/SCons/Tool/link.xml
+++ b/src/engine/SCons/Tool/link.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py
index b79be06..42d010d 100644
--- a/src/engine/SCons/Tool/linkloc.py
+++ b/src/engine/SCons/Tool/linkloc.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/linkloc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/linkloc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import re
diff --git a/src/engine/SCons/Tool/linkloc.xml b/src/engine/SCons/Tool/linkloc.xml
index 09b43cb..567ed66 100644
--- a/src/engine/SCons/Tool/linkloc.xml
+++ b/src/engine/SCons/Tool/linkloc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/m4.py b/src/engine/SCons/Tool/m4.py
index 38b9976..0ecc82a 100644
--- a/src/engine/SCons/Tool/m4.py
+++ b/src/engine/SCons/Tool/m4.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/m4.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/m4.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Builder
diff --git a/src/engine/SCons/Tool/m4.xml b/src/engine/SCons/Tool/m4.xml
index f919af9..f7e81e5 100644
--- a/src/engine/SCons/Tool/m4.xml
+++ b/src/engine/SCons/Tool/m4.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/masm.py b/src/engine/SCons/Tool/masm.py
index 90162f4..cf147a7 100644
--- a/src/engine/SCons/Tool/masm.py
+++ b/src/engine/SCons/Tool/masm.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/masm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/masm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/masm.xml b/src/engine/SCons/Tool/masm.xml
index acc3aa3..1760252 100644
--- a/src/engine/SCons/Tool/masm.xml
+++ b/src/engine/SCons/Tool/masm.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/midl.py b/src/engine/SCons/Tool/midl.py
index 4088fc4..f75204a 100644
--- a/src/engine/SCons/Tool/midl.py
+++ b/src/engine/SCons/Tool/midl.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/midl.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/midl.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Builder
@@ -79,7 +79,7 @@ def generate(env):
env['BUILDERS']['TypeLibrary'] = midl_builder
def exists(env):
- return msvc_exists()
+ return msvc_exists(env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/midl.xml b/src/engine/SCons/Tool/midl.xml
index cc1b880..717eb38 100644
--- a/src/engine/SCons/Tool/midl.xml
+++ b/src/engine/SCons/Tool/midl.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/mingw.py b/src/engine/SCons/Tool/mingw.py
index c2eaa96..8410d2f 100644
--- a/src/engine/SCons/Tool/mingw.py
+++ b/src/engine/SCons/Tool/mingw.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,10 +31,11 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/mingw.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mingw.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
+import glob
import SCons.Action
import SCons.Builder
@@ -42,29 +43,17 @@ import SCons.Defaults
import SCons.Tool
import SCons.Util
-# This is what we search for to find mingw:
-key_program = 'mingw32-gcc'
-
-def find(env):
- # First search in the SCons path
- path=env.WhereIs(key_program)
- if (path):
- return path
- # then the OS path:
- path=SCons.Util.WhereIs(key_program)
- if (path):
- return path
-
- # If that doesn't work try default location for mingw
- save_path=env['ENV']['PATH']
- env.AppendENVPath('PATH',r'c:\MinGW\bin')
- path =env.WhereIs(key_program)
- if not path:
- env['ENV']['PATH']=save_path
- return path
+mingw_paths = [
+ r'c:\MinGW\bin',
+ r'C:\cygwin64\bin',
+ r'C:\msys64',
+ r'C:\cygwin\bin',
+ r'C:\msys',
+]
+
def shlib_generator(target, source, env, for_signature):
- cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS'])
+ cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS'])
dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
if dll: cmd.extend(['-o', dll])
@@ -72,31 +61,32 @@ def shlib_generator(target, source, env, for_signature):
cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
- if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature))
+ if implib: cmd.append('-Wl,--out-implib,' + implib.get_string(for_signature))
def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
insert_def = env.subst("$WINDOWS_INSERT_DEF")
- if not insert_def in ['', '0', 0] and def_target: \
- cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature))
+ if insert_def not in ['', '0', 0] and def_target: \
+ cmd.append('-Wl,--output-def,' + def_target.get_string(for_signature))
return [cmd]
+
def shlib_emitter(target, source, env):
dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
no_import_lib = env.get('no_import_lib', 0)
if not dll:
- raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s Target(s) are:%s" % \
+ raise SCons.Errors.UserError(
+ "A shared library should have exactly one target with the suffix: %s Target(s) are:%s" % \
(env.subst("$SHLIBSUFFIX"), ",".join([str(t) for t in target])))
-
- if not no_import_lib and \
- not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
+ if not no_import_lib and \
+ not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
# Create list of target libraries as strings
- targetStrings=env.ReplaceIxes(dll,
- 'SHLIBPREFIX', 'SHLIBSUFFIX',
- 'LIBPREFIX', 'LIBSUFFIX')
-
+ targetStrings = env.ReplaceIxes(dll,
+ 'SHLIBPREFIX', 'SHLIBSUFFIX',
+ 'LIBPREFIX', 'LIBSUFFIX')
+
# Now add file nodes to target list
target.append(env.fs.File(targetStrings))
@@ -108,17 +98,18 @@ def shlib_emitter(target, source, env):
skip_def_insert = env.subst("$WINDOWS_INSERT_DEF") in ['', '0', 0]
if not def_source and not def_target and not skip_def_insert:
# Create list of target libraries and def files as strings
- targetStrings=env.ReplaceIxes(dll,
- 'SHLIBPREFIX', 'SHLIBSUFFIX',
- 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
-
+ targetStrings = env.ReplaceIxes(dll,
+ 'SHLIBPREFIX', 'SHLIBSUFFIX',
+ 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
+
# Now add file nodes to target list
target.append(env.fs.File(targetStrings))
return (target, source)
-
-shlib_action = SCons.Action.Action(shlib_generator, generator=1)
+
+shlib_action = SCons.Action.Action(shlib_generator, '$SHLINKCOMSTR', generator=1)
+ldmodule_action = SCons.Action.Action(shlib_generator, '$LDMODULECOMSTR', generator=1)
res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
@@ -126,38 +117,63 @@ res_builder = SCons.Builder.Builder(action=res_action, suffix='.o',
source_scanner=SCons.Tool.SourceFileScanner)
SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
+# This is what we search for to find mingw:
+# key_program = 'mingw32-gcc'
+key_program = 'mingw32-make'
+
+
+def find_version_specific_mingw_paths():
+ r"""
+ One example of default mingw install paths is:
+ C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev2\mingw64\bin
+
+ Use glob'ing to find such and add to mingw_paths
+ """
+ new_paths = glob.glob(r"C:\mingw-w64\*\mingw64\bin")
+
+ return new_paths
+
+
def generate(env):
- mingw = find(env)
+ global mingw_paths
+ # Check for reasoanble mingw default paths
+ mingw_paths += find_version_specific_mingw_paths()
+
+ mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths)
if mingw:
- dir = os.path.dirname(mingw)
- env.PrependENVPath('PATH', dir )
-
+ mingw_bin_dir = os.path.dirname(mingw)
+ env.AppendENVPath('PATH', mingw_bin_dir)
# Most of mingw is the same as gcc and friends...
gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas', 'gfortran', 'm4']
for tool in gnu_tools:
SCons.Tool.Tool(tool)(env)
- #... but a few things differ:
+ # ... but a few things differ:
env['CC'] = 'gcc'
+ # make sure the msvc tool doesnt break us, it added a /flag
+ if 'CCFLAGS' in env:
+ # make sure its a CLVar to handle list or str cases
+ if type(env['CCFLAGS']) is not SCons.Util.CLVar:
+ env['CCFLAGS'] = SCons.Util.CLVar(env['CCFLAGS'])
+ env['CCFLAGS'] = SCons.Util.CLVar(str(env['CCFLAGS']).replace('/nologo', ''))
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
env['CXX'] = 'g++'
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
- env['SHLINKCOM'] = shlib_action
- env['LDMODULECOM'] = shlib_action
- env.Append(SHLIBEMITTER = [shlib_emitter])
- env.Append(LDMODULEEMITTER = [shlib_emitter])
+ env['SHLINKCOM'] = shlib_action
+ env['LDMODULECOM'] = ldmodule_action
+ env.Append(SHLIBEMITTER=[shlib_emitter])
+ env.Append(LDMODULEEMITTER=[shlib_emitter])
env['AS'] = 'as'
- env['WIN32DEFPREFIX'] = ''
- env['WIN32DEFSUFFIX'] = '.def'
- env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}'
- env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}'
+ env['WIN32DEFPREFIX'] = ''
+ env['WIN32DEFSUFFIX'] = '.def'
+ env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}'
+ env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}'
env['SHOBJSUFFIX'] = '.o'
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
-
env['RC'] = 'windres'
env['RCFLAGS'] = SCons.Util.CLVar('')
env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
@@ -165,15 +181,21 @@ def generate(env):
env['RCINCSUFFIX'] = ''
env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
env['BUILDERS']['RES'] = res_builder
-
+
# Some setting from the platform also have to be overridden:
env['OBJSUFFIX'] = '.o'
env['LIBPREFIX'] = 'lib'
env['LIBSUFFIX'] = '.a'
env['PROGSUFFIX'] = '.exe'
+
def exists(env):
- return find(env)
+ mingw = SCons.Tool.find_program_path(env, key_program, default_paths=mingw_paths)
+ if mingw:
+ mingw_bin_dir = os.path.dirname(mingw)
+ env.AppendENVPath('PATH', mingw_bin_dir)
+
+ return mingw
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/mingw.xml b/src/engine/SCons/Tool/mingw.xml
index 4848637..b1f028d 100644
--- a/src/engine/SCons/Tool/mingw.xml
+++ b/src/engine/SCons/Tool/mingw.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/msgfmt.py b/src/engine/SCons/Tool/msgfmt.py
index 7e3e2a4..c8141a0 100644
--- a/src/engine/SCons/Tool/msgfmt.py
+++ b/src/engine/SCons/Tool/msgfmt.py
@@ -1,6 +1,6 @@
""" msgfmt tool """
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@
# 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/msgfmt.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msgfmt.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Builder import BuilderBase
#############################################################################
@@ -75,8 +75,22 @@ def _create_mo_file_builder(env, **kw):
#############################################################################
def generate(env,**kw):
""" Generate `msgfmt` tool """
+ import sys
+ import os
import SCons.Util
+ import SCons.Tool
from SCons.Tool.GettextCommon import _detect_msgfmt
+ from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+ from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+
+ if sys.platform == 'win32':
+ msgfmt = SCons.Tool.find_program_path(env, 'msgfmt', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if msgfmt:
+ msgfmt_bin_dir = os.path.dirname(msgfmt)
+ env.AppendENVPath('PATH', msgfmt_bin_dir)
+ else:
+ SCons.Warnings.Warning('msgfmt tool requested, but binary not found in ENV PATH')
+
try:
env['MSGFMT'] = _detect_msgfmt(env)
except:
diff --git a/src/engine/SCons/Tool/msgfmt.xml b/src/engine/SCons/Tool/msgfmt.xml
index e00f372..67a8e0d 100644
--- a/src/engine/SCons/Tool/msgfmt.xml
+++ b/src/engine/SCons/Tool/msgfmt.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/msginit.py b/src/engine/SCons/Tool/msginit.py
index 63daf7f..69e803a 100644
--- a/src/engine/SCons/Tool/msginit.py
+++ b/src/engine/SCons/Tool/msginit.py
@@ -3,7 +3,7 @@
Tool specific initialization of msginit tool.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,7 +24,7 @@ Tool specific initialization of msginit tool.
# 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/msginit.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msginit.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Warnings
import SCons.Builder
@@ -77,8 +77,22 @@ def _POInitBuilderWrapper(env, target=None, source=_null, **kw):
#############################################################################
def generate(env,**kw):
""" Generate the `msginit` tool """
+ import sys
+ import os
import SCons.Util
+ import SCons.Tool
from SCons.Tool.GettextCommon import _detect_msginit
+ from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+ from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+
+ if sys.platform == 'win32':
+ msginit = SCons.Tool.find_program_path(env, 'msginit', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if msginit:
+ msginit_bin_dir = os.path.dirname(msginit)
+ env.AppendENVPath('PATH', msginit_bin_dir)
+ else:
+ SCons.Warnings.Warning('msginit tool requested, but binary not found in ENV PATH')
+
try:
env['MSGINIT'] = _detect_msginit(env)
except:
diff --git a/src/engine/SCons/Tool/msginit.xml b/src/engine/SCons/Tool/msginit.xml
index 3a2a969..d09dde1 100644
--- a/src/engine/SCons/Tool/msginit.xml
+++ b/src/engine/SCons/Tool/msginit.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/msgmerge.py b/src/engine/SCons/Tool/msgmerge.py
index aef1f5f..4254fa6 100644
--- a/src/engine/SCons/Tool/msgmerge.py
+++ b/src/engine/SCons/Tool/msgmerge.py
@@ -3,7 +3,7 @@
Tool specific initialization for `msgmerge` tool.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,7 +24,7 @@ Tool specific initialization for `msgmerge` tool.
# 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/msgmerge.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msgmerge.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#############################################################################
def _update_or_init_po_files(target, source, env):
@@ -68,8 +68,21 @@ def _POUpdateBuilderWrapper(env, target=None, source=_null, **kw):
#############################################################################
def generate(env,**kw):
- """ Generate the `xgettext` tool """
+ """ Generate the `msgmerge` tool """
+ import sys
+ import os
+ import SCons.Tool
from SCons.Tool.GettextCommon import _detect_msgmerge
+ from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+ from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+
+ if sys.platform == 'win32':
+ msgmerge = SCons.Tool.find_program_path(env, 'msgmerge', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if msgmerge:
+ msgmerge_bin_dir = os.path.dirname(msgmerge)
+ env.AppendENVPath('PATH', msgmerge_bin_dir)
+ else:
+ SCons.Warnings.Warning('msgmerge tool requested, but binary not found in ENV PATH')
try:
env['MSGMERGE'] = _detect_msgmerge(env)
except:
diff --git a/src/engine/SCons/Tool/msgmerge.xml b/src/engine/SCons/Tool/msgmerge.xml
index 65d19e1..2944679 100644
--- a/src/engine/SCons/Tool/msgmerge.xml
+++ b/src/engine/SCons/Tool/msgmerge.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/mslib.py b/src/engine/SCons/Tool/mslib.py
index 3d79649..cecdbdc 100644
--- a/src/engine/SCons/Tool/mslib.py
+++ b/src/engine/SCons/Tool/mslib.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,9 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/mslib.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mslib.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
import SCons.Defaults
import SCons.Tool
@@ -54,8 +56,15 @@ def generate(env):
env['LIBPREFIX'] = ''
env['LIBSUFFIX'] = '.lib'
+ # Issue #3350
+ # Change tempfile argument joining character from a space to a newline
+ # mslink will fail if any single line is too long, but is fine with many lines
+ # in a tempfile
+ env['TEMPFILEARGJOIN'] = os.linesep
+
+
def exists(env):
- return msvc_exists()
+ return msvc_exists(env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/mslib.xml b/src/engine/SCons/Tool/mslib.xml
index 6ee2f22..a9b7cef 100644
--- a/src/engine/SCons/Tool/mslib.xml
+++ b/src/engine/SCons/Tool/mslib.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 1b16b63..9fbce4b 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,8 +32,9 @@ selection method.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/mslink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mslink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import os
import os.path
import SCons.Action
@@ -107,7 +108,7 @@ def _dllEmitter(target, source, env, paramtp):
raise SCons.Errors.UserError('A shared library should have exactly one target with the suffix: %s' % env.subst('$%sSUFFIX' % paramtp))
insert_def = env.subst("$WINDOWS_INSERT_DEF")
- if not insert_def in ['', '0', 0] and \
+ if insert_def not in ['', '0', 0] and \
not env.FindIxes(source, "WINDOWSDEFPREFIX", "WINDOWSDEFSUFFIX"):
# append a def file to the list of sources
@@ -158,7 +159,7 @@ def windowsLibEmitter(target, source, env):
def ldmodEmitter(target, source, env):
"""Emitter for loadable modules.
-
+
Loadable modules are identical to shared libraries on Windows, but building
them is subject to different parameters (LDMODULE*).
"""
@@ -219,7 +220,7 @@ def embedManifestDllCheck(target, source, env):
if env.get('WINDOWS_EMBED_MANIFEST', 0):
manifestSrc = target[0].get_abspath() + '.manifest'
if os.path.exists(manifestSrc):
- ret = (embedManifestDllAction) ([target[0]],None,env)
+ ret = (embedManifestDllAction) ([target[0]],None,env)
if ret:
raise SCons.Errors.UserError("Unable to embed manifest into %s" % (target[0]))
return ret
@@ -327,8 +328,14 @@ def generate(env):
env['LDMODULEEMITTER'] = [ldmodEmitter]
env['LDMODULECOM'] = compositeLdmodAction
+ # Issue #3350
+ # Change tempfile argument joining character from a space to a newline
+ # mslink will fail if any single line is too long, but is fine with many lines
+ # in a tempfile
+ env['TEMPFILEARGJOIN'] = os.linesep
+
def exists(env):
- return msvc_exists()
+ return msvc_exists(env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/mslink.xml b/src/engine/SCons/Tool/mslink.xml
index 24b79c7..692c1da 100644
--- a/src/engine/SCons/Tool/mslink.xml
+++ b/src/engine/SCons/Tool/mslink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/mssdk.py b/src/engine/SCons/Tool/mssdk.py
index dd9de93..7a38c6a 100644
--- a/src/engine/SCons/Tool/mssdk.py
+++ b/src/engine/SCons/Tool/mssdk.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/mssdk.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mssdk.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""engine.SCons.Tool.mssdk
diff --git a/src/engine/SCons/Tool/mssdk.xml b/src/engine/SCons/Tool/mssdk.xml
index 0ae3553..b84597e 100644
--- a/src/engine/SCons/Tool/mssdk.xml
+++ b/src/engine/SCons/Tool/mssdk.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py
index 2fe16c3..052a0b0 100644
--- a/src/engine/SCons/Tool/msvc.py
+++ b/src/engine/SCons/Tool/msvc.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,9 +31,10 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/msvc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msvc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
+import os
import re
import sys
@@ -112,7 +113,7 @@ def object_emitter(target, source, env, parent_emitter):
#
# See issue #2505 for a discussion of what to do if it turns
# out this assumption causes trouble in the wild:
- # http://scons.tigris.org/issues/show_bug.cgi?id=2505
+ # https://github.com/SCons/scons/issues/2505
if 'PCH' in env:
pch = env['PCH']
if str(target[0]) != SCons.Util.splitext(str(pch))[0] + '.obj':
@@ -161,7 +162,7 @@ def msvc_batch_key(action, env, target, source):
# Note we need to do the env.subst so $MSVC_BATCH can be a reference to
# another construction variable, which is why we test for False and 0
# as strings.
- if not 'MSVC_BATCH' in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None):
+ if 'MSVC_BATCH' not in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None):
# We're not using batching; return no key.
return None
t = target[0]
@@ -187,7 +188,7 @@ def msvc_output_flag(target, source, env, for_signature):
# len(source)==1 as batch mode can compile only one file
# (and it also fixed problem with compiling only one changed file
# with batch mode enabled)
- if not 'MSVC_BATCH' in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None):
+ if 'MSVC_BATCH' not in env or env.subst('$MSVC_BATCH') in ('0', 'False', '', None):
return '/Fo$TARGET'
else:
# The Visual C/C++ compiler requires a \ at the end of the /Fo
@@ -195,7 +196,10 @@ def msvc_output_flag(target, source, env, for_signature):
# that the test(s) for this can be run on non-Windows systems
# without having a hard-coded backslash mess up command-line
# argument parsing.
- return '/Fo${TARGET.dir}' + os.sep
+ # Adding double os.sep's as if the TARGET.dir has a space or otherwise
+ # needs to be quoted they are needed per MSVC's odd behavior
+ # See: https://github.com/SCons/scons/issues/3106
+ return '/Fo${TARGET.dir}' + os.sep*2
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR",
batch_key=msvc_batch_key,
@@ -259,7 +263,7 @@ def generate(env):
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
env['RC'] = 'rc'
- env['RCFLAGS'] = SCons.Util.CLVar('')
+ env['RCFLAGS'] = SCons.Util.CLVar('/nologo')
env['RCSUFFIXES']=['.rc','.rc2']
env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
env['BUILDERS']['RES'] = res_builder
@@ -268,6 +272,10 @@ def generate(env):
env['SHOBJPREFIX'] = '$OBJPREFIX'
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
+ # MSVC probably wont support unistd.h so default
+ # without it for lex generation
+ env["LEXUNISTD"] = SCons.Util.CLVar("--nounistd")
+
# Set-up ms tools paths
msvc_setup_env_once(env)
@@ -276,6 +284,12 @@ def generate(env):
msvc_set_PCHPDBFLAGS(env)
+ # Issue #3350
+ # Change tempfile argument joining character from a space to a newline
+ # mslink will fail if any single line is too long, but is fine with many lines
+ # in a tempfile
+ env['TEMPFILEARGJOIN'] = os.linesep
+
env['PCHCOM'] = '$CXX /Fo${TARGETS[1]} $CXXFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS $PCHPDBFLAGS'
env['BUILDERS']['PCH'] = pch_builder
@@ -286,7 +300,7 @@ def generate(env):
env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root()
def exists(env):
- return msvc_exists()
+ return msvc_exists(env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/msvc.xml b/src/engine/SCons/Tool/msvc.xml
index edc6936..b8b4f6d 100644
--- a/src/engine/SCons/Tool/msvc.xml
+++ b/src/engine/SCons/Tool/msvc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -305,7 +305,8 @@ containing the command-line options
for specifying directories to be searched
by the resource compiler.
The value of &cv-RCINCFLAGS; is created
-by appending &cv-RCINCPREFIX; and &cv-RCINCSUFFIX;
+by respectively prepending and appending
+&cv-RCINCPREFIX; and &cv-RCINCSUFFIX;
to the beginning and end
of each directory in &cv-CPPPATH;.
</para>
@@ -317,7 +318,7 @@ of each directory in &cv-CPPPATH;.
<para>
The prefix (flag) used to specify an include directory
on the resource compiler command line.
-This will be appended to the beginning of each directory
+This will be prepended to the beginning of each directory
in the &cv-CPPPATH; construction variable
when the &cv-RCINCFLAGS; variable is expanded.
</para>
@@ -352,6 +353,8 @@ constructor; setting it later has no effect.
<para>
Valid values for Windows are
+<literal>14.2</literal>,
+<literal>14.1</literal>,
<literal>14.0</literal>,
<literal>14.0Exp</literal>,
<literal>12.0</literal>,
@@ -424,18 +427,24 @@ This variable must be passed as an argument to the Environment()
constructor; setting it later has no effect.
This is currently only used on Windows, but in the future it will be
used on other OSes as well.
+If this is set and MSVC_VERSION is not set, this will search for
+all installed MSVC's that support the TARGET_ARCH, selecting the
+latest version for use.
</para>
<para>
Valid values for Windows are
<literal>x86</literal>,
+<literal>arm</literal>,
<literal>i386</literal>
(for 32 bits);
<literal>amd64</literal>,
+<literal>arm64</literal>,
<literal>emt64</literal>,
<literal>x86_64</literal>
(for 64 bits);
and <literal>ia64</literal> (Itanium).
+
For example, if you want to compile 64-bit binaries, you would set
<literal>TARGET_ARCH='x86_64'</literal> in your SCons environment.
</para>
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index 05531c6..38965e3 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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.
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/msvs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msvs.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -70,10 +70,14 @@ def xmlify(s):
s = s.replace('\n', '&#x0A;')
return s
-# Process a CPPPATH list in includes, given the env, target and source.
-# Returns a tuple of nodes.
def processIncludes(includes, env, target, source):
- return SCons.PathList.PathList(includes).subst_path(env, target, source)
+ """
+ Process a CPPPATH list in includes, given the env, target and source.
+ Returns a list of directory paths. These paths are absolute so we avoid
+ putting pound-prefixed paths in a Visual Studio project file.
+ """
+ return [env.Dir(i).abspath for i in
+ SCons.PathList.PathList(includes).subst_path(env, target, source)]
external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}'
@@ -149,9 +153,9 @@ def splitFully(path):
return [base]
def makeHierarchy(sources):
- '''Break a list of files into a hierarchy; for each value, if it is a string,
+ """Break a list of files into a hierarchy; for each value, if it is a string,
then it is a file. If it is a dictionary, it is a folder. The string is
- the original path of the file.'''
+ the original path of the file."""
hierarchy = {}
for file in sources:
@@ -189,7 +193,7 @@ class _UserGenerator(object):
elif SCons.Util.is_List(env['variant']):
variants = env['variant']
- if 'DebugSettings' not in env or env['DebugSettings'] == None:
+ if 'DebugSettings' not in env or env['DebugSettings'] is None:
dbg_settings = []
elif SCons.Util.is_Dict(env['DebugSettings']):
dbg_settings = [env['DebugSettings']]
@@ -348,10 +352,20 @@ V10DebugSettings = {
}
class _GenerateV10User(_UserGenerator):
- """Generates a Project'user file for MSVS 2010"""
+ """Generates a Project'user file for MSVS 2010 or later"""
def __init__(self, dspfile, source, env):
- self.versionstr = '4.0'
+ version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+ if version_num >= 14.2:
+ # Visual Studio 2019 is considered to be version 16.
+ self.versionstr = '16.0'
+ elif version_num >= 14.1:
+ # Visual Studio 2017 is considered to be version 15.
+ self.versionstr = '15.0'
+ elif version_num == 14.0:
+ self.versionstr = '14.0'
+ else:
+ self.versionstr = '4.0'
self.usrhead = V10UserHeader
self.usrconf = V10UserConfiguration
self.usrdebg = V10DebugSettings
@@ -397,7 +411,7 @@ class _DSPGenerator(object):
elif SCons.Util.is_List(env['variant']):
variants = env['variant']
- if 'buildtarget' not in env or env['buildtarget'] == None:
+ if 'buildtarget' not in env or env['buildtarget'] is None:
buildtarget = ['']
elif SCons.Util.is_String(env['buildtarget']):
buildtarget = [env['buildtarget']]
@@ -418,7 +432,7 @@ class _DSPGenerator(object):
for _ in variants:
buildtarget.append(bt)
- if 'outdir' not in env or env['outdir'] == None:
+ if 'outdir' not in env or env['outdir'] is None:
outdir = ['']
elif SCons.Util.is_String(env['outdir']):
outdir = [env['outdir']]
@@ -439,7 +453,7 @@ class _DSPGenerator(object):
for v in variants:
outdir.append(s)
- if 'runfile' not in env or env['runfile'] == None:
+ if 'runfile' not in env or env['runfile'] is None:
runfile = buildtarget[-1:]
elif SCons.Util.is_String(env['runfile']):
runfile = [env['runfile']]
@@ -462,15 +476,41 @@ class _DSPGenerator(object):
self.sconscript = env['MSVSSCONSCRIPT']
- if 'cmdargs' not in env or env['cmdargs'] == None:
- cmdargs = [''] * len(variants)
- elif SCons.Util.is_String(env['cmdargs']):
- cmdargs = [env['cmdargs']] * len(variants)
- elif SCons.Util.is_List(env['cmdargs']):
- if len(env['cmdargs']) != len(variants):
- raise SCons.Errors.InternalError("Sizes of 'cmdargs' and 'variant' lists must be the same.")
+ def GetKeyFromEnv(env, key, variants):
+ """
+ Retrieves a specific key from the environment. If the key is
+ present, it is expected to either be a string or a list with length
+ equal to the number of variants. The function returns a list of
+ the desired value (e.g. cpp include paths) guaranteed to be of
+ length equal to the length of the variants list.
+ """
+ if key not in env or env[key] is None:
+ return [''] * len(variants)
+ elif SCons.Util.is_String(env[key]):
+ return [env[key]] * len(variants)
+ elif SCons.Util.is_List(env[key]):
+ if len(env[key]) != len(variants):
+ raise SCons.Errors.InternalError("Sizes of '%s' and 'variant' lists must be the same." % key)
+ else:
+ return env[key]
else:
- cmdargs = env['cmdargs']
+ raise SCons.Errors.InternalError("Unsupported type for key '%s' in environment: %s" %
+ (key, type(env[key])))
+
+ cmdargs = GetKeyFromEnv(env, 'cmdargs', variants)
+
+ # The caller is allowed to put 'cppdefines' and/or 'cpppaths' in the
+ # environment, which is useful if they want to provide per-variant
+ # values for these. Otherwise, we fall back to using the global
+ # 'CPPDEFINES' and 'CPPPATH' functions.
+ if 'cppdefines' in env:
+ cppdefines = GetKeyFromEnv(env, 'cppdefines', variants)
+ else:
+ cppdefines = [env.get('CPPDEFINES', [])] * len(variants)
+ if 'cpppaths' in env:
+ cpppaths = GetKeyFromEnv(env, 'cpppaths', variants)
+ else:
+ cpppaths = [env.get('CPPPATH', [])] * len(variants)
self.env = env
@@ -513,14 +553,18 @@ class _DSPGenerator(object):
for n in sourcenames:
self.sources[n].sort(key=lambda a: a.lower())
- def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspfile=dspfile):
+ def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, cppdefines, cpppaths, dspfile=dspfile, env=env):
config = Config()
config.buildtarget = buildtarget
config.outdir = outdir
config.cmdargs = cmdargs
+ config.cppdefines = cppdefines
config.runfile = runfile
- match = re.match('(.*)\|(.*)', variant)
+ # Dir objects can't be pickled, so we need an absolute path here.
+ config.cpppaths = processIncludes(cpppaths, env, None, None)
+
+ match = re.match(r'(.*)\|(.*)', variant)
if match:
config.variant = match.group(1)
config.platform = match.group(2)
@@ -532,12 +576,12 @@ class _DSPGenerator(object):
print("Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'")
for i in range(len(variants)):
- AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i])
+ AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs[i], cppdefines[i], cpppaths[i])
self.platforms = []
for key in list(self.configs.keys()):
platform = self.configs[key].platform
- if not platform in self.platforms:
+ if platform not in self.platforms:
self.platforms.append(platform)
def Build(self):
@@ -553,16 +597,16 @@ V6DSPHeader = """\
CFG=%(name)s - Win32 %(confkey)s
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
-!MESSAGE
+!MESSAGE
!MESSAGE NMAKE /f "%(name)s.mak".
-!MESSAGE
+!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
+!MESSAGE
!MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s"
-!MESSAGE
+!MESSAGE
!MESSAGE Possible choices for configuration are:
-!MESSAGE
+!MESSAGE
"""
class _GenerateV6DSP(_DSPGenerator):
@@ -580,7 +624,7 @@ class _GenerateV6DSP(_DSPGenerator):
for kind in confkeys:
self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind))
- self.file.write('!MESSAGE \n\n')
+ self.file.write('!MESSAGE\n\n')
def PrintProject(self):
name = self.name
@@ -637,7 +681,7 @@ class _GenerateV6DSP(_DSPGenerator):
first = 1
else:
self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
- self.file.write('!ENDIF \n\n')
+ self.file.write('!ENDIF\n\n')
self.PrintSourceFiles()
self.file.write('# End Target\n'
'# End Project\n')
@@ -645,10 +689,10 @@ class _GenerateV6DSP(_DSPGenerator):
if self.nokeep == 0:
# now we pickle some data and add it to the file -- MSDEV will ignore it.
pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write(pdata + '\n')
pdata = pickle.dumps(self.sources,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write(pdata + '\n')
def PrintSourceFiles(self):
@@ -685,11 +729,13 @@ class _GenerateV6DSP(_DSPGenerator):
return # doesn't exist yet, so can't add anything to configs.
line = dspfile.readline()
+ # skip until marker
while line:
if line.find("# End Project") > -1:
break
line = dspfile.readline()
+ # read to get configs
line = dspfile.readline()
datas = line
while line and line != '\n':
@@ -707,12 +753,14 @@ class _GenerateV6DSP(_DSPGenerator):
self.configs.update(data)
+ # keep reading to get sources
data = None
line = dspfile.readline()
datas = line
while line and line != '\n':
line = dspfile.readline()
datas = datas + line
+ dspfile.close()
# OK, we've found our little pickled cache of data.
# it has a "# " in front of it, so we strip that.
@@ -878,6 +926,8 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
buildtarget = self.configs[kind].buildtarget
runfile = self.configs[kind].runfile
cmdargs = self.configs[kind].cmdargs
+ cpppaths = self.configs[kind].cpppaths
+ cppdefines = self.configs[kind].cppdefines
env_has_buildtarget = 'MSVSBUILDTARGET' in self.env
if not env_has_buildtarget:
@@ -895,9 +945,8 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
# This isn't perfect; CPPDEFINES and CPPPATH can contain $TARGET and $SOURCE,
# so they could vary depending on the command being generated. This code
# assumes they don't.
- preprocdefs = xmlify(';'.join(processDefines(self.env.get('CPPDEFINES', []))))
- includepath_Dirs = processIncludes(self.env.get('CPPPATH', []), self.env, None, None)
- includepath = xmlify(';'.join([str(x) for x in includepath_Dirs]))
+ preprocdefs = xmlify(';'.join(processDefines(cppdefines)))
+ includepath = xmlify(';'.join(processIncludes(cpppaths, self.env, None, None)))
if not env_has_buildtarget:
del self.env['MSVSBUILDTARGET']
@@ -917,10 +966,10 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
if self.nokeep == 0:
# now we pickle some data and add it to the file -- MSDEV will ignore it.
pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write('<!-- SCons Data:\n' + pdata + '\n')
pdata = pickle.dumps(self.sources,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write(pdata + '-->\n')
def printSources(self, hierarchy, commonprefix):
@@ -998,11 +1047,13 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
return # doesn't exist yet, so can't add anything to configs.
line = dspfile.readline()
+ # skip until marker
while line:
if line.find('<!-- SCons Data:') > -1:
break
line = dspfile.readline()
+ # read to get configs
line = dspfile.readline()
datas = line
while line and line != '\n':
@@ -1020,12 +1071,14 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
self.configs.update(data)
+ # keep reading to get sources
data = None
line = dspfile.readline()
datas = line
while line and line != '\n':
line = dspfile.readline()
datas = datas + line
+ dspfile.close()
# OK, we've found our little pickled cache of data.
try:
@@ -1052,7 +1105,7 @@ class _GenerateV7DSP(_DSPGenerator, _GenerateV7User):
V10DSPHeader = """\
<?xml version="1.0" encoding="%(encoding)s"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="%(versionstr)s" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
"""
V10DSPProjectConfiguration = """\
@@ -1067,6 +1120,7 @@ V10DSPGlobals = """\
\t\t<ProjectGuid>%(project_guid)s</ProjectGuid>
%(scc_attrs)s\t\t<RootNamespace>%(name)s</RootNamespace>
\t\t<Keyword>MakeFileProj</Keyword>
+\t\t<VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
\t</PropertyGroup>
"""
@@ -1080,7 +1134,7 @@ V10DSPPropertyGroupCondition = """\
V10DSPImportGroupCondition = """\
\t<ImportGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'" Label="PropertySheets">
-\t\t<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+\t\t<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
\t</ImportGroup>
"""
@@ -1096,6 +1150,11 @@ V10DSPCommandLine = """\
\t\t<NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>
"""
+V15DSPHeader = """\
+<?xml version="1.0" encoding="%(encoding)s"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+"""
+
class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
"""Generates a Project file for MSVS 2010"""
@@ -1110,6 +1169,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
def PrintHeader(self):
env = self.env
name = self.name
+ versionstr = self.versionstr
encoding = env.subst('$MSVSENCODING')
project_guid = env.get('MSVS_PROJECT_GUID', '')
scc_provider = env.get('MSVS_SCC_PROVIDER', '')
@@ -1154,7 +1214,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
name = self.name
confkeys = sorted(self.configs.keys())
- self.file.write('\t<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\n')
+ self.file.write('\t<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />\n')
toolset = ''
if 'MSVC_VERSION' in self.env:
@@ -1165,7 +1225,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
platform = self.configs[kind].platform
self.file.write(V10DSPPropertyGroupCondition % locals())
- self.file.write('\t<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\n')
+ self.file.write('\t<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />\n')
self.file.write('\t<ImportGroup Label="ExtensionSettings">\n')
self.file.write('\t</ImportGroup>\n')
@@ -1185,6 +1245,8 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
buildtarget = self.configs[kind].buildtarget
runfile = self.configs[kind].runfile
cmdargs = self.configs[kind].cmdargs
+ cpppaths = self.configs[kind].cpppaths
+ cppdefines = self.configs[kind].cppdefines
env_has_buildtarget = 'MSVSBUILDTARGET' in self.env
if not env_has_buildtarget:
@@ -1202,9 +1264,8 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
# This isn't perfect; CPPDEFINES and CPPPATH can contain $TARGET and $SOURCE,
# so they could vary depending on the command being generated. This code
# assumes they don't.
- preprocdefs = xmlify(';'.join(processDefines(self.env.get('CPPDEFINES', []))))
- includepath_Dirs = processIncludes(self.env.get('CPPPATH', []), self.env, None, None)
- includepath = xmlify(';'.join([str(x) for x in includepath_Dirs]))
+ preprocdefs = xmlify(';'.join(processDefines(cppdefines)))
+ includepath = xmlify(';'.join(processIncludes(cpppaths, self.env, None, None)))
if not env_has_buildtarget:
del self.env['MSVSBUILDTARGET']
@@ -1221,14 +1282,15 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
raise SCons.Errors.InternalError('Unable to open "' + self.filtersabs + '" for writing:' + str(detail))
self.filters_file.write('<?xml version="1.0" encoding="utf-8"?>\n'
- '<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\n')
+ '<Project ToolsVersion="%s" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\n' %
+ self.versionstr)
self.PrintSourceFiles()
self.filters_file.write('</Project>')
self.filters_file.close()
- self.file.write('\t<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\n'
+ self.file.write('\t<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />\n'
'\t<ImportGroup Label="ExtensionTargets">\n'
'\t</ImportGroup>\n'
'</Project>\n')
@@ -1236,10 +1298,10 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
if self.nokeep == 0:
# now we pickle some data and add it to the file -- MSDEV will ignore it.
pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write('<!-- SCons Data:\n' + pdata + '\n')
pdata = pickle.dumps(self.sources,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write(pdata + '-->\n')
def printFilters(self, hierarchy, name):
@@ -1287,7 +1349,7 @@ class _GenerateV10DSP(_DSPGenerator, _GenerateV10User):
'Other Files': ''}
cats = sorted([k for k in list(categories.keys()) if self.sources[k]],
- key = lambda a: a.lower())
+ key = lambda a: a.lower())
# print vcxproj.filters file first
self.filters_file.write('\t<ItemGroup>\n')
@@ -1423,7 +1485,7 @@ class _GenerateV7DSW(_DSWGenerator):
def AddConfig(self, variant, dswfile=dswfile):
config = Config()
- match = re.match('(.*)\|(.*)', variant)
+ match = re.match(r'(.*)\|(.*)', variant)
if match:
config.variant = match.group(1)
config.platform = match.group(2)
@@ -1446,13 +1508,16 @@ class _GenerateV7DSW(_DSWGenerator):
self.platforms = []
for key in list(self.configs.keys()):
platform = self.configs[key].platform
- if not platform in self.platforms:
+ if platform not 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)
+ if SCons.Util.splitext(name)[1] == '.filters':
+ # Ignore .filters project files
+ continue
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
@@ -1486,6 +1551,7 @@ class _GenerateV7DSW(_DSWGenerator):
while line:
line = dswfile.readline()
datas = datas + line
+ dswfile.close()
# OK, we've found our little pickled cache of data.
try:
@@ -1501,7 +1567,13 @@ 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 >= 12.0:
+ if self.version_num >= 14.2:
+ # Visual Studio 2019 is considered to be version 16.
+ self.file.write('# Visual Studio 16\n')
+ elif self.version_num > 14.0:
+ # Visual Studio 2015 and 2017 are both considered to be version 15.
+ self.file.write('# Visual Studio 15\n')
+ elif self.version_num >= 12.0:
self.file.write('# Visual Studio 14\n')
elif self.version_num >= 11.0:
self.file.write('# Visual Studio 11\n')
@@ -1519,7 +1591,7 @@ class _GenerateV7DSW(_DSWGenerator):
name = base
self.file.write('Project("%s") = "%s", "%s", "%s"\n'
% (external_makefile_guid, name, dspinfo['SLN_RELATIVE_FILE_PATH'], dspinfo['GUID']))
- if self.version_num >= 7.1 and self.version_num < 8.0:
+ if 7.1 <= self.version_num < 8.0:
self.file.write('\tProjectSection(ProjectDependencies) = postProject\n'
'\tEndProjectSection\n')
self.file.write('EndProject\n')
@@ -1610,7 +1682,7 @@ class _GenerateV7DSW(_DSWGenerator):
self.file.write('EndGlobal\n')
if self.nokeep == 0:
pdata = pickle.dumps(self.configs,PICKLE_PROTOCOL)
- pdata = base64.encodestring(pdata).decode()
+ pdata = base64.b64encode(pdata).decode()
self.file.write(pdata)
self.file.write('\n')
@@ -1720,7 +1792,7 @@ def GenerateProject(target, source, env):
dspfile = builddspfile.srcnode()
# this detects whether or not we're using a VariantDir
- if not dspfile is builddspfile:
+ if dspfile is not builddspfile:
try:
bdsp = open(str(builddspfile), "w+")
except IOError as detail:
@@ -1728,6 +1800,7 @@ def GenerateProject(target, source, env):
raise
bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
+ bdsp.close()
GenerateDSP(dspfile, source, env)
@@ -1735,7 +1808,7 @@ def GenerateProject(target, source, env):
builddswfile = target[1]
dswfile = builddswfile.srcnode()
- if not dswfile is builddswfile:
+ if dswfile is not builddswfile:
try:
bdsw = open(str(builddswfile), "w+")
@@ -1744,6 +1817,7 @@ def GenerateProject(target, source, env):
raise
bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
+ bdsw.close()
GenerateDSW(dswfile, source, env)
@@ -1771,11 +1845,10 @@ def projectEmitter(target, source, env):
# 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]))
+ includepath = xmlify(';'.join(processIncludes(env.get('CPPPATH', []), env, None, None)))
source = source + "; ppdefs:%s incpath:%s"%(preprocdefs, includepath)
- if 'buildtarget' in env and env['buildtarget'] != None:
+ if 'buildtarget' in env and env['buildtarget'] is not None:
if SCons.Util.is_String(env['buildtarget']):
source = source + ' "%s"' % env['buildtarget']
elif SCons.Util.is_List(env['buildtarget']):
@@ -1789,7 +1862,7 @@ def projectEmitter(target, source, env):
try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
except AttributeError: raise SCons.Errors.InternalError("buildtarget can be a string, a node, a list of strings or nodes, or None")
- if 'outdir' in env and env['outdir'] != None:
+ if 'outdir' in env and env['outdir'] is not None:
if SCons.Util.is_String(env['outdir']):
source = source + ' "%s"' % env['outdir']
elif SCons.Util.is_List(env['outdir']):
@@ -1952,8 +2025,14 @@ def generate(env):
default_MSVS_SConscript = env.File('SConstruct')
env['MSVSSCONSCRIPT'] = default_MSVS_SConscript
- env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
- env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}'
+ # Allow consumers to provide their own versions of MSVSSCONS and
+ # MSVSSCONSFLAGS. This helps support consumers who use wrapper scripts to
+ # invoke scons.
+ if 'MSVSSCONS' not in env:
+ env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
+ if 'MSVSSCONSFLAGS' not in env:
+ env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.get_abspath()}" -f ${MSVSSCONSCRIPT.name}'
+
env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
@@ -1990,7 +2069,7 @@ def generate(env):
env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
def exists(env):
- return msvc_exists()
+ return msvc_exists(env)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml
index 0408509..9f2353a 100644
--- a/src/engine/SCons/Tool/msvs.xml
+++ b/src/engine/SCons/Tool/msvs.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -17,160 +17,244 @@ See its __doc__ string for a discussion of the format.
<!ENTITY % variables-mod SYSTEM "../../../../doc/generated/variables.mod">
%variables-mod;
]>
-<sconsdoc
-xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd"
-xmlns="http://www.scons.org/dbxsd/v1.0"
-xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-xmlns:xs="http://www.w3.org/2001/XMLSchema"
-xmlns:ns="http://www.scons.org/dbxsd/v1.0"><tool name="msvs"> <summary> <para>
-Sets construction variables for Microsoft Visual Studio. </para> </summary>
-<sets> <item>MSVSPROJECTCOM</item> <item>MSVSSOLUTIONCOM</item>
-<item>MSVSSCONSCRIPT</item> <item>MSVSSCONS</item> <item>MSVSSCONSFLAGS</item>
-<item>MSVSSCONSCOM</item> <item>MSVSBUILDCOM</item>
-<item>MSVSREBUILDCOM</item> <item>MSVSCLEANCOM</item>
-<item>MSVSENCODING</item> </sets> <uses> </uses> </tool> <builder
-name="MSVSProject"> <summary> <para> Builds a Microsoft Visual Studio project
-file, and by default builds a solution file as well. </para> <para> This
-builds a Visual Studio project file, based on the version of Visual Studio
-that is configured (either the latest installed version, or the version
-specified by &cv-link-MSVS_VERSION; in the Environment constructor). For
-Visual Studio 6, it will generate a <filename>.dsp</filename> file. For Visual
-Studio 7 (.NET) and later versions, it will generate a
-<filename>.vcproj</filename> file. </para> <para> By default, this also
-generates a solution file for the specified project, a
-<filename>.dsw</filename> file for Visual Studio 6 or a
-<filename>.sln</filename> file for Visual Studio 7 (.NET). This behavior may
-be disabled by specifying <literal>auto_build_solution=0</literal> when you
-call &b-MSVSProject;, in which case you presumably want to build the solution
-file(s) by calling the &b-MSVSSolution; Builder (see below). </para> <para>
-The &b-MSVSProject; builder takes several lists of filenames to be placed into
-the project file. These are currently limited to <literal>srcs</literal>,
-<literal>incs</literal>, <literal>localincs</literal>,
-<literal>resources</literal>, and <literal>misc</literal>. These are pretty
-self-explanatory, but it should be noted that these lists are added to the
-&cv-link-SOURCES; construction variable as strings, NOT as SCons File Nodes.
-This is because they represent file names to be added to the project file, not
-the source files used to build the project file. </para> <para> The above
-filename lists are all optional, although at least one must be specified for
-the resulting project file to be non-empty. </para> <para> In addition to the
-above lists of values, the following values may be specified:
-</para><variablelist>
- <varlistentry>
- <term>target</term>
-
- <listitem>
- <para>The name of the target <filename>.dsp</filename> or
- <filename>.vcproj</filename> file. The correct suffix for the version
- of Visual Studio must be used, but the &cv-link-MSVSPROJECTSUFFIX;
- construction variable will be defined to the correct value (see
- example below).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>variant</term>
-
- <listitem>
- <para>The name of this particular variant. For Visual Studio 7
- projects, this can also be a list of variant names. These are
- typically things like "Debug" or "Release", but really can be anything
- you want. For Visual Studio 7 projects, they may also specify a target
- platform separated from the variant name by a <literal>|</literal>
- (vertical pipe) character: <literal>Debug|Xbox</literal>. The default
- target platform is Win32. Multiple calls to &b-MSVSProject; with
- different variants are allowed; all variants will be added to the
- project file with their appropriate build targets and
- sources.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>cmdargs</term>
-
- <listitem>
- <para>Additional command line arguments for the different
- variants. The number of <literal>cmdargs</literal> entries must match
- the number of <literal>variant</literal> entries, or be empty (not
- specified). If you give only one, it will automatically be propagated
- to all variants.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>buildtarget</term>
-
- <listitem>
- <para>An optional string, node, or list of strings or nodes (one
- per build variant), to tell the Visual Studio debugger what output
- target to use in what build variant. The number of
- <literal>buildtarget</literal> entries must match the number of
- <literal>variant</literal> entries.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>runfile</term>
-
- <listitem>
- <para>The name of the file that Visual Studio 7 and later will
- run and debug. This appears as the value of the
- <literal>Output</literal> field in the resulting Visual Studio project
- file. If this is not specified, the default is the same as the
- specified <literal>buildtarget</literal> value.</para>
- </listitem>
- </varlistentry>
- </variablelist><para> Note that because &SCons; always executes its build
-commands from the directory in which the &SConstruct; file is located, if you
-generate a project file in a different directory than the &SConstruct;
-directory, users will not be able to double-click on the file name in
-compilation error messages displayed in the Visual Studio console output
-window. This can be remedied by adding the Visual C/C++ <literal>/FC</literal>
-compiler option to the &cv-link-CCFLAGS; variable so that the compiler will
-print the full path name of any files that cause compilation errors. </para>
-<para> Example usage: </para>
- <example_commands>
+<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0" xmlns:ns="http://www.scons.org/dbxsd/v1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
+ <tool name="msvs">
+ <summary>
+ <para>Sets construction variables for Microsoft Visual Studio.</para>
+ </summary>
+ <sets>
+ <item>MSVSPROJECTCOM</item>
+ <item>MSVSSOLUTIONCOM</item>
+ <item>MSVSSCONSCRIPT</item>
+ <item>MSVSSCONS</item>
+ <item>MSVSSCONSFLAGS</item>
+ <item>MSVSSCONSCOM</item>
+ <item>MSVSBUILDCOM</item>
+ <item>MSVSREBUILDCOM</item>
+ <item>MSVSCLEANCOM</item>
+ <item>MSVSENCODING</item>
+ </sets>
+ <uses />
+ </tool>
+ <builder name="MSVSProject">
+ <summary>
+ <para>
+ Builds a Microsoft Visual Studio project file, and by default
+ builds a solution file as well.
+ </para>
+ <para>
+ This builds a Visual Studio project file, based on the
+ version of Visual Studio that is configured (either the
+ latest installed version, or the version specified by
+ &cv-link-MSVS_VERSION; in the Environment constructor). For
+ Visual Studio 6, it will generate a <filename>.dsp</filename>
+ file. For Visual Studio 7, 8, and 9, it will
+ generate a <filename>.vcproj</filename> file. For Visual
+ Studio 10 and later, it will generate a
+ <filename>.vcxproj</filename> file.
+ </para>
+ <para>
+ By default, this also generates a solution file for the
+ specified project, a <filename>.dsw</filename> file for
+ Visual Studio 6 or a <filename>.sln</filename> file for
+ Visual Studio 7 and later. This behavior may be disabled by
+ specifying <literal>auto_build_solution=0</literal> when you
+ call &b-MSVSProject;, in which case you presumably want to
+ build the solution file(s) by calling the &b-MSVSSolution;
+ Builder (see below).
+ </para>
+ <para>
+ The &b-MSVSProject; builder takes several lists of filenames
+ to be placed into the project file. These are currently
+ limited to <literal>srcs</literal>, <literal>incs</literal>,
+ <literal>localincs</literal>, <literal>resources</literal>, and
+ <literal>misc</literal>. These are pretty self-explanatory,
+ but it should be noted that these lists are added to the
+ &cv-link-SOURCES; construction variable as strings, NOT as
+ SCons File Nodes. This is because they represent file names
+ to be added to the project file, not the source files used
+ to build the project file.
+ </para>
+ <para>
+ The above filename lists are all optional, although at least
+ one must be specified for the resulting project file to
+ be non-empty.
+ </para>
+ <para>
+ In addition to the above lists of values, the following values
+ may be specified:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>target</term>
+ <listitem>
+ <para>
+ The name of the target <filename>.dsp</filename>
+ or <filename>.vcproj</filename> file.
+ The correct suffix for the version of Visual Studio
+ must be used, but the &cv-link-MSVSPROJECTSUFFIX;
+ construction variable will be defined to the correct
+ value (see example below).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>variant</term>
+ <listitem>
+ <para>
+ The name of this particular variant. For Visual Studio 7
+ projects, this can also be a list of variant names. These
+ are typically things like "Debug" or "Release", but
+ really can be anything you want. For Visual Studio
+ 7 projects, they may also specify a target platform
+ separated from the variant name by a <literal>|</literal>
+ (vertical pipe) character: <literal>Debug|Xbox</literal>.
+ The default target platform is Win32. Multiple calls
+ to &b-MSVSProject; with different variants are allowed;
+ all variants will be added to the project file with
+ their appropriate build targets and sources.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cmdargs</term>
+ <listitem>
+ <para>
+ Additional command line arguments
+ for the different variants. The number of
+ <literal>cmdargs</literal> entries must match the number
+ of <literal>variant</literal> entries, or be empty (not
+ specified). If you give only one, it will automatically
+ be propagated to all variants.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cppdefines</term>
+ <listitem>
+ <para>
+ Preprocessor definitions for the different variants.
+ The number of <literal>cppdefines</literal> entries
+ must match the number of <literal>variant</literal>
+ entries, or be empty (not specified). If you give
+ only one, it will automatically be propagated to all
+ variants. If you don't give this parameter, SCons
+ will use the invoking environment's
+ <literal>CPPDEFINES</literal> entry for all variants.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cpppaths</term>
+ <listitem>
+ <para>
+ Compiler include paths for the different variants.
+ The number of <literal>cpppaths</literal> entries
+ must match the number of <literal>variant</literal>
+ entries, or be empty (not specified). If you give
+ only one, it will automatically be propagated to all
+ variants. If you don't give this parameter, SCons
+ will use the invoking environment's
+ <literal>CPPPATH</literal> entry for all variants.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>buildtarget</term>
+ <listitem>
+ <para>
+ An optional string, node, or list of strings
+ or nodes (one per build variant), to tell
+ the Visual Studio debugger what output target
+ to use in what build variant. The number of
+ <literal>buildtarget</literal> entries must match the
+ number of <literal>variant</literal> entries.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>runfile</term>
+ <listitem>
+ <para>
+ The name of the file that Visual Studio 7 and
+ later will run and debug. This appears as the
+ value of the <literal>Output</literal> field in the
+ resulting Visual Studio project file. If this is not
+ specified, the default is the same as the specified
+ <literal>buildtarget</literal> value.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Note that because &SCons; always executes its build commands
+ from the directory in which the &SConstruct; file is located,
+ if you generate a project file in a different directory
+ than the &SConstruct; directory, users will not be able to
+ double-click on the file name in compilation error messages
+ displayed in the Visual Studio console output window. This can
+ be remedied by adding the Visual C/C++ <literal>/FC</literal>
+ compiler option to the &cv-link-CCFLAGS; variable so that
+ the compiler will print the full path name of any files that
+ cause compilation errors.
+ </para>
+ <para>Example usage:</para>
+ <example_commands>
barsrcs = ['bar.cpp']
barincs = ['bar.h']
barlocalincs = ['StdAfx.h']
barresources = ['bar.rc','resource.h']
barmisc = ['bar_readme.txt']
-dll = env.SharedLibrary(target = 'bar.dll',
- source = barsrcs)
+dll = env.SharedLibrary(target='bar.dll',
+ source=barsrcs)
buildtarget = [s for s in dll if str(s).endswith('dll')]
-env.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'],
- srcs = barsrcs,
- incs = barincs,
- localincs = barlocalincs,
- resources = barresources,
- misc = barmisc,
- buildtarget = buildtarget,
- variant = 'Release')
-</example_commands>
-<para>Starting with version 2.4 of
-SCons it's also possible to specify the optional argument
-<parameter>DebugSettings</parameter>, which creates files for debugging under
-Visual Studio:</para><variablelist>
- <varlistentry>
- <term>DebugSettings</term>
-
- <listitem>
- <para>A dictionary of debug settings that get written to the
- <filename>.vcproj.user</filename> or the
- <filename>.vcxproj.user</filename> file, depending on the version
- installed. As it is done for cmdargs (see above), you can specify a
- <parameter>DebugSettings</parameter> dictionary per variant. If you
- give only one, it will be propagated to all variants.</para>
- </listitem>
- </varlistentry>
- </variablelist><para>Currently, only Visual Studio v9.0 and Visual Studio
-version v11 are implemented, for other versions no file is generated. To
-generate the user file, you just need to add a
-<parameter>DebugSettings</parameter> dictionary to the environment with the
-right parameters for your MSVS version. If the dictionary is empty, or does
-not contain any good value, no file will be generated.</para><para>Following
-is a more contrived example, involving the setup of a project for variants and
-DebugSettings:</para><example_commands># Assuming you store your defaults in a file
+env.MSVSProject(target='Bar' + env['MSVSPROJECTSUFFIX'],
+ srcs=barsrcs,
+ incs=barincs,
+ localincs=barlocalincs,
+ resources=barresources,
+ misc=barmisc,
+ buildtarget=buildtarget,
+ variant='Release')
+ </example_commands>
+ <para>
+ Starting with version 2.4 of SCons it is
+ also possible to specify the optional argument
+ <parameter>DebugSettings</parameter>, which creates files
+ for debugging under Visual Studio:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>DebugSettings</term>
+ <listitem>
+ <para>
+ A dictionary of debug settings that get written
+ to the <filename>.vcproj.user</filename> or the
+ <filename>.vcxproj.user</filename> file, depending on the
+ version installed. As it is done for cmdargs (see above),
+ you can specify a <parameter>DebugSettings</parameter>
+ dictionary per variant. If you give only one, it will
+ be propagated to all variants.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ Currently, only Visual Studio v9.0 and Visual Studio
+ version v11 are implemented, for other versions no file
+ is generated. To generate the user file, you just need to
+ add a <parameter>DebugSettings</parameter> dictionary to the
+ environment with the right parameters for your MSVS version. If
+ the dictionary is empty, or does not contain any good value,
+ no file will be generated.
+ </para>
+ <para>
+ Following is a more contrived example, involving the setup
+ of a project for variants and DebugSettings:
+ </para>
+ <example_commands>
+# Assuming you store your defaults in a file
vars = Variables('variables.py')
msvcver = vars.args.get('vc', '9')
@@ -179,7 +263,7 @@ if msvcver == '9' or msvcver == '11':
env = Environment(MSVC_VERSION=msvcver+'.0', MSVC_BATCH=False)
else:
env = Environment()
-
+
AddOption('--userfile', action='store_true', dest='userfile', default=False,
help="Create Visual Studio Project user file")
@@ -214,10 +298,10 @@ V9DebugSettings = {
}
#
-# 2. Because there are a lot of different options depending on the Microsoft
-# Visual Studio version, if you use more than one version you have to
-# define a dictionary per version, for instance if you want to create a user
-# file to launch a specific application for testing your dll with Microsoft
+# 2. Because there are a lot of different options depending on the Microsoft
+# Visual Studio version, if you use more than one version you have to
+# define a dictionary per version, for instance if you want to create a user
+# file to launch a specific application for testing your dll with Microsoft
# Visual Studio 2012 (v11):
#
V10DebugSettings = {
@@ -249,7 +333,7 @@ V10DebugSettings = {
}
#
-# 3. Select the dictionary you want depending on the version of visual Studio
+# 3. Select the dictionary you want depending on the version of visual Studio
# Files you want to generate.
#
if not env.GetOption('userfile'):
@@ -258,7 +342,7 @@ elif env.get('MSVC_VERSION', None) == '9.0':
dbgSettings = V9DebugSettings
elif env.get('MSVC_VERSION', None) == '11.0':
dbgSettings = V10DebugSettings
-else:
+else:
dbgSettings = None
#
@@ -270,251 +354,365 @@ barlocalincs = ['StdAfx.h']
barresources = ['bar.rc','resource.h']
barmisc = ['ReadMe.txt']
-dll = env.SharedLibrary(target = 'bar.dll',
- source = barsrcs)
-
-env.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'],
- srcs = barsrcs,
- incs = barincs,
- localincs = barlocalincs,
- resources = barresources,
- misc = barmisc,
- buildtarget = [dll[0]] * 2,
- variant = ('Debug|Win32', 'Release|Win32'),
- cmdargs = 'vc=%s' % msvcver,
- DebugSettings = (dbgSettings, {}))
-</example_commands> </summary> </builder> <builder
-name="MSVSSolution"> <summary> <para>Builds a Microsoft Visual Studio solution
-file. </para> <para>This builds a Visual Studio solution file, based on the
-version of Visual Studio that is configured (either the latest installed
-version, or the version specified by &cv-link-MSVS_VERSION; in the
-construction environment). For Visual Studio 6, it will generate a
-<filename>.dsw</filename> file. For Visual Studio 7 (.NET), it will generate a
-<filename>.sln</filename> file. </para> <para> The following values must be
-specified: </para><variablelist>
- <varlistentry>
- <term>target</term>
-
- <listitem>
- <para>The name of the target .dsw or .sln file. The correct
- suffix for the version of Visual Studio must be used, but the value
- &cv-link-MSVSSOLUTIONSUFFIX; will be defined to the correct value (see
- example below).</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>variant</term>
-
- <listitem>
- <para>The name of this particular variant, or a list of variant
- names (the latter is only supported for MSVS 7 solutions). These are
- typically things like "Debug" or "Release", but really can be anything
- you want. For MSVS 7 they may also specify target platform, like this
- "Debug|Xbox". Default platform is Win32.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>projects</term>
-
- <listitem>
- <para>A list of project file names, or Project nodes returned by
- calls to the &b-MSVSProject; Builder, to be placed into the solution
- file. It should be noted that these file names are NOT added to the
- $SOURCES environment variable in form of files, but rather as strings.
- This is because they represent file names to be added to the solution
- file, not the source files used to build the solution
- file.</para>
- </listitem>
- </varlistentry>
- </variablelist> <para> Example Usage: </para> <example_commands>
-env.MSVSSolution(target = 'Bar' + env['MSVSSOLUTIONSUFFIX'], projects = ['bar'
-+ env['MSVSPROJECTSUFFIX']], variant = 'Release')
-</example_commands></summary></builder> <cvar name="MSVS"> <summary> <para>
-When the Microsoft Visual Studio tools are initialized, they set up this
-dictionary with the following keys: </para><variablelist>
- <varlistentry>
- <term>VERSION</term>
-
- <listitem>
- <para>the version of MSVS being used (can be set via
- &cv-link-MSVS_VERSION;)</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>VERSIONS</term>
-
- <listitem>
- <para>the available versions of MSVS installed</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>VCINSTALLDIR</term>
-
- <listitem>
- <para>installed directory of Visual C++</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>VSINSTALLDIR</term>
-
- <listitem>
- <para>installed directory of Visual Studio</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>FRAMEWORKDIR</term>
-
- <listitem>
- <para>installed directory of the .NET framework</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>FRAMEWORKVERSIONS</term>
-
- <listitem>
- <para>list of installed versions of the .NET framework, sorted
- latest to oldest.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>FRAMEWORKVERSION</term>
-
- <listitem>
- <para>latest installed version of the .NET
- framework</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>FRAMEWORKSDKDIR</term>
-
- <listitem>
- <para>installed location of the .NET SDK.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>PLATFORMSDKDIR</term>
-
- <listitem>
- <para>installed location of the Platform SDK.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>PLATFORMSDK_MODULES</term>
-
- <listitem>
- <para>dictionary of installed Platform SDK modules, where the
- dictionary keys are keywords for the various modules, and the values
- are 2-tuples where the first is the release date, and the second is
- the version number.</para>
- </listitem>
- </varlistentry>
- </variablelist><para>If a value isn't set, it wasn't available in the
-registry.</para></summary></cvar> <cvar name="MSVS_ARCH"> <summary> <para>Sets
-the architecture for which the generated project(s) should build. </para>
-<para>The default value is <literal>x86</literal>. <literal>amd64</literal> is
-also supported by &SCons; for some Visual Studio versions. Trying to set
-&cv-MSVS_ARCH; to an architecture that's not supported for a given Visual
-Studio version will generate an error. </para> </summary> </cvar> <cvar
-name="MSVS_PROJECT_GUID"> <summary> <para>The string placed in a generated
+dll = env.SharedLibrary(target='bar.dll',
+ source=barsrcs)
+
+env.MSVSProject(target='Bar' + env['MSVSPROJECTSUFFIX'],
+ srcs=barsrcs,
+ incs=barincs,
+ localincs=barlocalincs,
+ resources=barresources,
+ misc=barmisc,
+ buildtarget=[dll[0]] * 2,
+ variant=('Debug|Win32', 'Release|Win32'),
+ cmdargs='vc=%s' % msvcver,
+ DebugSettings=(dbgSettings, {}))
+ </example_commands>
+ </summary>
+ </builder>
+ <builder name="MSVSSolution">
+ <summary>
+ <para>Builds a Microsoft Visual Studio solution file.</para>
+ <para>
+ This builds a Visual Studio solution file, based on the
+ version of Visual Studio that is configured (either the
+ latest installed version, or the version specified by
+ &cv-link-MSVS_VERSION; in the construction environment). For
+ Visual Studio 6, it will generate a <filename>.dsw</filename>
+ file. For Visual Studio 7 (.NET), it will generate a
+ <filename>.sln</filename> file.
+ </para>
+ <para>The following values must be specified:</para>
+ <variablelist>
+ <varlistentry>
+ <term>target</term>
+ <listitem>
+ <para>
+ The name of the target .dsw or .sln file. The correct
+ suffix for the version of Visual Studio must be used,
+ but the value &cv-link-MSVSSOLUTIONSUFFIX; will be
+ defined to the correct value (see example below).
+ </para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>variant</term> <listitem>
+ <para>
+ The name of this particular variant, or a list of
+ variant names (the latter is only supported for MSVS
+ 7 solutions). These are typically things like "Debug"
+ or "Release", but really can be anything you want. For
+ MSVS 7 they may also specify target platform, like this
+ "Debug|Xbox". Default platform is Win32.
+ </para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>projects</term> <listitem>
+ <para>
+ A list of project file names, or Project nodes returned
+ by calls to the &b-MSVSProject; Builder, to be placed
+ into the solution file. It should be noted that these
+ file names are NOT added to the $SOURCES environment
+ variable in form of files, but rather as strings.
+ This is because they represent file names to be added
+ to the solution file, not the source files used to
+ build the solution file.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Example Usage:</para>
+ <example_commands>
+env.MSVSSolution(target='Bar' + env['MSVSSOLUTIONSUFFIX'], projects=['bar' + env['MSVSPROJECTSUFFIX']], variant='Release')
+ </example_commands>
+ </summary>
+ </builder> <cvar name="MSVS">
+ <summary>
+ <para>
+ When the Microsoft Visual Studio tools are initialized,
+ they set up this dictionary with the following keys:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>VERSION</term> <listitem>
+ <para>the version of MSVS being used (can be set via
+ &cv-link-MSVS_VERSION;)</para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>VERSIONS</term> <listitem>
+ <para>the available versions of MSVS installed</para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>VCINSTALLDIR</term> <listitem>
+ <para>installed directory of Visual C++</para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>VSINSTALLDIR</term> <listitem>
+ <para>installed directory of Visual Studio</para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>FRAMEWORKDIR</term> <listitem>
+ <para>installed directory of the .NET framework</para>
+ </listitem>
+ </varlistentry> <varlistentry>
+ <term>FRAMEWORKVERSIONS</term> <listitem>
+ <para>
+ list of installed versions of the .NET framework,
+ sorted latest to oldest.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>FRAMEWORKVERSION</term>
+ <listitem>
+ <para>latest installed version of the .NET framework</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>FRAMEWORKSDKDIR</term>
+ <listitem>
+ <para>installed location of the .NET SDK.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PLATFORMSDKDIR</term>
+ <listitem>
+ <para>installed location of the Platform SDK.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PLATFORMSDK_MODULES</term>
+ <listitem>
+ <para>
+ dictionary of installed Platform SDK modules, where the
+ dictionary keys are keywords for the various modules,
+ and the values are 2-tuples where the first is the
+ release date, and the second is the version number.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>If a value is not set, it was not available in the registry.</para>
+ </summary>
+ </cvar> <cvar name="MSVS_ARCH">
+ <summary>
+ <para>Sets the architecture for which the generated project(s) should build.</para>
+ <para>
+ The default value is <literal>x86</literal>.
+ <literal>amd64</literal> is also supported by &SCons; for
+ most Visual Studio versions. Since Visual Studio 2015
+ <literal>arm</literal> is supported, and since Visual Studio
+ 2017 <literal>arm64</literal> is supported.
+ Trying to set &cv-MSVS_ARCH;
+ to an architecture that's not supported for a given Visual
+ Studio version will generate an error.
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_PROJECT_GUID">
+ <summary>
+ <para>
+ The string placed in a generated
Microsoft Visual Studio project file as the value of the
-<literal>ProjectGUID</literal> attribute. There is no default value. If not
-defined, a new GUID is generated. </para> </summary> </cvar> <cvar
-name="MSVS_SCC_AUX_PATH"> <summary> <para>The path name placed in a generated
+ <literal>ProjectGUID</literal> attribute. There is no default
+ value. If not
+defined, a new GUID is generated.
+
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_SCC_AUX_PATH">
+ <summary>
+ <para>
+ The path name placed in a generated
Microsoft Visual Studio project file as the value of the
-<literal>SccAuxPath</literal> attribute if the
-<envar>MSVS_SCC_PROVIDER</envar> construction variable is also set. There is
-no default value. </para> </summary> </cvar> <cvar
-name="MSVS_SCC_CONNECTION_ROOT"> <summary> <para>The root path of projects in
-your SCC workspace, i.e the path under which all project and solution files
-will be generated. It is used as a reference path from which the relative
-paths of the generated Microsoft Visual Studio project and solution files are
-computed. The relative project file path is placed as the value of the
-<literal>SccLocalPath</literal> attribute of the project file and as the
-values of the
-<literal>SccProjectFilePathRelativizedFromConnection[i]</literal> (where [i]
-ranges from 0 to the number of projects in the solution) attributes of the
-<literal>GlobalSection(SourceCodeControl)</literal> section of the Microsoft
-Visual Studio solution file. Similarly the relative solution file path is
-placed as the values of the <literal>SccLocalPath[i]</literal> (where [i]
-ranges from 0 to the number of projects in the solution) attributes of the
-<literal>GlobalSection(SourceCodeControl)</literal> section of the Microsoft
-Visual Studio solution file. This is used only if the
-<envar>MSVS_SCC_PROVIDER</envar> construction variable is also set. The
-default value is the current working directory. </para> </summary> </cvar>
-<cvar name="MSVS_SCC_PROJECT_NAME"> <summary> <para>The project name placed in
-a generated Microsoft Visual Studio project file as the value of the
-<literal>SccProjectName</literal> attribute if the
-<envar>MSVS_SCC_PROVIDER</envar> construction variable is also set. In this
-case the string is also placed in the <literal>SccProjectName0</literal>
-attribute of the <literal>GlobalSection(SourceCodeControl)</literal> section
-of the Microsoft Visual Studio solution file. There is no default value.
-</para> </summary> </cvar> <cvar name="MSVS_SCC_PROVIDER"> <summary> <para>The
-string placed in a generated Microsoft Visual Studio project file as the value
-of the <literal>SccProvider</literal> attribute. The string is also placed in
-the <literal>SccProvider0</literal> attribute of the
-<literal>GlobalSection(SourceCodeControl)</literal> section of the Microsoft
-Visual Studio solution file. There is no default value. </para> </summary>
-</cvar> <cvar name="MSVS_VERSION"> <summary> <para>Sets the preferred version
-of Microsoft Visual Studio to use. </para> <para>If &cv-MSVS_VERSION; is not
-set, &SCons; will (by default) select the latest version of Visual Studio
-installed on your system. So, if you have version 6 and version 7 (MSVS .NET)
-installed, it will prefer version 7. You can override this by specifying the
-<envar>MSVS_VERSION</envar> variable in the Environment initialization,
-setting it to the appropriate version ('6.0' or '7.0', for example). If the
-specified version isn't installed, tool initialization will fail. </para>
-<para>This is obsolete: use &cv-MSVC_VERSION; instead. If &cv-MSVS_VERSION; is
-set and &cv-MSVC_VERSION; is not, &cv-MSVC_VERSION; will be set automatically
-to &cv-MSVS_VERSION;. If both are set to different values, scons will raise an
-error. </para> </summary> </cvar> <cvar name="MSVSBUILDCOM"> <summary>
-<para>The build command line placed in a generated Microsoft Visual Studio
-project file. The default is to have Visual Studio invoke SCons with any
-specified build targets. </para> </summary> </cvar> <cvar name="MSVSCLEANCOM">
-<summary> <para>The clean command line placed in a generated Microsoft Visual
-Studio project file. The default is to have Visual Studio invoke SCons with
-the -c option to remove any specified targets. </para> </summary> </cvar>
-<cvar name="MSVSENCODING"> <summary> <para>The encoding string placed in a
-generated Microsoft Visual Studio project file. The default is encoding
-<literal>Windows-1252</literal>. </para> </summary> </cvar> <cvar
-name="MSVSPROJECTCOM"> <summary> <para>The action used to generate Microsoft
-Visual Studio project files. </para> </summary> </cvar> <cvar
-name="MSVSPROJECTSUFFIX"> <summary> <para>The suffix used for Microsoft Visual
-Studio project (DSP) files. The default value is <filename>.vcproj</filename>
-when using Visual Studio version 7.x (.NET) or later version, and
-<filename>.dsp</filename> when using earlier versions of Visual Studio.
-</para> </summary> </cvar> <cvar name="MSVSREBUILDCOM"> <summary> <para>The
-rebuild command line placed in a generated Microsoft Visual Studio project
-file. The default is to have Visual Studio invoke SCons with any specified
-rebuild targets. </para> </summary> </cvar> <cvar name="MSVSSCONS"> <summary>
-<para>The SCons used in generated Microsoft Visual Studio project files. The
-default is the version of SCons being used to generate the project file.
-</para> </summary> </cvar> <cvar name="MSVSSCONSFLAGS"> <summary> <para>The
-SCons flags used in generated Microsoft Visual Studio project files. </para>
-</summary> </cvar> <cvar name="MSVSSCONSCOM"> <summary> <para>The default
-SCons command used in generated Microsoft Visual Studio project files. </para>
-</summary> </cvar> <cvar name="MSVSSCONSCRIPT"> <summary> <para>The sconscript
-file (that is, &SConstruct; or &SConscript; file) that will be invoked by
-Visual Studio project files (through the &cv-link-MSVSSCONSCOM; variable). The
-default is the same sconscript file that contains the call to &b-MSVSProject;
-to build the project file. </para> </summary> </cvar> <cvar
-name="MSVSSOLUTIONCOM"> <summary> <para>The action used to generate Microsoft
-Visual Studio solution files. </para> </summary> </cvar> <cvar
-name="MSVSSOLUTIONSUFFIX"> <summary> <para>The suffix used for Microsoft
-Visual Studio solution (DSW) files. The default value is
-<filename>.sln</filename> when using Visual Studio version 7.x (.NET), and
-<filename>.dsw</filename> when using earlier versions of Visual Studio.
-</para> </summary> </cvar> <cvar name="SCONS_HOME"> <summary> <para>The
-(optional) path to the SCons library directory, initialized from the external
-environment. If set, this is used to construct a shorter and more efficient
-search path in the &cv-link-MSVSSCONS; command line executed from Microsoft
-Visual Studio project files. </para> </summary> </cvar></sconsdoc>
+ <literal>SccAuxPath</literal> attribute if the
+ <envar>MSVS_SCC_PROVIDER</envar> construction variable is
+ also set. There is
+no default value.
+
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_SCC_CONNECTION_ROOT">
+ <summary>
+ <para>
+ The root path of projects in your SCC workspace, i.e the
+ path under which all project and solution files will be
+ generated. It is used as a reference path from which the
+ relative paths of the generated Microsoft Visual Studio project
+ and solution files are computed. The relative project file path
+ is placed as the value of the <literal>SccLocalPath</literal>
+ attribute of the project file and as the values of the
+ <literal>SccProjectFilePathRelativizedFromConnection[i]</literal>
+ (where [i] ranges from 0 to the number of projects in the solution)
+ attributes of the <literal>GlobalSection(SourceCodeControl)</literal>
+ section of the Microsoft Visual Studio solution file. Similarly
+ the relative solution file path is placed as the values of the
+ <literal>SccLocalPath[i]</literal> (where [i] ranges from 0
+ to the number of projects in the solution) attributes of the
+ <literal>GlobalSection(SourceCodeControl)</literal> section of
+ the Microsoft Visual Studio solution file. This is used only if
+ the <envar>MSVS_SCC_PROVIDER</envar> construction variable is
+ also set. The default value is the current working directory.
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_SCC_PROJECT_NAME">
+ <summary>
+ <para>
+ The project name placed in a generated Microsoft
+ Visual Studio project file as the value of the
+ <literal>SccProjectName</literal> attribute if the
+ <envar>MSVS_SCC_PROVIDER</envar> construction variable
+ is also set. In this case the string is also placed in
+ the <literal>SccProjectName0</literal> attribute of the
+ <literal>GlobalSection(SourceCodeControl)</literal> section
+ of the Microsoft Visual Studio solution file. There is no
+ default value.
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_SCC_PROVIDER">
+ <summary>
+ <para>
+ The string placed in a generated Microsoft
+ Visual Studio project file as the value of the
+ <literal>SccProvider</literal> attribute. The string is
+ also placed in the <literal>SccProvider0</literal> attribute
+ of the <literal>GlobalSection(SourceCodeControl)</literal>
+ section of the Microsoft Visual Studio solution file. There
+ is no default value.
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVS_VERSION">
+ <summary>
+ <para>Sets the preferred version of Microsoft Visual Studio to use.</para>
+ <para>
+ If &cv-MSVS_VERSION; is not set, &SCons; will (by default)
+ select the latest version of Visual Studio installed on your
+ system. So, if you have version 6 and version 7 (MSVS .NET)
+ installed, it will prefer version 7. You can override this by
+ specifying the <envar>MSVS_VERSION</envar> variable in the
+ Environment initialization, setting it to the appropriate
+ version ('6.0' or '7.0', for example). If the specified
+ version isn't installed, tool initialization will fail.
+ </para>
+ <para>
+ This is obsolete: use &cv-MSVC_VERSION; instead. If
+ &cv-MSVS_VERSION; is set and &cv-MSVC_VERSION; is
+ not, &cv-MSVC_VERSION; will be set automatically to
+ &cv-MSVS_VERSION;. If both are set to different values,
+ scons will raise an error.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSBUILDCOM">
+ <summary>
+ <para>
+ The build command line placed in a generated Microsoft Visual
+ Studio project file. The default is to have Visual Studio
+ invoke SCons with any specified build targets.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSCLEANCOM">
+ <summary>
+ <para>
+ The clean command line placed in a generated Microsoft Visual
+ Studio project file. The default is to have Visual Studio
+ invoke SCons with the -c option to remove any specified
+ targets.
+ </para>
+ </summary>
+ </cvar> <cvar name="MSVSENCODING">
+ <summary>
+ <para>
+ The encoding string placed in a generated Microsoft
+ Visual Studio project file. The default is encoding
+ <literal>Windows-1252</literal>.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSPROJECTCOM">
+ <summary>
+ <para>The action used to generate Microsoft Visual Studio project files.</para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSPROJECTSUFFIX">
+ <summary>
+ <para>
+ The suffix used for Microsoft Visual Studio project (DSP)
+ files. The default value is <filename>.vcproj</filename>
+ when using Visual Studio version 7.x (.NET) or later version,
+ and <filename>.dsp</filename> when using earlier versions of
+ Visual Studio.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSREBUILDCOM">
+ <summary>
+ <para>
+ The rebuild command line placed in a generated Microsoft
+ Visual Studio project file. The default is to have Visual
+ Studio invoke SCons with any specified rebuild targets.
+
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSSCONS">
+ <summary>
+ <para>
+ The SCons used in generated Microsoft Visual Studio project
+ files. The default is the version of SCons being used to
+ generate the project file.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSSCONSFLAGS">
+ <summary>
+ <para>
+ The SCons flags used in generated Microsoft Visual Studio project files.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSSCONSCOM">
+ <summary>
+ <para>
+ The default SCons command used in generated Microsoft Visual
+ Studio project files.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSSCONSCRIPT">
+ <summary>
+ <para>
+ The sconscript file (that is, &SConstruct; or &SConscript;
+ file) that will be invoked by Visual Studio project files
+ (through the &cv-link-MSVSSCONSCOM; variable). The default
+ is the same sconscript file that contains the call to
+ &b-MSVSProject; to build the project file.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="MSVSSOLUTIONCOM">
+ <summary>
+ <para>The action used to generate Microsoft Visual Studio solution files.</para>
+ </summary>
+ </cvar> <cvar name="MSVSSOLUTIONSUFFIX">
+ <summary>
+ <para>
+ The suffix used for Microsoft Visual Studio solution (DSW)
+ files. The default value is <filename>.sln</filename>
+ when using Visual Studio version 7.x (.NET), and
+ <filename>.dsw</filename> when using earlier versions of
+ Visual Studio.
+ </para>
+ </summary>
+ </cvar>
+ <cvar name="SCONS_HOME">
+ <summary>
+ <para>
+ The (optional) path to the SCons library directory,
+ initialized from the external environment. If set, this is
+ used to construct a shorter and more efficient search path in
+ the &cv-link-MSVSSCONS; command line executed from Microsoft
+ Visual Studio project files.
+ </para>
+ </summary>
+ </cvar>
+</sconsdoc>
diff --git a/src/engine/SCons/Tool/msvsTests.py b/src/engine/SCons/Tool/msvsTests.py
index 8c09487..e0b5ced 100644
--- a/src/engine/SCons/Tool/msvsTests.py
+++ b/src/engine/SCons/Tool/msvsTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 print_function
-__revision__ = "src/engine/SCons/Tool/msvsTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/msvsTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import sys
@@ -34,6 +34,7 @@ import TestUnit
from SCons.Tool.msvs import *
from SCons.Tool.MSCommon.vs import SupportedVSList
+import SCons.Node.FS
import SCons.Util
import SCons.Warnings
@@ -352,6 +353,36 @@ regdata_80 = r'''
"VCXDCMakeTool"="*.xdc"
'''.split('\n')
+regdata_140 = r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS]
+"MSMDir"="C:\\Program Files (x86)\\Common Files\\Merge Modules\\"
+"ProductDir"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\"
+"VS7EnvironmentLocation"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe"
+"EnvironmentPath"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\devenv.exe"
+"EnvironmentDirectory"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\"
+"VS7CommonDir"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\"
+"VS7CommonBinDir"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\BuildNumber]
+"1033"="14.0"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\Community]
+"ProductDir"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\JSLS_MSI]
+"Version"="14.0.25527"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\JSPS_MSI]
+"Version"="14.0.25527"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\Pro]
+"ProductDir"="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\professional]
+"IsInstallInProgress"="0"
+"CurrentOperation"="install"
+"SetupFeedUri"="http://go.microsoft.com/fwlink/?LinkID=659004&clcid=0x409"
+"SetupFeedLocalCache"="C:\\ProgramData\\Microsoft\\VisualStudioSecondaryInstaller\\14.0\\LastUsedFeed\\{68432bbb-c9a5-4a7b-bab3-ae5a49b28303}\\Feed.xml"
+"InstallResult"="0"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller\AppInsightsTools]
+"Version"="7.0.20620.1"
+'''.split('\n')
+
regdata_cv = r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
"ProgramFilesDir"="C:\Program Files"
"CommonFilesDir"="C:\Program Files\Common Files"
@@ -363,6 +394,7 @@ regdata_none = []
class DummyEnv(object):
def __init__(self, dict=None):
+ self.fs = SCons.Node.FS.FS()
if dict:
self.dict = dict
else:
@@ -385,6 +417,16 @@ class DummyEnv(object):
def has_key(self,name):
return name in self.dict
+ def get(self, name, value=None):
+ if self.has_key(name):
+ return self.dict[name]
+ else:
+ return value
+
+ def Dir(self, name):
+ return self.fs.Dir(name)
+
+
class RegKey(object):
"""key class for storing an 'open' registry key"""
def __init__(self,key):
@@ -482,8 +524,8 @@ class DummyRegistry(object):
def parse(self, data):
parents = [None, None]
parents[0] = self.root
- keymatch = re.compile('^\[(.*)\]$')
- valmatch = re.compile('^(?:"(.*)"|[@])="(.*)"$')
+ keymatch = re.compile(r'^\[(.*)\]$')
+ valmatch = re.compile(r'^(?:"(.*)"|[@])="(.*)"$')
for line in data:
m1 = keymatch.match(line)
if m1:
@@ -540,6 +582,10 @@ def DummyQueryValue(key, value):
def DummyExists(path):
return 1
+def DummyVsWhere(msvc_version):
+ # not testing versions with vswhere, so return none
+ return None
+
class msvsTestCase(unittest.TestCase):
"""This test case is run several times with different defaults.
See its subclasses below."""
@@ -550,6 +596,11 @@ class msvsTestCase(unittest.TestCase):
from SCons.Tool.MSCommon.vs import reset_installed_visual_studios
reset_installed_visual_studios()
+ self.test = TestCmd.TestCmd(workdir='')
+ # FS doesn't like the cwd to be something other than its root.
+ os.chdir(self.test.workpath(""))
+ self.fs = SCons.Node.FS.FS()
+
def test_get_default_version(self):
"""Test retrieval of the default visual studio version"""
@@ -603,13 +654,19 @@ class msvsTestCase(unittest.TestCase):
version_num, suite = msvs_parse_version(self.highest_version)
if version_num >= 10.0:
function_test = _GenerateV10DSP
+ suffix = '.vcxproj'
elif version_num >= 7.0:
function_test = _GenerateV7DSP
+ suffix = '.dsp'
else:
function_test = _GenerateV6DSP
+ suffix = '.dsp'
+
+ # Avoid any race conditions between the test cases when we test
+ # actually writing the files.
+ dspfile = 'test%s%s' % (hash(self), suffix)
str_function_test = str(function_test.__init__)
- dspfile = 'test.dsp'
source = 'test.cpp'
# Create the cmdargs test list
@@ -619,50 +676,95 @@ class msvsTestCase(unittest.TestCase):
'debug=False target_arch=32',
'debug=True target_arch=x64',
'debug=False target_arch=x64']
-
- # Tuple list : (parameter, dictionary of expected result per variant)
- tests_cmdargs = [(None, dict.fromkeys(list_variant, '')),
- ('', dict.fromkeys(list_variant, '')),
- (list_cmdargs[0], dict.fromkeys(list_variant, list_cmdargs[0])),
- (list_cmdargs, dict(list(zip(list_variant, list_cmdargs))))]
-
+ list_cppdefines = [['_A', '_B', 'C'], ['_B', '_C_'], ['D'], []]
+ list_cpppaths = [[r'C:\test1'], [r'C:\test1;C:\test2'],
+ [self.fs.Dir('subdir')], []]
+
+ def TestParamsFromList(test_variant, test_list):
+ """
+ Generates test data based on the parameters passed in.
+
+ Returns tuple list:
+ 1. Parameter.
+ 2. Dictionary of expected result per variant.
+ """
+ def normalizeParam(param):
+ """
+ Converts the raw data based into the AddConfig function of
+ msvs.py to the expected result.
+
+ Expects the following behavior:
+ 1. A value of None will be converted to an empty list.
+ 2. A File or Directory object will be converted to an
+ absolute path (because those objects can't be pickled).
+ 3. Otherwise, the parameter will be used.
+ """
+ if param is None:
+ return []
+ elif isinstance(param, list):
+ return [normalizeParam(p) for p in param]
+ elif hasattr(param, 'abspath'):
+ return param.abspath
+ else:
+ return param
+
+ return [
+ (None, dict.fromkeys(test_variant, '')),
+ ('', dict.fromkeys(test_variant, '')),
+ (test_list[0], dict.fromkeys(test_variant, normalizeParam(test_list[0]))),
+ (test_list, dict(list(zip(test_variant, [normalizeParam(x) for x in test_list]))))
+ ]
+
+ tests_cmdargs = TestParamsFromList(list_variant, list_cmdargs)
+ tests_cppdefines = TestParamsFromList(list_variant, list_cppdefines)
+ tests_cpppaths = TestParamsFromList(list_variant, list_cpppaths)
+
# Run the test for each test case
for param_cmdargs, expected_cmdargs in tests_cmdargs:
- debug('Testing %s. with :\n variant = %s \n cmdargs = "%s"' % \
- (str_function_test, list_variant, param_cmdargs))
- param_configs = []
- expected_configs = {}
- for platform in ['Win32', 'x64']:
- for variant in ['Debug', 'Release']:
- variant_platform = '%s|%s' % (variant, platform)
- runfile = '%s\\%s\\test.exe' % (platform, variant)
- buildtarget = '%s\\%s\\test.exe' % (platform, variant)
- outdir = '%s\\%s' % (platform, variant)
+ for param_cppdefines, expected_cppdefines in tests_cppdefines:
+ for param_cpppaths, expected_cpppaths in tests_cpppaths:
+ debug('Testing %s. with :\n variant = %s \n cmdargs = "%s" \n cppdefines = "%s" \n cpppaths = "%s"' % \
+ (str_function_test, list_variant, param_cmdargs, param_cppdefines, param_cpppaths))
+ param_configs = []
+ expected_configs = {}
+ for platform in ['Win32', 'x64']:
+ for variant in ['Debug', 'Release']:
+ variant_platform = '%s|%s' % (variant, platform)
+ runfile = '%s\\%s\\test.exe' % (platform, variant)
+ buildtarget = '%s\\%s\\test.exe' % (platform, variant)
+ outdir = '%s\\%s' % (platform, variant)
- # Create parameter list for this variant_platform
- param_configs.append([variant_platform, runfile, buildtarget, outdir])
-
- # Create expected dictionary result for this variant_platform
- expected_configs[variant_platform] = \
- {'variant': variant, 'platform': platform,
- 'runfile': runfile,
- 'buildtarget': buildtarget,
- 'outdir': outdir,
- 'cmdargs': expected_cmdargs[variant_platform]}
+ # Create parameter list for this variant_platform
+ param_configs.append([variant_platform, runfile, buildtarget, outdir])
+ # Create expected dictionary result for this variant_platform
+ expected_configs[variant_platform] = {
+ 'variant': variant,
+ 'platform': platform,
+ 'runfile': runfile,
+ 'buildtarget': buildtarget,
+ 'outdir': outdir,
+ 'cmdargs': expected_cmdargs[variant_platform],
+ 'cppdefines': expected_cppdefines[variant_platform],
+ 'cpppaths': expected_cpppaths[variant_platform],
+ }
+
# Create parameter environment with final parameter dictionary
param_dict = dict(list(zip(('variant', 'runfile', 'buildtarget', 'outdir'),
[list(l) for l in zip(*param_configs)])))
param_dict['cmdargs'] = param_cmdargs
+ param_dict['cppdefines'] = param_cppdefines
+ param_dict['cpppaths'] = param_cpppaths
# Hack to be able to run the test with a 'DummyEnv'
class _DummyEnv(DummyEnv):
- def subst(self, string) :
+ def subst(self, string, *args, **kwargs):
return string
env = _DummyEnv(param_dict)
env['MSVSSCONSCRIPT'] = ''
env['MSVS_VERSION'] = self.highest_version
+ env['MSVSBUILDTARGET'] = 'target'
# Call function to test
genDSP = function_test(dspfile, source, env)
@@ -672,6 +774,16 @@ class msvsTestCase(unittest.TestCase):
for key in list(genDSP.configs.keys()):
self.assertDictEqual(genDSP.configs[key].__dict__, expected_configs[key])
+ genDSP.Build()
+
+ # Delete the resulting file so we don't leave anything behind.
+ for file in [dspfile, dspfile + '.filters']:
+ path = os.path.realpath(file)
+ try:
+ os.remove(path)
+ except OSError:
+ pass
+
class msvs6aTestCase(msvsTestCase):
"""Test MSVS 6 Registry"""
registry = DummyRegistry(regdata_6a + regdata_cv)
@@ -783,6 +895,18 @@ class msvs80TestCase(msvsTestCase):
}
default_install_loc = install_locs['8.0']
+class msvs140TestCase(msvsTestCase):
+ """Test MSVS 140 Registry"""
+ registry = DummyRegistry(regdata_140 + regdata_cv)
+ default_version = '14.0'
+ highest_version = '14.0'
+ number_of_versions = 2
+ install_locs = {
+ '14.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 14.0',
+ 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 14.0\\VC'},
+ }
+ default_install_loc = install_locs['14.0']
+
class msvsEmptyTestCase(msvsTestCase):
"""Test Empty Registry"""
registry = DummyRegistry(regdata_none)
@@ -809,6 +933,7 @@ if __name__ == "__main__":
SCons.Util.RegEnumKey = DummyEnumKey
SCons.Util.RegEnumValue = DummyEnumValue
SCons.Util.RegQueryValueEx = DummyQueryValue
+ SCons.Tool.MSCommon.vc.find_vc_pdir_vswhere = DummyVsWhere
os.path.exists = DummyExists # make sure all files exist :-)
os.path.isfile = DummyExists # make sure all files are files :-)
@@ -824,6 +949,7 @@ if __name__ == "__main__":
msvs71TestCase,
msvs8ExpTestCase,
msvs80TestCase,
+ msvs140TestCase,
msvsEmptyTestCase,
]
diff --git a/src/engine/SCons/Tool/mwcc.py b/src/engine/SCons/Tool/mwcc.py
index 566f812..b2b2f5b 100644
--- a/src/engine/SCons/Tool/mwcc.py
+++ b/src/engine/SCons/Tool/mwcc.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/mwcc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mwcc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
diff --git a/src/engine/SCons/Tool/mwcc.xml b/src/engine/SCons/Tool/mwcc.xml
index 39e6dfa..e9f210c 100644
--- a/src/engine/SCons/Tool/mwcc.xml
+++ b/src/engine/SCons/Tool/mwcc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/mwld.py b/src/engine/SCons/Tool/mwld.py
index 9abeeb5..5049c55 100644
--- a/src/engine/SCons/Tool/mwld.py
+++ b/src/engine/SCons/Tool/mwld.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/mwld.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/mwld.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool
diff --git a/src/engine/SCons/Tool/mwld.xml b/src/engine/SCons/Tool/mwld.xml
index 993fefe..261a039 100644
--- a/src/engine/SCons/Tool/mwld.xml
+++ b/src/engine/SCons/Tool/mwld.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/nasm.py b/src/engine/SCons/Tool/nasm.py
index c605cc6..d4d0a1b 100644
--- a/src/engine/SCons/Tool/nasm.py
+++ b/src/engine/SCons/Tool/nasm.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/nasm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/nasm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/nasm.xml b/src/engine/SCons/Tool/nasm.xml
index 1834b34..6626411 100644
--- a/src/engine/SCons/Tool/nasm.xml
+++ b/src/engine/SCons/Tool/nasm.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/packaging.xml b/src/engine/SCons/Tool/packaging.xml
index ea39115..9b46000 100644
--- a/src/engine/SCons/Tool/packaging.xml
+++ b/src/engine/SCons/Tool/packaging.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/packaging/__init__.py b/src/engine/SCons/Tool/packaging/__init__.py
index b844afb..72b9eef 100644
--- a/src/engine/SCons/Tool/packaging/__init__.py
+++ b/src/engine/SCons/Tool/packaging/__init__.py
@@ -4,7 +4,7 @@ SCons Packaging Tool.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,18 +25,23 @@ SCons Packaging Tool.
# 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/packaging/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+import SCons.Defaults
import SCons.Environment
from SCons.Variables import *
from SCons.Errors import *
from SCons.Util import is_List, make_path_relative
from SCons.Warnings import warn, Warning
-import os, imp
-import SCons.Defaults
+import os
+import importlib
-__all__ = [ 'src_targz', 'src_tarbz2', 'src_zip', 'tarbz2', 'targz', 'zip', 'rpm', 'msi', 'ipk' ]
+__all__ = [
+ 'src_targz', 'src_tarbz2', 'src_tarxz', 'src_zip',
+ 'targz', 'tarbz2', 'tarxz', 'zip',
+ 'rpm', 'msi', 'ipk',
+]
#
# Utility and Builder function
@@ -102,7 +107,7 @@ def Package(env, target=None, source=None, **kw):
from SCons.Script import GetOption
kw['PACKAGETYPE'] = GetOption('package_type')
- if kw['PACKAGETYPE'] == None:
+ if kw['PACKAGETYPE'] is None:
if 'Tar' in env['BUILDERS']:
kw['PACKAGETYPE']='targz'
elif 'Zip' in env['BUILDERS']:
@@ -117,12 +122,12 @@ def Package(env, target=None, source=None, **kw):
# load the needed packagers.
def load_packager(type):
try:
- file,path,desc=imp.find_module(type, __path__)
- return imp.load_module(type, file, path, desc)
+ # the specific packager is a relative import
+ return importlib.import_module("." + type, __name__)
except ImportError as e:
- raise EnvironmentError("packager %s not available: %s"%(type,str(e)))
+ raise SConsEnvironmentError("packager %s not available: %s" % (type, str(e)))
- packagers=list(map(load_packager, PACKAGETYPE))
+ packagers = list(map(load_packager, PACKAGETYPE))
# set up targets and the PACKAGEROOT
try:
@@ -163,15 +168,22 @@ def Package(env, target=None, source=None, **kw):
# this exception means that a needed argument for the packager is
# missing. As our packagers get their "tags" as named function
# arguments we need to find out which one is missing.
- from inspect import getargspec
- args,varargs,varkw,defaults=getargspec(packager.package)
- if defaults!=None:
- args=args[:-len(defaults)] # throw away arguments with default values
+ #TODO: getargspec deprecated in Py3. cleanup when Py2.7 dropped.
+ try:
+ from inspect import getfullargspec
+ argspec = getfullargspec(packager.package)
+ except ImportError:
+ from inspect import getargspec
+ argspec = getargspec(packager.package)
+ args = argspec.args
+ if argspec.defaults:
+ # throw away arguments with default values
+ args = args[:-len(argspec.defaults)]
args.remove('env')
args.remove('target')
args.remove('source')
# now remove any args for which we have a value in kw.
- args=[x for x in args if x not in kw]
+ args = [x for x in args if x not in kw]
if len(args)==0:
raise # must be a different error, so re-raise
@@ -283,10 +295,9 @@ def stripinstallbuilder(target, source, env):
It also warns about files which have no install builder attached.
"""
def has_no_install_location(file):
- return not (file.has_builder() and\
- hasattr(file.builder, 'name') and\
- (file.builder.name=="InstallBuilder" or\
- file.builder.name=="InstallAsBuilder"))
+ return not (file.has_builder() and hasattr(file.builder, 'name')
+ and file.builder.name in ["InstallBuilder", "InstallAsBuilder"])
+
if len([src for src in source if has_no_install_location(src)]):
warn(Warning, "there are files to package which have no\
diff --git a/src/engine/SCons/Tool/packaging/__init__.xml b/src/engine/SCons/Tool/packaging/__init__.xml
index 0ee0f6b..1643def 100644
--- a/src/engine/SCons/Tool/packaging/__init__.xml
+++ b/src/engine/SCons/Tool/packaging/__init__.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -64,13 +64,15 @@ the following packagers available:
<para>
* msi - Microsoft Installer
- * rpm - Redhat Package Manger
+ * rpm - RPM Package Manger
* ipkg - Itsy Package Management System
- * tarbz2 - compressed tar
- * targz - compressed tar
+ * tarbz2 - bzip2 compressed tar
+ * targz - gzip compressed tar
+ * tarxz - xz compressed tar
* zip - zip file
- * src_tarbz2 - compressed tar source
- * src_targz - compressed tar source
+ * src_tarbz2 - bzip2 compressed tar source
+ * src_targz - gzip compressed tar source
+ * src_tarxz - xz compressed tar source
* src_zip - zip file source
</para>
@@ -106,7 +108,9 @@ This is used to fill in the
<literal>Architecture:</literal>
field in an Ipkg
<filename>control</filename> file,
-and as part of the name of a generated RPM file.
+and the <literal>BuildArch:</literal> field
+in the RPM <filename>.spec</filename> file,
+as well as forming part of the name of a generated RPM package file.
</para>
</summary>
</cvar>
@@ -120,7 +124,6 @@ the <filename>control</filename> for Ipkg,
the <filename>.wxs</filename> for MSI).
If set, the function will be called
after the SCons template for the file has been written.
-XXX
</para>
</summary>
</cvar>
@@ -164,10 +167,10 @@ section of an RPM
<cvar name="LICENSE">
<summary>
<para>
-The abbreviated name of the license under which
-this project is released (gpl, lpgl, bsd etc.).
+The abbreviated name, preferably the SPDX code, of the license under which
+this project is released (GPL-3.0, LGPL-2.1, BSD-2-Clause etc.).
See http://www.opensource.org/licenses/alphabetical
-for a list of license names.
+for a list of license names and SPDX codes.
</para>
</summary>
</cvar>
@@ -383,6 +386,7 @@ This is used to fill in the
<literal>BuildRequires:</literal>
field in the RPM
<filename>.spec</filename> file.
+Note this should only be used on a host managed by rpm as the dependencies will not be resolvable at build time otherwise.
</para>
</summary>
</cvar>
@@ -441,7 +445,8 @@ field in the RPM
<para>
This is used to fill in the
<literal>Epoch:</literal>
-field in the controlling information for RPM packages.
+field in the RPM
+<filename>.spec</filename> file.
</para>
</summary>
</cvar>
@@ -468,6 +473,38 @@ field in the RPM
</summary>
</cvar>
+<cvar name="X_RPM_EXTRADEFS">
+<summary>
+<para>
+A list used to supply extra defintions or flags
+to be added to the RPM <filename>.spec</filename> file.
+Each item is added as-is with a carriage return appended.
+This is useful if some specific RPM feature not otherwise
+anticipated by SCons needs to be turned on or off.
+Note if this variable is omitted, SCons will by
+default supply the value
+<literal>'%global debug_package %{nil}'</literal>
+to disable debug package generation.
+To enable debug package generation, include this
+variable set either to None, or to a custom
+list that does not include the default line.
+Added in version 3.1.
+</para>
+
+<example_commands>
+env.Package(
+ NAME = 'foo',
+...
+ X_RPM_EXTRADEFS = [
+ '%define _unpackaged_files_terminate_build 0'
+ '%define _missing_doc_files_terminate_build 0'
+ ],
+... )
+</example_commands>
+
+</summary>
+</cvar>
+
<cvar name="X_RPM_GROUP">
<summary>
<para>
diff --git a/src/engine/SCons/Tool/packaging/ipk.py b/src/engine/SCons/Tool/packaging/ipk.py
index 71fa2b0..dbf5be8 100644
--- a/src/engine/SCons/Tool/packaging/ipk.py
+++ b/src/engine/SCons/Tool/packaging/ipk.py
@@ -2,8 +2,8 @@
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
-#
+# Copyright (c) 2001 - 2019 The SCons Foundation
+#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -24,11 +24,13 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/ipk.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/ipk.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
import SCons.Builder
import SCons.Node.FS
-import os
+import SCons.Util
from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot
@@ -115,15 +117,17 @@ def build_specfiles(source, target, env):
#
#
opened_files={}
- def open_file(needle, haystack):
+ def open_file(needle, haystack=None):
try:
return opened_files[needle]
except KeyError:
- file=filter(lambda x: x.get_path().rfind(needle)!=-1, haystack)[0]
- opened_files[needle]=open(file.get_abspath(), 'w')
+ files = filter(lambda x: x.get_path().rfind(needle) != -1, haystack)
+ # Py3: filter returns an iterable, not a list
+ file = list(files)[0]
+ opened_files[needle] = open(file.get_abspath(), 'w')
return opened_files[needle]
- control_file=open_file('control', target)
+ control_file = open_file('control', target)
if 'X_IPK_DESCRIPTION' not in env:
env['X_IPK_DESCRIPTION']="%s\n %s"%(env['SUMMARY'],
@@ -145,7 +149,7 @@ Description: $X_IPK_DESCRIPTION
control_file.write(env.subst(content))
#
- # now handle the various other files, which purpose it is to set post-,
+ # now handle the various other files, which purpose it is to set post-,
# pre-scripts and mark files as config files.
#
# We do so by filtering the source files for files which are marked with
@@ -157,14 +161,14 @@ Description: $X_IPK_DESCRIPTION
# into the same named file.
#
for f in [x for x in source if 'PACKAGING_CONFIG' in dir(x)]:
- config=open_file('conffiles')
+ config = open_file('conffiles')
config.write(f.PACKAGING_INSTALL_LOCATION)
config.write('\n')
for str in 'POSTRM PRERM POSTINST PREINST'.split():
name="PACKAGING_X_IPK_%s"%str
for f in [x for x in source if name in dir(x)]:
- file=open_file(name)
+ file = open_file(name)
file.write(env[str])
#
diff --git a/src/engine/SCons/Tool/packaging/msi.py b/src/engine/SCons/Tool/packaging/msi.py
index 827ce76..4a48b47 100644
--- a/src/engine/SCons/Tool/packaging/msi.py
+++ b/src/engine/SCons/Tool/packaging/msi.py
@@ -4,7 +4,7 @@ The msi packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@ The msi packager.
# 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/packaging/msi.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/msi.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import SCons
@@ -63,8 +63,8 @@ def convert_to_id(s, id_set):
"""
charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz0123456789_.'
if s[0] in '0123456789.':
- s += '_'+s
- id = [c for c in s if c in charset]
+ s = '_' + s
+ id = ''.join([c for c in s if c in charset])
# did we already generate an id for this file?
try:
@@ -108,14 +108,13 @@ def gen_dos_short_file_name(file, filename_set):
# strip forbidden characters.
forbidden = '."/[]:;=, '
- fname = [c for c in fname if c not in forbidden]
+ fname = ''.join([c for c in fname if c not in forbidden])
# check if we already generated a filename with the same number:
# thisis1.txt, thisis2.txt etc.
duplicate, num = not None, 1
while duplicate:
- shortname = "%s%s" % (fname[:8-len(str(num))].upper(),\
- str(num))
+ shortname = "%s%s" % (fname[:8-len(str(num))].upper(), str(num))
if len(ext) >= 2:
shortname = "%s%s" % (shortname, ext[:4].upper())
@@ -189,7 +188,7 @@ def build_wxsfile(target, source, env):
""" Compiles a .wxs file from the keywords given in env['msi_spec'] and
by analyzing the tree of source nodes and their tags.
"""
- file = open(target[0].get_abspath(), 'w')
+ f = open(target[0].get_abspath(), 'w')
try:
# Create a document with the Wix root tag
@@ -210,7 +209,7 @@ def build_wxsfile(target, source, env):
build_license_file(target[0].get_dir(), env)
# write the xml to a file
- file.write( doc.toprettyxml() )
+ f.write( doc.toprettyxml() )
# call a user specified function
if 'CHANGE_SPECFILE' in env:
@@ -218,6 +217,8 @@ def build_wxsfile(target, source, env):
except KeyError as e:
raise SCons.Errors.UserError( '"%s" package field for MSI is missing.' % e.args[0] )
+ finally:
+ f.close()
#
# setup function
@@ -301,7 +302,7 @@ def build_wxsfile_file_section(root, files, NAME, VERSION, VENDOR, filename_set,
if c.nodeName == 'Directory'
and c.attributes['LongName'].value == escape(d)]
- if already_created != []:
+ if already_created:
Directory = already_created[0]
dir_parts.remove(d)
upper_dir += d
@@ -441,14 +442,13 @@ def build_license_file(directory, spec):
pass # ignore this as X_MSI_LICENSE_TEXT is optional
if name!='' or text!='':
- file = open( os.path.join(directory.get_path(), 'License.rtf'), 'w' )
- file.write('{\\rtf')
- if text!='':
- file.write(text.replace('\n', '\\par '))
- else:
- file.write(name+'\\par\\par')
- file.write('}')
- file.close()
+ with open(os.path.join(directory.get_path(), 'License.rtf'), 'w') as f:
+ f.write('{\\rtf')
+ if text!='':
+ f.write(text.replace('\n', '\\par '))
+ else:
+ f.write(name+'\\par\\par')
+ f.write('}')
#
# mandatory and optional package tags
diff --git a/src/engine/SCons/Tool/packaging/rpm.py b/src/engine/SCons/Tool/packaging/rpm.py
index 3c48b02..a948e29 100644
--- a/src/engine/SCons/Tool/packaging/rpm.py
+++ b/src/engine/SCons/Tool/packaging/rpm.py
@@ -4,7 +4,7 @@ The rpm packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@ The rpm packager.
# 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/packaging/rpm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/rpm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
@@ -51,10 +51,9 @@ def package(env, target, source, PACKAGEROOT, NAME, VERSION,
if str(target[0])!="%s-%s"%(NAME, VERSION):
raise UserError( "Setting target is not supported for rpm." )
else:
- # This should be overridable from the construction environment,
- # which it is by using ARCHITECTURE=.
+ # Deduce the build architecture, but allow it to be overridden
+ # by setting ARCHITECTURE in the construction env.
buildarchitecture = SCons.Tool.rpmutils.defaultMachine()
-
if 'ARCHITECTURE' in kw:
buildarchitecture = kw['ARCHITECTURE']
@@ -126,20 +125,18 @@ def build_specfile(target, source, env):
""" Builds a RPM specfile from a dictionary with string metadata and
by analyzing a tree of nodes.
"""
- file = open(target[0].get_abspath(), 'w')
-
- try:
- file.write( build_specfile_header(env) )
- file.write( build_specfile_sections(env) )
- file.write( build_specfile_filesection(env, source) )
- file.close()
+ with open(target[0].get_abspath(), 'w') as ofp:
+ try:
+ ofp.write(build_specfile_header(env))
+ ofp.write(build_specfile_sections(env))
+ ofp.write(build_specfile_filesection(env, source))
- # call a user specified function
- if 'CHANGE_SPECFILE' in env:
- env['CHANGE_SPECFILE'](target, source)
+ # call a user specified function
+ if 'CHANGE_SPECFILE' in env:
+ env['CHANGE_SPECFILE'](target, source)
- except KeyError as e:
- raise SCons.Errors.UserError( '"%s" package field for RPM is missing.' % e.args[0] )
+ except KeyError as e:
+ raise SCons.Errors.UserError('"%s" package field for RPM is missing.' % e.args[0])
#
@@ -201,7 +198,8 @@ def build_specfile_header(spec):
'PACKAGEVERSION' : '%%define release %s\nRelease: %%{release}\n',
'X_RPM_GROUP' : 'Group: %s\n',
'SUMMARY' : 'Summary: %s\n',
- 'LICENSE' : 'License: %s\n', }
+ 'LICENSE' : 'License: %s\n',
+ }
str = str + SimpleTagCompiler(mandatory_header_fields).compile( spec )
@@ -211,6 +209,7 @@ def build_specfile_header(spec):
'X_RPM_URL' : 'Url: %s\n',
'SOURCE_URL' : 'Source: %s\n',
'SUMMARY_' : 'Summary(%s): %s\n',
+ 'ARCHITECTURE' : 'BuildArch: %s\n',
'X_RPM_DISTRIBUTION' : 'Distribution: %s\n',
'X_RPM_ICON' : 'Icon: %s\n',
'X_RPM_PACKAGER' : 'Packager: %s\n',
@@ -229,19 +228,33 @@ def build_specfile_header(spec):
'X_RPM_PREFIX' : 'Prefix: %s\n',
# internal use
- 'X_RPM_BUILDROOT' : 'BuildRoot: %s\n', }
+ 'X_RPM_BUILDROOT' : 'BuildRoot: %s\n',
+ }
# fill in default values:
- # Adding a BuildRequires renders the .rpm unbuildable under System, which
+ # Adding a BuildRequires renders the .rpm unbuildable under systems which
# are not managed by rpm, since the database to resolve this dependency is
# missing (take Gentoo as an example)
-# if not s.has_key('x_rpm_BuildRequires'):
-# s['x_rpm_BuildRequires'] = 'scons'
+ #if 'X_RPM_BUILDREQUIRES' not in spec:
+ # spec['X_RPM_BUILDREQUIRES'] = 'scons'
if 'X_RPM_BUILDROOT' not in spec:
spec['X_RPM_BUILDROOT'] = '%{_tmppath}/%{name}-%{version}-%{release}'
str = str + SimpleTagCompiler(optional_header_fields, mandatory=0).compile( spec )
+
+ # Add any extra specfile definitions the user may have supplied.
+ # These flags get no processing, they are just added.
+ # github #3164: if we don't turn off debug package generation
+ # the tests which build packages all fail. If there are no
+ # extra flags, default to adding this one. If the user wants
+ # to turn this back on, supply the flag set to None.
+
+ if 'X_RPM_EXTRADEFS' not in spec:
+ spec['X_RPM_EXTRADEFS'] = ['%global debug_package %{nil}']
+ for extra in spec['X_RPM_EXTRADEFS']:
+ str += extra + '\n'
+
return str
#
diff --git a/src/engine/SCons/Tool/packaging/src_tarbz2.py b/src/engine/SCons/Tool/packaging/src_tarbz2.py
index b40e550..b628ccd 100644
--- a/src/engine/SCons/Tool/packaging/src_tarbz2.py
+++ b/src/engine/SCons/Tool/packaging/src_tarbz2.py
@@ -1,10 +1,10 @@
-"""SCons.Tool.Packaging.tarbz2
+"""SCons.Tool.Packaging.src_tarbz2
The tarbz2 SRC packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The tarbz2 SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/src_tarbz2.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/src_tarbz2.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import putintopackageroot
diff --git a/src/engine/SCons/Tool/packaging/src_targz.py b/src/engine/SCons/Tool/packaging/src_targz.py
index 01fc91a..4c7469c 100644
--- a/src/engine/SCons/Tool/packaging/src_targz.py
+++ b/src/engine/SCons/Tool/packaging/src_targz.py
@@ -1,10 +1,10 @@
-"""SCons.Tool.Packaging.targz
+"""SCons.Tool.Packaging.src_targz
The targz SRC packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The targz SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/src_targz.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/src_targz.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import putintopackageroot
diff --git a/src/engine/SCons/Options/BoolOption.py b/src/engine/SCons/Tool/packaging/src_tarxz.py
index 5960a2e..6688c46 100644
--- a/src/engine/SCons/Options/BoolOption.py
+++ b/src/engine/SCons/Tool/packaging/src_tarxz.py
@@ -1,5 +1,10 @@
+"""SCons.Tool.Packaging.src_tarxz
+
+The tarxz SRC packager.
+"""
+
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,27 +26,15 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Options/BoolOption.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
+__revision__ = "src/engine/SCons/Tool/packaging/src_tarxz.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-warned = False
+from SCons.Tool.packaging import putintopackageroot
-def BoolOption(*args, **kw):
- global warned
- if not warned:
- msg = "The BoolOption() function is deprecated; use the BoolVariable() function instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
- return SCons.Variables.BoolVariable(*args, **kw)
+def package(env, target, source, PACKAGEROOT, **kw):
+ bld = env['BUILDERS']['Tar']
+ bld.set_suffix('.tar.xz')
+ target, source = putintopackageroot(target, source, env, PACKAGEROOT, honor_install_location=0)
+ return bld(env, target, source, TARFLAGS='-Jc')
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/packaging/src_zip.py b/src/engine/SCons/Tool/packaging/src_zip.py
index ea21a87..d56f3aa 100644
--- a/src/engine/SCons/Tool/packaging/src_zip.py
+++ b/src/engine/SCons/Tool/packaging/src_zip.py
@@ -4,7 +4,7 @@ The zip SRC packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The zip SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/src_zip.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/src_zip.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import putintopackageroot
diff --git a/src/engine/SCons/Tool/packaging/tarbz2.py b/src/engine/SCons/Tool/packaging/tarbz2.py
index c919cab..e371f1b 100644
--- a/src/engine/SCons/Tool/packaging/tarbz2.py
+++ b/src/engine/SCons/Tool/packaging/tarbz2.py
@@ -1,10 +1,10 @@
"""SCons.Tool.Packaging.tarbz2
-The tarbz2 SRC packager.
+The tarbz2 packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +26,13 @@ The tarbz2 SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/tarbz2.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/tarbz2.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot
def package(env, target, source, PACKAGEROOT, **kw):
bld = env['BUILDERS']['Tar']
- bld.set_suffix('.tar.gz')
+ bld.set_suffix('.tar.bz2')
target, source = putintopackageroot(target, source, env, PACKAGEROOT)
target, source = stripinstallbuilder(target, source, env)
return bld(env, target, source, TARFLAGS='-jc')
diff --git a/src/engine/SCons/Tool/packaging/targz.py b/src/engine/SCons/Tool/packaging/targz.py
index e9e984e..121e4a4 100644
--- a/src/engine/SCons/Tool/packaging/targz.py
+++ b/src/engine/SCons/Tool/packaging/targz.py
@@ -1,10 +1,10 @@
"""SCons.Tool.Packaging.targz
-The targz SRC packager.
+The targz packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The targz SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/targz.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/targz.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot
diff --git a/src/engine/SCons/Options/EnumOption.py b/src/engine/SCons/Tool/packaging/tarxz.py
index 5e030d9..3ec9822 100644
--- a/src/engine/SCons/Options/EnumOption.py
+++ b/src/engine/SCons/Tool/packaging/tarxz.py
@@ -1,5 +1,10 @@
+"""SCons.Tool.Packaging.tarxz
+
+The tarxz packager.
+"""
+
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,27 +26,16 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Options/EnumOption.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
-
-__doc__ = """Place-holder for the old SCons.Options module hierarchy
-
-This is for backwards compatibility. The new equivalent is the Variables/
-class hierarchy. These will have deprecation warnings added (some day),
-and will then be removed entirely (some day).
-"""
-
-import SCons.Variables
-import SCons.Warnings
+__revision__ = "src/engine/SCons/Tool/packaging/tarxz.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-warned = False
+from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot
-def EnumOption(*args, **kw):
- global warned
- if not warned:
- msg = "The EnumOption() function is deprecated; use the EnumVariable() function instead."
- SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg)
- warned = True
- return SCons.Variables.EnumVariable(*args, **kw)
+def package(env, target, source, PACKAGEROOT, **kw):
+ bld = env['BUILDERS']['Tar']
+ bld.set_suffix('.tar.xz')
+ target, source = putintopackageroot(target, source, env, PACKAGEROOT)
+ target, source = stripinstallbuilder(target, source, env)
+ return bld(env, target, source, TARFLAGS='-Jc')
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/packaging/zip.py b/src/engine/SCons/Tool/packaging/zip.py
index 3b80ead..11ab3b5 100644
--- a/src/engine/SCons/Tool/packaging/zip.py
+++ b/src/engine/SCons/Tool/packaging/zip.py
@@ -4,7 +4,7 @@ The zip SRC packager.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ The zip SRC packager.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/packaging/zip.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/packaging/zip.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Tool.packaging import stripinstallbuilder, putintopackageroot
diff --git a/src/engine/SCons/Tool/pdf.py b/src/engine/SCons/Tool/pdf.py
index 381732a..50988b6 100644
--- a/src/engine/SCons/Tool/pdf.py
+++ b/src/engine/SCons/Tool/pdf.py
@@ -6,7 +6,7 @@ Add an explicit action to run epstopdf to convert .eps files to .pdf
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Add an explicit action to run epstopdf to convert .eps files to .pdf
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/pdf.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/pdf.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Builder
import SCons.Tool
diff --git a/src/engine/SCons/Tool/pdf.xml b/src/engine/SCons/Tool/pdf.xml
index 9688a6f..876de15 100644
--- a/src/engine/SCons/Tool/pdf.xml
+++ b/src/engine/SCons/Tool/pdf.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/pdflatex.py b/src/engine/SCons/Tool/pdflatex.py
index d539770..2c559f7 100644
--- a/src/engine/SCons/Tool/pdflatex.py
+++ b/src/engine/SCons/Tool/pdflatex.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/pdflatex.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/pdflatex.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Util
diff --git a/src/engine/SCons/Tool/pdflatex.xml b/src/engine/SCons/Tool/pdflatex.xml
index 4dae90b..975d5e9 100644
--- a/src/engine/SCons/Tool/pdflatex.xml
+++ b/src/engine/SCons/Tool/pdflatex.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/pdftex.py b/src/engine/SCons/Tool/pdftex.py
index 06e9d7c..c658aa0 100644
--- a/src/engine/SCons/Tool/pdftex.py
+++ b/src/engine/SCons/Tool/pdftex.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/pdftex.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/pdftex.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import SCons.Action
diff --git a/src/engine/SCons/Tool/pdftex.xml b/src/engine/SCons/Tool/pdftex.xml
index e84296a..0a265e7 100644
--- a/src/engine/SCons/Tool/pdftex.xml
+++ b/src/engine/SCons/Tool/pdftex.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/qt.py b/src/engine/SCons/Tool/qt.py
index e7c1b95..a582e6f 100644
--- a/src/engine/SCons/Tool/qt.py
+++ b/src/engine/SCons/Tool/qt.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,10 +33,11 @@ selection method.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/qt.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/qt.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import re
+import glob
import SCons.Action
import SCons.Builder
@@ -44,6 +45,8 @@ import SCons.Defaults
import SCons.Scanner
import SCons.Tool
import SCons.Util
+import SCons.Tool.cxx
+cplusplus = SCons.Tool.cxx
class ToolQtWarning(SCons.Warnings.Warning):
pass
@@ -60,12 +63,40 @@ header_extensions = [".h", ".hxx", ".hpp", ".hh"]
if SCons.Util.case_sensitive_suffixes('.h', '.H'):
header_extensions.append('.H')
-import SCons.Tool.cxx
-cplusplus = SCons.Tool.cxx
-#cplusplus = __import__('cxx', globals(), locals(), [])
-
cxx_suffixes = cplusplus.CXXSuffixes
+
+def find_platform_specific_qt_paths():
+ """
+ find non-standard QT paths
+
+ If the platform does not put QT tools in standard search paths,
+ the path is expected to be set using QTDIR. SCons violates
+ the normal rule of not pulling from the user's environment
+ in this case. However, some test cases try to validate what
+ happens when QTDIR is unset, so we need to try to make a guess.
+
+ :return: a guess at a path
+ """
+
+ # qt_bin_dirs = []
+ qt_bin_dir = None
+ if os.path.isfile('/etc/redhat-release'):
+ with open('/etc/redhat-release','r') as rr:
+ lines = rr.readlines()
+ distro = lines[0].split()[0]
+ if distro == 'CentOS':
+ # Centos installs QT under /usr/{lib,lib64}/qt{4,5,-3.3}/bin
+ # so we need to handle this differently
+ # qt_bin_dirs = glob.glob('/usr/lib64/qt*/bin')
+ # TODO: all current Fedoras do the same, need to look deeper here.
+ qt_bin_dir = '/usr/lib64/qt-3.3/bin'
+
+ return qt_bin_dir
+
+
+QT_BIN_DIR = find_platform_specific_qt_paths()
+
def checkMocIncluded(target, source, env):
moc = target[0]
cpp = source[0]
@@ -73,7 +104,7 @@ def checkMocIncluded(target, source, env):
# not really sure about the path transformations (moc.cwd? cpp.cwd?) :-/
path = SCons.Defaults.CScan.path(env, moc.cwd)
includes = SCons.Defaults.CScan(cpp, env, path)
- if not moc in includes:
+ if moc not in includes:
SCons.Warnings.warn(
GeneratedMocFileNotIncluded,
"Generated moc file '%s' is not included by '%s'" %
@@ -94,7 +125,7 @@ class _Automoc(object):
def __init__(self, objBuilderName):
self.objBuilderName = objBuilderName
-
+
def __call__(self, target, source, env):
"""
Smart autoscan function. Gets the list of objects for the Program
@@ -109,25 +140,25 @@ class _Automoc(object):
debug = int(env.subst('$QT_DEBUG'))
except ValueError:
debug = 0
-
+
# some shortcuts used in the scanner
splitext = SCons.Util.splitext
objBuilder = getattr(env, self.objBuilderName)
-
+
# some regular expressions:
# Q_OBJECT detection
- q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]')
+ q_object_search = re.compile(r'[^A-Za-z0-9]Q_OBJECT[^A-Za-z0-9]')
# cxx and c comment 'eater'
#comment = re.compile(r'(//.*)|(/\*(([^*])|(\*[^/]))*\*/)')
# CW: something must be wrong with the regexp. See also bug #998222
# CURRENTLY THERE IS NO TEST CASE FOR THAT
-
+
# The following is kind of hacky to get builders working properly (FIXME)
objBuilderEnv = objBuilder.env
objBuilder.env = env
mocBuilderEnv = env.Moc.env
env.Moc.env = env
-
+
# make a deep copy for the result; MocH objects will be appended
out_sources = source[:]
@@ -140,7 +171,7 @@ class _Automoc(object):
cpp = obj.sources[0]
if not splitext(str(cpp))[1] in cxx_suffixes:
if debug:
- print("scons: qt: '%s' is no cxx file. Discarded." % str(cpp))
+ print("scons: qt: '%s' is no cxx file. Discarded." % str(cpp))
# c or fortran source
continue
#cpp_contents = comment.sub('', cpp.get_text_contents())
@@ -188,13 +219,12 @@ AutomocStatic = _Automoc('StaticObject')
def _detect(env):
"""Not really safe, but fast method to detect the QT library"""
- QTDIR = None
- if not QTDIR:
- QTDIR = env.get('QTDIR',None)
+
+ QTDIR = env.get('QTDIR',None)
if not QTDIR:
QTDIR = os.environ.get('QTDIR',None)
if not QTDIR:
- moc = env.WhereIs('moc')
+ moc = env.WhereIs('moc') or env.WhereIs('moc',QT_BIN_DIR)
if moc:
QTDIR = os.path.dirname(os.path.dirname(moc))
SCons.Warnings.warn(
@@ -237,7 +267,7 @@ def uicScannerFunc(node, env, path):
return result
uicScanner = SCons.Scanner.Base(uicScannerFunc,
- name = "UicScanner",
+ name = "UicScanner",
node_class = SCons.Node.FS.File,
node_factory = SCons.Node.FS.File,
recursive = 0)
@@ -313,7 +343,7 @@ def generate(env):
mocBld.prefix[cxx] = '$QT_MOCCXXPREFIX'
mocBld.suffix[cxx] = '$QT_MOCCXXSUFFIX'
- # register the builders
+ # register the builders
env['BUILDERS']['Uic'] = uicBld
env['BUILDERS']['Moc'] = mocBld
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
diff --git a/src/engine/SCons/Tool/qt.xml b/src/engine/SCons/Tool/qt.xml
index 86d50d6..560a11d 100644
--- a/src/engine/SCons/Tool/qt.xml
+++ b/src/engine/SCons/Tool/qt.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/rmic.py b/src/engine/SCons/Tool/rmic.py
index 9e1eaee..d6f7b2b 100644
--- a/src/engine/SCons/Tool/rmic.py
+++ b/src/engine/SCons/Tool/rmic.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/rmic.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/rmic.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
@@ -40,6 +40,9 @@ import SCons.Builder
import SCons.Node.FS
import SCons.Util
+from SCons.Tool.JavaCommon import get_java_install_dirs
+
+
def emit_rmic_classes(target, source, env):
"""Create and return lists of Java RMI stub and skeleton
class files to be created from a set of class files.
@@ -105,6 +108,16 @@ def generate(env):
"""Add Builders and construction variables for rmic to an Environment."""
env['BUILDERS']['RMIC'] = RMICBuilder
+ if env['PLATFORM'] == 'win32':
+ version = env.get('JAVAVERSION', None)
+ # Ensure that we have a proper path for rmic
+ paths = get_java_install_dirs('win32', version=version)
+ rmic = SCons.Tool.find_program_path(env, 'rmic', default_paths=paths)
+ # print("RMIC: %s"%rmic)
+ if rmic:
+ rmic_bin_dir = os.path.dirname(rmic)
+ env.AppendENVPath('PATH', rmic_bin_dir)
+
env['RMIC'] = 'rmic'
env['RMICFLAGS'] = SCons.Util.CLVar('')
env['RMICCOM'] = '$RMIC $RMICFLAGS -d ${TARGET.attributes.java_lookupdir} -classpath ${SOURCE.attributes.java_classdir} ${SOURCES.attributes.java_classname}'
diff --git a/src/engine/SCons/Tool/rmic.xml b/src/engine/SCons/Tool/rmic.xml
index 2b0d42b..2a273d3 100644
--- a/src/engine/SCons/Tool/rmic.xml
+++ b/src/engine/SCons/Tool/rmic.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/rpcgen.py b/src/engine/SCons/Tool/rpcgen.py
index 1f2c66d..b9f8ca6 100644
--- a/src/engine/SCons/Tool/rpcgen.py
+++ b/src/engine/SCons/Tool/rpcgen.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/rpcgen.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/rpcgen.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from SCons.Builder import Builder
import SCons.Util
@@ -43,7 +43,7 @@ rpcgen_service = cmd % ('m', '$RPCGENSERVICEFLAGS')
rpcgen_xdr = cmd % ('c', '$RPCGENXDRFLAGS')
def generate(env):
- "Add RPCGEN Builders and construction variables for an Environment."
+ """Add RPCGEN Builders and construction variables for an Environment."""
client = Builder(action=rpcgen_client, suffix='_clnt.c', src_suffix='.x')
header = Builder(action=rpcgen_header, suffix='.h', src_suffix='.x')
diff --git a/src/engine/SCons/Tool/rpcgen.xml b/src/engine/SCons/Tool/rpcgen.xml
index 60f216e..1ee9df9 100644
--- a/src/engine/SCons/Tool/rpcgen.xml
+++ b/src/engine/SCons/Tool/rpcgen.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/rpm.py b/src/engine/SCons/Tool/rpm.py
index 5cd97b3..0253365 100644
--- a/src/engine/SCons/Tool/rpm.py
+++ b/src/engine/SCons/Tool/rpm.py
@@ -11,7 +11,7 @@ tar.gz consisting of the source file and a specfile.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ tar.gz consisting of the source file and a specfile.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/rpm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/rpm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import re
@@ -51,43 +51,44 @@ def get_cmd(source, env):
if SCons.Util.is_List(source):
tar_file_with_included_specfile = source[0]
return "%s %s %s"%(env['RPM'], env['RPMFLAGS'],
- tar_file_with_included_specfile.get_abspath() )
+ tar_file_with_included_specfile.get_abspath())
def build_rpm(target, source, env):
# create a temporary rpm build root.
- tmpdir = os.path.join( os.path.dirname( target[0].get_abspath() ), 'rpmtemp' )
+ tmpdir = os.path.join(os.path.dirname(target[0].get_abspath()), 'rpmtemp')
if os.path.exists(tmpdir):
shutil.rmtree(tmpdir)
# now create the mandatory rpm directory structure.
for d in ['RPMS', 'SRPMS', 'SPECS', 'BUILD']:
- os.makedirs( os.path.join( tmpdir, d ) )
+ os.makedirs(os.path.join(tmpdir, d))
# set the topdir as an rpmflag.
- env.Prepend( RPMFLAGS = '--define \'_topdir %s\'' % tmpdir )
+ env.Prepend(RPMFLAGS = '--define \'_topdir %s\'' % tmpdir)
# now call rpmbuild to create the rpm package.
handle = subprocess.Popen(get_cmd(source, env),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True)
- output = SCons.Util.to_str(handle.stdout.read())
+ with handle.stdout:
+ output = SCons.Util.to_str(handle.stdout.read())
status = handle.wait()
if status:
- raise SCons.Errors.BuildError( node=target[0],
- errstr=output,
- filename=str(target[0]) )
+ raise SCons.Errors.BuildError(node=target[0],
+ errstr=output,
+ filename=str(target[0]))
else:
# XXX: assume that LC_ALL=C is set while running rpmbuild
- output_files = re.compile( 'Wrote: (.*)' ).findall( output )
+ output_files = re.compile('Wrote: (.*)').findall(output)
- for output, input in zip( output_files, target ):
+ for output, input in zip(output_files, target):
rpm_output = os.path.basename(output)
expected = os.path.basename(input.get_path())
assert expected == rpm_output, "got %s but expected %s" % (rpm_output, expected)
- shutil.copy( output, input.get_abspath() )
+ shutil.copy(output, input.get_abspath())
# cleanup before leaving.
diff --git a/src/engine/SCons/Tool/rpmutils.py b/src/engine/SCons/Tool/rpmutils.py
index f71d664..a2400ff 100644
--- a/src/engine/SCons/Tool/rpmutils.py
+++ b/src/engine/SCons/Tool/rpmutils.py
@@ -14,7 +14,7 @@ exact syntax.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -36,7 +36,7 @@ exact syntax.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/rpmutils.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/rpmutils.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import platform
@@ -482,9 +482,11 @@ def updateRpmDicts(rpmrc, pyfile):
"""
try:
# Read old rpmutils.py file
- oldpy = open(pyfile,"r").readlines()
+ with open(pyfile,"r") as f:
+ oldpy = f.readlines()
# Read current rpmrc.in file
- rpm = open(rpmrc,"r").readlines()
+ with open(rpmrc,"r") as f:
+ rpm = f.readlines()
# Parse for data
data = {}
# Allowed section names that get parsed
@@ -511,24 +513,23 @@ def updateRpmDicts(rpmrc, pyfile):
# Insert data
data[key][tokens[1]] = tokens[2:]
# Write new rpmutils.py file
- out = open(pyfile,"w")
- pm = 0
- for l in oldpy:
- if pm:
- if l.startswith('# End of rpmrc dictionaries'):
- pm = 0
+ with open(pyfile,"w") as out:
+ pm = 0
+ for l in oldpy:
+ if pm:
+ if l.startswith('# End of rpmrc dictionaries'):
+ pm = 0
+ out.write(l)
+ else:
out.write(l)
- else:
- out.write(l)
- if l.startswith('# Start of rpmrc dictionaries'):
- pm = 1
- # Write data sections to single dictionaries
- for key, entries in data.items():
- out.write("%s = {\n" % key)
- for arch in sorted(entries.keys()):
- out.write(" '%s' : ['%s'],\n" % (arch, "','".join(entries[arch])))
- out.write("}\n\n")
- out.close()
+ if l.startswith('# Start of rpmrc dictionaries'):
+ pm = 1
+ # Write data sections to single dictionaries
+ for key, entries in data.items():
+ out.write("%s = {\n" % key)
+ for arch in sorted(entries.keys()):
+ out.write(" '%s' : ['%s'],\n" % (arch, "','".join(entries[arch])))
+ out.write("}\n\n")
except:
pass
diff --git a/src/engine/SCons/Tool/sgiar.py b/src/engine/SCons/Tool/sgiar.py
index a421cc1..d82ec89 100644
--- a/src/engine/SCons/Tool/sgiar.py
+++ b/src/engine/SCons/Tool/sgiar.py
@@ -11,7 +11,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/sgiar.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sgiar.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/sgiar.xml b/src/engine/SCons/Tool/sgiar.xml
index ffbc80e..6d28475 100644
--- a/src/engine/SCons/Tool/sgiar.xml
+++ b/src/engine/SCons/Tool/sgiar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sgic++.py b/src/engine/SCons/Tool/sgic++.py
index 7a9b1e9..84d775a 100644
--- a/src/engine/SCons/Tool/sgic++.py
+++ b/src/engine/SCons/Tool/sgic++.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sgic++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sgic++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
from SCons.Tool.sgicxx import *
diff --git a/src/engine/SCons/Tool/sgic++.xml b/src/engine/SCons/Tool/sgic++.xml
index 03ca3b1..bab0392 100644
--- a/src/engine/SCons/Tool/sgic++.xml
+++ b/src/engine/SCons/Tool/sgic++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sgicc.py b/src/engine/SCons/Tool/sgicc.py
index e9f561d..537f1a3 100644
--- a/src/engine/SCons/Tool/sgicc.py
+++ b/src/engine/SCons/Tool/sgicc.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sgicc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sgicc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
from . import cc
diff --git a/src/engine/SCons/Tool/sgicc.xml b/src/engine/SCons/Tool/sgicc.xml
index 1e12bf3..f26944b 100644
--- a/src/engine/SCons/Tool/sgicc.xml
+++ b/src/engine/SCons/Tool/sgicc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sgicxx.py b/src/engine/SCons/Tool/sgicxx.py
index 61c415b..d44ec26 100644
--- a/src/engine/SCons/Tool/sgicxx.py
+++ b/src/engine/SCons/Tool/sgicxx.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sgicxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sgicxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/sgilink.py b/src/engine/SCons/Tool/sgilink.py
index c327151..ca9e69c 100644
--- a/src/engine/SCons/Tool/sgilink.py
+++ b/src/engine/SCons/Tool/sgilink.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sgilink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sgilink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/sgilink.xml b/src/engine/SCons/Tool/sgilink.xml
index ede0eed..7cc9818 100644
--- a/src/engine/SCons/Tool/sgilink.xml
+++ b/src/engine/SCons/Tool/sgilink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sunar.py b/src/engine/SCons/Tool/sunar.py
index cd1e18d..07d45b2 100644
--- a/src/engine/SCons/Tool/sunar.py
+++ b/src/engine/SCons/Tool/sunar.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sunar.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunar.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Defaults
import SCons.Tool
diff --git a/src/engine/SCons/Tool/sunar.xml b/src/engine/SCons/Tool/sunar.xml
index b97e6a2..97d1a05 100644
--- a/src/engine/SCons/Tool/sunar.xml
+++ b/src/engine/SCons/Tool/sunar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sunc++.py b/src/engine/SCons/Tool/sunc++.py
index 1219bcf..1611fe9 100644
--- a/src/engine/SCons/Tool/sunc++.py
+++ b/src/engine/SCons/Tool/sunc++.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sunc++.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunc++.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
#forward proxy to the preffered cxx version
diff --git a/src/engine/SCons/Tool/sunc++.xml b/src/engine/SCons/Tool/sunc++.xml
index 2e7b220..d1d0160 100644
--- a/src/engine/SCons/Tool/sunc++.xml
+++ b/src/engine/SCons/Tool/sunc++.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/suncc.py b/src/engine/SCons/Tool/suncc.py
index bc4eb4f..da6ca6e 100644
--- a/src/engine/SCons/Tool/suncc.py
+++ b/src/engine/SCons/Tool/suncc.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/suncc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/suncc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/suncc.xml b/src/engine/SCons/Tool/suncc.xml
index 61cfb30..f191eda 100644
--- a/src/engine/SCons/Tool/suncc.xml
+++ b/src/engine/SCons/Tool/suncc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/suncxx.py b/src/engine/SCons/Tool/suncxx.py
index 1545500..1ee1c6a 100644
--- a/src/engine/SCons/Tool/suncxx.py
+++ b/src/engine/SCons/Tool/suncxx.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/suncxx.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/suncxx.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons
@@ -52,11 +52,17 @@ def get_package_info(package_name, pkginfo, pkgchk):
version = None
pathname = None
try:
- sadm_contents = open('/var/sadm/install/contents', 'r').read()
+ from subprocess import DEVNULL # py3k
+ except ImportError:
+ DEVNULL = open(os.devnull, 'wb')
+
+ try:
+ with open('/var/sadm/install/contents', 'r') as f:
+ sadm_contents = f.read()
except EnvironmentError:
pass
else:
- sadm_re = re.compile('^(\S*/bin/CC)(=\S*)? %s$' % package_name, re.M)
+ sadm_re = re.compile(r'^(\S*/bin/CC)(=\S*)? %s$' % package_name, re.M)
sadm_match = sadm_re.search(sadm_contents)
if sadm_match:
pathname = os.path.dirname(sadm_match.group(1))
@@ -64,12 +70,12 @@ def get_package_info(package_name, pkginfo, pkgchk):
try:
p = subprocess.Popen([pkginfo, '-l', package_name],
stdout=subprocess.PIPE,
- stderr=open('/dev/null', 'w'))
+ stderr=DEVNULL)
except EnvironmentError:
pass
else:
pkginfo_contents = p.communicate()[0]
- version_re = re.compile('^ *VERSION:\s*(.*)$', re.M)
+ version_re = re.compile(r'^ *VERSION:\s*(.*)$', re.M)
version_match = version_re.search(pkginfo_contents)
if version_match:
version = version_match.group(1)
@@ -78,7 +84,7 @@ def get_package_info(package_name, pkginfo, pkgchk):
try:
p = subprocess.Popen([pkgchk, '-l', package_name],
stdout=subprocess.PIPE,
- stderr=open('/dev/null', 'w'))
+ stderr=DEVNULL)
except EnvironmentError:
pass
else:
diff --git a/src/engine/SCons/Tool/sunf77.py b/src/engine/SCons/Tool/sunf77.py
index 9842d31..c1c216f 100644
--- a/src/engine/SCons/Tool/sunf77.py
+++ b/src/engine/SCons/Tool/sunf77.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sunf77.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunf77.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/sunf77.xml b/src/engine/SCons/Tool/sunf77.xml
index 8f6ecaf..fafcb8d 100644
--- a/src/engine/SCons/Tool/sunf77.xml
+++ b/src/engine/SCons/Tool/sunf77.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sunf90.py b/src/engine/SCons/Tool/sunf90.py
index 7245f99..4cabee8 100644
--- a/src/engine/SCons/Tool/sunf90.py
+++ b/src/engine/SCons/Tool/sunf90.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sunf90.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunf90.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/sunf90.xml b/src/engine/SCons/Tool/sunf90.xml
index 8f151fe..f979e15 100644
--- a/src/engine/SCons/Tool/sunf90.xml
+++ b/src/engine/SCons/Tool/sunf90.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sunf95.py b/src/engine/SCons/Tool/sunf95.py
index aae8828..077b1bc 100644
--- a/src/engine/SCons/Tool/sunf95.py
+++ b/src/engine/SCons/Tool/sunf95.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/sunf95.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunf95.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Util
diff --git a/src/engine/SCons/Tool/sunf95.xml b/src/engine/SCons/Tool/sunf95.xml
index a2c77da..4072d36 100644
--- a/src/engine/SCons/Tool/sunf95.xml
+++ b/src/engine/SCons/Tool/sunf95.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/sunlink.py b/src/engine/SCons/Tool/sunlink.py
index 175157f..8d965fa 100644
--- a/src/engine/SCons/Tool/sunlink.py
+++ b/src/engine/SCons/Tool/sunlink.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/sunlink.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/sunlink.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import os.path
diff --git a/src/engine/SCons/Tool/sunlink.xml b/src/engine/SCons/Tool/sunlink.xml
index b652f5c..68eee54 100644
--- a/src/engine/SCons/Tool/sunlink.xml
+++ b/src/engine/SCons/Tool/sunlink.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/swig.py b/src/engine/SCons/Tool/swig.py
index dedf103..2e61b91 100644
--- a/src/engine/SCons/Tool/swig.py
+++ b/src/engine/SCons/Tool/swig.py
@@ -10,7 +10,7 @@ selection method.
from __future__ import print_function
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,9 +32,10 @@ from __future__ import print_function
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/swig.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/swig.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
+import sys
import re
import subprocess
@@ -69,7 +70,9 @@ def _find_modules(src):
directors = 0
mnames = []
try:
- matches = _reModule.findall(open(src).read())
+ with open(src) as f:
+ data = f.read()
+ matches = _reModule.findall(data)
except IOError:
# If the file's not yet generated, guess the module name from the file stem
matches = []
@@ -134,21 +137,31 @@ def _swigEmitter(target, source, env):
def _get_swig_version(env, swig):
"""Run the SWIG command line tool to get and return the version number"""
+ version = None
swig = env.subst(swig)
+ if not swig:
+ return version
pipe = SCons.Action._subproc(env, SCons.Util.CLVar(swig) + ['-version'],
stdin = 'devnull',
stderr = 'devnull',
stdout = subprocess.PIPE)
- if pipe.wait() != 0: return
+ if pipe.wait() != 0:
+ return version
# MAYBE: out = SCons.Util.to_str (pipe.stdout.read())
- out = SCons.Util.to_str(pipe.stdout.read())
- match = re.search('SWIG Version\s+(\S+).*', out, re.MULTILINE)
+ with pipe.stdout:
+ out = SCons.Util.to_str(pipe.stdout.read())
+
+ match = re.search(r'SWIG Version\s+(\S+).*', out, re.MULTILINE)
if match:
- if verbose: print("Version is:%s"%match.group(1))
- return match.group(1)
+ version = match.group(1)
+ if verbose:
+ print("Version is: %s" % version)
else:
- if verbose: print("Unable to detect version: [%s]"%out)
+ if verbose:
+ print("Unable to detect version: [%s]" % out)
+
+ return version
def generate(env):
"""Add Builders and construction variables for swig to an Environment."""
@@ -169,6 +182,18 @@ def generate(env):
java_file.add_action('.i', SwigAction)
java_file.add_emitter('.i', _swigEmitter)
+ from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+ from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+ from SCons.Platform.win32 import CHOCO_DEFAULT_PATH
+
+ if sys.platform == 'win32':
+ swig = SCons.Tool.find_program_path(env, 'swig', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS + CHOCO_DEFAULT_PATH)
+ if swig:
+ swig_bin_dir = os.path.dirname(swig)
+ env.AppendENVPath('PATH', swig_bin_dir)
+ else:
+ SCons.Warnings.Warning('swig tool requested, but binary not found in ENV PATH')
+
if 'SWIG' not in env:
env['SWIG'] = env.Detect(swigs) or swigs[0]
env['SWIGVERSION'] = _get_swig_version(env, env['SWIG'])
diff --git a/src/engine/SCons/Tool/swig.xml b/src/engine/SCons/Tool/swig.xml
index 53d92ef..65a5971 100644
--- a/src/engine/SCons/Tool/swig.xml
+++ b/src/engine/SCons/Tool/swig.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -153,7 +153,8 @@ An automatically-generated construction variable
containing the SWIG command-line options
for specifying directories to be searched for included files.
The value of &cv-_SWIGINCFLAGS; is created
-by appending &cv-SWIGINCPREFIX; and &cv-SWIGINCSUFFIX;
+by respectively prepending and appending
+&cv-SWIGINCPREFIX; and &cv-SWIGINCSUFFIX;
to the beginning and end
of each directory in &cv-SWIGPATH;.
</para>
@@ -164,7 +165,7 @@ of each directory in &cv-SWIGPATH;.
<summary>
<para>
The prefix used to specify an include directory on the SWIG command line.
-This will be appended to the beginning of each directory
+This will be prepended to the beginning of each directory
in the &cv-SWIGPATH; construction variable
when the &cv-_SWIGINCFLAGS; variable is automatically generated.
</para>
@@ -238,7 +239,7 @@ through the automatically-generated
&cv-_SWIGINCFLAGS;
construction variable,
which is constructed by
-appending the values of the
+respectively prepending and appending the values of the
&cv-SWIGINCPREFIX; and &cv-SWIGINCSUFFIX;
construction variables
to the beginning and end
diff --git a/src/engine/SCons/Tool/tar.py b/src/engine/SCons/Tool/tar.py
index 77392ae..08c80f2 100644
--- a/src/engine/SCons/Tool/tar.py
+++ b/src/engine/SCons/Tool/tar.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/tar.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/tar.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Action
import SCons.Builder
diff --git a/src/engine/SCons/Tool/tar.xml b/src/engine/SCons/Tool/tar.xml
index 637b7db..95e8418 100644
--- a/src/engine/SCons/Tool/tar.xml
+++ b/src/engine/SCons/Tool/tar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/tex.py b/src/engine/SCons/Tool/tex.py
index 990c9fa..9beb557 100644
--- a/src/engine/SCons/Tool/tex.py
+++ b/src/engine/SCons/Tool/tex.py
@@ -10,7 +10,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -33,7 +33,7 @@ selection method.
#
from __future__ import print_function
-__revision__ = "src/engine/SCons/Tool/tex.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/tex.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import re
@@ -74,15 +74,15 @@ openout_bcf_re = re.compile(r"OUTPUT *(.*\.bcf)")
#printglossary_re = re.compile(r"^[^%]*\\printglossary", re.MULTILINE)
# search to find rerun warnings
-warning_rerun_str = '(^LaTeX Warning:.*Rerun)|(^Package \w+ Warning:.*Rerun)'
+warning_rerun_str = r'(^LaTeX Warning:.*Rerun)|(^Package \w+ Warning:.*Rerun)'
warning_rerun_re = re.compile(warning_rerun_str, re.MULTILINE)
# search to find citation rerun warnings
-rerun_citations_str = "^LaTeX Warning:.*\n.*Rerun to get citations correct"
+rerun_citations_str = r"^LaTeX Warning:.*\n.*Rerun to get citations correct"
rerun_citations_re = re.compile(rerun_citations_str, re.MULTILINE)
# search to find undefined references or citations warnings
-undefined_references_str = '(^LaTeX Warning:.*undefined references)|(^Package \w+ Warning:.*undefined citations)'
+undefined_references_str = r'(^LaTeX Warning:.*undefined references)|(^Package \w+ Warning:.*undefined citations)'
undefined_references_re = re.compile(undefined_references_str, re.MULTILINE)
# used by the emitter
@@ -297,7 +297,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
logfilename = targetbase + '.log'
logContent = ''
if os.path.isfile(logfilename):
- logContent = open(logfilename, "r").read()
+ with open(logfilename, "r") as f:
+ logContent = f.read()
# Read the fls file to find all .aux files
@@ -305,7 +306,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
flsContent = ''
auxfiles = []
if os.path.isfile(flsfilename):
- flsContent = open(flsfilename, "r").read()
+ with open(flsfilename, "r") as f:
+ flsContent = f.read()
auxfiles = openout_aux_re.findall(flsContent)
# remove duplicates
dups = {}
@@ -315,7 +317,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
bcffiles = []
if os.path.isfile(flsfilename):
- flsContent = open(flsfilename, "r").read()
+ with open(flsfilename, "r") as f:
+ flsContent = f.read()
bcffiles = openout_bcf_re.findall(flsContent)
# remove duplicates
dups = {}
@@ -338,7 +341,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
already_bibtexed.append(auxfilename)
target_aux = os.path.join(targetdir, auxfilename)
if os.path.isfile(target_aux):
- content = open(target_aux, "r").read()
+ with open(target_aux, "r") as f:
+ content = f.read()
if content.find("bibdata") != -1:
if Verbose:
print("Need to run bibtex on ",auxfilename)
@@ -361,7 +365,8 @@ def InternalLaTeXAuxAction(XXXLaTeXAction, target = None, source= None, env=None
already_bibtexed.append(bcffilename)
target_bcf = os.path.join(targetdir, bcffilename)
if os.path.isfile(target_bcf):
- content = open(target_bcf, "r").read()
+ with open(target_bcf, "r") as f:
+ content = f.read()
if content.find("bibdata") != -1:
if Verbose:
print("Need to run biber on ",bcffilename)
@@ -647,7 +652,7 @@ def ScanFiles(theFile, target, paths, file_tests, file_tests_search, env, graphi
if incResult:
aux_files.append(os.path.join(targetdir, incResult.group(1)))
if Verbose:
- print("\include file names : ", aux_files)
+ print(r"\include file names : ", aux_files)
# recursively call this on each of the included files
inc_files = [ ]
inc_files.extend( include_re.findall(content) )
@@ -776,7 +781,7 @@ def tex_emitter_core(target, source, env, graphics_extensions):
# add side effects if feature is present.If file is to be generated,add all side effects
if Verbose and theSearch:
print("check side effects for ",suffix_list[-1])
- if (theSearch != None) or (not source[0].exists() ):
+ if theSearch is not None or not source[0].exists():
file_list = [targetbase,]
# for bibunit we need a list of files
if suffix_list[-1] == 'bibunit':
@@ -790,7 +795,7 @@ def tex_emitter_core(target, source, env, graphics_extensions):
for multibibmatch in multibib_re.finditer(content):
if Verbose:
print("multibib match ",multibibmatch.group(1))
- if multibibmatch != None:
+ if multibibmatch is not None:
baselist = multibibmatch.group(1).split(',')
if Verbose:
print("multibib list ", baselist)
@@ -813,7 +818,8 @@ def tex_emitter_core(target, source, env, graphics_extensions):
# read fls file to get all other files that latex creates and will read on the next pass
# remove files from list that we explicitly dealt with above
if os.path.isfile(flsfilename):
- content = open(flsfilename, "r").read()
+ with open(flsfilename, "r") as f:
+ content = f.read()
out_files = openout_re.findall(content)
myfiles = [auxfilename, logfilename, flsfilename, targetbase+'.dvi',targetbase+'.pdf']
for filename in out_files[:]:
diff --git a/src/engine/SCons/Tool/tex.xml b/src/engine/SCons/Tool/tex.xml
index 87741c0..c293977 100644
--- a/src/engine/SCons/Tool/tex.xml
+++ b/src/engine/SCons/Tool/tex.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/textfile.py b/src/engine/SCons/Tool/textfile.py
index 7303e06..58a5007 100644
--- a/src/engine/SCons/Tool/textfile.py
+++ b/src/engine/SCons/Tool/textfile.py
@@ -1,6 +1,6 @@
# -*- python -*-
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -44,7 +44,7 @@ Textfile/Substfile builder for SCons.
is unpredictable whether the expansion will occur.
"""
-__revision__ = "src/engine/SCons/Tool/textfile.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/textfile.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons
diff --git a/src/engine/SCons/Tool/textfile.xml b/src/engine/SCons/Tool/textfile.xml
index bca7232..31d2d4f 100644
--- a/src/engine/SCons/Tool/textfile.xml
+++ b/src/engine/SCons/Tool/textfile.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
@@ -147,7 +147,7 @@ and the result replaces the key.
</para>
<example_commands>
-env = Environment(tools = ['default', 'textfile'])
+env = Environment(tools=['default'])
env['prefix'] = '/usr/bin'
script_dict = {'@prefix@': '/bin', '@exec_prefix@': '$prefix'}
@@ -174,7 +174,7 @@ env.Substfile('bar.in', SUBST_DICT = good_bar)
# the SUBST_DICT may be in common (and not an override)
substutions = {}
-subst = Environment(tools = ['textfile'], SUBST_DICT = substitutions)
+subst = Environment(tools=['textfile'], SUBST_DICT=substitutions)
substitutions['@foo@'] = 'foo'
subst['SUBST_DICT']['@bar@'] = 'bar'
subst.Substfile('pgm1.c', [Value('#include "@foo@.h"'),
diff --git a/src/engine/SCons/Tool/tlib.py b/src/engine/SCons/Tool/tlib.py
index c0a755e..4d8101b 100644
--- a/src/engine/SCons/Tool/tlib.py
+++ b/src/engine/SCons/Tool/tlib.py
@@ -5,7 +5,7 @@ XXX
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ XXX
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/tlib.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/tlib.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Tool
import SCons.Tool.bcc32
diff --git a/src/engine/SCons/Tool/tlib.xml b/src/engine/SCons/Tool/tlib.xml
index cb15db3..2fd8c08 100644
--- a/src/engine/SCons/Tool/tlib.xml
+++ b/src/engine/SCons/Tool/tlib.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/wix.py b/src/engine/SCons/Tool/wix.py
index 3ddfa84..e79e4a1 100644
--- a/src/engine/SCons/Tool/wix.py
+++ b/src/engine/SCons/Tool/wix.py
@@ -8,7 +8,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/wix.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/wix.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.Builder
import SCons.Action
diff --git a/src/engine/SCons/Tool/wixTests.py b/src/engine/SCons/Tool/wixTests.py
index 965ca57..f2649a3 100644
--- a/src/engine/SCons/Tool/wixTests.py
+++ b/src/engine/SCons/Tool/wixTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/wixTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/wixTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import unittest
import os.path
@@ -33,7 +33,6 @@ from SCons.Tool.wix import *
from SCons.Environment import Environment
import TestCmd
-import TestUnit
# create fake candle and light, so the tool's exists() method will succeed
@@ -53,8 +52,7 @@ class WixTestCase(unittest.TestCase):
assert env.subst('$WIXSRCSUF') == '.wxs'
if __name__ == "__main__":
- suite = unittest.makeSuite(WixTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/xgettext.py b/src/engine/SCons/Tool/xgettext.py
index 2e2934b..185558e 100644
--- a/src/engine/SCons/Tool/xgettext.py
+++ b/src/engine/SCons/Tool/xgettext.py
@@ -3,7 +3,7 @@
Tool specific initialization of `xgettext` tool.
"""
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,7 +24,24 @@ Tool specific initialization of `xgettext` tool.
# 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/xgettext.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/xgettext.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
+
+import os
+import re
+import subprocess
+import sys
+
+import SCons.Action
+import SCons.Node.FS
+import SCons.Tool
+import SCons.Util
+from SCons.Builder import BuilderBase
+from SCons.Environment import _null
+from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+from SCons.Tool.GettextCommon import _POTargetFactory
+from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
+from SCons.Tool.GettextCommon import _xgettext_exists
#############################################################################
@@ -41,10 +58,6 @@ class _CmdRunner(object):
self.commandstr = commandstr
def __call__(self, target, source, env):
- import SCons.Action
- import subprocess
- import os
- import sys
kw = {
'stdin': 'devnull',
'stdout': subprocess.PIPE,
@@ -57,11 +70,10 @@ class _CmdRunner(object):
self.out, self.err = proc.communicate()
self.status = proc.wait()
if self.err:
- sys.stderr.write(unicode(self.err))
+ sys.stderr.write(SCons.Util.UnicodeType(self.err))
return self.status
def strfunction(self, target, source, env):
- import os
comstr = self.commandstr
if env.subst(comstr, target=target, source=source) == "":
comstr = self.command
@@ -74,9 +86,6 @@ class _CmdRunner(object):
#############################################################################
def _update_pot_file(target, source, env):
""" Action function for `POTUpdate` builder """
- import re
- import os
- import SCons.Action
nop = lambda target, source, env: 0
# Save scons cwd and os cwd (NOTE: they may be different. After the job, we
@@ -154,10 +163,6 @@ def _update_pot_file(target, source, env):
#############################################################################
#############################################################################
-from SCons.Builder import BuilderBase
-
-
-#############################################################################
class _POTBuilder(BuilderBase):
def _execute(self, env, target, source, *args):
if not target:
@@ -175,10 +180,6 @@ class _POTBuilder(BuilderBase):
def _scan_xgettext_from_files(target, source, env, files=None, path=None):
""" Parses `POTFILES.in`-like file and returns list of extracted file names.
"""
- import re
- import SCons.Util
- import SCons.Node.FS
-
if files is None:
return 0
if not SCons.Util.is_List(files):
@@ -230,10 +231,6 @@ def _scan_xgettext_from_files(target, source, env, files=None, path=None):
#############################################################################
def _pot_update_emitter(target, source, env):
""" Emitter function for `POTUpdate` builder """
- from SCons.Tool.GettextCommon import _POTargetFactory
- import SCons.Util
- import SCons.Node.FS
-
if 'XGETTEXTFROM' in env:
xfrom = env['XGETTEXTFROM']
else:
@@ -261,10 +258,6 @@ def _pot_update_emitter(target, source, env):
#############################################################################
#############################################################################
-from SCons.Environment import _null
-
-
-#############################################################################
def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
return env._POTUpdateBuilder(target, source, **kw)
@@ -274,8 +267,6 @@ def _POTUpdateBuilderWrapper(env, target=None, source=_null, **kw):
#############################################################################
def _POTUpdateBuilder(env, **kw):
""" Creates `POTUpdate` builder object """
- import SCons.Action
- from SCons.Tool.GettextCommon import _POTargetFactory
kw['action'] = SCons.Action.Action(_update_pot_file, None)
kw['suffix'] = '$POTSUFFIX'
kw['target_factory'] = _POTargetFactory(env, alias='$POTUPDATE_ALIAS').File
@@ -288,9 +279,14 @@ def _POTUpdateBuilder(env, **kw):
#############################################################################
def generate(env, **kw):
""" Generate `xgettext` tool """
- import SCons.Util
- from SCons.Tool.GettextCommon import RPaths, _detect_xgettext
+ if sys.platform == 'win32':
+ xgettext = SCons.Tool.find_program_path(env, 'xgettext', default_paths=MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if xgettext:
+ xgettext_bin_dir = os.path.dirname(xgettext)
+ env.AppendENVPath('PATH', xgettext_bin_dir)
+ else:
+ SCons.Warnings.Warning('xgettext tool requested, but binary not found in ENV PATH')
try:
env['XGETTEXT'] = _detect_xgettext(env)
except:
@@ -347,7 +343,6 @@ def generate(env, **kw):
#############################################################################
def exists(env):
""" Check, whether the tool exists """
- from SCons.Tool.GettextCommon import _xgettext_exists
try:
return _xgettext_exists(env)
except:
diff --git a/src/engine/SCons/Tool/xgettext.xml b/src/engine/SCons/Tool/xgettext.xml
index 0b68c14..079693f 100644
--- a/src/engine/SCons/Tool/xgettext.xml
+++ b/src/engine/SCons/Tool/xgettext.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/yacc.py b/src/engine/SCons/Tool/yacc.py
index 4f9fbc2..6857574 100644
--- a/src/engine/SCons/Tool/yacc.py
+++ b/src/engine/SCons/Tool/yacc.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,16 +31,25 @@ selection method.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Tool/yacc.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/yacc.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
+import sys
import SCons.Defaults
import SCons.Tool
import SCons.Util
+from SCons.Platform.mingw import MINGW_DEFAULT_PATHS
+from SCons.Platform.cygwin import CYGWIN_DEFAULT_PATHS
+from SCons.Platform.win32 import CHOCO_DEFAULT_PATH
YaccAction = SCons.Action.Action("$YACCCOM", "$YACCCOMSTR")
+if sys.platform == 'win32':
+ BINS = ['bison', 'yacc', 'win_bison']
+else:
+ BINS = ["bison", "yacc"]
+
def _yaccEmitter(target, source, env, ysuf, hsuf):
yaccflags = env.subst("$YACCFLAGS", target=target, source=source)
flags = SCons.Util.CLVar(yaccflags)
@@ -94,6 +103,29 @@ def ymEmitter(target, source, env):
def yyEmitter(target, source, env):
return _yaccEmitter(target, source, env, ['.yy'], '$YACCHXXFILESUFFIX')
+def get_yacc_path(env, append_paths=False):
+ """
+ Find the path to the yacc tool, searching several possible names
+
+ Only called in the Windows case, so the default_path
+ can be Windows-specific
+
+ :param env: current construction environment
+ :param append_paths: if set, add the path to the tool to PATH
+ :return: path to yacc tool, if found
+ """
+ for prog in BINS:
+ bin_path = SCons.Tool.find_program_path(
+ env,
+ prog,
+ default_paths=CHOCO_DEFAULT_PATH + MINGW_DEFAULT_PATHS + CYGWIN_DEFAULT_PATHS )
+ if bin_path:
+ if append_paths:
+ env.AppendENVPath('PATH', os.path.dirname(bin_path))
+ return bin_path
+ SCons.Warnings.Warning('yacc tool requested, but yacc or bison binary not found in ENV PATH')
+
+
def generate(env):
"""Add Builders and construction variables for yacc to an Environment."""
c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
@@ -113,17 +145,22 @@ def generate(env):
cxx_file.add_action('.yy', YaccAction)
cxx_file.add_emitter('.yy', yyEmitter)
- env['YACC'] = env.Detect('bison') or 'yacc'
+ if sys.platform == 'win32':
+ # ignore the return, all we need is for the path to be added
+ _ = get_yacc_path(env, append_paths=True)
+
+ env["YACC"] = env.Detect(BINS)
env['YACCFLAGS'] = SCons.Util.CLVar('')
env['YACCCOM'] = '$YACC $YACCFLAGS -o $TARGET $SOURCES'
env['YACCHFILESUFFIX'] = '.h'
-
env['YACCHXXFILESUFFIX'] = '.hpp'
-
env['YACCVCGFILESUFFIX'] = '.vcg'
def exists(env):
- return env.Detect(['bison', 'yacc'])
+ if sys.platform == 'win32':
+ return get_yacc_path(env)
+ else:
+ return env.Detect(BINS)
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Tool/yacc.xml b/src/engine/SCons/Tool/yacc.xml
index 6bdbd53..8ba3658 100644
--- a/src/engine/SCons/Tool/yacc.xml
+++ b/src/engine/SCons/Tool/yacc.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Tool/zip.py b/src/engine/SCons/Tool/zip.py
index 0f6a8dd..b7efdc7 100644
--- a/src/engine/SCons/Tool/zip.py
+++ b/src/engine/SCons/Tool/zip.py
@@ -9,7 +9,7 @@ selection method.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/zip.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Tool/zip.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
diff --git a/src/engine/SCons/Tool/zip.xml b/src/engine/SCons/Tool/zip.xml
index 82eb61a..d7622dd 100644
--- a/src/engine/SCons/Tool/zip.xml
+++ b/src/engine/SCons/Tool/zip.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-Copyright (c) 2001 - 2017 The SCons Foundation
+Copyright (c) 2001 - 2019 The SCons Foundation
This file is processed by the bin/SConsDoc.py module.
See its __doc__ string for a discussion of the format.
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 2a1604b..5b4c225 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -3,7 +3,7 @@
Various utility functions go here.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,7 +24,7 @@ Various utility functions go here.
# 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/Util.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Util.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import sys
@@ -33,25 +33,23 @@ import re
import types
import codecs
import pprint
+import hashlib
PY3 = sys.version_info[0] == 3
try:
+ from collections import UserDict, UserList, UserString
+except ImportError:
from UserDict import UserDict
-except ImportError as e:
- from collections import UserDict
-
-try:
from UserList import UserList
-except ImportError as e:
- from collections import UserList
-
-from collections import Iterable
+ from UserString import UserString
try:
- from UserString import UserString
-except ImportError as e:
- from collections import UserString
+ from collections.abc import Iterable, MappingView
+except ImportError:
+ from collections import Iterable
+
+from collections import OrderedDict
# Don't "from types import ..." these because we need to get at the
# types module later to look for UnicodeType.
@@ -63,7 +61,7 @@ MethodType = types.MethodType
FunctionType = types.FunctionType
try:
- unicode
+ _ = type(unicode)
except NameError:
UnicodeType = str
else:
@@ -106,7 +104,7 @@ def containsOnly(str, set):
return 1
def splitext(path):
- "Same as os.path.splitext() but faster."
+ """Same as os.path.splitext() but faster."""
sep = rightmost_separator(path, os.sep)
dot = path.rfind('.')
# An ext is only real if it has at least one non-digit char
@@ -371,7 +369,13 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
DictTypes = (dict, UserDict)
ListTypes = (list, UserList)
-SequenceTypes = (list, tuple, UserList)
+
+try:
+ # Handle getting dictionary views.
+ SequenceTypes = (list, tuple, UserList, MappingView)
+except NameError:
+ SequenceTypes = (list, tuple, UserList)
+
# Note that profiling data shows a speed-up when comparing
# explicitly with str and unicode instead of simply comparing
@@ -481,10 +485,7 @@ def to_String_for_subst(s,
if isinstance(s, BaseStringTypes):
return s
elif isinstance(s, SequenceTypes):
- l = []
- for e in s:
- l.append(to_String_for_subst(e))
- return ' '.join( s )
+ return ' '.join([to_String_for_subst(e) for e in s])
elif isinstance(s, UserString):
# s.data can only be either a unicode or a regular
# string. Please see the UserString initializer.
@@ -656,13 +657,15 @@ except ImportError:
pass
RegError = _NoError
-WinError = None
+
# Make sure we have a definition of WindowsError so we can
# run platform-independent tests of Windows functionality on
# platforms other than Windows. (WindowsError is, in fact, an
# OSError subclass on Windows.)
+
class PlainWindowsError(OSError):
pass
+
try:
WinError = WindowsError
except NameError:
@@ -676,7 +679,7 @@ if can_read_reg:
HKEY_USERS = hkey_mod.HKEY_USERS
def RegGetValue(root, key):
- """This utility function returns a value in the registry
+ r"""This utility function returns a value in the registry
without having to open the key first. Only available on
Windows platforms with a version of Python that can read the
registry. Returns the same thing as
@@ -883,7 +886,7 @@ def PrependPath(oldpath, newpath, sep = os.pathsep,
# now we add them only if they are unique
for path in newpaths:
normpath = os.path.normpath(os.path.normcase(path))
- if path and not normpath in normpaths:
+ if path and normpath not in normpaths:
paths.append(path)
normpaths.append(normpath)
@@ -963,7 +966,7 @@ def AppendPath(oldpath, newpath, sep = os.pathsep,
# now we add them only if they are unique
for path in newpaths:
normpath = os.path.normpath(os.path.normcase(path))
- if path and not normpath in normpaths:
+ if path and normpath not in normpaths:
paths.append(path)
normpaths.append(normpath)
paths.reverse()
@@ -999,7 +1002,9 @@ if sys.platform == 'cygwin':
def get_native_path(path):
"""Transforms an absolute path into a native path for the system. In
Cygwin, this converts from a Cygwin path to a Windows one."""
- return os.popen('cygpath -w ' + path).read().replace('\n', '')
+ with os.popen('cygpath -w ' + path) as p:
+ npath = p.read().replace('\n', '')
+ return npath
else:
def get_native_path(path):
"""Transforms an absolute path into a native path for the system.
@@ -1032,64 +1037,9 @@ class CLVar(UserList):
return UserList.__add__(self, CLVar(other))
def __radd__(self, other):
return UserList.__radd__(self, CLVar(other))
- def __coerce__(self, other):
- return (self, CLVar(other))
def __str__(self):
return ' '.join(self.data)
-# A dictionary that preserves the order in which items are added.
-# Submitted by David Benjamin to ActiveState's Python Cookbook web site:
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
-# Including fixes/enhancements from the follow-on discussions.
-class OrderedDict(UserDict):
- def __init__(self, dict = None):
- self._keys = []
- UserDict.__init__(self, dict)
-
- def __delitem__(self, key):
- UserDict.__delitem__(self, key)
- self._keys.remove(key)
-
- def __setitem__(self, key, item):
- UserDict.__setitem__(self, key, item)
- if key not in self._keys: self._keys.append(key)
-
- def clear(self):
- UserDict.clear(self)
- self._keys = []
-
- def copy(self):
- dict = OrderedDict()
- dict.update(self)
- return dict
-
- def items(self):
- return list(zip(self._keys, list(self.values())))
-
- def keys(self):
- return self._keys[:]
-
- def popitem(self):
- try:
- key = self._keys[-1]
- except IndexError:
- raise KeyError('dictionary is empty')
-
- val = self[key]
- del self[key]
-
- return (key, val)
-
- def setdefault(self, key, failobj = None):
- UserDict.setdefault(self, key, failobj)
- if key not in self._keys: self._keys.append(key)
-
- def update(self, dict):
- for (key, val) in dict.items():
- self.__setitem__(key, val)
-
- def values(self):
- return list(map(self.get, self._keys))
class Selector(OrderedDict):
"""A callable ordered dictionary that maps file suffixes to
@@ -1231,10 +1181,13 @@ def unique(s):
# ASPN: Python Cookbook: Remove duplicates from a sequence
# First comment, dated 2001/10/13.
# (Also in the printed Python Cookbook.)
+# This not currently used, in favor of the next function...
def uniquer(seq, idfun=None):
- if idfun is None:
- def idfun(x): return x
+ def default_idfun(x):
+ return x
+ if not idfun:
+ idfun = default_idfun
seen = {}
result = []
for item in seq:
@@ -1431,8 +1384,8 @@ def make_path_relative(path):
# The original idea for AddMethod() and RenameFunction() come from the
# following post to the ActiveState Python Cookbook:
#
-# ASPN: Python Cookbook : Install bound methods in an instance
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613
+# ASPN: Python Cookbook : Install bound methods in an instance
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613
#
# That code was a little fragile, though, so the following changes
# have been wrung on it:
@@ -1449,8 +1402,8 @@ def make_path_relative(path):
# the "new" module, as alluded to in Alex Martelli's response to the
# following Cookbook post:
#
-# ASPN: Python Cookbook : Dynamically added methods to a class
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
+# ASPN: Python Cookbook : Dynamically added methods to a class
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
def AddMethod(obj, function, name=None):
"""
@@ -1499,46 +1452,54 @@ def RenameFunction(function, name):
function.__defaults__)
-md5 = False
-
+if hasattr(hashlib, 'md5'):
+ md5 = True
-def MD5signature(s):
- return str(s)
-
-
-def MD5filesignature(fname, chunksize=65536):
- with open(fname, "rb") as f:
- result = f.read()
- return result
+ def MD5signature(s):
+ """
+ Generate md5 signature of a string
-try:
- import hashlib
-except ImportError:
- pass
-else:
- if hasattr(hashlib, 'md5'):
- md5 = True
+ :param s: either string or bytes. Normally should be bytes
+ :return: String of hex digits representing the signature
+ """
+ m = hashlib.md5()
- def MD5signature(s):
- m = hashlib.md5()
+ try:
+ m.update(to_bytes(s))
+ except TypeError as e:
+ m.update(to_bytes(str(s)))
- try:
- m.update(to_bytes(s))
- except TypeError as e:
- m.update(to_bytes(str(s)))
+ return m.hexdigest()
- return m.hexdigest()
+ def MD5filesignature(fname, chunksize=65536):
+ """
+ Generate the md5 signature of a file
- def MD5filesignature(fname, chunksize=65536):
- m = hashlib.md5()
- f = open(fname, "rb")
+ :param fname: file to hash
+ :param chunksize: chunk size to read
+ :return: String of Hex digits representing the signature
+ """
+ m = hashlib.md5()
+ with open(fname, "rb") as f:
while True:
blck = f.read(chunksize)
if not blck:
break
m.update(to_bytes(blck))
- f.close()
- return m.hexdigest()
+ return m.hexdigest()
+else:
+ # if md5 algorithm not available, just return data unmodified
+ # could add alternative signature scheme here
+ md5 = False
+
+ def MD5signature(s):
+ return str(s)
+
+ def MD5filesignature(fname, chunksize=65536):
+ with open(fname, "rb") as f:
+ result = f.read()
+ return result
+
def MD5collect(signatures):
"""
@@ -1553,7 +1514,6 @@ def MD5collect(signatures):
return MD5signature(', '.join(signatures))
-
def silent_intern(x):
"""
Perform sys.intern() on the passed argument and return the result.
@@ -1577,7 +1537,7 @@ def silent_intern(x):
class Null(object):
""" Null objects always and reliably "do nothing." """
def __new__(cls, *args, **kwargs):
- if not '_instance' in vars(cls):
+ if '_instance' not in vars(cls):
cls._instance = super(Null, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, *args, **kwargs):
@@ -1612,16 +1572,66 @@ class NullSeq(Null):
del __revision__
-def to_bytes (s):
+
+def to_bytes(s):
+ if s is None:
+ return b'None'
+ if not PY3 and isinstance(s, UnicodeType):
+ # PY2, must encode unicode
+ return bytearray(s, 'utf-8')
if isinstance (s, (bytes, bytearray)) or bytes is str:
+ # Above case not covered here as py2 bytes and strings are the same
return s
- return bytes (s, 'utf-8')
+ return bytes(s, 'utf-8')
-def to_str (s):
+
+def to_str(s):
+ if s is None:
+ return 'None'
if bytes is str or is_String(s):
return s
return str (s, 'utf-8')
+
+def cmp(a, b):
+ """
+ Define cmp because it's no longer available in python3
+ Works under python 2 as well
+ """
+ return (a > b) - (a < b)
+
+
+def get_env_bool(env, name, default=False):
+ """Get a value of env[name] converted to boolean. The value of env[name] is
+ interpreted as follows: 'true', 'yes', 'y', 'on' (case insensitive) and
+ anything convertible to int that yields non-zero integer are True values;
+ '0', 'false', 'no', 'n' and 'off' (case insensitive) are False values. For
+ all other cases, default value is returned.
+
+ :Parameters:
+ - `env` - dict or dict-like object, a convainer with variables
+ - `name` - name of the variable in env to be returned
+ - `default` - returned when env[name] does not exist or can't be converted to bool
+ """
+ try:
+ var = env[name]
+ except KeyError:
+ return default
+ try:
+ return bool(int(var))
+ except ValueError:
+ if str(var).lower() in ('true', 'yes', 'y', 'on'):
+ return True
+ elif str(var).lower() in ('false', 'no', 'n', 'off'):
+ return False
+ else:
+ return default
+
+
+def get_os_env_bool(name, default=False):
+ """Same as get_env_bool(os.environ, name, default)."""
+ return get_env_bool(os.environ, name, default)
+
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 1df4069..41a1647 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/UtilTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/UtilTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import SCons.compat
@@ -32,15 +32,18 @@ import unittest
from collections import UserDict, UserList, UserString
import TestCmd
-import TestUnit
import SCons.Errors
from SCons.Util import *
-try: eval('unicode')
-except NameError: HasUnicode = False
-else: HasUnicode = True
+try:
+ eval('unicode')
+except NameError:
+ HasUnicode = False
+else:
+ HasUnicode = True
+
class OutBuffer(object):
def __init__(self):
@@ -49,47 +52,59 @@ class OutBuffer(object):
def write(self, str):
self.buffer = self.buffer + str
+
class dictifyTestCase(unittest.TestCase):
def test_dictify(self):
"""Test the dictify() function"""
r = SCons.Util.dictify(['a', 'b', 'c'], [1, 2, 3])
- assert r == {'a':1, 'b':2, 'c':3}, r
+ assert r == {'a': 1, 'b': 2, 'c': 3}, r
r = {}
SCons.Util.dictify(['a'], [1], r)
SCons.Util.dictify(['b'], [2], r)
SCons.Util.dictify(['c'], [3], r)
- assert r == {'a':1, 'b':2, 'c':3}, r
+ assert r == {'a': 1, 'b': 2, 'c': 3}, r
+
class UtilTestCase(unittest.TestCase):
def test_splitext(self):
- assert splitext('foo') == ('foo','')
- assert splitext('foo.bar') == ('foo','.bar')
- assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'),'')
+ assert splitext('foo') == ('foo', '')
+ assert splitext('foo.bar') == ('foo', '.bar')
+ assert splitext(os.path.join('foo.bar', 'blat')) == (os.path.join('foo.bar', 'blat'), '')
class Node(object):
def __init__(self, name, children=[]):
self.children = children
self.name = name
self.nocache = None
+
def __str__(self):
return self.name
+
def exists(self):
return 1
+
def rexists(self):
return 1
+
def has_builder(self):
return 1
+
def has_explicit_builder(self):
return 1
+
def side_effect(self):
return 1
+
def precious(self):
return 1
+
def always_build(self):
return 1
+
def is_up_to_date(self):
return 1
+
def noclean(self):
return 1
@@ -116,7 +131,7 @@ class UtilTestCase(unittest.TestCase):
"""
lines = expect.split('\n')[:-1]
- lines = ['[E BSPACN ]'+l for l in lines]
+ lines = ['[E BSPACN ]' + l for l in lines]
withtags = '\n'.join(lines) + '\n'
return foo, expect, withtags
@@ -151,13 +166,14 @@ class UtilTestCase(unittest.TestCase):
"""
lines = expect.split('\n')[:-1]
- lines = ['[E BSPACN ]'+l for l in lines]
+ lines = ['[E BSPACN ]' + l for l in lines]
withtags = '\n'.join(lines) + '\n'
return blat_o, expect, withtags
def test_render_tree(self):
"""Test the render_tree() function"""
+
def get_children(node):
return node.children
@@ -178,6 +194,7 @@ class UtilTestCase(unittest.TestCase):
def test_print_tree(self):
"""Test the print_tree() function"""
+
def get_children(node):
return node.children
@@ -244,7 +261,7 @@ class UtilTestCase(unittest.TestCase):
assert is_Dict(UserDict())
# os.environ is not a dictionary in python 3
- if sys.version_info < (3,0):
+ if sys.version_info < (3, 0):
assert is_Dict(os.environ)
try:
@@ -258,7 +275,7 @@ class UtilTestCase(unittest.TestCase):
assert not is_Dict(())
assert not is_Dict("")
if HasUnicode:
- exec("assert not is_Dict(u'')")
+ exec ("assert not is_Dict(u'')")
def test_is_List(self):
assert is_List([])
@@ -274,12 +291,12 @@ class UtilTestCase(unittest.TestCase):
assert not is_List({})
assert not is_List("")
if HasUnicode:
- exec("assert not is_List(u'')")
+ exec ("assert not is_List(u'')")
def test_is_String(self):
assert is_String("")
if HasUnicode:
- exec("assert is_String(u'')")
+ exec ("assert is_String(u'')")
assert is_String(UserString(''))
try:
class mystr(str):
@@ -305,39 +322,51 @@ class UtilTestCase(unittest.TestCase):
assert not is_Tuple({})
assert not is_Tuple("")
if HasUnicode:
- exec("assert not is_Tuple(u'')")
+ exec ("assert not is_Tuple(u'')")
+
+ def test_to_Bytes(self):
+ """ Test the to_Bytes method"""
+ if not PY3:
+ self.assertEqual(to_bytes(UnicodeType('Hello')),
+ bytearray(u'Hello', 'utf-8'),
+ "Check that to_bytes creates byte array when presented with unicode string. PY2 only")
def test_to_String(self):
"""Test the to_String() method."""
assert to_String(1) == "1", to_String(1)
- assert to_String([ 1, 2, 3]) == str([1, 2, 3]), to_String([1,2,3])
+ assert to_String([1, 2, 3]) == str([1, 2, 3]), to_String([1, 2, 3])
assert to_String("foo") == "foo", to_String("foo")
+ assert to_String(None) == 'None'
+ # test low level string converters too
+ assert to_str(None) == 'None'
+ assert to_bytes(None) == b'None'
- s1=UserString('blah')
+ s1 = UserString('blah')
assert to_String(s1) == s1, s1
assert to_String(s1) == 'blah', s1
class Derived(UserString):
pass
+
s2 = Derived('foo')
assert to_String(s2) == s2, s2
assert to_String(s2) == 'foo', s2
if HasUnicode:
- s3=UserString(unicode('bar'))
+ s3 = UserString(unicode('bar'))
assert to_String(s3) == s3, s3
assert to_String(s3) == unicode('bar'), s3
assert isinstance(to_String(s3), unicode), \
- type(to_String(s3))
+ type(to_String(s3))
if HasUnicode:
s4 = unicode('baz')
assert to_String(s4) == unicode('baz'), to_String(s4)
assert isinstance(to_String(s4), unicode), \
- type(to_String(s4))
+ type(to_String(s4))
def test_WhereIs(self):
- test = TestCmd.TestCmd(workdir = '')
+ test = TestCmd.TestCmd(workdir='')
sub1_xxx_exe = test.workpath('sub1', 'xxx.exe')
sub2_xxx_exe = test.workpath('sub2', 'xxx.exe')
@@ -360,17 +389,17 @@ class UtilTestCase(unittest.TestCase):
env_path = os.environ['PATH']
try:
- pathdirs_1234 = [ test.workpath('sub1'),
- test.workpath('sub2'),
- test.workpath('sub3'),
- test.workpath('sub4'),
- ] + env_path.split(os.pathsep)
-
- pathdirs_1243 = [ test.workpath('sub1'),
- test.workpath('sub2'),
- test.workpath('sub4'),
- test.workpath('sub3'),
- ] + env_path.split(os.pathsep)
+ pathdirs_1234 = [test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub3'),
+ test.workpath('sub4'),
+ ] + env_path.split(os.pathsep)
+
+ pathdirs_1243 = [test.workpath('sub1'),
+ test.workpath('sub2'),
+ test.workpath('sub4'),
+ test.workpath('sub3'),
+ ] + env_path.split(os.pathsep)
os.environ['PATH'] = os.pathsep.join(pathdirs_1234)
wi = WhereIs('xxx.exe')
@@ -380,9 +409,9 @@ class UtilTestCase(unittest.TestCase):
wi = WhereIs('xxx.exe', os.pathsep.join(pathdirs_1243))
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx.exe',reject = sub3_xxx_exe)
+ wi = WhereIs('xxx.exe', reject=sub3_xxx_exe)
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx.exe', pathdirs_1243, reject = sub3_xxx_exe)
+ wi = WhereIs('xxx.exe', pathdirs_1243, reject=sub3_xxx_exe)
assert wi == test.workpath(sub4_xxx_exe), wi
os.environ['PATH'] = os.pathsep.join(pathdirs_1243)
@@ -394,19 +423,19 @@ class UtilTestCase(unittest.TestCase):
assert wi == test.workpath(sub3_xxx_exe), wi
if sys.platform == 'win32':
- wi = WhereIs('xxx', pathext = '')
+ wi = WhereIs('xxx', pathext='')
assert wi is None, wi
- wi = WhereIs('xxx', pathext = '.exe')
+ wi = WhereIs('xxx', pathext='.exe')
assert wi == test.workpath(sub4_xxx_exe), wi
- wi = WhereIs('xxx', path = pathdirs_1234, pathext = '.BAT;.EXE')
+ wi = WhereIs('xxx', path=pathdirs_1234, pathext='.BAT;.EXE')
assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
# Test that we return a normalized path even when
# the path contains forward slashes.
forward_slash = test.workpath('') + '/sub3'
- wi = WhereIs('xxx', path = forward_slash, pathext = '.EXE')
+ wi = WhereIs('xxx', path=forward_slash, pathext='.EXE')
assert wi.lower() == test.workpath(sub3_xxx_exe).lower(), wi
del os.environ['PATH']
@@ -426,24 +455,27 @@ class UtilTestCase(unittest.TestCase):
assert get_environment_var("$BAR ") == None, get_environment_var("$BAR ")
assert get_environment_var("FOO$BAR") == None, get_environment_var("FOO$BAR")
assert get_environment_var("$FOO[0]") == None, get_environment_var("$FOO[0]")
- assert get_environment_var("${some('complex expression')}") == None, get_environment_var("${some('complex expression')}")
+ assert get_environment_var("${some('complex expression')}") == None, get_environment_var(
+ "${some('complex expression')}")
def test_Proxy(self):
"""Test generic Proxy class."""
+
class Subject(object):
def foo(self):
return 1
+
def bar(self):
return 2
- s=Subject()
+ s = Subject()
s.baz = 3
class ProxyTest(Proxy):
def bar(self):
return 4
- p=ProxyTest(s)
+ p = ProxyTest(s)
assert p.foo() == 1, p.foo()
assert p.bar() == 4, p.bar()
@@ -477,8 +509,10 @@ class UtilTestCase(unittest.TestCase):
filename = tempfile.mktemp()
str = '1234567890 ' + filename
try:
- open(filename, 'w').write(str)
- assert open(get_native_path(filename)).read() == str
+ with open(filename, 'w') as f:
+ f.write(str)
+ with open(get_native_path(filename)) as f:
+ assert f.read() == str
finally:
try:
os.unlink(filename)
@@ -490,49 +524,49 @@ class UtilTestCase(unittest.TestCase):
p1 = r'C:\dir\num\one;C:\dir\num\two'
p2 = r'C:\mydir\num\one;C:\mydir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
- p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
- p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
- p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
- assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
- assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+ p1 = PrependPath(p1, r'C:\dir\num\two', sep=';')
+ p1 = PrependPath(p1, r'C:\dir\num\three', sep=';')
+ p2 = PrependPath(p2, r'C:\mydir\num\three', sep=';')
+ p2 = PrependPath(p2, r'C:\mydir\num\one', sep=';')
+ assert (p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+ assert (p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
def test_AppendPath(self):
"""Test appending to a path."""
p1 = r'C:\dir\num\one;C:\dir\num\two'
p2 = r'C:\mydir\num\one;C:\mydir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
- p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
- p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
- p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
- assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
- assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+ p1 = AppendPath(p1, r'C:\dir\num\two', sep=';')
+ p1 = AppendPath(p1, r'C:\dir\num\three', sep=';')
+ p2 = AppendPath(p2, r'C:\mydir\num\three', sep=';')
+ p2 = AppendPath(p2, r'C:\mydir\num\one', sep=';')
+ assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ assert (p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
def test_PrependPathPreserveOld(self):
"""Test prepending to a path while preserving old paths"""
p1 = r'C:\dir\num\one;C:\dir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';', delete_existing=0)
- p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
- assert(p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two')
+ p1 = PrependPath(p1, r'C:\dir\num\two', sep=';', delete_existing=0)
+ p1 = PrependPath(p1, r'C:\dir\num\three', sep=';')
+ assert (p1 == r'C:\dir\num\three;C:\dir\num\one;C:\dir\num\two')
def test_AppendPathPreserveOld(self):
"""Test appending to a path while preserving old paths"""
p1 = r'C:\dir\num\one;C:\dir\num\two'
# have to include the pathsep here so that the test will work on UNIX too.
- p1 = AppendPath(p1,r'C:\dir\num\one',sep = ';', delete_existing=0)
- p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
- assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ p1 = AppendPath(p1, r'C:\dir\num\one', sep=';', delete_existing=0)
+ p1 = AppendPath(p1, r'C:\dir\num\three', sep=';')
+ assert (p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
def test_addPathIfNotExists(self):
"""Test the AddPathIfNotExists() function"""
- env_dict = { 'FOO' : os.path.normpath('/foo/bar') + os.pathsep + \
- os.path.normpath('/baz/blat'),
- 'BAR' : os.path.normpath('/foo/bar') + os.pathsep + \
- os.path.normpath('/baz/blat'),
- 'BLAT' : [ os.path.normpath('/foo/bar'),
- os.path.normpath('/baz/blat') ] }
+ env_dict = {'FOO': os.path.normpath('/foo/bar') + os.pathsep + \
+ os.path.normpath('/baz/blat'),
+ 'BAR': os.path.normpath('/foo/bar') + os.pathsep + \
+ os.path.normpath('/baz/blat'),
+ 'BLAT': [os.path.normpath('/foo/bar'),
+ os.path.normpath('/baz/blat')]}
AddPathIfNotExists(env_dict, 'FOO', os.path.normpath('/foo/bar'))
AddPathIfNotExists(env_dict, 'BAR', os.path.normpath('/bar/foo'))
AddPathIfNotExists(env_dict, 'BAZ', os.path.normpath('/foo/baz'))
@@ -545,9 +579,9 @@ class UtilTestCase(unittest.TestCase):
os.path.normpath('/foo/bar') + os.pathsep + \
os.path.normpath('/baz/blat'), env_dict['BAR']
assert env_dict['BAZ'] == os.path.normpath('/foo/baz'), env_dict['BAZ']
- assert env_dict['BLAT'] == [ os.path.normpath('/baz/foo'),
- os.path.normpath('/foo/bar'),
- os.path.normpath('/baz/blat') ], env_dict['BLAT' ]
+ assert env_dict['BLAT'] == [os.path.normpath('/baz/foo'),
+ os.path.normpath('/foo/bar'),
+ os.path.normpath('/baz/blat')], env_dict['BLAT']
def test_CLVar(self):
"""Test the command-line construction variable class"""
@@ -656,10 +690,11 @@ class UtilTestCase(unittest.TestCase):
def __str__(self):
return self.name
+
def get_suffix(self):
return os.path.splitext(self.name)[1]
- s = Selector({'a' : 'AAA', 'b' : 'BBB'})
+ s = Selector({'a': 'AAA', 'b': 'BBB'})
assert s['a'] == 'AAA', s['a']
assert s['b'] == 'BBB', s['b']
exc_caught = None
@@ -679,7 +714,7 @@ class UtilTestCase(unittest.TestCase):
env = DummyEnv()
- s = Selector({'.d' : 'DDD', '.e' : 'EEE'})
+ s = Selector({'.d': 'DDD', '.e': 'EEE'})
ret = s(env, [])
assert ret is None, ret
ret = s(env, [MyNode('foo.d')])
@@ -692,9 +727,9 @@ class UtilTestCase(unittest.TestCase):
ret = s(env, [MyNode('bar.x')])
assert ret == 'XXX', ret
- env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'})
+ env = DummyEnv({'FSUFF': '.f', 'GSUFF': '.g'})
- s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'})
+ s = Selector({'$FSUFF': 'FFF', '$GSUFF': 'GGG'})
ret = s(env, [MyNode('foo.f')])
assert ret == 'FFF', ret
ret = s(env, [MyNode('bar.g')])
@@ -733,12 +768,12 @@ class UtilTestCase(unittest.TestCase):
def test_LogicalLines(self):
"""Test the LogicalLines class"""
content = u"""
-foo \
-bar \
+foo \\
+bar \\
baz
foo
-bling \
-bling \ bling
+bling \\
+bling \\ bling
bling
"""
fobj = io.StringIO(content)
@@ -780,9 +815,11 @@ class MD5TestCase(unittest.TestCase):
s = MD5signature('222')
assert 'bcbe3365e6ac95ea2c0343a2395834dd' == s, s
+
class NodeListTestCase(unittest.TestCase):
def test_simple_attributes(self):
"""Test simple attributes of a NodeList class"""
+
class TestClass(object):
def __init__(self, name, child=None):
self.child = child
@@ -793,18 +830,21 @@ class NodeListTestCase(unittest.TestCase):
t3 = TestClass('t3')
nl = NodeList([t1, t2, t3])
- assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
- assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
- nl[0:2].child.bar
+ assert nl.bar == ['t1', 't2', 't3'], nl.bar
+ assert nl[0:2].child.bar == ['t1child', 't2child'], \
+ nl[0:2].child.bar
def test_callable_attributes(self):
"""Test callable attributes of a NodeList class"""
+
class TestClass(object):
def __init__(self, name, child=None):
self.child = child
self.bar = name
+
def foo(self):
return self.bar + "foo"
+
def getself(self):
return self
@@ -813,13 +853,13 @@ class NodeListTestCase(unittest.TestCase):
t3 = TestClass('t3')
nl = NodeList([t1, t2, t3])
- assert nl.foo() == [ 't1foo', 't2foo', 't3foo' ], nl.foo()
- assert nl.bar == [ 't1', 't2', 't3' ], nl.bar
- assert nl.getself().bar == [ 't1', 't2', 't3' ], nl.getself().bar
- assert nl[0:2].child.foo() == [ 't1childfoo', 't2childfoo' ], \
- nl[0:2].child.foo()
- assert nl[0:2].child.bar == [ 't1child', 't2child' ], \
- nl[0:2].child.bar
+ assert nl.foo() == ['t1foo', 't2foo', 't3foo'], nl.foo()
+ assert nl.bar == ['t1', 't2', 't3'], nl.bar
+ assert nl.getself().bar == ['t1', 't2', 't3'], nl.getself().bar
+ assert nl[0:2].child.foo() == ['t1childfoo', 't2childfoo'], \
+ nl[0:2].child.foo()
+ assert nl[0:2].child.bar == ['t1child', 't2child'], \
+ nl[0:2].child.bar
def test_null(self):
"""Test a null NodeList"""
@@ -835,21 +875,113 @@ class flattenTestCase(unittest.TestCase):
def test_scalar(self):
"""Test flattening a scalar"""
result = flatten('xyz')
- assert result == ['xyz'], result
+ self.assertEqual(result, ['xyz'], result)
+
+ def test_dictionary_values(self):
+ """Test flattening the dictionary values"""
+ items = {"a": 1, "b": 2, "c": 3}
+ result = flatten(items.values())
+ self.assertEqual(sorted(result), [1, 2, 3])
+
+
+class OsEnviron(object):
+ """Used to temporarily mock os.environ"""
+
+ def __init__(self, environ):
+ self._environ = environ
+
+ def start(self):
+ self._stored = os.environ
+ os.environ = self._environ
+
+ def stop(self):
+ os.environ = self._stored
+ del self._stored
+
+ def __enter__(self):
+ self.start()
+ return os.environ
+
+ def __exit__(self, *args):
+ self.stop()
+
+
+class get_env_boolTestCase(unittest.TestCase):
+ def test_missing(self):
+ env = dict()
+ var = get_env_bool(env, 'FOO')
+ assert var is False, "var should be False, not %s" % repr(var)
+ env = {'FOO': '1'}
+ var = get_env_bool(env, 'BAR')
+ assert var is False, "var should be False, not %s" % repr(var)
+
+ def test_true(self):
+ for foo in ['TRUE', 'True', 'true',
+ 'YES', 'Yes', 'yes',
+ 'Y', 'y',
+ 'ON', 'On', 'on',
+ '1', '20', '-1']:
+ env = {'FOO': foo}
+ var = get_env_bool(env, 'FOO')
+ assert var is True, 'var should be True, not %s' % repr(var)
+
+ def test_false(self):
+ for foo in ['FALSE', 'False', 'false',
+ 'NO', 'No', 'no',
+ 'N', 'n',
+ 'OFF', 'Off', 'off',
+ '0']:
+ env = {'FOO': foo}
+ var = get_env_bool(env, 'FOO', True)
+ assert var is False, 'var should be True, not %s' % repr(var)
+
+ def test_default(self):
+ env = {'FOO': 'other'}
+ var = get_env_bool(env, 'FOO', True)
+ assert var is True, 'var should be True, not %s' % repr(var)
+ var = get_env_bool(env, 'FOO', False)
+ assert var is False, 'var should be False, not %s' % repr(var)
+
+
+class get_os_env_boolTestCase(unittest.TestCase):
+ def test_missing(self):
+ with OsEnviron(dict()):
+ var = get_os_env_bool('FOO')
+ assert var is False, "var should be False, not %s" % repr(var)
+ with OsEnviron({'FOO': '1'}):
+ var = get_os_env_bool('BAR')
+ assert var is False, "var should be False, not %s" % repr(var)
+
+ def test_true(self):
+ for foo in ['TRUE', 'True', 'true',
+ 'YES', 'Yes', 'yes',
+ 'Y', 'y',
+ 'ON', 'On', 'on',
+ '1', '20', '-1']:
+ with OsEnviron({'FOO': foo}):
+ var = get_os_env_bool('FOO')
+ assert var is True, 'var should be True, not %s' % repr(var)
+
+ def test_false(self):
+ for foo in ['FALSE', 'False', 'false',
+ 'NO', 'No', 'no',
+ 'N', 'n',
+ 'OFF', 'Off', 'off',
+ '0']:
+ with OsEnviron({'FOO': foo}):
+ var = get_os_env_bool('FOO', True)
+ assert var is False, 'var should be True, not %s' % repr(var)
+
+ def test_default(self):
+ with OsEnviron({'FOO': 'other'}):
+ var = get_os_env_bool('FOO', True)
+ assert var is True, 'var should be True, not %s' % repr(var)
+ var = get_os_env_bool('FOO', False)
+ assert var is False, 'var should be False, not %s' % repr(var)
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ dictifyTestCase,
- flattenTestCase,
- MD5TestCase,
- NodeListTestCase,
- UtilTestCase,
- ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/BoolVariable.py b/src/engine/SCons/Variables/BoolVariable.py
index 881a6b4..4cb9f35 100644
--- a/src/engine/SCons/Variables/BoolVariable.py
+++ b/src/engine/SCons/Variables/BoolVariable.py
@@ -12,7 +12,7 @@ Usage example::
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Usage example::
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/BoolVariable.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/BoolVariable.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__all__ = ['BoolVariable',]
diff --git a/src/engine/SCons/Variables/BoolVariableTests.py b/src/engine/SCons/Variables/BoolVariableTests.py
index 42beaee..a184378 100644
--- a/src/engine/SCons/Variables/BoolVariableTests.py
+++ b/src/engine/SCons/Variables/BoolVariableTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/BoolVariableTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/BoolVariableTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Variables
@@ -118,8 +116,7 @@ class BoolVariableTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.makeSuite(BoolVariableTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/EnumVariable.py b/src/engine/SCons/Variables/EnumVariable.py
index b6fc382..ba9f972 100644
--- a/src/engine/SCons/Variables/EnumVariable.py
+++ b/src/engine/SCons/Variables/EnumVariable.py
@@ -15,7 +15,7 @@ Usage example::
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -37,7 +37,7 @@ Usage example::
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/EnumVariable.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/EnumVariable.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__all__ = ['EnumVariable',]
@@ -45,7 +45,7 @@ __all__ = ['EnumVariable',]
import SCons.Errors
def _validator(key, val, env, vals):
- if not val in vals:
+ if val not in vals:
raise SCons.Errors.UserError(
'Invalid value for option %s: %s. Valid values are: %s' % (key, val, vals))
diff --git a/src/engine/SCons/Variables/EnumVariableTests.py b/src/engine/SCons/Variables/EnumVariableTests.py
index caef48f..28b9d68 100644
--- a/src/engine/SCons/Variables/EnumVariableTests.py
+++ b/src/engine/SCons/Variables/EnumVariableTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/EnumVariableTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/EnumVariableTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Variables
@@ -195,8 +193,7 @@ class EnumVariableTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.makeSuite(EnumVariableTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/ListVariable.py b/src/engine/SCons/Variables/ListVariable.py
index 8f9a9a8..a30f265 100644
--- a/src/engine/SCons/Variables/ListVariable.py
+++ b/src/engine/SCons/Variables/ListVariable.py
@@ -25,7 +25,7 @@ Usage example::
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -46,7 +46,7 @@ Usage example::
# 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/Variables/ListVariable.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/ListVariable.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
# Known Bug: This should behave like a Set-Type, but does not really,
# since elements can occur twice.
@@ -96,7 +96,7 @@ def _converter(val, allowedElems, mapdict):
else:
val = [_f for _f in val.split(',') if _f]
val = [mapdict.get(v, v) for v in val]
- notAllowed = [v for v in val if not v in allowedElems]
+ notAllowed = [v for v in val if v not in allowedElems]
if notAllowed:
raise ValueError("Invalid value(s) for option: %s" %
','.join(notAllowed))
diff --git a/src/engine/SCons/Variables/ListVariableTests.py b/src/engine/SCons/Variables/ListVariableTests.py
index be45aed..86e2c9e 100644
--- a/src/engine/SCons/Variables/ListVariableTests.py
+++ b/src/engine/SCons/Variables/ListVariableTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,14 +21,12 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/ListVariableTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/ListVariableTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import copy
import sys
import unittest
-import TestUnit
-
import SCons.Errors
import SCons.Variables
@@ -125,8 +123,7 @@ class ListVariableTestCase(unittest.TestCase):
n = l.__class__(copy.copy(l))
if __name__ == "__main__":
- suite = unittest.makeSuite(ListVariableTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/PackageVariable.py b/src/engine/SCons/Variables/PackageVariable.py
index 8e229b7..7c23cca 100644
--- a/src/engine/SCons/Variables/PackageVariable.py
+++ b/src/engine/SCons/Variables/PackageVariable.py
@@ -28,7 +28,7 @@ Usage example:
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -50,7 +50,7 @@ Usage example:
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/PackageVariable.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/PackageVariable.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__all__ = ['PackageVariable',]
diff --git a/src/engine/SCons/Variables/PackageVariableTests.py b/src/engine/SCons/Variables/PackageVariableTests.py
index 30a88b5..2e48536 100644
--- a/src/engine/SCons/Variables/PackageVariableTests.py
+++ b/src/engine/SCons/Variables/PackageVariableTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Variables/PackageVariableTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/PackageVariableTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
@@ -30,8 +30,6 @@ import SCons.Errors
import SCons.Variables
import TestCmd
-import TestUnit
-
class PackageVariableTestCase(unittest.TestCase):
def test_PackageVariable(self):
@@ -115,8 +113,7 @@ class PackageVariableTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.makeSuite(PackageVariableTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/PathVariable.py b/src/engine/SCons/Variables/PathVariable.py
index dc5fcd2..bf123fb 100644
--- a/src/engine/SCons/Variables/PathVariable.py
+++ b/src/engine/SCons/Variables/PathVariable.py
@@ -45,7 +45,7 @@ Usage example::
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -67,7 +67,7 @@ Usage example::
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/PathVariable.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/PathVariable.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__all__ = ['PathVariable',]
diff --git a/src/engine/SCons/Variables/PathVariableTests.py b/src/engine/SCons/Variables/PathVariableTests.py
index c8518af..d862887 100644
--- a/src/engine/SCons/Variables/PathVariableTests.py
+++ b/src/engine/SCons/Variables/PathVariableTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/Variables/PathVariableTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/PathVariableTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import sys
@@ -31,8 +31,6 @@ import SCons.Errors
import SCons.Variables
import TestCmd
-import TestUnit
-
class PathVariableTestCase(unittest.TestCase):
def test_PathVariable(self):
@@ -228,8 +226,7 @@ class PathVariableTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.makeSuite(PathVariableTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/VariablesTests.py b/src/engine/SCons/Variables/VariablesTests.py
index dc507ce..ed2edab 100644
--- a/src/engine/SCons/Variables/VariablesTests.py
+++ b/src/engine/SCons/Variables/VariablesTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,17 +21,17 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/Variables/VariablesTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/VariablesTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
import TestSCons
-import TestUnit
import SCons.Variables
import SCons.Subst
import SCons.Warnings
+from SCons.Util import cmp
class Environment(object):
@@ -49,12 +49,6 @@ class Environment(object):
return key in self.dict
-def cmp(a, b):
- """
- Define cmp because it's no longer available in python3
- Works under python 2 as well
- """
- return (a > b) - (a < b)
def check(key, value, env):
@@ -65,7 +59,9 @@ def check(key, value, env):
def checkSave(file, expected):
gdict = {}
ldict = {}
- exec(open(file, 'r').read(), gdict, ldict)
+ with open(file, 'r') as f:
+ exec(f.read(), gdict, ldict)
+
assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict)
class VariablesTestCase(unittest.TestCase):
@@ -492,9 +488,29 @@ B: b - alpha test
default: 42
actual: 54
"""
+
+ expectBackwards = """
+B: b - alpha test
+ default: 42
+ actual: 54
+
+ANSWER: THE answer to THE question
+ default: 42
+ actual: 54
+
+A: a - alpha test
+ default: 42
+ actual: 54
+"""
text = opts.GenerateHelpText(env, sort=cmp)
assert text == expectAlpha, text
+ textBool = opts.GenerateHelpText(env, sort=True)
+ assert text == expectAlpha, text
+
+ textBackwards = opts.GenerateHelpText(env, sort=lambda x, y: cmp(y, x))
+ assert textBackwards == expectBackwards, "Expected:\n%s\nGot:\n%s\n"%(textBackwards, expectBackwards)
+
def test_FormatVariableHelpText(self):
"""Test generating custom format help text"""
opts = SCons.Variables.Variables()
@@ -675,13 +691,7 @@ class UnknownVariablesTestCase(unittest.TestCase):
if __name__ == "__main__":
- suite = unittest.TestSuite()
- tclasses = [ VariablesTestCase,
- UnknownVariablesTestCase ]
- for tclass in tclasses:
- names = unittest.getTestCaseNames(tclass, 'test_')
- suite.addTests(list(map(tclass, names)))
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/Variables/__init__.py b/src/engine/SCons/Variables/__init__.py
index 784f795..5b4b3af 100644
--- a/src/engine/SCons/Variables/__init__.py
+++ b/src/engine/SCons/Variables/__init__.py
@@ -5,7 +5,7 @@ customizable variables to an SCons build.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,10 +26,11 @@ customizable variables to an SCons build.
# 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/Variables/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Variables/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os.path
import sys
+from functools import cmp_to_key
import SCons.Environment
import SCons.Errors
@@ -98,7 +99,7 @@ class Variables(object):
option.converter = converter
self.options.append(option)
-
+
# options might be added after the 'unknown' dict has been set up,
# so we remove the key and all its aliases from that dict
for alias in list(option.aliases) + [ option.key ]:
@@ -167,7 +168,7 @@ class Variables(object):
# first set the defaults:
for option in self.options:
- if not option.default is None:
+ if option.default is not None:
values[option.key] = option.default
# next set the value specified in the options file
@@ -287,9 +288,13 @@ class Variables(object):
env - an environment that is used to get the current values
of the options.
+ cmp - Either a function as follows: The specific sort function should take two arguments and return -1, 0 or 1
+ or a boolean to indicate if it should be sorted.
"""
- if sort:
+ if callable(sort):
+ options = sorted(self.options, key=cmp_to_key(lambda x,y: sort(x.key,y.key)))
+ elif sort is True:
options = sorted(self.options, key=lambda x: x.key)
else:
options = self.options
diff --git a/src/engine/SCons/Warnings.py b/src/engine/SCons/Warnings.py
index 33ba050..1c84d57 100644
--- a/src/engine/SCons/Warnings.py
+++ b/src/engine/SCons/Warnings.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ This file implements the warnings framework for SCons.
"""
-__revision__ = "src/engine/SCons/Warnings.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/Warnings.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
@@ -74,12 +74,6 @@ class MisleadingKeywordsWarning(WarningOnByDefault):
class MissingSConscriptWarning(WarningOnByDefault):
pass
-class NoMD5ModuleWarning(WarningOnByDefault):
- pass
-
-class NoMetaclassSupportWarning(WarningOnByDefault):
- pass
-
class NoObjectCountWarning(WarningOnByDefault):
pass
@@ -153,6 +147,9 @@ class DeprecatedSigModuleWarning(MandatoryDeprecatedWarning):
class DeprecatedBuilderKeywordsWarning(MandatoryDeprecatedWarning):
pass
+class DeprecatedMissingSConscriptWarning(DeprecatedWarning):
+ pass
+
# The below is a list of 2-tuples. The first element is a class object.
# The second element is true if that class is enabled, false if it is disabled.
@@ -185,8 +182,8 @@ def warn(clazz, *args):
global _enabled, _warningAsException, _warningOut
warning = clazz(args)
- for clazz, flag in _enabled:
- if isinstance(warning, clazz):
+ for cls, flag in _enabled:
+ if isinstance(warning, cls):
if flag:
if _warningAsException:
raise warning
@@ -196,9 +193,10 @@ def warn(clazz, *args):
break
def process_warn_strings(arguments):
- """Process string specifications of enabling/disabling warnings,
- as passed to the --warn option or the SetOption('warn') function.
-
+ """Process requests to enable/disable warnings.
+
+ The requests are strings passed to the --warn option or the
+ SetOption('warn') function.
An argument to this option should be of the form <warning-class>
or no-<warning-class>. The warning class is munged in order
@@ -213,7 +211,6 @@ def process_warn_strings(arguments):
As a special case, --warn=all and --warn=no-all will enable or
disable (respectively) the base Warning class of all warnings.
-
"""
def _capitalize(s):
diff --git a/src/engine/SCons/WarningsTests.py b/src/engine/SCons/WarningsTests.py
index fbba547..2b36eb2 100644
--- a/src/engine/SCons/WarningsTests.py
+++ b/src/engine/SCons/WarningsTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,13 +21,11 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/WarningsTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/WarningsTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import sys
import unittest
-import TestUnit
-
import SCons.Warnings
class TestOutput(object):
@@ -127,8 +125,7 @@ class WarningsTestCase(unittest.TestCase):
assert to.out == "Foo", to.out
if __name__ == "__main__":
- suite = unittest.makeSuite(WarningsTestCase, 'test_')
- TestUnit.run(suite)
+ unittest.main()
# Local Variables:
# tab-width:4
diff --git a/src/engine/SCons/__init__.py b/src/engine/SCons/__init__.py
index 5a22146..c915441 100644
--- a/src/engine/SCons/__init__.py
+++ b/src/engine/SCons/__init__.py
@@ -5,7 +5,7 @@ The main package for the SCons software construction utility.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,17 +27,17 @@ The main package for the SCons software construction utility.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-__version__ = "3.0.0"
+__version__ = "3.1.0"
-__build__ = "rel_3.0.0:4395:8972f6a2f699"
+__build__ = "e724ae812eb96f4858a132f5b8c769724744faf6"
-__buildsys__ = "ubuntu-16"
+__buildsys__ = "kufra"
-__date__ = "2017/09/18 12:59:24"
+__date__ = "2019-07-21 00:04:47"
-__developer__ = "bdbaddog"
+__developer__ = "bdeegan"
# make sure compatibility is always in place
import SCons.compat
diff --git a/src/engine/SCons/compat/__init__.py b/src/engine/SCons/compat/__init__.py
index 7973732..dcbd8e8 100644
--- a/src/engine/SCons/compat/__init__.py
+++ b/src/engine/SCons/compat/__init__.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,31 +57,22 @@ function defined below loads the module as the "real" name (without the
rest of our code will find our pre-loaded compatibility module.
"""
-__revision__ = "src/engine/SCons/compat/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/compat/__init__.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import sys
-import imp # Use the "imp" module to protect imports from fixers.
+import importlib
PYPY = hasattr(sys, 'pypy_translation_info')
-def import_as(module, name):
- """
- Imports the specified module (from our local directory) as the
- specified name, returning the loaded module object.
- """
- dir = os.path.split(__file__)[0]
- return imp.load_module(name, *imp.find_module(module, [dir]))
-
-
def rename_module(new, old):
"""
- Attempts to import the old module and load it under the new name.
+ Attempt to import the old module and load it under the new name.
Used for purely cosmetic name changes in Python 3.x.
"""
try:
- sys.modules[new] = imp.load_module(old, *imp.find_module(old))
+ sys.modules[new] = importlib.import_module(old)
return True
except ImportError:
return False
@@ -98,7 +89,7 @@ import pickle
# Was pickle.HIGHEST_PROTOCOL
# Changed to 2 so py3.5+'s pickle will be compatible with py2.7.
-PICKLE_PROTOCOL = 2
+PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
# TODO: FIXME
# In 3.x, 'profile' automatically loads the fast version if available.
@@ -122,28 +113,28 @@ except AttributeError:
# intern into the sys package
sys.intern = intern
-# Preparing for 3.x. UserDict, UserList, UserString are in
-# collections for 3.x, but standalone in 2.7.x
+# UserDict, UserList, UserString are in # collections for 3.x,
+# but standalone in 2.7.x. Monkey-patch into collections for 2.7.
import collections
try:
collections.UserDict
except AttributeError:
- exec ('from UserDict import UserDict as _UserDict')
+ from UserDict import UserDict as _UserDict
collections.UserDict = _UserDict
del _UserDict
try:
collections.UserList
except AttributeError:
- exec ('from UserList import UserList as _UserList')
+ from UserList import UserList as _UserList
collections.UserList = _UserList
del _UserList
try:
collections.UserString
except AttributeError:
- exec ('from UserString import UserString as _UserString')
+ from UserString import UserString as _UserString
collections.UserString = _UserString
del _UserString
diff --git a/src/engine/SCons/compat/_scons_dbm.py b/src/engine/SCons/compat/_scons_dbm.py
index 7adbeb9..ec5e261 100644
--- a/src/engine/SCons/compat/_scons_dbm.py
+++ b/src/engine/SCons/compat/_scons_dbm.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ that the whichdb.whichdb() implementstation in the various 2.X versions of
Python won't blow up even if dbm wasn't compiled in.
"""
-__revision__ = "src/engine/SCons/compat/_scons_dbm.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/compat/_scons_dbm.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
class error(Exception):
pass
diff --git a/src/engine/SCons/cpp.py b/src/engine/SCons/cpp.py
index ff750c2..7c4ac92 100644
--- a/src/engine/SCons/cpp.py
+++ b/src/engine/SCons/cpp.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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/cpp.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/cpp.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
__doc__ = """
SCons C Pre-Processor module
@@ -43,15 +43,18 @@ import re
# that we want to fetch, using the regular expressions to which the lists
# of preprocessor directives map.
cpp_lines_dict = {
- # Fetch the rest of a #if/#elif/#ifdef/#ifndef as one argument,
+ # Fetch the rest of a #if/#elif as one argument,
+ # with white space optional.
+ ('if', 'elif') : r'\s*(.+)',
+
+ # Fetch the rest of a #ifdef/#ifndef as one argument,
# separated from the keyword by white space.
- ('if', 'elif', 'ifdef', 'ifndef',)
- : '\s+(.+)',
+ ('ifdef', 'ifndef',): r'\s+(.+)',
# Fetch the rest of a #import/#include/#include_next line as one
# argument, with white space optional.
('import', 'include', 'include_next',)
- : '\s*(.+)',
+ : r'\s*(.+)',
# We don't care what comes after a #else or #endif line.
('else', 'endif',) : '',
@@ -61,10 +64,10 @@ cpp_lines_dict = {
# 2) The optional parentheses and arguments (if it's a function-like
# macro, '' if it's not).
# 3) The expansion value.
- ('define',) : '\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)',
+ ('define',) : r'\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)',
# Fetch the #undefed keyword from a #undef line.
- ('undef',) : '\s+([_A-Za-z][A-Za-z0-9_]*)',
+ ('undef',) : r'\s+([_A-Za-z][A-Za-z0-9_]*)',
}
# Create a table that maps each individual C preprocessor directive to
@@ -82,9 +85,9 @@ del op_list
# Create a list of the expressions we'll use to match all of the
# preprocessor directives. These are the same as the directives
# themselves *except* that we must use a negative lookahead assertion
-# when matching "if" so it doesn't match the "if" in "ifdef."
+# when matching "if" so it doesn't match the "if" in "ifdef" or "ifndef".
override = {
- 'if' : 'if(?!def)',
+ 'if' : 'if(?!n?def)',
}
l = [override.get(x, x) for x in list(Table.keys())]
@@ -94,7 +97,7 @@ l = [override.get(x, x) for x in list(Table.keys())]
# a list of tuples, one for each preprocessor line. The preprocessor
# directive will be the first element in each tuple, and the rest of
# the line will be the second element.
-e = '^\s*#\s*(' + '|'.join(l) + ')(.*)$'
+e = r'^\s*#\s*(' + '|'.join(l) + ')(.*)$'
# And last but not least, compile the expression.
CPP_Expression = re.compile(e, re.M)
@@ -141,12 +144,12 @@ CPP_to_Python_Ops_Expression = re.compile(expr)
# A separate list of expressions to be evaluated and substituted
# sequentially, not all at once.
CPP_to_Python_Eval_List = [
- ['defined\s+(\w+)', '"\\1" in __dict__'],
- ['defined\s*\((\w+)\)', '"\\1" in __dict__'],
- ['/\*.*\*/', ''],
- ['/\*.*', ''],
- ['//.*', ''],
- ['(0x[0-9A-Fa-f]*)[UL]+', '\\1'],
+ [r'defined\s+(\w+)', '"\\1" in __dict__'],
+ [r'defined\s*\((\w+)\)', '"\\1" in __dict__'],
+ [r'/\*.*\*/', ''],
+ [r'/\*.*', ''],
+ [r'//.*', ''],
+ [r'(0x[0-9A-Fa-f]*)[UL]+', '\\1'],
]
# Replace the string representations of the regular expressions in the
@@ -162,7 +165,7 @@ def CPP_to_Python(s):
"""
s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s)
for expr, repl in CPP_to_Python_Eval_List:
- s = expr.sub(repl, s)
+ s = re.sub(expr, repl, s)
return s
@@ -207,7 +210,7 @@ class FunctionEvaluator(object):
parts = []
for s in self.expansion:
- if not s in self.args:
+ if s not in self.args:
s = repr(s)
parts.append(s)
statement = ' + '.join(parts)
@@ -222,11 +225,11 @@ line_continuations = re.compile('\\\\\r?\n')
# Search for a "function call" macro on an expansion. Returns the
# two-tuple of the "function" name itself, and a string containing the
# arguments within the call parentheses.
-function_name = re.compile('(\S+)\(([^)]*)\)')
+function_name = re.compile(r'(\S+)\(([^)]*)\)')
# Split a string containing comma-separated function call arguments into
# the separate arguments.
-function_arg_separator = re.compile(',\s*')
+function_arg_separator = re.compile(r',\s*')
diff --git a/src/engine/SCons/cppTests.py b/src/engine/SCons/cppTests.py
index 2108277..6d41ab0 100644
--- a/src/engine/SCons/cppTests.py
+++ b/src/engine/SCons/cppTests.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
from __future__ import absolute_import
-__revision__ = "src/engine/SCons/cppTests.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/cppTests.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import atexit
import sys
@@ -346,6 +346,80 @@ nested_ifs_input = """
+ifndef_input = """
+#define DEFINED 0
+
+#ifndef DEFINED
+#include "file45-no"
+#else
+#include "file45-yes"
+#endif
+
+#ifndef NOT_DEFINED
+#include <file46-yes>
+#else
+#include <file46-no>
+#endif
+"""
+
+
+if_defined_no_space_input = """
+#define DEFINED 0
+
+#if(defined DEFINED)
+#include "file47-yes"
+#endif
+
+#if(!defined DEFINED)
+#include <file48-no>
+#elif(!defined DEFINED)
+#include <file49-no>
+#else
+#include <file50-yes>
+#endif
+
+#if!(defined DEFINED)
+#include "file51-no"
+#elif!(defined DEFINED)
+#include <file52-no>
+#else
+#include "file53-yes"
+#endif
+"""
+
+if_no_space_input = """
+#define DEFINED 0
+
+#if(DEFINED)
+#include "file54-no"
+#endif
+
+#if!(DEFINED)
+#include <file55-yes>
+#elif!(DEFINED)
+#include <file56-no>
+#endif
+
+#if(DEFINED)
+#include "file57-no"
+#elif(!DEFINED)
+#include <file58-yes>
+#endif
+
+#if!( DEFINED)
+#include "file59-yes"
+#elif!( DEFINED)
+#include <file60-no>
+#endif
+
+#if( DEFINED)
+#include "file61-no"
+#elif(! DEFINED)
+#include <file62-yes>
+#endif
+"""
+
+
# pp_class = PreProcessor
# #pp_class = DumbPreProcessor
@@ -426,6 +500,25 @@ class cppTestCase(unittest.TestCase):
result = self.cpp.process_contents(nested_ifs_input)
assert expect == result, (expect, result)
+ def test_ifndef(self):
+ """Test basic #ifndef processing"""
+ expect = self.ifndef_expect
+ result = self.cpp.process_contents(ifndef_input)
+ assert expect == result, (expect, result)
+
+ def test_if_defined_no_space(self):
+ """Test #if(defined, i.e.without space but parenthesis"""
+ expect = self.if_defined_no_space_expect
+ result = self.cpp.process_contents(if_defined_no_space_input)
+ assert expect == result, (expect, result)
+
+ def test_if_no_space(self):
+ """Test #if(, i.e. without space but parenthesis"""
+ expect = self.if_no_space_expect
+ result = self.cpp.process_contents(if_no_space_input)
+ assert expect == result, (expect, result)
+
+
class cppAllTestCase(cppTestCase):
def setUp(self):
self.cpp = self.cpp_class(current = ".",
@@ -513,6 +606,24 @@ class PreProcessorTestCase(cppAllTestCase):
('include', '"', 'file7-yes'),
]
+ ifndef_expect = [
+ ('include', '"', 'file45-yes'),
+ ('include', '<', 'file46-yes'),
+ ]
+
+ if_defined_no_space_expect = [
+ ('include', '"', 'file47-yes'),
+ ('include', '<', 'file50-yes'),
+ ('include', '"', 'file53-yes'),
+ ]
+
+ if_no_space_expect = [
+ ('include', '<', 'file55-yes'),
+ ('include', '<', 'file58-yes'),
+ ('include', '"', 'file59-yes'),
+ ('include', '<', 'file62-yes'),
+ ]
+
class DumbPreProcessorTestCase(cppAllTestCase):
cpp_class = cpp.DumbPreProcessor
@@ -625,7 +736,34 @@ class DumbPreProcessorTestCase(cppAllTestCase):
('include', '"', 'file7-yes')
]
+ ifndef_expect = [
+ ('include', '"', 'file45-no'),
+ ('include', '"', 'file45-yes'),
+ ('include', '<', 'file46-yes'),
+ ('include', '<', 'file46-no'),
+ ]
+
+ if_defined_no_space_expect = [
+ ('include', '"', 'file47-yes'),
+ ('include', '<', 'file48-no'),
+ ('include', '<', 'file49-no'),
+ ('include', '<', 'file50-yes'),
+ ('include', '"', 'file51-no'),
+ ('include', '<', 'file52-no'),
+ ('include', '"', 'file53-yes'),
+ ]
+ if_no_space_expect = [
+ ('include', '"', 'file54-no'),
+ ('include', '<', 'file55-yes'),
+ ('include', '<', 'file56-no'),
+ ('include', '"', 'file57-no'),
+ ('include', '<', 'file58-yes'),
+ ('include', '"', 'file59-yes'),
+ ('include', '<', 'file60-no'),
+ ('include', '"', 'file61-no'),
+ ('include', '<', 'file62-yes'),
+ ]
import os
import re
@@ -679,7 +817,8 @@ class fileTestCase(unittest.TestCase):
return '\n'.join(map(strip_spaces, lines))
def write(self, file, contents):
- open(file, 'w').write(self.strip_initial_spaces(contents))
+ with open(file, 'w') as f:
+ f.write(self.strip_initial_spaces(contents))
def test_basic(self):
"""Test basic file inclusion"""
diff --git a/src/engine/SCons/dblite.py b/src/engine/SCons/dblite.py
index 87a1763..14bd93d 100644
--- a/src/engine/SCons/dblite.py
+++ b/src/engine/SCons/dblite.py
@@ -75,7 +75,8 @@ class dblite(object):
def __init__(self, file_base_name, flag, mode):
assert flag in (None, "r", "w", "c", "n")
- if (flag is None): flag = "r"
+ if flag is None:
+ flag = "r"
base, ext = os.path.splitext(file_base_name)
if ext == dblite_suffix:
@@ -106,17 +107,20 @@ class dblite(object):
self._chown_to = -1 # don't chown
self._chgrp_to = -1 # don't chgrp
- if (self._flag == "n"):
- self._open(self._file_name, "wb", self._mode)
+ if self._flag == "n":
+ with self._open(self._file_name, "wb", self._mode):
+ pass # just make sure it exists
else:
try:
f = self._open(self._file_name, "rb")
except IOError as e:
- if (self._flag != "c"):
+ if self._flag != "c":
raise e
- self._open(self._file_name, "wb", self._mode)
+ with self._open(self._file_name, "wb", self._mode):
+ pass # just make sure it exists
else:
p = f.read()
+ f.close()
if len(p) > 0:
try:
if bytes is not str:
@@ -132,7 +136,7 @@ class dblite(object):
corruption_warning(self._file_name)
def close(self):
- if (self._needs_sync):
+ if self._needs_sync:
self.sync()
def __del__(self):
diff --git a/src/engine/SCons/exitfuncs.py b/src/engine/SCons/exitfuncs.py
index 2b7bd51..c5414a2 100644
--- a/src/engine/SCons/exitfuncs.py
+++ b/src/engine/SCons/exitfuncs.py
@@ -5,7 +5,7 @@ Register functions which are executed when SCons exits for any reason.
"""
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@ Register functions which are executed when SCons exits for any reason.
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
-__revision__ = "src/engine/SCons/exitfuncs.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/engine/SCons/exitfuncs.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import atexit
diff --git a/src/script/scons-configure-cache.py b/src/script/scons-configure-cache.py
index 9b8b737..757a79f 100644
--- a/src/script/scons-configure-cache.py
+++ b/src/script/scons-configure-cache.py
@@ -2,7 +2,7 @@
#
# SCons - a Software Constructor
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,102 +23,139 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+'''Show or convert the configuration of an SCons cache directory.
+
+A cache of derived files is stored by file signature.
+The files are split into directories named by the first few
+digits of the signature. The prefix length used for directory
+names can be changed by this script.
+'''
+
from __future__ import print_function
+import argparse
+import glob
+import json
+import os
-__revision__ = "src/script/scons-configure-cache.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/script/scons-configure-cache.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-__version__ = "3.0.0"
+__version__ = "3.1.0"
-__build__ = "rel_3.0.0:4395:8972f6a2f699"
+__build__ = "e724ae812eb96f4858a132f5b8c769724744faf6"
-__buildsys__ = "ubuntu-16"
+__buildsys__ = "kufra"
-__date__ = "2017/09/18 12:59:24"
+__date__ = "2019-07-21 00:04:47"
-__developer__ = "bdbaddog"
+__developer__ = "bdeegan"
-import argparse
-import glob
-import json
-import os
def rearrange_cache_entries(current_prefix_len, new_prefix_len):
- print('Changing prefix length from', current_prefix_len, 'to', new_prefix_len)
+ '''Move cache files if prefix length changed.
+
+ Move the existing cache files to new directories of the
+ appropriate name length and clean up the old directories.
+ '''
+ print('Changing prefix length from', current_prefix_len,
+ 'to', new_prefix_len)
dirs = set()
old_dirs = set()
for file in glob.iglob(os.path.join('*', '*')):
name = os.path.basename(file)
- dir = name[:current_prefix_len].upper()
- if dir not in old_dirs:
- print('Migrating', dir)
- old_dirs.add(dir)
- dir = name[:new_prefix_len].upper()
- if dir not in dirs:
- os.mkdir(dir)
- dirs.add(dir)
- os.rename(file, os.path.join(dir, name))
+ dname = name[:current_prefix_len].upper()
+ if dname not in old_dirs:
+ print('Migrating', dname)
+ old_dirs.add(dname)
+ dname = name[:new_prefix_len].upper()
+ if dname not in dirs:
+ os.mkdir(dname)
+ dirs.add(dname)
+ os.rename(file, os.path.join(dname, name))
# Now delete the original directories
- for dir in old_dirs:
- os.rmdir(dir)
+ for dname in old_dirs:
+ os.rmdir(dname)
+
-# This dictionary should have one entry per entry in the cache config
-# Each entry should have the following:
+# The configuration dictionary should have one entry per entry in the
+# cache config. The value of each entry should include the following:
# implicit - (optional) This is to allow adding a new config entry and also
# changing the behaviour of the system at the same time. This
-# indicates the value the config entry would have had if it had been
-# specified.
+# indicates the value the config entry would have had if it had
+# been specified.
# default - The value the config entry should have if it wasn't previously
# specified
# command-line - parameters to pass to ArgumentParser.add_argument
-# converter - (optional) Function to call if it's necessary to do some work
+# converter - (optional) Function to call if conversion is required
# if this configuration entry changes
config_entries = {
- 'prefix_len' : {
- 'implicit' : 1,
- 'default' : 2 ,
- 'command-line' : {
- 'help' : 'Length of cache file name used as subdirectory prefix',
- 'metavar' : '<number>',
- 'type' : int
- },
- 'converter' : rearrange_cache_entries
+ 'prefix_len': {
+ 'implicit': 1,
+ 'default': 2,
+ 'command-line': {
+ 'help': 'Length of cache file name used as subdirectory prefix',
+ 'metavar': '<number>',
+ 'type': int
+ },
+ 'converter': rearrange_cache_entries
}
}
+
parser = argparse.ArgumentParser(
- description = 'Modify the configuration of an scons cache directory',
- epilog = '''
- Unless you specify an option, it will not be changed (if it is
- already set in the cache config), or changed to an appropriate
- default (it it is not set).
- '''
- )
+ description='Modify the configuration of an scons cache directory',
+ epilog='''
+ Unspecified options will not be changed unless they are not
+ set at all, in which case they are set to an appropriate default.
+ ''')
parser.add_argument('cache-dir', help='Path to scons cache directory')
for param in config_entries:
- parser.add_argument('--' + param.replace('_', '-'),
+ parser.add_argument('--' + param.replace('_', '-'),
**config_entries[param]['command-line'])
-parser.add_argument('--version', action='version', version='%(prog)s 1.0')
+parser.add_argument('--version',
+ action='version',
+ version='%(prog)s 1.0')
+parser.add_argument('--show',
+ action="store_true",
+ help="show current configuration")
# Get the command line as a dict without any of the unspecified entries.
args = dict([x for x in vars(parser.parse_args()).items() if x[1]])
# It seems somewhat strange to me, but positional arguments don't get the -
# in the name changed to _, whereas optional arguments do...
-os.chdir(args['cache-dir'])
+cache = args['cache-dir']
+if not os.path.isdir(cache):
+ raise RuntimeError("There is no cache directory named %s" % cache)
+os.chdir(cache)
del args['cache-dir']
if not os.path.exists('config'):
+ # old config dirs did not have a 'config' file. Try to update.
# Validate the only files in the directory are directories 0-9, a-f
- expected = [ '{:X}'.format(x) for x in range(0, 16) ]
+ expected = ['{:X}'.format(x) for x in range(0, 16)]
if not set(os.listdir('.')).issubset(expected):
- raise RuntimeError("This doesn't look like a version 1 cache directory")
+ raise RuntimeError(
+ "%s does not look like a valid version 1 cache directory" % cache)
config = dict()
else:
with open('config') as conf:
config = json.load(conf)
-# Find any keys that aren't currently set but should be
+if args.get('show', None):
+ print("Current configuration in '%s':" % cache)
+ print(json.dumps(config, sort_keys=True,
+ indent=4, separators=(',', ': ')))
+ # in case of the show argument, emit some stats as well
+ file_count = 0
+ for _, _, files in os.walk('.'):
+ file_count += len(files)
+ if file_count: # skip config file if it exists
+ file_count -= 1
+ print("Cache contains %s files" % file_count)
+ del args['show']
+
+# Find any keys that are not currently set but should be
for key in config_entries:
if key not in config:
if 'implicit' in config_entries[key]:
@@ -128,10 +165,10 @@ for key in config_entries:
if key not in args:
args[key] = config_entries[key]['default']
-#Now we go through each entry in args to see if it changes an existing config
-#setting.
+# Now go through each entry in args to see if it changes an existing config
+# setting.
for key in args:
- if args[key] != config[key]:
+ if args[key] != config[key]:
if 'converter' in config_entries[key]:
config_entries[key]['converter'](config[key], args[key])
config[key] = args[key]
diff --git a/src/script/scons-time.py b/src/script/scons-time.py
index 08bde60..975ff64 100644
--- a/src/script/scons-time.py
+++ b/src/script/scons-time.py
@@ -9,7 +9,7 @@
#
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import division, print_function
-__revision__ = "src/script/scons-time.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/script/scons-time.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import getopt
import glob
@@ -41,29 +41,15 @@ import shutil
import sys
import tempfile
import time
-
-def make_temp_file(**kw):
- try:
- result = tempfile.mktemp(**kw)
- result = os.path.realpath(result)
- except TypeError:
- try:
- save_template = tempfile.template
- prefix = kw['prefix']
- del kw['prefix']
- tempfile.template = prefix
- result = tempfile.mktemp(**kw)
- finally:
- tempfile.template = save_template
- return result
+import subprocess
def HACK_for_exec(cmd, *args):
- '''
+ """
For some reason, Python won't allow an exec() within a function
that also declares an internal function (including lambda functions).
This function is a hack that calls exec() in a function with no
internal functions.
- '''
+ """
if not args: exec(cmd)
elif len(args) == 1: exec(cmd, args[0])
else: exec(cmd, args[0], args[1])
@@ -121,7 +107,7 @@ class Line(object):
# in the line's index number. We might want to represent
# this some way rather than just drawing the line straight
# between the two points on either side.
- if not y is None:
+ if y is not None:
print(fmt % (x, y))
print('e')
@@ -147,7 +133,7 @@ class Gnuplotter(Plotter):
return line.plot_string()
def vertical_bar(self, x, type, label, comment):
- if self.get_min_x() <= x and x <= self.get_max_x():
+ if self.get_min_x() <= x <= self.get_max_x():
points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))]
self.line(points, type, label, comment)
@@ -155,13 +141,13 @@ class Gnuplotter(Plotter):
result = []
for line in self.lines:
result.extend(line.get_x_values())
- return [r for r in result if not r is None]
+ return [r for r in result if r is not None]
def get_all_y_values(self):
result = []
for line in self.lines:
result.extend(line.get_y_values())
- return [r for r in result if not r is None]
+ return [r for r in result if r is not None]
def get_min_x(self):
try:
@@ -248,14 +234,16 @@ def unzip(fname):
os.makedirs(dir)
except:
pass
- open(name, 'wb').write(zf.read(name))
+ with open(name, 'wb') as f:
+ f.write(zf.read(name))
def read_tree(dir):
for dirpath, dirnames, filenames in os.walk(dir):
for fn in filenames:
fn = os.path.join(dirpath, fn)
if os.path.isfile(fn):
- open(fn, 'rb').read()
+ with open(fn, 'rb') as f:
+ f.read()
def redirect_to_file(command, log):
return '%s > %s 2>&1' % (command, log)
@@ -264,7 +252,7 @@ def tee_to_file(command, log):
return '%s 2>&1 | tee %s' % (command, log)
-
+
class SConsTimer(object):
"""
Usage: scons-time SUBCOMMAND [ARGUMENTS]
@@ -360,7 +348,7 @@ class SConsTimer(object):
'SCons' : 'Total SCons execution time',
'commands' : 'Total command execution time',
}
-
+
time_string_all = 'Total .* time'
#
@@ -456,14 +444,20 @@ class SConsTimer(object):
def log_execute(self, command, log):
command = self.subst(command, self.__dict__)
- output = os.popen(command).read()
+ p = os.popen(command)
+ output = p.read()
+ p.close()
+ #TODO: convert to subrocess, os.popen is obsolete. This didn't work:
+ #process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
+ #output = process.stdout.read()
+ #process.stdout.close()
+ #process.wait()
if self.verbose:
sys.stdout.write(output)
# TODO: Figure out
# Not sure we need to write binary here
- open(log, 'w').write(output)
-
- #
+ with open(log, 'w') as f:
+ f.write(str(output))
def archive_splitext(self, path):
"""
@@ -628,13 +622,14 @@ class SConsTimer(object):
search_string = self.time_string_all
else:
search_string = time_string
- contents = open(file).read()
+ with open(file) as f:
+ contents = f.read()
if not contents:
sys.stderr.write('file %s has no contents!\n' % repr(file))
return None
result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:]
result = [ float(r) for r in result ]
- if not time_string is None:
+ if time_string is not None:
try:
result = result[0]
except IndexError:
@@ -673,7 +668,8 @@ class SConsTimer(object):
search_string = self.memory_string_all
else:
search_string = memory_string
- lines = open(file).readlines()
+ with open(file) as f:
+ lines = f.readlines()
lines = [ l for l in lines if l.startswith(search_string) ][-4:]
result = [ int(l.split()[-1]) for l in lines[-4:] ]
if len(result) == 1:
@@ -685,14 +681,14 @@ class SConsTimer(object):
Returns the counts of the specified object_name.
"""
object_string = ' ' + object_name + '\n'
- lines = open(file).readlines()
+ with open(file) as f:
+ lines = f.readlines()
line = [ l for l in lines if l.endswith(object_string) ][0]
result = [ int(field) for field in line.split()[:4] ]
if index is not None:
result = result[index]
return result
- #
command_alias = {}
@@ -814,7 +810,9 @@ class SConsTimer(object):
self.title = a
if self.config_file:
- exec(open(self.config_file, 'r').read(), self.__dict__)
+ with open(self.config_file, 'r') as f:
+ config = f.read()
+ exec(config, self.__dict__)
if self.chdir:
os.chdir(self.chdir)
@@ -923,7 +921,7 @@ class SConsTimer(object):
elif o in ('-p', '--prefix'):
self.prefix = a
elif o in ('--stage',):
- if not a in self.stages:
+ if a not in self.stages:
sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (self.name, a))
sys.exit(1)
stage = a
@@ -933,7 +931,9 @@ class SConsTimer(object):
self.title = a
if self.config_file:
- HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__)
+ with open(self.config_file, 'r') as f:
+ config = f.read()
+ HACK_for_exec(config, self.__dict__)
if self.chdir:
os.chdir(self.chdir)
@@ -1035,7 +1035,7 @@ class SConsTimer(object):
elif o in ('-p', '--prefix'):
self.prefix = a
elif o in ('--stage',):
- if not a in self.stages:
+ if a not in self.stages:
sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (self.name, a))
sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name))
sys.exit(1)
@@ -1053,7 +1053,9 @@ class SConsTimer(object):
object_name = args.pop(0)
if self.config_file:
- HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__)
+ with open(self.config_file, 'r') as f:
+ config = f.read()
+ HACK_for_exec(config, self.__dict__)
if self.chdir:
os.chdir(self.chdir)
@@ -1191,7 +1193,9 @@ class SConsTimer(object):
sys.exit(1)
if self.config_file:
- exec(open(self.config_file, 'r').read(), self.__dict__)
+ with open(self.config_file, 'r') as f:
+ config = f.read()
+ exec(config, self.__dict__)
if args:
self.archive_list = args
@@ -1231,7 +1235,7 @@ class SConsTimer(object):
return os.path.join(dir, 'src', 'engine')
def prep_aegis_run(self, commands, removals):
- self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-')
+ self.aegis_tmpdir = tempfile.mkdtemp(prefix=self.name + '-aegis-')
removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir))
self.aegis_parent_project = os.path.splitext(self.aegis_project)[0]
@@ -1239,21 +1243,19 @@ class SConsTimer(object):
self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir)
commands.extend([
- 'mkdir %(aegis_tmpdir)s',
(lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'),
'%(aegis)s -cp -ind -p %(aegis_parent_project)s .',
'%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .',
])
def prep_subversion_run(self, commands, removals):
- self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-')
+ self.svn_tmpdir = tempfile.mkdtemp(prefix=self.name + '-svn-')
removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir))
self.scons = self.scons_path(self.svn_tmpdir)
self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir)
commands.extend([
- 'mkdir %(svn_tmpdir)s',
'%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(svn_tmpdir)s',
])
@@ -1300,11 +1302,9 @@ class SConsTimer(object):
if self.targets2 is None:
self.targets2 = self.targets
- self.tmpdir = make_temp_file(prefix = self.name + '-')
+ self.tmpdir = tempfile.mkdtemp(prefix=self.name + '-')
commands.extend([
- 'mkdir %(tmpdir)s',
-
(os.chdir, 'cd %%s', self.tmpdir),
])
@@ -1357,7 +1357,6 @@ class SConsTimer(object):
if not os.environ.get('PRESERVE'):
commands.extend(removals)
-
commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir))
self.run_command_list(commands, self.__dict__)
@@ -1424,14 +1423,16 @@ class SConsTimer(object):
elif o in ('--title',):
self.title = a
elif o in ('--which',):
- if not a in list(self.time_strings.keys()):
+ if a not in list(self.time_strings.keys()):
sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (self.name, a))
sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name))
sys.exit(1)
which = a
if self.config_file:
- HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__)
+ with open(self.config_file, 'r') as f:
+ config = f.read()
+ HACK_for_exec(config, self.__dict__)
if self.chdir:
os.chdir(self.chdir)
diff --git a/src/script/scons.bat b/src/script/scons.bat
index f759e43..75e2a49 100644
--- a/src/script/scons.bat
+++ b/src/script/scons.bat
@@ -1,11 +1,11 @@
-@REM Copyright (c) 2001 - 2017 The SCons Foundation
-@REM src/script/scons.bat rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog
+@REM Copyright (c) 2001 - 2019 The SCons Foundation
+@REM src/script/scons.bat e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan
@echo off
set SCONS_ERRORLEVEL=
if "%OS%" == "Windows_NT" goto WinNT
@REM for 9x/Me you better not have more than 9 args
-python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-3.0.0'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-3.0.0'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %1 %2 %3 %4 %5 %6 %7 %8 %9
+python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-3.1.0'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-3.1.0'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %1 %2 %3 %4 %5 %6 %7 %8 %9
@REM no way to set exit status of this script for 9x/Me
goto endscons
@@ -16,10 +16,14 @@ goto endscons
:WinNT
setlocal
@REM ensure the script will be executed with the Python it was installed for
-set path=%~dp0;%~dp0..;%path%
+pushd %~dp0..
+set path=%~dp0;%CD%;%path%
+popd
@REM try the script named as the .bat file in current dir, then in Scripts subdir
set scriptname=%~dp0%~n0.py
if not exist "%scriptname%" set scriptname=%~dp0Scripts\%~n0.py
+@REM Handle when running from wheel where the script has no .py extension
+if not exist "%scriptname%" set scriptname=%~dp0%~n0
python "%scriptname%" %*
endlocal & set SCONS_ERRORLEVEL=%ERRORLEVEL%
diff --git a/src/script/scons.py b/src/script/scons.py
index bee0224..b3172b1 100644..100755
--- a/src/script/scons.py
+++ b/src/script/scons.py
@@ -2,7 +2,7 @@
#
# SCons - a Software Constructor
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,22 +25,30 @@
from __future__ import print_function
-__revision__ = "src/script/scons.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/script/scons.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-__version__ = "3.0.0"
+__version__ = "3.1.0"
-__build__ = "rel_3.0.0:4395:8972f6a2f699"
+__build__ = "e724ae812eb96f4858a132f5b8c769724744faf6"
-__buildsys__ = "ubuntu-16"
+__buildsys__ = "kufra"
-__date__ = "2017/09/18 12:59:24"
+__date__ = "2019-07-21 00:04:47"
-__developer__ = "bdbaddog"
+__developer__ = "bdeegan"
+
+# This is the entry point to the SCons program.
+# The only job of this script is to work out where the guts of the program
+# could be and import them, where the real work begins.
+# SCons can be invoked several different ways
+# - from an installed location
+# - from a "local install" copy
+# - from a source tree, which has a different dir struture than the other two
+# Try to account for all those possibilities.
import os
import sys
-
##############################################################################
# BEGIN STANDARD SCons SCRIPT HEADER
#
@@ -50,57 +58,53 @@ import sys
# should also change other scripts that use this same header.
##############################################################################
-# Strip the script directory from sys.path() so on case-insensitive
-# (WIN32) systems Python doesn't think that the "scons" script is the
-# "SCons" package. Replace it with our own library directories
-# (version-specific first, in case they installed by hand there,
-# followed by generic) so we pick up the right version of the build
-# engine modules if they're in either directory.
-
-
+# compatibility check
if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0):
msg = "scons: *** SCons version %s does not run under Python version %s.\n\
-Python < 3.5 is not yet supported.\n"
+Python 2.7 or >= 3.5 is required.\n"
sys.stderr.write(msg % (__version__, sys.version.split()[0]))
sys.exit(1)
-
-script_dir = sys.path[0]
-
-if script_dir in sys.path:
- sys.path.remove(script_dir)
+# Strip the script directory from sys.path so on case-insensitive
+# (WIN32) systems Python doesn't think that the "scons" script is the
+# "SCons" package.
+script_dir = os.path.dirname(os.path.realpath(__file__))
+script_path = os.path.realpath(os.path.dirname(__file__))
+if script_path in sys.path:
+ sys.path.remove(script_path)
libs = []
if "SCONS_LIB_DIR" in os.environ:
libs.append(os.environ["SCONS_LIB_DIR"])
-# - running from source takes priority (since 2.3.2), excluding SCONS_LIB_DIR settings
-script_path = os.path.abspath(os.path.dirname(__file__))
-source_path = os.path.join(script_path, '..', 'engine')
-libs.append(source_path)
+# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR
+source_path = os.path.join(script_path, os.pardir, 'engine')
+if os.path.isdir(source_path):
+ libs.append(source_path)
+# add local-install locations
local_version = 'scons-local-' + __version__
local = 'scons-local'
if script_dir:
local_version = os.path.join(script_dir, local_version)
local = os.path.join(script_dir, local)
-libs.append(os.path.abspath(local_version))
-libs.append(os.path.abspath(local))
+if os.path.isdir(local_version):
+ libs.append(os.path.abspath(local_version))
+if os.path.isdir(local):
+ libs.append(os.path.abspath(local))
scons_version = 'scons-%s' % __version__
# preferred order of scons lookup paths
prefs = []
-
-# - running from egg check
+# if we can find package information, use it
try:
import pkg_resources
except ImportError:
pass
else:
- # when running from an egg add the egg's directory
try:
d = pkg_resources.get_distribution('scons')
except pkg_resources.DistributionNotFound:
@@ -109,18 +113,18 @@ else:
prefs.append(d.location)
if sys.platform == 'win32':
- # sys.prefix is (likely) C:\Python*;
- # check only C:\Python*.
+ # Use only sys.prefix on Windows
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))
else:
# On other (POSIX) platforms, things are more complicated due to
- # the variety of path names and library locations. Try to be smart
- # about it.
+ # the variety of path names and library locations.
+ # Build up some possibilities, then transform them into candidates
+ temp = []
if script_dir == 'bin':
# script_dir is `pwd`/bin;
# check `pwd`/lib/scons*.
- prefs.append(os.getcwd())
+ temp.append(os.getcwd())
else:
if script_dir == '.' or script_dir == '':
script_dir = os.getcwd()
@@ -128,42 +132,41 @@ else:
if tail == "bin":
# script_dir is /foo/bin;
# check /foo/lib/scons*.
- prefs.append(head)
+ temp.append(head)
head, tail = os.path.split(sys.prefix)
if tail == "usr":
# sys.prefix is /foo/usr;
# check /foo/usr/lib/scons* first,
# then /foo/usr/local/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(os.path.join(sys.prefix, "local"))
+ temp.append(sys.prefix)
+ temp.append(os.path.join(sys.prefix, "local"))
elif tail == "local":
h, t = os.path.split(head)
if t == "usr":
# sys.prefix is /foo/usr/local;
# check /foo/usr/local/lib/scons* first,
# then /foo/usr/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(head)
+ temp.append(sys.prefix)
+ temp.append(head)
else:
# sys.prefix is /foo/local;
# check only /foo/local/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
else:
# sys.prefix is /foo (ends in neither /usr or /local);
# check only /foo/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
+
+ # suffix these to add to our original prefs:
+ prefs.extend([os.path.join(x, 'lib') for x in temp])
+ prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3],
+ 'site-packages') for x in temp])
- temp = [os.path.join(x, 'lib') for x in prefs]
- temp.extend([os.path.join(x,
- 'lib',
- 'python' + sys.version[:3],
- 'site-packages') for x in prefs])
- prefs = temp
# Add the parent directory of the current python's library to the
- # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64,
- # not /usr/lib.
+ # preferences. This picks up differences between, e.g., lib and lib64,
+ # and finds the base location in case of a non-copying virtualenv.
try:
libpath = os.__file__
except AttributeError:
@@ -177,9 +180,9 @@ else:
prefs.append(libpath)
# Look first for 'scons-__version__' in all of our preference libs,
-# then for 'scons'.
-libs.extend([os.path.join(x, scons_version) for x in prefs])
-libs.extend([os.path.join(x, 'scons') for x in prefs])
+# then for 'scons'. Skip paths that do not exist.
+libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)])
+libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)])
sys.path = libs + sys.path
@@ -191,9 +194,9 @@ if __name__ == "__main__":
try:
import SCons.Script
except ImportError:
- print("SCons import failed. Unable to find engine files in:")
+ sys.stderr.write("SCons import failed. Unable to find engine files in:\n")
for path in libs:
- print(" {}".format(path))
+ sys.stderr.write(" {}\n".format(path))
raise
# this does all the work, and calls sys.exit
diff --git a/src/script/sconsign.py b/src/script/sconsign.py
index d3450ab..a0d7b7e 100644
--- a/src/script/sconsign.py
+++ b/src/script/sconsign.py
@@ -2,7 +2,7 @@
#
# SCons - a Software Constructor
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -25,17 +25,17 @@
from __future__ import print_function
-__revision__ = "src/script/sconsign.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/script/sconsign.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
-__version__ = "3.0.0"
+__version__ = "3.1.0"
-__build__ = "rel_3.0.0:4395:8972f6a2f699"
+__build__ = "e724ae812eb96f4858a132f5b8c769724744faf6"
-__buildsys__ = "ubuntu-16"
+__buildsys__ = "kufra"
-__date__ = "2017/09/18 12:59:24"
+__date__ = "2019-07-21 00:04:47"
-__developer__ = "bdbaddog"
+__developer__ = "bdeegan"
import os
import sys
@@ -49,48 +49,53 @@ import sys
# should also change other scripts that use this same header.
##############################################################################
-# Strip the script directory from sys.path() so on case-insensitive
-# (WIN32) systems Python doesn't think that the "scons" script is the
-# "SCons" package. Replace it with our own library directories
-# (version-specific first, in case they installed by hand there,
-# followed by generic) so we pick up the right version of the build
-# engine modules if they're in either directory.
-
+# compatibility check
+if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0):
+ msg = "scons: *** SCons version %s does not run under Python version %s.\n\
+Python 2.7 or >= 3.5 is required.\n"
+ sys.stderr.write(msg % (__version__, sys.version.split()[0]))
+ sys.exit(1)
-script_dir = sys.path[0]
-
-if script_dir in sys.path:
- sys.path.remove(script_dir)
+# Strip the script directory from sys.path so on case-insensitive
+# (WIN32) systems Python doesn't think that the "scons" script is the
+# "SCons" package.
+script_dir = os.path.dirname(os.path.realpath(__file__))
+script_path = os.path.realpath(os.path.dirname(__file__))
+if script_path in sys.path:
+ sys.path.remove(script_path)
libs = []
if "SCONS_LIB_DIR" in os.environ:
libs.append(os.environ["SCONS_LIB_DIR"])
-# - running from source takes priority (since 2.3.2), excluding SCONS_LIB_DIR settings
-script_path = os.path.abspath(os.path.dirname(__file__))
-source_path = os.path.join(script_path, '..', 'engine')
-libs.append(source_path)
+# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR
+source_path = os.path.join(script_path, os.pardir, 'engine')
+if os.path.isdir(source_path):
+ libs.append(source_path)
+# add local-install locations
local_version = 'scons-local-' + __version__
local = 'scons-local'
if script_dir:
local_version = os.path.join(script_dir, local_version)
local = os.path.join(script_dir, local)
-libs.append(os.path.abspath(local_version))
-libs.append(os.path.abspath(local))
+if os.path.isdir(local_version):
+ libs.append(os.path.abspath(local_version))
+if os.path.isdir(local):
+ libs.append(os.path.abspath(local))
scons_version = 'scons-%s' % __version__
# preferred order of scons lookup paths
prefs = []
+# if we can find package information, use it
try:
import pkg_resources
except ImportError:
pass
else:
- # when running from an egg add the egg's directory
try:
d = pkg_resources.get_distribution('scons')
except pkg_resources.DistributionNotFound:
@@ -99,77 +104,76 @@ else:
prefs.append(d.location)
if sys.platform == 'win32':
- # sys.prefix is (likely) C:\Python*;
- # check only C:\Python*.
+ # Use only sys.prefix on Windows
prefs.append(sys.prefix)
prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))
else:
# On other (POSIX) platforms, things are more complicated due to
- # the variety of path names and library locations. Try to be smart
- # about it.
+ # the variety of path names and library locations.
+ # Build up some possibilities, then transform them into candidates
+ temp = []
if script_dir == 'bin':
# script_dir is `pwd`/bin;
# check `pwd`/lib/scons*.
- prefs.append(os.getcwd())
+ temp.append(os.getcwd())
else:
- if script_dir == '.' or script_dir == '':
+ if script_dir in ('.', ''):
script_dir = os.getcwd()
head, tail = os.path.split(script_dir)
if tail == "bin":
# script_dir is /foo/bin;
# check /foo/lib/scons*.
- prefs.append(head)
+ temp.append(head)
head, tail = os.path.split(sys.prefix)
if tail == "usr":
# sys.prefix is /foo/usr;
# check /foo/usr/lib/scons* first,
# then /foo/usr/local/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(os.path.join(sys.prefix, "local"))
+ temp.append(sys.prefix)
+ temp.append(os.path.join(sys.prefix, "local"))
elif tail == "local":
h, t = os.path.split(head)
if t == "usr":
# sys.prefix is /foo/usr/local;
# check /foo/usr/local/lib/scons* first,
# then /foo/usr/lib/scons*.
- prefs.append(sys.prefix)
- prefs.append(head)
+ temp.append(sys.prefix)
+ temp.append(head)
else:
# sys.prefix is /foo/local;
# check only /foo/local/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
else:
# sys.prefix is /foo (ends in neither /usr or /local);
# check only /foo/lib/scons*.
- prefs.append(sys.prefix)
+ temp.append(sys.prefix)
+
+ # suffix these to add to our original prefs:
+ prefs.extend([os.path.join(x, 'lib') for x in temp])
+ prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3],
+ 'site-packages') for x in temp])
- temp = [os.path.join(x, 'lib') for x in prefs]
- temp.extend([os.path.join(x,
- 'lib',
- 'python' + sys.version[:3],
- 'site-packages') for x in prefs])
- prefs = temp
# Add the parent directory of the current python's library to the
- # preferences. On SuSE-91/AMD64, for example, this is /usr/lib64,
- # not /usr/lib.
+ # preferences. This picks up differences between, e.g., lib and lib64,
+ # and finds the base location in case of a non-copying virtualenv.
try:
libpath = os.__file__
except AttributeError:
pass
else:
# Split /usr/libfoo/python*/os.py to /usr/libfoo/python*.
- libpath, tail = os.path.split(libpath)
+ libpath, _ = os.path.split(libpath)
# Split /usr/libfoo/python* to /usr/libfoo
libpath, tail = os.path.split(libpath)
# Check /usr/libfoo/scons*.
prefs.append(libpath)
# Look first for 'scons-__version__' in all of our preference libs,
-# then for 'scons'.
-libs.extend([os.path.join(x, scons_version) for x in prefs])
-libs.extend([os.path.join(x, 'scons') for x in prefs])
+# then for 'scons'. Skip paths that do not exist.
+libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)])
+libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)])
sys.path = libs + sys.path
@@ -181,23 +185,23 @@ import SCons.compat
try:
import whichdb
+
whichdb = whichdb.whichdb
except ImportError as e:
from dbm import whichdb
import time
import pickle
-import imp
import SCons.SConsign
+
def my_whichdb(filename):
if filename[-7:] == ".dblite":
return "SCons.dblite"
try:
- f = open(filename + ".dblite", "rb")
- f.close()
- return "SCons.dblite"
+ with open(filename + ".dblite", "rb"):
+ return "SCons.dblite"
except IOError:
pass
return _orig_whichdb(filename)
@@ -212,6 +216,8 @@ whichdb = my_whichdb
#dbm.whichdb = my_whichdb
def my_import(mname):
+ import imp
+
if '.' in mname:
i = mname.rfind('.')
parent = my_import(mname[:i])
@@ -221,25 +227,41 @@ def my_import(mname):
fp, pathname, description = imp.find_module(mname)
return imp.load_module(mname, fp, pathname, description)
+
class Flagger(object):
default_value = 1
+
def __setitem__(self, item, value):
self.__dict__[item] = value
self.default_value = 0
+
def __getitem__(self, item):
return self.__dict__.get(item, self.default_value)
+
Do_Call = None
Print_Directories = []
Print_Entries = []
Print_Flags = Flagger()
Verbose = 0
Readable = 0
+Warns = 0
+
def default_mapper(entry, name):
+ """
+ Stringify an entry that doesn't have an explicit mapping.
+
+ Args:
+ entry: entry
+ name: field name
+
+ Returns: str
+
+ """
try:
- val = eval("entry."+name)
- except:
+ val = eval("entry." + name)
+ except AttributeError:
val = None
if sys.version_info.major >= 3 and isinstance(val, bytes):
# This is a dirty hack for py 2/3 compatibility. csig is a bytes object
@@ -248,7 +270,18 @@ def default_mapper(entry, name):
val = val.decode()
return str(val)
-def map_action(entry, name):
+
+def map_action(entry, _):
+ """
+ Stringify an action entry and signature.
+
+ Args:
+ entry: action entry
+ second argument is not used
+
+ Returns: str
+
+ """
try:
bact = entry.bact
bactsig = entry.bactsig
@@ -256,7 +289,18 @@ def map_action(entry, name):
return None
return '%s [%s]' % (bactsig, bact)
-def map_timestamp(entry, name):
+
+def map_timestamp(entry, _):
+ """
+ Stringify a timestamp entry.
+
+ Args:
+ entry: timestamp entry
+ second argument is not used
+
+ Returns: str
+
+ """
try:
timestamp = entry.timestamp
except AttributeError:
@@ -266,19 +310,39 @@ def map_timestamp(entry, name):
else:
return str(timestamp)
-def map_bkids(entry, name):
+
+def map_bkids(entry, _):
+ """
+ Stringify an implicit entry.
+
+ Args:
+ entry:
+ second argument is not used
+
+ Returns: str
+
+ """
try:
bkids = entry.bsources + entry.bdepends + entry.bimplicit
bkidsigs = entry.bsourcesigs + entry.bdependsigs + entry.bimplicitsigs
except AttributeError:
return None
- result = []
- for i in range(len(bkids)):
- result.append(nodeinfo_string(bkids[i], bkidsigs[i], " "))
- if result == []:
+
+ if len(bkids) != len(bkidsigs):
+ global Warns
+ Warns += 1
+ # add warning to result rather than direct print so it will line up
+ msg = "Warning: missing information, {} ids but {} sigs"
+ result = [msg.format(len(bkids), len(bkidsigs))]
+ else:
+ result = []
+ result += [nodeinfo_string(bkid, bkidsig, " ")
+ for bkid, bkidsig in zip(bkids, bkidsigs)]
+ if not result:
return None
return "\n ".join(result)
+
map_field = {
'action' : map_action,
'timestamp' : map_timestamp,
@@ -289,6 +353,7 @@ map_name = {
'implicit' : 'bkids',
}
+
def field(name, entry, verbose=Verbose):
if not Print_Flags[name]:
return None
@@ -299,6 +364,7 @@ def field(name, entry, verbose=Verbose):
val = name + ": " + val
return val
+
def nodeinfo_raw(name, ninfo, prefix=""):
# This just formats the dictionary, which we would normally use str()
# to do, except that we want the keys sorted for deterministic output.
@@ -314,6 +380,7 @@ def nodeinfo_raw(name, ninfo, prefix=""):
name = repr(name)
return name + ': {' + ', '.join(l) + '}'
+
def nodeinfo_cooked(name, ninfo, prefix=""):
try:
field_list = ninfo.field_list
@@ -321,15 +388,19 @@ def nodeinfo_cooked(name, ninfo, prefix=""):
field_list = []
if '\n' in name:
name = repr(name)
- outlist = [name+':'] + [_f for _f in [field(x, ninfo, Verbose) for x in field_list] if _f]
+ outlist = [name + ':'] + [
+ f for f in [field(x, ninfo, Verbose) for x in field_list] if f
+ ]
if Verbose:
sep = '\n ' + prefix
else:
sep = ' '
return sep.join(outlist)
+
nodeinfo_string = nodeinfo_cooked
+
def printfield(name, entry, prefix=""):
outlist = field("implicit", entry, 0)
if outlist:
@@ -343,13 +414,15 @@ def printfield(name, entry, prefix=""):
else:
print(" " + outact)
+
def printentries(entries, location):
if Print_Entries:
for name in Print_Entries:
try:
entry = entries[name]
except KeyError:
- sys.stderr.write("sconsign: no entry `%s' in `%s'\n" % (name, location))
+ err = "sconsign: no entry `%s' in `%s'\n" % (name, location)
+ sys.stderr.write(err)
else:
try:
ninfo = entry.ninfo
@@ -369,6 +442,7 @@ def printentries(entries, location):
print(nodeinfo_string(name, entry.ninfo))
printfield(name, entry.binfo)
+
class Do_SConsignDB(object):
def __init__(self, dbm_name, dbm):
self.dbm_name = dbm_name
@@ -376,8 +450,8 @@ class Do_SConsignDB(object):
def __call__(self, fname):
# The *dbm modules stick their own file suffixes on the names
- # that are passed in. This is causes us to jump through some
- # hoops here to be able to allow the user
+ # that are passed in. This causes us to jump through some
+ # hoops here.
try:
# Try opening the specified file name. Example:
# SPECIFIED OPENED BY self.dbm.open()
@@ -389,29 +463,35 @@ class Do_SConsignDB(object):
print_e = e
try:
# That didn't work, so try opening the base name,
- # so that if the actually passed in 'sconsign.dblite'
+ # so that if they actually passed in 'sconsign.dblite'
# (for example), the dbm module will put the suffix back
# on for us and open it anyway.
db = self.dbm.open(os.path.splitext(fname)[0], "r")
except (IOError, OSError):
# That didn't work either. See if the file name
- # they specified just exists (independent of the dbm
+ # they specified even exists (independent of the dbm
# suffix-mangling).
try:
- open(fname, "r")
+ with open(fname, "rb"):
+ pass # this is a touch only, we don't use it here.
except (IOError, OSError) as e:
# Nope, that file doesn't even exist, so report that
# fact back.
print_e = e
- sys.stderr.write("sconsign: %s\n" % (print_e))
+ sys.stderr.write("sconsign: %s\n" % print_e)
return
except KeyboardInterrupt:
raise
except pickle.UnpicklingError:
- sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" % (self.dbm_name, fname))
+ sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n"
+ % (self.dbm_name, fname))
return
except Exception as e:
- sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" % (self.dbm_name, fname, e))
+ sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n"
+ % (self.dbm_name, fname, e))
+ exc_type, _, _ = sys.exc_info()
+ if exc_type.__name__ == "ValueError" and sys.version_info < (3,0,0):
+ sys.stderr.write("Python 2 only supports pickle protocols 0-2.\n")
return
if Print_Directories:
@@ -419,41 +499,50 @@ class Do_SConsignDB(object):
try:
val = db[dir]
except KeyError:
- sys.stderr.write("sconsign: no dir `%s' in `%s'\n" % (dir, args[0]))
+ err = "sconsign: no dir `%s' in `%s'\n" % (dir, args[0])
+ sys.stderr.write(err)
else:
self.printentries(dir, val)
else:
for dir in sorted(db.keys()):
self.printentries(dir, db[dir])
- def printentries(self, dir, val):
- print('=== ' + dir + ':')
+ @staticmethod
+ def printentries(dir, val):
+ try:
+ print('=== ' + dir + ':')
+ except TypeError:
+ print('=== ' + dir.decode() + ':')
printentries(pickle.loads(val), dir)
+
def Do_SConsignDir(name):
try:
- fp = open(name, 'rb')
+ with open(name, 'rb') as fp:
+ try:
+ sconsign = SCons.SConsign.Dir(fp)
+ except KeyboardInterrupt:
+ raise
+ except pickle.UnpicklingError:
+ err = "sconsign: ignoring invalid .sconsign file `%s'\n" % (name)
+ sys.stderr.write(err)
+ return
+ except Exception as e:
+ err = "sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e)
+ sys.stderr.write(err)
+ return
+ printentries(sconsign.entries, args[0])
except (IOError, OSError) as e:
- sys.stderr.write("sconsign: %s\n" % (e))
- return
- try:
- sconsign = SCons.SConsign.Dir(fp)
- except KeyboardInterrupt:
- raise
- except pickle.UnpicklingError:
- sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % (name))
- return
- except Exception as e:
- sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e))
+ sys.stderr.write("sconsign: %s\n" % e)
return
- printentries(sconsign.entries, args[0])
+
##############################################################################
import getopt
helpstr = """\
-Usage: sconsign [OPTIONS] FILE [...]
+Usage: sconsign [OPTIONS] [FILE ...]
Options:
-a, --act, --action Print build action information.
-c, --csig Print content signature information.
@@ -469,13 +558,17 @@ Options:
-v, --verbose Verbose, describe each field.
"""
-opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv",
- ['act', 'action',
- 'csig', 'dir=', 'entry=',
- 'format=', 'help', 'implicit',
- 'raw', 'readable',
- 'size', 'timestamp', 'verbose'])
-
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv",
+ ['act', 'action',
+ 'csig', 'dir=', 'entry=',
+ 'format=', 'help', 'implicit',
+ 'raw', 'readable',
+ 'size', 'timestamp', 'verbose'])
+except getopt.GetoptError as err:
+ sys.stderr.write(str(err) + '\n')
+ print(helpstr)
+ sys.exit(2)
for o, a in opts:
if o in ('-a', '--act', '--action'):
@@ -489,8 +582,7 @@ for o, a in opts:
elif o in ('-f', '--format'):
# Try to map the given DB format to a known module
# name, that we can then try to import...
- Module_Map = {'dblite' : 'SCons.dblite',
- 'sconsign' : None}
+ Module_Map = {'dblite': 'SCons.dblite', 'sconsign': None}
dbm_name = Module_Map.get(a, a)
if dbm_name:
try:
@@ -498,12 +590,13 @@ for o, a in opts:
dbm = my_import(dbm_name)
else:
import SCons.dblite
+
dbm = SCons.dblite
# Ensure that we don't ignore corrupt DB files,
# this was handled by calling my_import('SCons.dblite')
# again in earlier versions...
SCons.dblite.ignore_corrupt_dbfiles = 0
- except:
+ except ImportError:
sys.stderr.write("sconsign: illegal file format `%s'\n" % a)
print(helpstr)
sys.exit(2)
@@ -526,19 +619,21 @@ for o, a in opts:
elif o in ('-v', '--verbose'):
Verbose = 1
-
if Do_Call:
for a in args:
Do_Call(a)
else:
+ if not args:
+ args = [".sconsign.dblite"]
for a in args:
dbm_name = whichdb(a)
if dbm_name:
- Map_Module = {'SCons.dblite' : 'dblite'}
+ Map_Module = {'SCons.dblite': 'dblite'}
if dbm_name != "SCons.dblite":
dbm = my_import(dbm_name)
else:
import SCons.dblite
+
dbm = SCons.dblite
# Ensure that we don't ignore corrupt DB files,
# this was handled by calling my_import('SCons.dblite')
@@ -548,6 +643,8 @@ else:
else:
Do_SConsignDir(a)
+ if Warns:
+ print("NOTE: there were %d warnings, please check output" % Warns)
sys.exit(0)
# Local Variables:
diff --git a/src/setup.py b/src/setup.py
index 7a2b84a..790b1ea 100644..100755
--- a/src/setup.py
+++ b/src/setup.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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,6 +20,17 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+from __future__ import print_function
+
+
+import distutils.command.build_scripts
+import distutils.command.install_scripts
+import distutils.command.install_lib
+import distutils.command.install_data
+import distutils.command.install
+import distutils.core
+import distutils
+# import setuptools
"""
NOTE: Installed SCons is not importable like usual Python packages. It is
executed explicitly with command line scripts. This allows multiple
@@ -32,15 +43,14 @@ NOTE: Installed SCons is not importable like usual Python packages. It is
below is dedicated to make it happen on various platforms.
"""
-from __future__ import print_function
-__revision__ = "src/setup.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/setup.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
import os
import stat
import sys
-Version = "3.0.0"
+Version = "3.1.0"
man_pages = [
'scons.1',
@@ -66,25 +76,6 @@ if not sys.platform == 'win32':
else:
is_win32 = 1
-import distutils
-import distutils.core
-import distutils.command.install
-import distutils.command.install_data
-import distutils.command.install_lib
-import distutils.command.install_scripts
-import distutils.command.build_scripts
-import distutils.msvccompiler
-
-
-def get_build_version():
- """ monkey patch distutils msvc version if we're not on windows.
- We need to use vc version 9 for python 2.7.x and it defaults to 6
- for non-windows platforms and there is no way to override it besides
- monkey patching"""
- return 9
-
-
-distutils.msvccompiler.get_build_version = get_build_version
_install = distutils.command.install.install
_install_data = distutils.command.install_data.install_data
@@ -175,7 +166,7 @@ class install(_install):
self.no_scons_script = 0
self.no_version_script = 0
self.install_bat = 0
- self.no_install_bat = not is_win32
+ self.no_install_bat = False # not is_win32
self.install_man = 0
self.no_install_man = is_win32
self.standard_lib = 0
@@ -257,10 +248,12 @@ class install_lib(_install_lib):
if Options.standalone_lib:
# ...but they asked for a standalone directory.
self.install_dir = os.path.join(prefix, "scons")
- elif Options.version_lib or not Options.standard_lib:
+ elif Options.version_lib:
# ...they asked for a version-specific directory,
- # or they get it by default.
self.install_dir = os.path.join(prefix, "scons-%s" % Version)
+ elif not Options.standard_lib:
+ # default.
+ self.install_dir = os.path.join(prefix, "scons")
msg = "Installed SCons library modules into %s" % self.install_dir
Installed.append(msg)
@@ -333,8 +326,8 @@ class install_scripts(_install_scripts):
scons = os.path.join(self.install_dir, base)
scons_ver = scons + '-' + Version
if is_win32:
- scons += '.py'
- scons_ver += '.py'
+ scons = scons + '.py'
+ scons_ver = scons_ver + '.py'
create_version_script(src, scons_ver)
create_basename_script(src, scons, scons_ver)
@@ -362,7 +355,8 @@ class install_scripts(_install_scripts):
# Use symbolic versions of permissions so this script doesn't fail to parse under python3.x
exec_and_read_permission = stat.S_IXOTH | stat.S_IXUSR | stat.S_IXGRP | stat.S_IROTH | stat.S_IRUSR | stat.S_IRGRP
mode_mask = 4095 # Octal 07777 used because python3 has different octal syntax than python 2
- mode = ((os.stat(file)[stat.ST_MODE]) | exec_and_read_permission) & mode_mask
+ mode = ((os.stat(file)[stat.ST_MODE]) |
+ exec_and_read_permission) & mode_mask
# log.info("changing mode of %s to %o", file, mode)
os.chmod(file, mode)
# --- /distutils copy/paste ---
@@ -420,18 +414,19 @@ arguments = {
'version': Version,
'description': description,
'long_description': long_description,
- 'author': 'Steven Knight',
- 'author_email': 'knight@baldmt.com',
+ 'author': 'William Deegan',
+ 'author_email': 'bill@baddogconsulting.com',
'url': "http://www.scons.org/",
'packages': ["SCons",
"SCons.compat",
"SCons.Node",
- "SCons.Options",
"SCons.Platform",
"SCons.Scanner",
"SCons.Script",
"SCons.Tool",
+ "SCons.Tool.clangCommon",
"SCons.Tool.docbook",
+ 'SCons.Tool.clangCommon',
"SCons.Tool.MSCommon",
"SCons.Tool.packaging",
"SCons.Variables",
@@ -512,7 +507,7 @@ arguments = {
'install_lib': install_lib,
'install_data': install_data,
'install_scripts': install_scripts,
- 'build_scripts': build_scripts}
+ 'build_scripts': build_scripts},
}
distutils.core.setup(**arguments)
diff --git a/src/test_files.py b/src/test_files.py
index e552751..42fb397 100644
--- a/src/test_files.py
+++ b/src/test_files.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
#
from __future__ import print_function
-__revision__ = "src/test_files.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/test_files.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""
Verify that we have certain important files in our distribution
diff --git a/src/test_interrupts.py b/src/test_interrupts.py
index 744677f..4ae0969 100644
--- a/src/test_interrupts.py
+++ b/src/test_interrupts.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
from __future__ import print_function
-__revision__ = "src/test_interrupts.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/test_interrupts.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""
Verify that the SCons source code contains only correct handling of
@@ -87,7 +87,8 @@ exceptall_pat = re.compile(r' *except(?: *| +Exception *, *[^: ]+):[^\n]*')
uncaughtKeyboardInterrupt = 0
for f in files:
- contents = open(os.path.join(scons_lib_dir, f)).read()
+ with open(os.path.join(scons_lib_dir, f)) as ifp:
+ contents = ifp.read()
try_except_lines = {}
lastend = 0
while True:
diff --git a/src/test_pychecker.py b/src/test_pychecker.py
index b0c231f..a93033d 100644
--- a/src/test_pychecker.py
+++ b/src/test_pychecker.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 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 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-__revision__ = "src/test_pychecker.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/test_pychecker.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""
Use pychecker to catch various Python coding errors.
@@ -63,7 +63,8 @@ else:
src_engine_ = os.path.join(src_engine, '')
MANIFEST = os.path.join(src_engine, 'MANIFEST.in')
-files = open(MANIFEST).read().split()
+with open(MANIFEST) as f:
+ files = f.read().split()
files = [f for f in files if f[-3:] == '.py']
diff --git a/src/test_setup.py b/src/test_setup.py
index af8ed66..b540ab2 100644
--- a/src/test_setup.py
+++ b/src/test_setup.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
#
from __future__ import print_function
-__revision__ = "src/test_setup.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/test_setup.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""
Test how the setup.py script installs SCons.
@@ -176,21 +176,26 @@ tar_gz = os.path.join(cwd, 'build', 'dist', '%s.tar.gz' % scons_version)
zip = os.path.join(cwd, 'build', 'dist', '%s.zip' % scons_version)
if os.path.isfile(zip):
- try: import zipfile
- except ImportError: pass
+ try:
+ import zipfile
+ except ImportError:
+ pass
else:
- zf = zipfile.ZipFile(zip, 'r')
-
- for name in zf.namelist():
- dir = os.path.dirname(name)
- try: os.makedirs(dir)
- except: pass
- # if the file exists, then delete it before writing
- # to it so that we don't end up trying to write to a symlink:
- if os.path.isfile(name) or os.path.islink(name):
- os.unlink(name)
- if not os.path.isdir(name):
- open(name, 'w').write(zf.read(name))
+ with zipfile.ZipFile(zip, 'r') as zf:
+
+ for name in zf.namelist():
+ dname = os.path.dirname(name)
+ try:
+ os.makedirs(dname)
+ except FileExistsError:
+ pass
+ # if the file exists, then delete it before writing
+ # to it so that we don't end up trying to write to a symlink:
+ if os.path.isfile(name) or os.path.islink(name):
+ os.unlink(name)
+ if not os.path.isdir(name):
+ with open(name, 'w') as ofp:
+ ofp.write(zf.read(name))
if not os.path.isdir(scons_version) and os.path.isfile(tar_gz):
# Unpack the .tar.gz file. This should create the scons_version/
diff --git a/src/test_strings.py b/src/test_strings.py
index ec62e82..ad2c755 100644
--- a/src/test_strings.py
+++ b/src/test_strings.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright (c) 2001 - 2017 The SCons Foundation
+# Copyright (c) 2001 - 2019 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -23,7 +23,7 @@
#
from __future__ import print_function
-__revision__ = "src/test_strings.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
+__revision__ = "src/test_strings.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan"
"""
Verify that we have proper strings like Copyright notices on all the
@@ -98,7 +98,8 @@ class Checker(object):
for fname in filenames:
fpath = os.path.join(dirpath, fname)
if self.search_this(fpath) and not self.remove_this(fname, fpath):
- body = open(fpath, 'r').read()
+ with open(fpath, 'r') as f:
+ body = f.read()
for expr in self.expressions:
if not expr.search(body):
msg = '%s: missing %s' % (fpath, repr(expr.pattern))
@@ -107,8 +108,8 @@ class Checker(object):
class CheckUnexpandedStrings(Checker):
expressions = [
- re.compile('Copyright (c) 2001 - 2017 The SCons Foundation'),
- re.compile('src/test_strings.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog'),
+ re.compile('Copyright (c) 2001 - 2019 The SCons Foundation'),
+ re.compile('src/test_strings.py e724ae812eb96f4858a132f5b8c769724744faf6 2019-07-21 00:04:47 bdeegan'),
]
def must_be_built(self):
return None
@@ -208,12 +209,10 @@ check_list = [
'doc/user/SCons-win32-install-4.jpg',
'examples',
'gentoo',
- 'QMTest/classes.qmc',
- 'QMTest/configuration',
- 'QMTest/TestCmd.py',
- 'QMTest/TestCmdTests.py',
- 'QMTest/TestCommon.py',
- 'QMTest/TestCommonTests.py',
+ 'testing/framework/TestCmd.py',
+ 'testing/framework/TestCmdTests.py',
+ 'testing/framework/TestCommon.py',
+ 'testing/framework/TestCommonTests.py',
'src/MANIFEST.in',
'src/setup.cfg',
'src/engine/MANIFEST.in',