From c32dcc895d29ff9f11cd656d8fb19d0fd14f4dca Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Tue, 8 Feb 2022 12:16:16 +0000 Subject: [PATCH 01/13] Enable windows arm64 targets - Add FreeType 2.11.1 support - Add MSBuild platform selection for ARM64 - Add support for static builds for FreeType versions 2.10 and above --- doc/users/next_whats_new/windows_arm64.rst | 8 ++++++ lib/matplotlib/__init__.py | 6 ++++- setupext.py | 30 +++++++++++++++++----- 3 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 doc/users/next_whats_new/windows_arm64.rst diff --git a/doc/users/next_whats_new/windows_arm64.rst b/doc/users/next_whats_new/windows_arm64.rst new file mode 100644 index 000000000000..97ac39a46912 --- /dev/null +++ b/doc/users/next_whats_new/windows_arm64.rst @@ -0,0 +1,8 @@ +Windows on Arm Support +---------------------- + +Preliminary support for windows on arm64 target added. + +Matplotlib for windows/arm64 requires FreeType 2.11 or above. + +No binary wheels are available yet but can be build from source. \ No newline at end of file diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index e68c3cb68f7d..000e1c328d4c 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -100,6 +100,7 @@ import sys import tempfile import warnings +import platform import numpy from packaging.version import parse as parse_version @@ -1199,7 +1200,10 @@ def is_interactive(): def _init_tests(): # The version of FreeType to install locally for running the # tests. This must match the value in `setupext.py` - LOCAL_FREETYPE_VERSION = '2.6.1' + if sys.platform.startswith('win') and platform.machine() == 'ARM64': + LOCAL_FREETYPE_VERSION = '2.11.1' + else: + LOCAL_FREETYPE_VERSION = '2.6.1' from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or diff --git a/setupext.py b/setupext.py index fbd56d76eee2..4148facec989 100644 --- a/setupext.py +++ b/setupext.py @@ -14,6 +14,7 @@ import tarfile import textwrap import urllib.request +from packaging import version from setuptools import Distribution, Extension @@ -167,12 +168,18 @@ def get_and_extract_tarball(urls, sha, dirname): '955e17244e9b38adb0c98df66abb50467312e6bb70eac07e49ce6bd1a20e809a', '2.10.1': '3a60d391fd579440561bf0e7f31af2222bc610ad6ce4d9d7bd2165bca8669110', + '2.11.1': + 'f8db94d307e9c54961b39a1cc799a67d46681480696ed72ecf78d4473770f09b' } # This is the version of FreeType to use when building a local version. It # must match the value in lib/matplotlib.__init__.py and also needs to be # changed below in the embedded windows build script (grep for "REMINDER" in # this file). Also update the cache path in `.circleci/config.yml`. -LOCAL_FREETYPE_VERSION = '2.6.1' +if sys.platform.startswith('win') and platform.machine() == 'ARM64': # older versions are not supported for win/arm64 + LOCAL_FREETYPE_VERSION = '2.11.1' +else: + LOCAL_FREETYPE_VERSION = '2.6.1' + LOCAL_FREETYPE_HASH = _freetype_hashes.get(LOCAL_FREETYPE_VERSION, 'unknown') # Also update the cache path in `.circleci/config.yml`. @@ -645,9 +652,10 @@ def do_custom_build(self, env): subprocess.check_call([make], env=env, cwd=src_path) else: # compilation on windows shutil.rmtree(src_path / "objs", ignore_errors=True) + is_x64 = platform.architecture()[0] == '64bit' msbuild_platform = ( - 'x64' if platform.architecture()[0] == '64bit' else 'Win32') - base_path = Path("build/freetype-2.6.1/builds/windows") + 'ARM64' if platform.machine() == 'ARM64' else 'x64' if is_x64 else 'Win32') + base_path = Path("build/freetype-{}/builds/windows".format(LOCAL_FREETYPE_VERSION)) vc = 'vc2010' sln_path = ( base_path / vc / "freetype.sln" @@ -677,15 +685,23 @@ def do_custom_build(self, env): cc = get_ccompiler() cc.initialize() # Get msbuild in the %PATH% of cc.spawn. + # Freetype 2.10.0+ support static builds and use them if available as they are easier to deploy + msbuild_configuration = 'Release Static' if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0") else 'Release' cc.spawn(["msbuild", str(sln_path), "/t:Clean;Build", - f"/p:Configuration=Release;Platform={msbuild_platform}"]) + f"/p:Configuration={msbuild_configuration};Platform={msbuild_platform}"]) # Move to the corresponding Unix build path. (src_path / "objs" / ".libs").mkdir() # Be robust against change of FreeType version. - lib_path, = (src_path / "objs" / vc / msbuild_platform).glob( - "freetype*.lib") - shutil.copy2(lib_path, src_path / "objs/.libs/libfreetype.lib") + lib_paths = Path(src_path / "objs").rglob('freetype*.lib') + libfreetype_file = None + for lib_path in lib_paths: + # check if freetype.lib in required platform directory + if msbuild_platform in lib_path.resolve().as_uri(): + libfreetype_file = lib_path + continue + print("Copying {} to {}".format(lib_path.resolve(), src_path / "objs/.libs/libfreetype.lib")) + shutil.copy2(libfreetype_file, src_path / "objs/.libs/libfreetype.lib") class Qhull(SetupPackage): From df7f8c03744c70bb29656a2d2fd54f9d23a8f236 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Mon, 14 Feb 2022 17:23:29 +0000 Subject: [PATCH 02/13] refactor to skip codecov --- lib/matplotlib/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 000e1c328d4c..f99a0930e059 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1200,10 +1200,8 @@ def is_interactive(): def _init_tests(): # The version of FreeType to install locally for running the # tests. This must match the value in `setupext.py` - if sys.platform.startswith('win') and platform.machine() == 'ARM64': - LOCAL_FREETYPE_VERSION = '2.11.1' - else: - LOCAL_FREETYPE_VERSION = '2.6.1' + win_arm64 = sys.platform.startswith('win') and platform.machine() == 'ARM64' + LOCAL_FREETYPE_VERSION = '2.11.1' if win_arm64 else '2.6.1' from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or From 5d79ce57b3f3e4ab2dd4fca4827a748721f6c079 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Tue, 15 Feb 2022 10:47:44 +0000 Subject: [PATCH 03/13] fix linting errors --- lib/matplotlib/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index f99a0930e059..c52629459bc8 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1200,8 +1200,9 @@ def is_interactive(): def _init_tests(): # The version of FreeType to install locally for running the # tests. This must match the value in `setupext.py` - win_arm64 = sys.platform.startswith('win') and platform.machine() == 'ARM64' - LOCAL_FREETYPE_VERSION = '2.11.1' if win_arm64 else '2.6.1' + win_arm64 = sys.platform.startswith('win') and \ + platform.machine() == 'ARM64' + LOCAL_FREETYPE_VERSION = '2.11.1' if win_arm64 else '2.6.1' from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or From 5595d346f80f380ead097ed493eb6550084c4528 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Thu, 17 Feb 2022 16:19:18 +0000 Subject: [PATCH 04/13] revert changes in lib/matplotlib/__init__.py --- lib/matplotlib/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index c52629459bc8..a3533749b230 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1200,10 +1200,7 @@ def is_interactive(): def _init_tests(): # The version of FreeType to install locally for running the # tests. This must match the value in `setupext.py` - win_arm64 = sys.platform.startswith('win') and \ - platform.machine() == 'ARM64' - LOCAL_FREETYPE_VERSION = '2.11.1' if win_arm64 else '2.6.1' - + LOCAL_FREETYPE_VERSION = '2.6.1' from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or ft2font.__freetype_build_type__ != 'local'): From 1f54d47815283d76fe9edec87c1e312420df5533 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Thu, 17 Feb 2022 16:22:52 +0000 Subject: [PATCH 05/13] Update setupext.py Co-authored-by: Thomas A Caswell --- setupext.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/setupext.py b/setupext.py index 4148facec989..392ef8614d40 100644 --- a/setupext.py +++ b/setupext.py @@ -175,10 +175,13 @@ def get_and_extract_tarball(urls, sha, dirname): # must match the value in lib/matplotlib.__init__.py and also needs to be # changed below in the embedded windows build script (grep for "REMINDER" in # this file). Also update the cache path in `.circleci/config.yml`. -if sys.platform.startswith('win') and platform.machine() == 'ARM64': # older versions are not supported for win/arm64 +TESTING_VERSION_OF_FREETYPE = '2.6.1' +if sys.platform.startswith('win') and platform.machine() == 'ARM64': + # older versions of freetype are not supported for win/arm64 + # Matplotlib tests will not pass LOCAL_FREETYPE_VERSION = '2.11.1' else: - LOCAL_FREETYPE_VERSION = '2.6.1' + LOCAL_FREETYPE_VERSION = TESTING_VERSION_OF_FREETYPE LOCAL_FREETYPE_HASH = _freetype_hashes.get(LOCAL_FREETYPE_VERSION, 'unknown') From b509068668121c49bb2b1fa2215035aa80f55f11 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 17 Feb 2022 23:03:59 -0500 Subject: [PATCH 06/13] STY: remove trailing whitespace --- setupext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index 392ef8614d40..7ff596a6e94c 100644 --- a/setupext.py +++ b/setupext.py @@ -176,7 +176,7 @@ def get_and_extract_tarball(urls, sha, dirname): # changed below in the embedded windows build script (grep for "REMINDER" in # this file). Also update the cache path in `.circleci/config.yml`. TESTING_VERSION_OF_FREETYPE = '2.6.1' -if sys.platform.startswith('win') and platform.machine() == 'ARM64': +if sys.platform.startswith('win') and platform.machine() == 'ARM64': # older versions of freetype are not supported for win/arm64 # Matplotlib tests will not pass LOCAL_FREETYPE_VERSION = '2.11.1' From 76d2e02c4413ca6aee375a9b9296b9d22fc1c422 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Fri, 18 Feb 2022 08:57:29 +0000 Subject: [PATCH 07/13] Minor clean up to keep the line length bit short --- lib/matplotlib/__init__.py | 1 - setupext.py | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index a3533749b230..4b87e6146498 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -100,7 +100,6 @@ import sys import tempfile import warnings -import platform import numpy from packaging.version import parse as parse_version diff --git a/setupext.py b/setupext.py index 7ff596a6e94c..edeb0c8c04fd 100644 --- a/setupext.py +++ b/setupext.py @@ -688,11 +688,14 @@ def do_custom_build(self, env): cc = get_ccompiler() cc.initialize() # Get msbuild in the %PATH% of cc.spawn. - # Freetype 2.10.0+ support static builds and use them if available as they are easier to deploy - msbuild_configuration = 'Release Static' if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0") else 'Release' + # Freetype 2.10.0+ support static builds. + if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0"): + msbuild_config = 'Release Static' + else: + msbuild_config = 'Release' cc.spawn(["msbuild", str(sln_path), "/t:Clean;Build", - f"/p:Configuration={msbuild_configuration};Platform={msbuild_platform}"]) + f"/p:Configuration={msbuild_config};Platform={msbuild_platform}"]) # Move to the corresponding Unix build path. (src_path / "objs" / ".libs").mkdir() # Be robust against change of FreeType version. From af3a7af74177a2bf73338f9a61ecf050c04a09dd Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Fri, 18 Feb 2022 09:37:37 +0000 Subject: [PATCH 08/13] restore empty line missed in __init__.py --- lib/matplotlib/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 4b87e6146498..e68c3cb68f7d 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1200,6 +1200,7 @@ def _init_tests(): # The version of FreeType to install locally for running the # tests. This must match the value in `setupext.py` LOCAL_FREETYPE_VERSION = '2.6.1' + from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or ft2font.__freetype_build_type__ != 'local'): From 08cb182368a8ed8eec3153204cb69e4ad0478430 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Fri, 18 Feb 2022 14:13:16 +0000 Subject: [PATCH 09/13] minor refactoring --- setupext.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/setupext.py b/setupext.py index edeb0c8c04fd..6b16bef25453 100644 --- a/setupext.py +++ b/setupext.py @@ -689,10 +689,12 @@ def do_custom_build(self, env): cc = get_ccompiler() cc.initialize() # Get msbuild in the %PATH% of cc.spawn. # Freetype 2.10.0+ support static builds. - if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0"): - msbuild_config = 'Release Static' - else: - msbuild_config = 'Release' + msbuild_config = ( + "Release Static" + if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0") + else "Release" + ) + cc.spawn(["msbuild", str(sln_path), "/t:Clean;Build", f"/p:Configuration={msbuild_config};Platform={msbuild_platform}"]) From a0cb369999aa8ba03a4ad838384e7c6c44715161 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 10 Mar 2022 12:53:32 -0500 Subject: [PATCH 10/13] DOC: tweak tense --- doc/users/next_whats_new/windows_arm64.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/users/next_whats_new/windows_arm64.rst b/doc/users/next_whats_new/windows_arm64.rst index 97ac39a46912..dcaf0e3b618a 100644 --- a/doc/users/next_whats_new/windows_arm64.rst +++ b/doc/users/next_whats_new/windows_arm64.rst @@ -5,4 +5,4 @@ Preliminary support for windows on arm64 target added. Matplotlib for windows/arm64 requires FreeType 2.11 or above. -No binary wheels are available yet but can be build from source. \ No newline at end of file +No binary wheels are available yet but can be built from source. \ No newline at end of file From 48652599fd8c2d16e10f85a54aaf58813174f8dd Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Thu, 10 Mar 2022 20:34:54 +0000 Subject: [PATCH 11/13] Minor clean up and refactoring for freetype lib finding part --- setupext.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/setupext.py b/setupext.py index 6b16bef25453..5ab2404abdea 100644 --- a/setupext.py +++ b/setupext.py @@ -656,9 +656,15 @@ def do_custom_build(self, env): else: # compilation on windows shutil.rmtree(src_path / "objs", ignore_errors=True) is_x64 = platform.architecture()[0] == '64bit' - msbuild_platform = ( - 'ARM64' if platform.machine() == 'ARM64' else 'x64' if is_x64 else 'Win32') - base_path = Path("build/freetype-{}/builds/windows".format(LOCAL_FREETYPE_VERSION)) + if platform.machine() == 'ARM64': + msbuild_platform = 'ARM64' + elif is_x64: + msbuild_platform = 'x64' + else: + msbuild_platform = 'Win32' + base_path = Path( + f"build/freetype-{LOCAL_FREETYPE_VERSION}/builds/windows" + ) vc = 'vc2010' sln_path = ( base_path / vc / "freetype.sln" @@ -702,14 +708,13 @@ def do_custom_build(self, env): (src_path / "objs" / ".libs").mkdir() # Be robust against change of FreeType version. lib_paths = Path(src_path / "objs").rglob('freetype*.lib') - libfreetype_file = None - for lib_path in lib_paths: - # check if freetype.lib in required platform directory - if msbuild_platform in lib_path.resolve().as_uri(): - libfreetype_file = lib_path - continue - print("Copying {} to {}".format(lib_path.resolve(), src_path / "objs/.libs/libfreetype.lib")) - shutil.copy2(libfreetype_file, src_path / "objs/.libs/libfreetype.lib") + # Select FreeType library for required platform + lib_path = next( + p for p in lib_paths + if msbuild_platform in p.resolve().as_uri() + ) + print(f"Copying {lib_path} to {src_path}/objs/.libs/libfreetype.lib") + shutil.copy2(lib_path, src_path / "objs/.libs/libfreetype.lib") class Qhull(SetupPackage): From e773f935a1d6533a783afdbc404e226aba732841 Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Thu, 10 Mar 2022 20:42:24 +0000 Subject: [PATCH 12/13] remove next and do a simple list unpacking --- setupext.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setupext.py b/setupext.py index 5ab2404abdea..42a3a4ad310f 100644 --- a/setupext.py +++ b/setupext.py @@ -709,10 +709,10 @@ def do_custom_build(self, env): # Be robust against change of FreeType version. lib_paths = Path(src_path / "objs").rglob('freetype*.lib') # Select FreeType library for required platform - lib_path = next( + lib_path, = [ p for p in lib_paths if msbuild_platform in p.resolve().as_uri() - ) + ] print(f"Copying {lib_path} to {src_path}/objs/.libs/libfreetype.lib") shutil.copy2(lib_path, src_path / "objs/.libs/libfreetype.lib") From 4e05fa3cc2e53432c7b388fabe18777987b7bcae Mon Sep 17 00:00:00 2001 From: Niyas Sait Date: Fri, 11 Mar 2022 14:54:24 +0000 Subject: [PATCH 13/13] fix line length: keep < 79 char --- setupext.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setupext.py b/setupext.py index 42a3a4ad310f..e1ebcbb5d586 100644 --- a/setupext.py +++ b/setupext.py @@ -697,13 +697,15 @@ def do_custom_build(self, env): # Freetype 2.10.0+ support static builds. msbuild_config = ( "Release Static" - if version.parse(LOCAL_FREETYPE_VERSION) >= version.parse("2.10.0") + if version.parse(LOCAL_FREETYPE_VERSION) >= + version.parse("2.10.0") else "Release" ) cc.spawn(["msbuild", str(sln_path), "/t:Clean;Build", - f"/p:Configuration={msbuild_config};Platform={msbuild_platform}"]) + f"/p:Configuration={msbuild_config};" + f"Platform={msbuild_platform}"]) # Move to the corresponding Unix build path. (src_path / "objs" / ".libs").mkdir() # Be robust against change of FreeType version. @@ -713,7 +715,9 @@ def do_custom_build(self, env): p for p in lib_paths if msbuild_platform in p.resolve().as_uri() ] - print(f"Copying {lib_path} to {src_path}/objs/.libs/libfreetype.lib") + print( + f"Copying {lib_path} to {src_path}/objs/.libs/libfreetype.lib" + ) shutil.copy2(lib_path, src_path / "objs/.libs/libfreetype.lib")