diff --git a/.hgtags b/.hgtags index c49a598ee6c..382210174b9 100644 --- a/.hgtags +++ b/.hgtags @@ -155,3 +155,4 @@ c0d64105463581f85d0e368e8d6e59b7fd8f12b1 v3.5.0b4 1a58b1227501e046eee13d90f113417b60843301 v3.5.0rc1 cc15d736d860303b9da90d43cd32db39bab048df v3.5.0rc2 66ed52375df802f9d0a34480daaa8ce79fc41313 v3.5.0rc3 +2d033fedfa7f1e325fd14ccdaa9cb42155da206f v3.5.0rc4 diff --git a/Include/patchlevel.h b/Include/patchlevel.h index e42d13d5f3c..f0ca3a1b083 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 5 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 3 +#define PY_RELEASE_SERIAL 4 /* Version as a string */ -#define PY_VERSION "3.5.0rc3" +#define PY_VERSION "3.5.0rc4+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index b344616e600..82b78a0ffe4 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -14,6 +14,8 @@ for older versions in distutils.msvc9compiler and distutils.msvccompiler. # ported to VS 2015 by Steve Dower import os +import shutil +import stat import subprocess from distutils.errors import DistutilsExecError, DistutilsPlatformError, \ @@ -25,7 +27,7 @@ from distutils.util import get_platform import winreg from itertools import count -def _find_vcvarsall(): +def _find_vcvarsall(plat_spec): with winreg.OpenKeyEx( winreg.HKEY_LOCAL_MACHINE, r"Software\Microsoft\VisualStudio\SxS\VC7", @@ -33,7 +35,7 @@ def _find_vcvarsall(): ) as key: if not key: log.debug("Visual C++ is not registered") - return None + return None, None best_version = 0 best_dir = None @@ -51,14 +53,23 @@ def _find_vcvarsall(): best_version, best_dir = version, vc_dir if not best_version: log.debug("No suitable Visual C++ version found") - return None + return None, None vcvarsall = os.path.join(best_dir, "vcvarsall.bat") if not os.path.isfile(vcvarsall): log.debug("%s cannot be found", vcvarsall) - return None + return None, None - return vcvarsall + vcruntime = None + vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST.get(plat_spec) + if vcruntime_spec: + vcruntime = os.path.join(best_dir, + vcruntime_spec.format(best_version)) + if not os.path.isfile(vcruntime): + log.debug("%s cannot be found", vcruntime) + vcruntime = None + + return vcvarsall, vcruntime def _get_vc_env(plat_spec): if os.getenv("DISTUTILS_USE_SDK"): @@ -67,7 +78,7 @@ def _get_vc_env(plat_spec): for key, value in os.environ.items() } - vcvarsall = _find_vcvarsall() + vcvarsall, vcruntime = _find_vcvarsall(plat_spec) if not vcvarsall: raise DistutilsPlatformError("Unable to find vcvarsall.bat") @@ -83,12 +94,16 @@ def _get_vc_env(plat_spec): raise DistutilsPlatformError("Error executing {}" .format(exc.cmd)) - return { + env = { key.lower(): value for key, _, value in (line.partition('=') for line in out.splitlines()) if key and value } + + if vcruntime: + env['py_vcruntime_redist'] = vcruntime + return env def _find_exe(exe, paths=None): """Return path to an MSVC executable program. @@ -115,6 +130,20 @@ PLAT_TO_VCVARS = { 'win-amd64' : 'amd64', } +# A map keyed by get_platform() return values to the file under +# the VC install directory containing the vcruntime redistributable. +_VCVARS_PLAT_TO_VCRUNTIME_REDIST = { + 'x86' : 'redist\\x86\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', + 'amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', + 'x86_amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll', +} + +# A set containing the DLLs that are guaranteed to be available for +# all micro versions of this Python version. Known extension +# dependencies that are not in this set will be copied to the output +# path. +_BUNDLED_DLLS = frozenset(['vcruntime140.dll']) + class MSVCCompiler(CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, as defined by the CCompiler abstract class.""" @@ -189,6 +218,7 @@ class MSVCCompiler(CCompiler) : self.rc = _find_exe("rc.exe", paths) # resource compiler self.mc = _find_exe("mc.exe", paths) # message compiler self.mt = _find_exe("mt.exe", paths) # message compiler + self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '') for dir in vc_env.get('include', '').split(os.pathsep): if dir: @@ -199,20 +229,26 @@ class MSVCCompiler(CCompiler) : self.add_library_dir(dir) self.preprocess_options = None - # Use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib + # If vcruntime_redist is available, link against it dynamically. Otherwise, + # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib # later to dynamically link to ucrtbase but not vcruntime. self.compile_options = [ - '/nologo', '/Ox', '/MT', '/W3', '/GL', '/DNDEBUG' + '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG' ] + self.compile_options.append('/MD' if self._vcruntime_redist else '/MT') + self.compile_options_debug = [ - '/nologo', '/Od', '/MTd', '/Zi', '/W3', '/D_DEBUG' + '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG' ] ldflags = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib', + '/nologo', '/INCREMENTAL:NO', '/LTCG' ] + if not self._vcruntime_redist: + ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib')) + ldflags_debug = [ - '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib', + '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL' ] self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1'] @@ -446,15 +482,29 @@ class MSVCCompiler(CCompiler) : if extra_postargs: ld_args.extend(extra_postargs) - self.mkpath(os.path.dirname(output_filename)) + output_dir = os.path.dirname(os.path.abspath(output_filename)) + self.mkpath(output_dir) try: log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args)) self.spawn([self.linker] + ld_args) + self._copy_vcruntime(output_dir) except DistutilsExecError as msg: raise LinkError(msg) else: log.debug("skipping %s (up-to-date)", output_filename) + def _copy_vcruntime(self, output_dir): + vcruntime = self._vcruntime_redist + if not vcruntime or not os.path.isfile(vcruntime): + return + + if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS: + return + + log.debug('Copying "%s"', vcruntime) + vcruntime = shutil.copy(vcruntime, output_dir) + os.chmod(vcruntime, stat.S_IWRITE) + def spawn(self, cmd): old_path = os.getenv('path') try: diff --git a/Lib/distutils/tests/test_msvccompiler.py b/Lib/distutils/tests/test_msvccompiler.py index 1f8890792e2..874d6035e8d 100644 --- a/Lib/distutils/tests/test_msvccompiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -16,22 +16,73 @@ class msvccompilerTestCase(support.TempdirManager, unittest.TestCase): def test_no_compiler(self): + import distutils._msvccompiler as _msvccompiler # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found - from distutils._msvccompiler import _get_vc_env - def _find_vcvarsall(): - return None + def _find_vcvarsall(plat_spec): + return None, None - import distutils._msvccompiler as _msvccompiler old_find_vcvarsall = _msvccompiler._find_vcvarsall _msvccompiler._find_vcvarsall = _find_vcvarsall try: - self.assertRaises(DistutilsPlatformError, _get_vc_env, + self.assertRaises(DistutilsPlatformError, + _msvccompiler._get_vc_env, 'wont find this version') finally: _msvccompiler._find_vcvarsall = old_find_vcvarsall + def test_compiler_options(self): + import distutils._msvccompiler as _msvccompiler + # suppress path to vcruntime from _find_vcvarsall to + # check that /MT is added to compile options + old_find_vcvarsall = _msvccompiler._find_vcvarsall + def _find_vcvarsall(plat_spec): + return old_find_vcvarsall(plat_spec)[0], None + _msvccompiler._find_vcvarsall = _find_vcvarsall + try: + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + + self.assertIn('/MT', compiler.compile_options) + self.assertNotIn('/MD', compiler.compile_options) + finally: + _msvccompiler._find_vcvarsall = old_find_vcvarsall + + def test_vcruntime_copy(self): + import distutils._msvccompiler as _msvccompiler + # force path to a known file - it doesn't matter + # what we copy as long as its name is not in + # _msvccompiler._BUNDLED_DLLS + old_find_vcvarsall = _msvccompiler._find_vcvarsall + def _find_vcvarsall(plat_spec): + return old_find_vcvarsall(plat_spec)[0], __file__ + _msvccompiler._find_vcvarsall = _find_vcvarsall + try: + tempdir = self.mkdtemp() + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + compiler._copy_vcruntime(tempdir) + + self.assertTrue(os.path.isfile(os.path.join( + tempdir, os.path.basename(__file__)))) + finally: + _msvccompiler._find_vcvarsall = old_find_vcvarsall + + def test_vcruntime_skip_copy(self): + import distutils._msvccompiler as _msvccompiler + + tempdir = self.mkdtemp() + compiler = _msvccompiler.MSVCCompiler() + compiler.initialize() + dll = compiler._vcruntime_redist + self.assertTrue(os.path.isfile(dll)) + + compiler._copy_vcruntime(tempdir) + + self.assertFalse(os.path.isfile(os.path.join( + tempdir, os.path.basename(dll)))) + def test_suite(): return unittest.makeSuite(msvccompilerTestCase) diff --git a/Misc/NEWS b/Misc/NEWS index 31acc9fc7aa..4c3385007e2 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -14,6 +14,9 @@ Core and Builtins Library ------- +- Issue #23144: Make sure that HTMLParser.feed() returns all the data, even + when convert_charrefs is True. + - Issue #24982: shutil.make_archive() with the "zip" format now adds entries for directories (including empty directories) in ZIP file. @@ -86,6 +89,23 @@ Build when external libraries are not available. +What's New in Python 3.5.0 release candidate 4? +=============================================== + +Release date: 2015-09-09 + +Library +------- + +- Issue #25029: Fixes MemoryError in test_strptime. + +Build +----- + +- Issue #25027: Reverts partial-static build options and adds + vcruntime140.dll to Windows installation. + + What's New in Python 3.5.0 release candidate 3? =============================================== @@ -105,8 +125,6 @@ Library ------- - Issue #24917: time_strftime() buffer over-read. -- Issue #23144: Make sure that HTMLParser.feed() returns all the data, even - when convert_charrefs is True. - Issue #24748: To resolve a compatibility problem found with py2exe and pywin32, imp.load_dynamic() once again ignores previously loaded modules @@ -116,7 +134,6 @@ Library - Issue #24635: Fixed a bug in typing.py where isinstance([], typing.Iterable) would return True once, then False on subsequent calls. - - Issue #24989: Fixed buffer overread in BytesIO.readline() if a position is set beyond size. Based on patch by John Leitch. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index eca67d9e286..9de3c843322 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -648,9 +648,6 @@ time_strftime(PyObject *self, PyObject *args) * will be ahead of time... */ for (i = 1024; ; i += i) { -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - int err; -#endif outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char)); if (outbuf == NULL) { PyErr_NoMemory(); @@ -660,10 +657,14 @@ time_strftime(PyObject *self, PyObject *args) buflen = format_time(outbuf, i, fmt, &buf); _Py_END_SUPPRESS_IPH #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - err = errno; + /* VisualStudio .NET 2005 does this properly */ + if (buflen == 0 && errno == EINVAL) { + PyErr_SetString(PyExc_ValueError, "Invalid format string"); + PyMem_Free(outbuf); + break; + } #endif - if (buflen > 0 || fmtlen == 0 || - (fmtlen > 4 && i >= 256 * fmtlen)) { + if (buflen > 0 || i >= 256 * fmtlen) { /* If the buffer is 256 times as long as the format, it's probably not failing for lack of room! More likely, the format yields an empty result, @@ -679,13 +680,6 @@ time_strftime(PyObject *self, PyObject *args) break; } PyMem_Free(outbuf); -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* VisualStudio .NET 2005 does this properly */ - if (buflen == 0 && err == EINVAL) { - PyErr_SetString(PyExc_ValueError, "Invalid format string"); - break; - } -#endif } #ifdef HAVE_WCSFTIME PyMem_Free(format); diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index f63c30dd137..c1303e1aacb 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -36,7 +36,7 @@ true true - MultiThreaded + MultiThreadedDLL true Level3 ProgramDatabase @@ -47,7 +47,7 @@ Disabled false - MultiThreadedDebug + MultiThreadedDebugDLL $(OutDir);%(AdditionalLibraryDirectories) @@ -57,9 +57,7 @@ true true true - ucrtd.lib;%(AdditionalDependencies) - ucrt.lib;%(AdditionalDependencies) - LIBC;libucrt.lib;libucrtd.lib;%(IgnoreSpecificDefaultLibraries) + LIBC;%(IgnoreSpecificDefaultLibraries) MachineX86 MachineX64 $(OutDir)$(TargetName).pgd diff --git a/PCbuild/tcl.vcxproj b/PCbuild/tcl.vcxproj index e9287c7b37d..464c83ce80c 100644 --- a/PCbuild/tcl.vcxproj +++ b/PCbuild/tcl.vcxproj @@ -61,8 +61,8 @@ - ucrt - symbols,ucrt + msvcrt + symbols,msvcrt INSTALLDIR="$(OutDir.TrimEnd(`\`))" INSTALL_DIR="$(OutDir.TrimEnd(`\`))" DEBUGFLAGS="-wd4456 -wd4457 -wd4458 -wd4459 -wd4996" setlocal diff --git a/PCbuild/tix.vcxproj b/PCbuild/tix.vcxproj index a1dad1e301e..f857f9e67f1 100644 --- a/PCbuild/tix.vcxproj +++ b/PCbuild/tix.vcxproj @@ -57,8 +57,8 @@ BUILDDIRTOP="$(BuildDirTop)" TCL_DIR="$(tclDir.TrimEnd(`\`))" TK_DIR="$(tkDir.TrimEnd(`\`))" INSTALL_DIR="$(OutDir.TrimEnd(`\`))" - DEBUG=1 NODEBUG=0 UCRT=1 TCL_DBGX=g TK_DBGX=g - DEBUG=0 NODEBUG=1 UCRT=1 + DEBUG=1 NODEBUG=0 TCL_DBGX=g TK_DBGX=g + DEBUG=0 NODEBUG=1 setlocal @(ExpectedOutputs->'if not exist "%(FullPath)" goto build',' ') diff --git a/PCbuild/tk.vcxproj b/PCbuild/tk.vcxproj index 589338cf5cf..20749f719f5 100644 --- a/PCbuild/tk.vcxproj +++ b/PCbuild/tk.vcxproj @@ -60,8 +60,8 @@ - ucrt - symbols,ucrt + msvcrt + symbols,msvcrt TCLDIR="$(tclDir.TrimEnd(`\`))" INSTALLDIR="$(OutDir.TrimEnd(`\`))" DEBUGFLAGS="-wd4456 -wd4457 -wd4458 -wd4459 -wd4996" setlocal diff --git a/README b/README index 986941c362f..0542e7e635c 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.5.0 release candidate 3 +This is Python version 3.5.0 release candidate 4 ================================================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, diff --git a/Tools/msi/build.bat b/Tools/msi/build.bat index 716934ae703..5f53a1be6cb 100644 --- a/Tools/msi/build.bat +++ b/Tools/msi/build.bat @@ -22,15 +22,15 @@ if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX6 call "%PCBUILD%env.bat" x86 if defined BUILDX86 ( - call "%PCBUILD%build.bat" -d + call "%PCBUILD%build.bat" -d -e if errorlevel 1 goto :eof - call "%PCBUILD%build.bat" + call "%PCBUILD%build.bat" -e if errorlevel 1 goto :eof ) if defined BUILDX64 ( - call "%PCBUILD%build.bat" -p x64 -d + call "%PCBUILD%build.bat" -p x64 -d -e if errorlevel 1 goto :eof - call "%PCBUILD%build.bat" -p x64 + call "%PCBUILD%build.bat" -p x64 -e if errorlevel 1 goto :eof ) diff --git a/Tools/msi/buildrelease.bat b/Tools/msi/buildrelease.bat index 2e73f8fe7cf..d22ba1013fb 100644 --- a/Tools/msi/buildrelease.bat +++ b/Tools/msi/buildrelease.bat @@ -121,7 +121,7 @@ if not "%CERTNAME%" EQU "" ( if not "%SKIPBUILD%" EQU "1" ( call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -d -t %TARGET% %CERTOPTS% if errorlevel 1 exit /B - call "%PCBUILD%build.bat" -p %BUILD_PLAT% -t %TARGET% %CERTOPTS% + call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %CERTOPTS% if errorlevel 1 exit /B @rem build.bat turns echo back on, so we disable it again @echo off diff --git a/Tools/msi/exe/exe_files.wxs b/Tools/msi/exe/exe_files.wxs index 3b5fce446c6..9e47b5d9809 100644 --- a/Tools/msi/exe/exe_files.wxs +++ b/Tools/msi/exe/exe_files.wxs @@ -29,6 +29,9 @@ + + + diff --git a/Tools/msi/make_zip.proj b/Tools/msi/make_zip.proj index 2f16032086c..766fe8597c0 100644 --- a/Tools/msi/make_zip.proj +++ b/Tools/msi/make_zip.proj @@ -16,7 +16,8 @@ $(OutputPath)\en-us\$(TargetName)$(TargetExt) "$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py" $(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -a $(ArchName) - set DOC_FILENAME=python$(PythonVersion).chm + set DOC_FILENAME=python$(PythonVersion).chm +set VCREDIST_PATH=$(VS140COMNTOOLS)\..\..\VC\redist\$(Platform)\Microsoft.VC140.CRT diff --git a/Tools/msi/make_zip.py b/Tools/msi/make_zip.py index ba711c484a9..09ee49166d9 100644 --- a/Tools/msi/make_zip.py +++ b/Tools/msi/make_zip.py @@ -64,9 +64,6 @@ FULL_LAYOUT = [ ('Tools/', 'Tools', '**/*', include_in_tools), ] -if os.getenv('DOC_FILENAME'): - FULL_LAYOUT.append(('Doc/', 'Doc/build/htmlhelp', os.getenv('DOC_FILENAME'), None)) - EMBED_LAYOUT = [ ('/', 'PCBuild/$arch', 'python*.exe', is_not_debug), ('/', 'PCBuild/$arch', '*.pyd', is_not_debug), @@ -74,6 +71,12 @@ EMBED_LAYOUT = [ ('python35.zip', 'Lib', '**/*', include_in_lib), ] +if os.getenv('DOC_FILENAME'): + FULL_LAYOUT.append(('Doc/', 'Doc/build/htmlhelp', os.getenv('DOC_FILENAME'), None)) +if os.getenv('VCREDIST_PATH'): + FULL_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None)) + EMBED_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None)) + def copy_to_layout(target, rel_sources): count = 0 diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props index 29be1293280..cc52c7ae5ca 100644 --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -118,6 +118,9 @@ redist + + redist +