Skip to content

bpo-35920: Windows 10 ARM32 platform support #11774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Doc/library/platform.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ 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'``.

.. versionadded:: 3.8

.. function:: win32_is_iot()

Returns True if the windows edition returned by win32_edition is recognized
as an IoT edition.

.. versionadded:: 3.8


Mac OS Platform
---------------
Expand Down
16 changes: 14 additions & 2 deletions Lib/distutils/_msvccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Lib/distutils/spawn.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions Lib/distutils/sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 13 additions & 3 deletions Lib/distutils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -38,6 +38,8 @@ def get_platform ():
if os.name == 'nt':
if 'amd64' in sys.version.lower():
return 'win-amd64'
if '(arm)' in sys.version.lower():
return 'win-arm32'
return sys.platform

# Set for cross builds explicitly
Expand Down Expand Up @@ -90,8 +92,16 @@ def get_platform ():

return "%s-%s-%s" % (osname, release, machine)

# get_platform ()

def get_platform():
if os.name == 'nt':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's only define TARGET_TO_PLAT for Windows as well. Even though it's static, it still gets constructed on each call and it doesn't have any meaning on other OS's.

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()

def convert_path (pathname):
"""Return 'pathname' as a name that will work on the native filesystem,
Expand Down
21 changes: 21 additions & 0 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,27 @@ 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:
try:
import winreg
except ImportError:
import _winreg as winreg
except ImportError:
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

def win32_ver(release='', version='', csd='', ptype=''):
try:
from sys import getwindowsversion
Expand Down
2 changes: 2 additions & 0 deletions Lib/sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ def get_platform():
if os.name == 'nt':
if 'amd64' in sys.version.lower():
return 'win-amd64'
if '(arm)' in sys.version.lower():
return 'win-arm32'
return sys.platform

if os.name != "posix" or not hasattr(os, 'uname'):
Expand Down
32 changes: 31 additions & 1 deletion Lib/test/test_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ 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, WinDLL
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")))
info = CPINFOEXW()
return GetCPInfoEx(cp, 0, info)

class Queue(object):
"""
Expand Down Expand Up @@ -3078,9 +3098,19 @@ 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):
self.assertEqual(codecs.code_page_decode(cp, b'abc'), ('abc', 3), f'cp{cp}')
else:
if support.verbose:
print(f" skipping cp={cp}")
self.assertEqual(codecs.code_page_decode(42, b'abc'),
('\uf061\uf062\uf063', 3))

Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -116,6 +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 unavailable")
def test_registry_parsing(self):
# the original, minimum contents of the MIME database in the
# Windows registry is undocumented AFAIK.
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import uuid
import warnings
from test import support
from platform import win32_is_iot

try:
import resource
Expand Down Expand Up @@ -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):
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_startfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import unittest
from test import support
import os
import platform
import sys
from os import path

Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_sundry.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_winreg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
16 changes: 16 additions & 0 deletions PC/bdist_wininst/bdist_wininst.vcxproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
Expand All @@ -9,6 +13,10 @@
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="PGInstrument|ARM">
<Configuration>PGInstrument</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="PGInstrument|Win32">
<Configuration>PGInstrument</Configuration>
<Platform>Win32</Platform>
Expand All @@ -17,6 +25,10 @@
<Configuration>PGInstrument</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="PGUpdate|ARM">
<Configuration>PGUpdate</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="PGUpdate|Win32">
<Configuration>PGUpdate</Configuration>
<Platform>Win32</Platform>
Expand All @@ -25,6 +37,10 @@
<Configuration>PGUpdate</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
Expand Down
2 changes: 1 addition & 1 deletion PCbuild/build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions PCbuild/pcbuild.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down