From 43ebbd54c89b1450788b0c38719251df8eb34144 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Wed, 1 Aug 2018 18:19:04 -0700 Subject: [PATCH 1/8] CPython for Windows ARM32 proof-of-concept changes Changes should be refactored into mergable PRs --- Doc/library/platform.rst | 11 +++++++++++ Lib/distutils/_msvccompiler.py | 16 ++++++++++++++-- Lib/distutils/sysconfig.py | 10 +++++++++- Lib/distutils/util.py | 23 +++++++++++++++++++++-- Lib/platform.py | 22 ++++++++++++++++++++++ Lib/sysconfig.py | 2 ++ Lib/test/test_mimetypes.py | 2 ++ Lib/test/test_os.py | 3 ++- Lib/test/test_startfile.py | 2 ++ Lib/test/test_sundry.py | 3 ++- Lib/test/test_winreg.py | 3 ++- PC/bdist_wininst/bdist_wininst.vcxproj | 16 ++++++++++++++++ PCbuild/build.bat | 2 +- PCbuild/pcbuild.sln | 9 +++++---- 14 files changed, 111 insertions(+), 13 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 60c6089ad3ccb5..29b1ec3bb2f16f 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -216,6 +216,17 @@ Windows Platform later (support for this was added in Python 2.6). It obviously only runs on Win32 compatible platforms. +.. function:: win32_edition() + + Returns a string representing the current Windows edition. Possible + values include but are not limited to ``'Enterprise'``, ``'IoTUAP'``, + ``'ServerStandard'``, and ``'nanoserver'``. + +.. function:: win32_is_iot() + + Returns True if the windows edition returned by win32_edition is recognized + as an IoT edition. + Mac OS Platform --------------- diff --git a/Lib/distutils/_msvccompiler.py b/Lib/distutils/_msvccompiler.py index 58b20a21024733..c7ac3f049ebf22 100644 --- a/Lib/distutils/_msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -89,13 +89,24 @@ def _find_vc2017(): return None, None +PLAT_SPEC_TO_RUNTIME = { + 'x86' : 'x86', + 'x86_amd64' : 'x64', + 'x86_arm' : 'arm', +} + def _find_vcvarsall(plat_spec): _, best_dir = _find_vc2017() vcruntime = None - vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86' + + if plat_spec in PLAT_SPEC_TO_RUNTIME: + vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec] + else: + vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86' + if best_dir: vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**", - "Microsoft.VC141.CRT", "vcruntime140.dll") + vcruntime_plat, "Microsoft.VC141.CRT", "vcruntime140.dll") try: import glob vcruntime = glob.glob(vcredist, recursive=True)[-1] @@ -178,6 +189,7 @@ def _find_exe(exe, paths=None): PLAT_TO_VCVARS = { 'win32' : 'x86', 'win-amd64' : 'x86_amd64', + 'win-arm32' : 'x86_arm', } # A set containing the DLLs that are guaranteed to be available for diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index a3494670db18c1..cfe19c7fef1c8c 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -15,6 +15,7 @@ import sys from .errors import DistutilsPlatformError +from .util import get_platform, get_host_platform # These are needed in a couple of spots, so just compute them once. PREFIX = os.path.normpath(sys.prefix) @@ -449,7 +450,14 @@ def _init_nt(): # XXX hmmm.. a normal install puts include files here g['INCLUDEPY'] = get_python_inc(plat_specific=0) - g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] + # if cross-compiling replace hardcoded platform-specific EXT_SUFFIX + # with an EXT_SUFFIX that matches the target platform + if get_platform() == get_host_platform(): + g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] + else: + plat_tag = get_platform().replace('-', '_') + g['EXT_SUFFIX'] = '.cp{0.major}{0.minor}-{1}.pyd'.format(sys.version_info, plat_tag) + g['EXE'] = ".exe" g['VERSION'] = get_python_version().replace(".", "") g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 15cd2ad9a9afb8..1341b598148f6e 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -15,7 +15,7 @@ from distutils import log from distutils.errors import DistutilsByteCompileError -def get_platform (): +def get_host_platform (): """Return a string that identifies the current platform. This is used mainly to distinguish platform-specific build directories and platform-specific built distributions. Typically includes the OS name and version and the @@ -38,6 +38,8 @@ def get_platform (): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' + if 'arm32' in sys.version.lower(): + return 'win-arm32' return sys.platform # Set for cross builds explicitly @@ -90,8 +92,25 @@ def get_platform (): return "%s-%s-%s" % (osname, release, machine) -# get_platform () +# get_host_platform () + +def get_platform (): + TARGET_TO_PLAT = { + 'x86' : 'win32', + 'x64' : 'win-amd64', + 'arm' : 'win-arm32', + } + + targetPlatformFromEnvironment = os.environ.get('VSCMD_ARG_TGT_ARCH') + if targetPlatformFromEnvironment != None and targetPlatformFromEnvironment in TARGET_TO_PLAT: + targetPlatform = TARGET_TO_PLAT[targetPlatformFromEnvironment] + else: + targetPlatform = get_host_platform() + + return targetPlatform + +# get_platform () def convert_path (pathname): """Return 'pathname' as a name that will work on the native filesystem, diff --git a/Lib/platform.py b/Lib/platform.py index 2ab68aed786138..4ebf6fa652faaa 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -334,6 +334,28 @@ def _syscmd_ver(system='', release='', version='', (6, None): "post2012ServerR2", } +def win32_is_iot(): + return win32_edition() in ('IoTUAP', 'NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS') + +def win32_edition(): + try: + from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE + except ImportError: + from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE + + key = None + try: + key = OpenKeyEx(HKEY_LOCAL_MACHINE, + r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') + return QueryValueEx(key, 'EditionId')[0] + except OSError: + pass + finally: + if key: + CloseKey(key) + + return None + def win32_ver(release='', version='', csd='', ptype=''): try: from sys import getwindowsversion diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index cc8c7962b1bca2..2b6ef02853b881 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -626,6 +626,8 @@ def get_platform(): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' + if 'arm32' in sys.version.lower(): + return 'win-arm32' return sys.platform if os.name != "posix" or not hasattr(os, 'uname'): diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 554d3d5cead5db..99e742990cd66a 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -6,6 +6,7 @@ import unittest from test import support +from platform import win32_edition # Tell it we don't know about external files: mimetypes.knownfiles = [] @@ -116,6 +117,7 @@ def tearDown(self): mimetypes.types_map.clear() mimetypes.types_map.update(self.original_types_map) + @unittest.skipIf(win32_edition() in ('NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS'), "mime types registry keys not available on NanoServer") def test_registry_parsing(self): # the original, minimum contents of the MIME database in the # Windows registry is undocumented AFAIK. diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 4c620ccae9c84c..48562dc3fb9423 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -28,6 +28,7 @@ import uuid import warnings from test import support +from platform import win32_is_iot try: import resource @@ -2446,7 +2447,7 @@ def test_bad_fd(self): # Return None when an fd doesn't actually exist. self.assertIsNone(os.device_encoding(123456)) - @unittest.skipUnless(os.isatty(0) and (sys.platform.startswith('win') or + @unittest.skipUnless(os.isatty(0) and not win32_is_iot() and (sys.platform.startswith('win') or (hasattr(locale, 'nl_langinfo') and hasattr(locale, 'CODESET'))), 'test requires a tty and either Windows or nl_langinfo(CODESET)') def test_device_encoding(self): diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py index f59252e97ad051..1a26a8025e6243 100644 --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -10,6 +10,7 @@ import unittest from test import support import os +import platform import sys from os import path @@ -20,6 +21,7 @@ class TestCase(unittest.TestCase): def test_nonexisting(self): self.assertRaises(OSError, startfile, "nonexisting.vbs") + @unittest.skipIf(platform.win32_is_iot(), "starting files is not supported on Windows IoT Core or nanoserver") def test_empty(self): # We need to make sure the child process starts in a directory # we're not about to delete. If we're running under -j, that diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py index 6e36a6123daa0e..2accad1aeebd4f 100644 --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -1,5 +1,6 @@ """Do a minimal test of all the modules that aren't otherwise tested.""" import importlib +import platform import sys from test import support import unittest @@ -25,7 +26,7 @@ def test_untested_modules_can_be_imported(self): import distutils.unixccompiler import distutils.command.bdist_dumb - if sys.platform.startswith('win'): + if sys.platform.startswith('win') and not platform.win32_is_iot(): import distutils.command.bdist_msi import distutils.command.bdist import distutils.command.bdist_rpm diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 11d054e16cdbfa..dc2b46e42521f3 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -5,7 +5,7 @@ import unittest from test import support import threading -from platform import machine +from platform import machine, win32_edition # Do this first so test will be skipped if module doesn't exist support.import_module('winreg', required_on=['win']) @@ -399,6 +399,7 @@ def test_named_arguments(self): DeleteKeyEx(key=HKEY_CURRENT_USER, sub_key=test_key_name, access=KEY_ALL_ACCESS, reserved=0) + @unittest.skipIf(win32_edition() in ('WindowsCoreHeadless', 'IoTEdgeOS'), "APIs not available on WindowsCoreHeadless") def test_reflection_functions(self): # Test that we can call the query, enable, and disable functions # on a key which isn't on the reflection list with no consequences. diff --git a/PC/bdist_wininst/bdist_wininst.vcxproj b/PC/bdist_wininst/bdist_wininst.vcxproj index 70bfb9c9337943..d2f1bb75e30d87 100644 --- a/PC/bdist_wininst/bdist_wininst.vcxproj +++ b/PC/bdist_wininst/bdist_wininst.vcxproj @@ -1,6 +1,10 @@  + + Debug + ARM + Debug Win32 @@ -9,6 +13,10 @@ Debug x64 + + PGInstrument + ARM + PGInstrument Win32 @@ -17,6 +25,10 @@ PGInstrument x64 + + PGUpdate + ARM + PGUpdate Win32 @@ -25,6 +37,10 @@ PGUpdate x64 + + Release + ARM + Release Win32 diff --git a/PCbuild/build.bat b/PCbuild/build.bat index 759aa5221b4266..cd0c07abbf352b 100644 --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -41,7 +41,7 @@ echo. echo.Available arguments: echo. -c Release ^| Debug ^| PGInstrument ^| PGUpdate echo. Set the configuration (default: Release) -echo. -p x64 ^| Win32 +echo. -p x64 ^| Win32 ^| ARM echo. Set the platform (default: Win32) echo. -t Build ^| Rebuild ^| Clean ^| CleanAll echo. Set the target manually diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index e9239365b5c1af..fc8c7318ac7538 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -595,16 +595,16 @@ Global {D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|Win32.Build.0 = Release|Win32 {D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|x64.ActiveCfg = Release|x64 {D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|x64.Build.0 = Release|x64 - {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|ARM.ActiveCfg = Debug|Win32 + {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|ARM.ActiveCfg = Debug|ARM {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|Win32.ActiveCfg = Debug|Win32 {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|x64.ActiveCfg = Release|x64 - {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|ARM.ActiveCfg = PGInstrument|Win32 + {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|Win32.ActiveCfg = Release|Win32 {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|x64.ActiveCfg = Release|x64 - {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|ARM.ActiveCfg = PGUpdate|Win32 + {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|Win32.ActiveCfg = Release|Win32 {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|x64.ActiveCfg = Release|x64 - {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|ARM.ActiveCfg = Release|Win32 + {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|ARM.ActiveCfg = Release|ARM {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|Win32.ActiveCfg = Release|Win32 {EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Release|x64.ActiveCfg = Release|x64 {447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|ARM.ActiveCfg = Debug|ARM @@ -894,6 +894,7 @@ Global {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.PGUpdate|x64.Build.0 = PGUpdate|x64 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|ARM.ActiveCfg = Release|ARM + {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|ARM.Build.0 = Release|ARM {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.ActiveCfg = Release|Win32 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|Win32.Build.0 = Release|Win32 {0F6EE4A4-C75F-4578-B4B3-2D64F4B9B782}.Release|x64.ActiveCfg = Release|x64 From f85d78480fdf51b603b5d704948d6b275c5d445a Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Fri, 19 Apr 2019 12:11:57 -0700 Subject: [PATCH 2/8] fix debug suffix --- Lib/distutils/sysconfig.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index cfe19c7fef1c8c..bf056fbb23b9f3 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -456,7 +456,8 @@ def _init_nt(): g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] else: plat_tag = get_platform().replace('-', '_') - g['EXT_SUFFIX'] = '.cp{0.major}{0.minor}-{1}.pyd'.format(sys.version_info, plat_tag) + host_plat_tag = get_host_platform().replace('-', '_') + g['EXT_SUFFIX'] = _imp.extension_suffixes()[0].replace(host_plat_tag, plat_tag) g['EXE'] = ".exe" g['VERSION'] = get_python_version().replace(".", "") From ad6cce27f55204fccaaf4e0d5be2eb538187f7f6 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Fri, 19 Apr 2019 16:56:59 -0700 Subject: [PATCH 3/8] check for codecs before using them --- Lib/test/test_codecs.py | 47 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 05843c54bd5f9a..03a34515ff5932 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -27,6 +27,39 @@ def check(input, expect): self.assertEqual(coder(input), (expect, len(input))) return check +# On small versions of Windows like Windows IoT or Windows Nano Server not all codepages are present +def is_code_page_present(cp): + from ctypes import POINTER, WINFUNCTYPE, windll, WinError, Structure + from ctypes.wintypes import BOOL, UINT, BYTE, WCHAR, UINT, DWORD + + MAX_LEADBYTES = 12 # 5 ranges, 2 bytes ea., 0 term. + MAX_DEFAULTCHAR = 2 # single or double byte + MAX_PATH = 260 + class CPINFOEXW(ctypes.Structure): + _fields_ = [("MaxCharSize", UINT), + ("DefaultChar", BYTE*MAX_DEFAULTCHAR), + ("LeadByte", BYTE*MAX_LEADBYTES), + ("UnicodeDefaultChar", WCHAR), + ("CodePage", UINT), + ("CodePageName", WCHAR*MAX_PATH)] + + prototype = WINFUNCTYPE(BOOL, UINT, DWORD, POINTER(CPINFOEXW)) + GetCPInfoEx = prototype(("GetCPInfoExW", windll.kernel32)) + + def errcheck(result, func, args): + if not result: + from ctypes import WinError + raise OSError(2, "code page not found") + return args + + from ctypes import WinError + try: + GetCPInfoEx.errcheck = errcheck + info = CPINFOEXW() + GetCPInfoEx(cp,0, info) + return True + except OSError: + return False class Queue(object): """ @@ -3078,9 +3111,21 @@ def test_multibyte_encoding(self): def test_code_page_decode_flags(self): # Issue #36312: For some code pages (e.g. UTF-7) flags for # MultiByteToWideChar() must be set to 0. + if support.verbose: + sys.stdout.write('\n') for cp in (50220, 50221, 50222, 50225, 50227, 50229, *range(57002, 57011+1), 65000): - self.assertEqual(codecs.code_page_decode(cp, b'abc'), ('abc', 3)) + # On small versions of Windows like Windows IoT + # not all codepages are present. + # A missing codepage causes an OSError exception + # so check for the codepage before decoding + if is_code_page_present(cp): + if support.verbose: + sys.stdout.write(" testing cp={}\n".format(cp)) + self.assertEqual(codecs.code_page_decode(cp, b'abc'), ('abc', 3)) + else: + if support.verbose: + sys.stdout.write(" skipping cp={}\n".format(cp)) self.assertEqual(codecs.code_page_decode(42, b'abc'), ('\uf061\uf062\uf063', 3)) From 77d776efcc3234ede100576cb0a0a7501804afab Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Mon, 22 Apr 2019 12:20:31 -0700 Subject: [PATCH 4/8] Address code review feedback --- Doc/library/platform.rst | 6 +++++- Lib/distutils/sysconfig.py | 10 +--------- Lib/distutils/util.py | 18 +++++------------- Lib/platform.py | 10 +++------- Lib/test/test_codecs.py | 27 ++++++--------------------- Lib/test/test_mimetypes.py | 3 ++- 6 files changed, 22 insertions(+), 52 deletions(-) diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst index 29b1ec3bb2f16f..e07f9d613a0d21 100644 --- a/Doc/library/platform.rst +++ b/Doc/library/platform.rst @@ -222,11 +222,15 @@ Windows Platform values include but are not limited to ``'Enterprise'``, ``'IoTUAP'``, ``'ServerStandard'``, and ``'nanoserver'``. + .. versionadded:: 3.8 + .. function:: win32_is_iot() - Returns True if the windows edition returned by win32_edition is recognized + Returns True if the windows edition returned by win32_edition is recognized as an IoT edition. + .. versionadded:: 3.8 + Mac OS Platform --------------- diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index bf056fbb23b9f3..999da2621ced8b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -450,15 +450,7 @@ def _init_nt(): # XXX hmmm.. a normal install puts include files here g['INCLUDEPY'] = get_python_inc(plat_specific=0) - # if cross-compiling replace hardcoded platform-specific EXT_SUFFIX - # with an EXT_SUFFIX that matches the target platform - if get_platform() == get_host_platform(): - g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] - else: - plat_tag = get_platform().replace('-', '_') - host_plat_tag = get_host_platform().replace('-', '_') - g['EXT_SUFFIX'] = _imp.extension_suffixes()[0].replace(host_plat_tag, plat_tag) - + g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] g['EXE'] = ".exe" g['VERSION'] = get_python_version().replace(".", "") g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 1341b598148f6e..4ee811ab4bba79 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -15,7 +15,7 @@ from distutils import log from distutils.errors import DistutilsByteCompileError -def get_host_platform (): +def get_host_platform(): """Return a string that identifies the current platform. This is used mainly to distinguish platform-specific build directories and platform-specific built distributions. Typically includes the OS name and version and the @@ -92,25 +92,17 @@ def get_host_platform (): return "%s-%s-%s" % (osname, release, machine) -# get_host_platform () - -def get_platform (): +def get_platform(): TARGET_TO_PLAT = { 'x86' : 'win32', 'x64' : 'win-amd64', 'arm' : 'win-arm32', } - targetPlatformFromEnvironment = os.environ.get('VSCMD_ARG_TGT_ARCH') - - if targetPlatformFromEnvironment != None and targetPlatformFromEnvironment in TARGET_TO_PLAT: - targetPlatform = TARGET_TO_PLAT[targetPlatformFromEnvironment] + if os.name == 'nt': + return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() else: - targetPlatform = get_host_platform() - - return targetPlatform - -# get_platform () + return get_host_platform() def convert_path (pathname): """Return 'pathname' as a name that will work on the native filesystem, diff --git a/Lib/platform.py b/Lib/platform.py index 4ebf6fa652faaa..6722810453ce9a 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -343,16 +343,12 @@ def win32_edition(): except ImportError: from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE - key = None try: - key = OpenKeyEx(HKEY_LOCAL_MACHINE, - r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') - return QueryValueEx(key, 'EditionId')[0] + with OpenKeyEx(HKEY_LOCAL_MACHINE, + r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') as key: + return QueryValueEx(key, 'EditionId')[0] except OSError: pass - finally: - if key: - CloseKey(key) return None diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 03a34515ff5932..027a84e275e369 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -29,7 +29,7 @@ def check(input, expect): # On small versions of Windows like Windows IoT or Windows Nano Server not all codepages are present def is_code_page_present(cp): - from ctypes import POINTER, WINFUNCTYPE, windll, WinError, Structure + from ctypes import POINTER, WINFUNCTYPE, windll, WinError, Structure, WinDLL from ctypes.wintypes import BOOL, UINT, BYTE, WCHAR, UINT, DWORD MAX_LEADBYTES = 12 # 5 ranges, 2 bytes ea., 0 term. @@ -44,22 +44,9 @@ class CPINFOEXW(ctypes.Structure): ("CodePageName", WCHAR*MAX_PATH)] prototype = WINFUNCTYPE(BOOL, UINT, DWORD, POINTER(CPINFOEXW)) - GetCPInfoEx = prototype(("GetCPInfoExW", windll.kernel32)) - - def errcheck(result, func, args): - if not result: - from ctypes import WinError - raise OSError(2, "code page not found") - return args - - from ctypes import WinError - try: - GetCPInfoEx.errcheck = errcheck - info = CPINFOEXW() - GetCPInfoEx(cp,0, info) - return True - except OSError: - return False + GetCPInfoEx = prototype(("GetCPInfoExW", WinDLL("kernel32"))) + info = CPINFOEXW() + return GetCPInfoEx(cp, 0, info) class Queue(object): """ @@ -3120,12 +3107,10 @@ def test_code_page_decode_flags(self): # A missing codepage causes an OSError exception # so check for the codepage before decoding if is_code_page_present(cp): - if support.verbose: - sys.stdout.write(" testing cp={}\n".format(cp)) - self.assertEqual(codecs.code_page_decode(cp, b'abc'), ('abc', 3)) + self.assertEqual(codecs.code_page_decode(cp, b'abc'), ('abc', 3), f'cp{cp}') else: if support.verbose: - sys.stdout.write(" skipping cp={}\n".format(cp)) + print(f" skipping cp={cp}") self.assertEqual(codecs.code_page_decode(42, b'abc'), ('\uf061\uf062\uf063', 3)) diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 99e742990cd66a..c4b2fe2047a71d 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -117,7 +117,8 @@ def tearDown(self): mimetypes.types_map.clear() mimetypes.types_map.update(self.original_types_map) - @unittest.skipIf(win32_edition() in ('NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS'), "mime types registry keys not available on NanoServer") + @unittest.skipIf(win32_edition() in ('NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS'), + "MIME types registry keys unavailable") def test_registry_parsing(self): # the original, minimum contents of the MIME database in the # Windows registry is undocumented AFAIK. From cec2b28743d8a24ee00c6a9aed93b71f7dc94e55 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Mon, 22 Apr 2019 12:49:55 -0700 Subject: [PATCH 5/8] fixes platform.win32_edition on non-Windows platforms --- Lib/platform.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py index 6722810453ce9a..f6f38cea921f1c 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -339,16 +339,19 @@ def win32_is_iot(): def win32_edition(): try: - from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE + try: + import winreg + except ImportError: + import _winreg as winreg except ImportError: - from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE - - try: - with OpenKeyEx(HKEY_LOCAL_MACHINE, - r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') as key: - return QueryValueEx(key, 'EditionId')[0] - except OSError: pass + else: + try: + cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion' + with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key: + return winreg.QueryValueEx(key, 'EditionId')[0] + except OSError: + pass return None From fc21d477143daa13dbaa4a61d09e0f10e8dad352 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Mon, 22 Apr 2019 17:13:00 -0700 Subject: [PATCH 6/8] add news, fix get_platform() --- Lib/distutils/util.py | 13 ++++++------- Lib/sysconfig.py | 2 +- .../2019-04-22-16-59-20.bpo-35920.VSfGOI.rst | 3 +++ 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2019-04-22-16-59-20.bpo-35920.VSfGOI.rst diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 4ee811ab4bba79..23dac420ba7d27 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -38,7 +38,7 @@ def get_host_platform(): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' - if 'arm32' in sys.version.lower(): + if 'arm' in sys.version.lower(): return 'win-arm32' return sys.platform @@ -93,13 +93,12 @@ def get_host_platform(): return "%s-%s-%s" % (osname, release, machine) def get_platform(): - TARGET_TO_PLAT = { - 'x86' : 'win32', - 'x64' : 'win-amd64', - 'arm' : 'win-arm32', - } - if os.name == 'nt': + TARGET_TO_PLAT = { + 'x86' : 'win32', + 'x64' : 'win-amd64', + 'arm' : 'win-arm32', + } return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() else: return get_host_platform() diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 2b6ef02853b881..a3168d7d2f00fc 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -626,7 +626,7 @@ def get_platform(): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' - if 'arm32' in sys.version.lower(): + if 'arm' in sys.version.lower(): return 'win-arm32' return sys.platform diff --git a/Misc/NEWS.d/next/Windows/2019-04-22-16-59-20.bpo-35920.VSfGOI.rst b/Misc/NEWS.d/next/Windows/2019-04-22-16-59-20.bpo-35920.VSfGOI.rst new file mode 100644 index 00000000000000..455e82450eb2b5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2019-04-22-16-59-20.bpo-35920.VSfGOI.rst @@ -0,0 +1,3 @@ +Added platform.win32_edition() and platform.win32_is_iot(). Added support +for cross-compiling packages for Windows ARM32. Skip tests that are not +expected to work on Windows IoT Core ARM32. From b4c3a7445467342f34c5add1efab535859419fc6 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Tue, 23 Apr 2019 17:26:34 -0700 Subject: [PATCH 7/8] fix macos test failure --- Lib/distutils/sysconfig.py | 1 - Lib/distutils/util.py | 2 +- Lib/sysconfig.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 999da2621ced8b..a3494670db18c1 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -15,7 +15,6 @@ import sys from .errors import DistutilsPlatformError -from .util import get_platform, get_host_platform # These are needed in a couple of spots, so just compute them once. PREFIX = os.path.normpath(sys.prefix) diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 23dac420ba7d27..50550e1893418c 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -38,7 +38,7 @@ def get_host_platform(): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' - if 'arm' in sys.version.lower(): + if '(arm)' in sys.version.lower(): return 'win-arm32' return sys.platform diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index a3168d7d2f00fc..8446c8deb2427e 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -626,7 +626,7 @@ def get_platform(): if os.name == 'nt': if 'amd64' in sys.version.lower(): return 'win-amd64' - if 'arm' in sys.version.lower(): + if '(arm)' in sys.version.lower(): return 'win-arm32' return sys.platform From d48686dc98a72348fcad6f48b09df705aafe8b21 Mon Sep 17 00:00:00 2001 From: Paul Monson Date: Wed, 24 Apr 2019 11:25:28 -0700 Subject: [PATCH 8/8] break circular dependency --- Lib/distutils/spawn.py | 2 +- Lib/distutils/sysconfig.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index d3a12c28339782..ceb94945dc8bed 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -81,7 +81,6 @@ def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0): "command %r failed with exit status %d" % (cmd, rc)) if sys.platform == 'darwin': - from distutils import sysconfig _cfg_target = None _cfg_target_split = None @@ -95,6 +94,7 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0): if sys.platform == 'darwin': global _cfg_target, _cfg_target_split if _cfg_target is None: + from distutils import sysconfig _cfg_target = sysconfig.get_config_var( 'MACOSX_DEPLOYMENT_TARGET') or '' if _cfg_target: diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index a3494670db18c1..999da2621ced8b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -15,6 +15,7 @@ import sys from .errors import DistutilsPlatformError +from .util import get_platform, get_host_platform # These are needed in a couple of spots, so just compute them once. PREFIX = os.path.normpath(sys.prefix)