Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fcbe1df

Browse files
committed
Issue #25027: Reverts partial-static build options and adds vcruntime140.dll to Windows installation.
1 parent 0130e29 commit fcbe1df

13 files changed

Lines changed: 151 additions & 38 deletions

File tree

Lib/distutils/_msvccompiler.py

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
# ported to VS 2015 by Steve Dower
1515

1616
import os
17+
import shutil
18+
import stat
1719
import subprocess
1820

1921
from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
@@ -25,15 +27,15 @@
2527
import winreg
2628
from itertools import count
2729

28-
def _find_vcvarsall():
30+
def _find_vcvarsall(plat_spec):
2931
with winreg.OpenKeyEx(
3032
winreg.HKEY_LOCAL_MACHINE,
3133
r"Software\Microsoft\VisualStudio\SxS\VC7",
3234
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
3335
) as key:
3436
if not key:
3537
log.debug("Visual C++ is not registered")
36-
return None
38+
return None, None
3739

3840
best_version = 0
3941
best_dir = None
@@ -51,14 +53,23 @@ def _find_vcvarsall():
5153
best_version, best_dir = version, vc_dir
5254
if not best_version:
5355
log.debug("No suitable Visual C++ version found")
54-
return None
56+
return None, None
5557

5658
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
5759
if not os.path.isfile(vcvarsall):
5860
log.debug("%s cannot be found", vcvarsall)
59-
return None
61+
return None, None
6062

61-
return vcvarsall
63+
vcruntime = None
64+
vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST.get(plat_spec)
65+
if vcruntime_spec:
66+
vcruntime = os.path.join(best_dir,
67+
vcruntime_spec.format(best_version))
68+
if not os.path.isfile(vcruntime):
69+
log.debug("%s cannot be found", vcruntime)
70+
vcruntime = None
71+
72+
return vcvarsall, vcruntime
6273

6374
def _get_vc_env(plat_spec):
6475
if os.getenv("DISTUTILS_USE_SDK"):
@@ -67,7 +78,7 @@ def _get_vc_env(plat_spec):
6778
for key, value in os.environ.items()
6879
}
6980

70-
vcvarsall = _find_vcvarsall()
81+
vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
7182
if not vcvarsall:
7283
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
7384

@@ -83,12 +94,16 @@ def _get_vc_env(plat_spec):
8394
raise DistutilsPlatformError("Error executing {}"
8495
.format(exc.cmd))
8596

86-
return {
97+
env = {
8798
key.lower(): value
8899
for key, _, value in
89100
(line.partition('=') for line in out.splitlines())
90101
if key and value
91102
}
103+
104+
if vcruntime:
105+
env['py_vcruntime_redist'] = vcruntime
106+
return env
92107

93108
def _find_exe(exe, paths=None):
94109
"""Return path to an MSVC executable program.
@@ -115,6 +130,20 @@ def _find_exe(exe, paths=None):
115130
'win-amd64' : 'amd64',
116131
}
117132

133+
# A map keyed by get_platform() return values to the file under
134+
# the VC install directory containing the vcruntime redistributable.
135+
_VCVARS_PLAT_TO_VCRUNTIME_REDIST = {
136+
'x86' : 'redist\\x86\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
137+
'amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
138+
'x86_amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
139+
}
140+
141+
# A set containing the DLLs that are guaranteed to be available for
142+
# all micro versions of this Python version. Known extension
143+
# dependencies that are not in this set will be copied to the output
144+
# path.
145+
_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
146+
118147
class MSVCCompiler(CCompiler) :
119148
"""Concrete class that implements an interface to Microsoft Visual C++,
120149
as defined by the CCompiler abstract class."""
@@ -189,6 +218,7 @@ def initialize(self, plat_name=None):
189218
self.rc = _find_exe("rc.exe", paths) # resource compiler
190219
self.mc = _find_exe("mc.exe", paths) # message compiler
191220
self.mt = _find_exe("mt.exe", paths) # message compiler
221+
self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
192222

193223
for dir in vc_env.get('include', '').split(os.pathsep):
194224
if dir:
@@ -199,20 +229,26 @@ def initialize(self, plat_name=None):
199229
self.add_library_dir(dir)
200230

201231
self.preprocess_options = None
202-
# Use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
232+
# If vcruntime_redist is available, link against it dynamically. Otherwise,
233+
# use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
203234
# later to dynamically link to ucrtbase but not vcruntime.
204235
self.compile_options = [
205-
'/nologo', '/Ox', '/MT', '/W3', '/GL', '/DNDEBUG'
236+
'/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
206237
]
238+
self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
239+
207240
self.compile_options_debug = [
208-
'/nologo', '/Od', '/MTd', '/Zi', '/W3', '/D_DEBUG'
241+
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
209242
]
210243

211244
ldflags = [
212-
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/nodefaultlib:libucrt.lib', 'ucrt.lib',
245+
'/nologo', '/INCREMENTAL:NO', '/LTCG'
213246
]
247+
if not self._vcruntime_redist:
248+
ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
249+
214250
ldflags_debug = [
215-
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL', '/nodefaultlib:libucrtd.lib', 'ucrtd.lib',
251+
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
216252
]
217253

218254
self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
@@ -446,15 +482,29 @@ def link(self,
446482
if extra_postargs:
447483
ld_args.extend(extra_postargs)
448484

449-
self.mkpath(os.path.dirname(output_filename))
485+
output_dir = os.path.dirname(os.path.abspath(output_filename))
486+
self.mkpath(output_dir)
450487
try:
451488
log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
452489
self.spawn([self.linker] + ld_args)
490+
self._copy_vcruntime(output_dir)
453491
except DistutilsExecError as msg:
454492
raise LinkError(msg)
455493
else:
456494
log.debug("skipping %s (up-to-date)", output_filename)
457495

496+
def _copy_vcruntime(self, output_dir):
497+
vcruntime = self._vcruntime_redist
498+
if not vcruntime or not os.path.isfile(vcruntime):
499+
return
500+
501+
if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
502+
return
503+
504+
log.debug('Copying "%s"', vcruntime)
505+
vcruntime = shutil.copy(vcruntime, output_dir)
506+
os.chmod(vcruntime, stat.S_IWRITE)
507+
458508
def spawn(self, cmd):
459509
old_path = os.getenv('path')
460510
try:

Lib/distutils/tests/test_msvccompiler.py

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import unittest
44
import os
55

6+
import distutils._msvccompiler as _msvccompiler
7+
68
from distutils.errors import DistutilsPlatformError
79
from distutils.tests import support
810
from test.support import run_unittest
@@ -19,19 +21,65 @@ def test_no_compiler(self):
1921
# makes sure query_vcvarsall raises
2022
# a DistutilsPlatformError if the compiler
2123
# is not found
22-
from distutils._msvccompiler import _get_vc_env
23-
def _find_vcvarsall():
24-
return None
24+
def _find_vcvarsall(plat_spec):
25+
return None, None
2526

26-
import distutils._msvccompiler as _msvccompiler
2727
old_find_vcvarsall = _msvccompiler._find_vcvarsall
2828
_msvccompiler._find_vcvarsall = _find_vcvarsall
2929
try:
30-
self.assertRaises(DistutilsPlatformError, _get_vc_env,
30+
self.assertRaises(DistutilsPlatformError,
31+
_msvccompiler._get_vc_env,
3132
'wont find this version')
3233
finally:
3334
_msvccompiler._find_vcvarsall = old_find_vcvarsall
3435

36+
def test_compiler_options(self):
37+
# suppress path to vcruntime from _find_vcvarsall to
38+
# check that /MT is added to compile options
39+
old_find_vcvarsall = _msvccompiler._find_vcvarsall
40+
def _find_vcvarsall(plat_spec):
41+
return old_find_vcvarsall(plat_spec)[0], None
42+
_msvccompiler._find_vcvarsall = _find_vcvarsall
43+
try:
44+
compiler = _msvccompiler.MSVCCompiler()
45+
compiler.initialize()
46+
47+
self.assertIn('/MT', compiler.compile_options)
48+
self.assertNotIn('/MD', compiler.compile_options)
49+
finally:
50+
_msvccompiler._find_vcvarsall = old_find_vcvarsall
51+
52+
def test_vcruntime_copy(self):
53+
# force path to a known file - it doesn't matter
54+
# what we copy as long as its name is not in
55+
# _msvccompiler._BUNDLED_DLLS
56+
old_find_vcvarsall = _msvccompiler._find_vcvarsall
57+
def _find_vcvarsall(plat_spec):
58+
return old_find_vcvarsall(plat_spec)[0], __file__
59+
_msvccompiler._find_vcvarsall = _find_vcvarsall
60+
try:
61+
tempdir = self.mkdtemp()
62+
compiler = _msvccompiler.MSVCCompiler()
63+
compiler.initialize()
64+
compiler._copy_vcruntime(tempdir)
65+
66+
self.assertTrue(os.path.isfile(os.path.join(
67+
tempdir, os.path.basename(__file__))))
68+
finally:
69+
_msvccompiler._find_vcvarsall = old_find_vcvarsall
70+
71+
def test_vcruntime_skip_copy(self):
72+
tempdir = self.mkdtemp()
73+
compiler = _msvccompiler.MSVCCompiler()
74+
compiler.initialize()
75+
dll = compiler._vcruntime_redist
76+
self.assertTrue(os.path.isfile(dll))
77+
78+
compiler._copy_vcruntime(tempdir)
79+
80+
self.assertFalse(os.path.isfile(os.path.join(
81+
tempdir, os.path.basename(dll))))
82+
3583
def test_suite():
3684
return unittest.makeSuite(msvccompilerTestCase)
3785

Misc/NEWS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ Library
1212

1313
- Issue #25029: Fixes MemoryError in test_strptime
1414

15+
Build
16+
-----
17+
18+
- Issue #25027: Reverts partial-static build options and adds
19+
vcruntime140.dll to Windows installation.
20+
21+
1522
What's New in Python 3.5.0 release candidate 3?
1623
===============================================
1724

PCbuild/pyproject.props

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<IntrinsicFunctions>true</IntrinsicFunctions>
3737
<StringPooling>true</StringPooling>
3838
<ExceptionHandling></ExceptionHandling>
39-
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
39+
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
4040
<FunctionLevelLinking>true</FunctionLevelLinking>
4141
<WarningLevel>Level3</WarningLevel>
4242
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@@ -47,7 +47,7 @@
4747
<ClCompile Condition="$(Configuration) == 'Debug'">
4848
<Optimization>Disabled</Optimization>
4949
<WholeProgramOptimization>false</WholeProgramOptimization>
50-
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
50+
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
5151
</ClCompile>
5252
<Link>
5353
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -57,9 +57,7 @@
5757
<RandomizedBaseAddress>true</RandomizedBaseAddress>
5858
<DataExecutionPrevention>true</DataExecutionPrevention>
5959
<SuppressStartupBanner>true</SuppressStartupBanner>
60-
<AdditionalDependencies Condition="$(Configuration) == 'Debug'">ucrtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
61-
<AdditionalDependencies Condition="$(Configuration) != 'Debug'">ucrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
62-
<IgnoreSpecificDefaultLibraries>LIBC;libucrt.lib;libucrtd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
60+
<IgnoreSpecificDefaultLibraries>LIBC;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
6361
<TargetMachine>MachineX86</TargetMachine>
6462
<TargetMachine Condition="'$(Platform)' == 'x64'">MachineX64</TargetMachine>
6563
<ProfileGuidedDatabase Condition="$(SupportPGO)">$(OutDir)$(TargetName).pgd</ProfileGuidedDatabase>

PCbuild/tcl.vcxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
6262

6363
<PropertyGroup>
64-
<TclOpts>ucrt</TclOpts>
65-
<TclOpts Condition="$(Configuration) == 'Debug'">symbols,ucrt</TclOpts>
64+
<TclOpts>msvcrt</TclOpts>
65+
<TclOpts Condition="$(Configuration) == 'Debug'">symbols,msvcrt</TclOpts>
6666
<TclDirs>INSTALLDIR="$(OutDir.TrimEnd(`\`))" INSTALL_DIR="$(OutDir.TrimEnd(`\`))"</TclDirs>
6767
<DebugFlags Condition="'$(Configuration)' == 'Debug'">DEBUGFLAGS="-wd4456 -wd4457 -wd4458 -wd4459 -wd4996"</DebugFlags>
6868
<NMakeBuildCommandLine>setlocal

PCbuild/tix.vcxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@
5757

5858
<PropertyGroup>
5959
<TixDirs>BUILDDIRTOP="$(BuildDirTop)" TCL_DIR="$(tclDir.TrimEnd(`\`))" TK_DIR="$(tkDir.TrimEnd(`\`))" INSTALL_DIR="$(OutDir.TrimEnd(`\`))"</TixDirs>
60-
<DebugFlags Condition="'$(Configuration)' == 'Debug'">DEBUG=1 NODEBUG=0 UCRT=1 TCL_DBGX=g TK_DBGX=g</DebugFlags>
61-
<DebugFlags Condition="'$(Configuration)' != 'Debug'">DEBUG=0 NODEBUG=1 UCRT=1</DebugFlags>
60+
<DebugFlags Condition="'$(Configuration)' == 'Debug'">DEBUG=1 NODEBUG=0 TCL_DBGX=g TK_DBGX=g</DebugFlags>
61+
<DebugFlags Condition="'$(Configuration)' != 'Debug'">DEBUG=0 NODEBUG=1</DebugFlags>
6262
<NMakeBuildCommandLine>setlocal
6363
@(ExpectedOutputs->'if not exist "%(FullPath)" goto build','
6464
')

PCbuild/tk.vcxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@
6060
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
6161

6262
<PropertyGroup>
63-
<TkOpts>ucrt</TkOpts>
64-
<TkOpts Condition="$(Configuration) == 'Debug'">symbols,ucrt</TkOpts>
63+
<TkOpts>msvcrt</TkOpts>
64+
<TkOpts Condition="$(Configuration) == 'Debug'">symbols,msvcrt</TkOpts>
6565
<TkDirs>TCLDIR="$(tclDir.TrimEnd(`\`))" INSTALLDIR="$(OutDir.TrimEnd(`\`))"</TkDirs>
6666
<DebugFlags Condition="'$(Configuration)' == 'Debug'">DEBUGFLAGS="-wd4456 -wd4457 -wd4458 -wd4459 -wd4996"</DebugFlags>
6767
<NMakeBuildCommandLine>setlocal

Tools/msi/build.bat

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ if not defined BUILDX86 if not defined BUILDX64 (set BUILDX86=1) && (set BUILDX6
2020
call "%PCBUILD%env.bat" x86
2121

2222
if defined BUILDX86 (
23-
call "%PCBUILD%build.bat" -d
23+
call "%PCBUILD%build.bat" -d -e
2424
if errorlevel 1 goto :eof
25-
call "%PCBUILD%build.bat"
25+
call "%PCBUILD%build.bat" -e
2626
if errorlevel 1 goto :eof
2727
)
2828
if defined BUILDX64 (
29-
call "%PCBUILD%build.bat" -p x64 -d
29+
call "%PCBUILD%build.bat" -p x64 -d -e
3030
if errorlevel 1 goto :eof
31-
call "%PCBUILD%build.bat" -p x64
31+
call "%PCBUILD%build.bat" -p x64 -e
3232
if errorlevel 1 goto :eof
3333
)
3434

Tools/msi/buildrelease.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ if not "%CERTNAME%" EQU "" (
121121
if not "%SKIPBUILD%" EQU "1" (
122122
call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -d -t %TARGET% %CERTOPTS%
123123
if errorlevel 1 exit /B
124-
call "%PCBUILD%build.bat" -p %BUILD_PLAT% -t %TARGET% %CERTOPTS%
124+
call "%PCBUILD%build.bat" -e -p %BUILD_PLAT% -t %TARGET% %CERTOPTS%
125125
if errorlevel 1 exit /B
126126
@rem build.bat turns echo back on, so we disable it again
127127
@echo off

Tools/msi/exe/exe_files.wxs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
<Component Id="pythonw.exe" Directory="InstallDirectory" Guid="$(var.PythonwExeComponentGuid)">
3030
<File Name="pythonw.exe" KeyPath="yes" />
3131
</Component>
32+
<Component Id="vcruntime140.dll" Directory="InstallDirectory" Guid="*">
33+
<File Name="vcruntime140.dll" Source="!(bindpath.redist)vcruntime140.dll" KeyPath="yes" />
34+
</Component>
3235
</ComponentGroup>
3336
</Fragment>
3437

0 commit comments

Comments
 (0)