Skip to content
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

Restored 32-bit support #7234

Merged
merged 3 commits into from Jun 27, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .appveyor.yml
Expand Up @@ -10,8 +10,8 @@ environment:
TEST_OPTIONS:
DEPLOY: YES
matrix:
- PYTHON: C:/Python311-x64
ARCHITECTURE: x64
- PYTHON: C:/Python311
ARCHITECTURE: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
- PYTHON: C:/Python38-x64
ARCHITECTURE: x64
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-docker.yml
Expand Up @@ -39,6 +39,7 @@ jobs:
centos-stream-8-amd64,
centos-stream-9-amd64,
debian-11-bullseye-amd64,
debian-12-bookworm-x86,
debian-12-bookworm-amd64,
fedora-37-amd64,
fedora-38-amd64,
Expand Down
8 changes: 8 additions & 0 deletions Tests/32bit_segfault_check.py
@@ -0,0 +1,8 @@
#!/usr/bin/env python3

import sys

from PIL import Image

if sys.maxsize < 2**32:
im = Image.new("L", (999999, 999999), 0)
5 changes: 5 additions & 0 deletions Tests/check_large_memory.py
@@ -1,3 +1,5 @@
import sys

import pytest

from PIL import Image
Expand All @@ -21,6 +23,9 @@
XDIM = 48000


pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system")


def _write_png(tmp_path, xdim, ydim):
f = str(tmp_path / "temp.png")
im = Image.new("L", (xdim, ydim), 0)
Expand Down
5 changes: 5 additions & 0 deletions Tests/check_large_memory_numpy.py
@@ -1,3 +1,5 @@
import sys

import pytest

from PIL import Image
Expand All @@ -17,6 +19,9 @@
XDIM = 48000


pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system")


def _write_png(tmp_path, xdim, ydim):
dtype = np.uint8
a = np.zeros((xdim, ydim), dtype=dtype)
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_core_resources.py
@@ -1,3 +1,5 @@
import sys

import pytest

from PIL import Image
Expand Down Expand Up @@ -108,6 +110,9 @@ def test_set_blocks_max(self):

with pytest.raises(ValueError):
Image.core.set_blocks_max(-1)
if sys.maxsize < 2**32:
with pytest.raises(ValueError):
Image.core.set_blocks_max(2**29)

@pytest.mark.skipif(is_pypy(), reason="Images not collected")
def test_set_blocks_max_stats(self):
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_file_webp.py
@@ -1,5 +1,6 @@
import io
import re
import sys
import warnings

import pytest
Expand Down Expand Up @@ -144,6 +145,7 @@ def test_write_unsupported_mode_P(self, tmp_path):

self._roundtrip(tmp_path, "P", 50.0)

@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_write_encoding_error_message(self, tmp_path):
temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGB", (15000, 15000))
Expand Down
5 changes: 4 additions & 1 deletion Tests/test_image_putdata.py
Expand Up @@ -38,7 +38,10 @@ def put(value):
assert put(0xFFFFFFFF) == (255, 255, 255, 255)
assert put(-1) == (255, 255, 255, 255)
assert put(-1) == (255, 255, 255, 255)
assert put(sys.maxsize) == (255, 255, 255, 255)
if sys.maxsize > 2**32:
assert put(sys.maxsize) == (255, 255, 255, 255)
else:
assert put(sys.maxsize) == (255, 255, 255, 127)


def test_pypy_performance():
Expand Down
3 changes: 3 additions & 0 deletions Tests/test_map.py
@@ -1,3 +1,5 @@
import sys

import pytest

from PIL import Image
Expand Down Expand Up @@ -34,6 +36,7 @@ def test_tobytes():
Image.MAX_IMAGE_PIXELS = max_pixels


@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_ysize():
numpy = pytest.importorskip("numpy", reason="NumPy not installed")

Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Expand Up @@ -16,6 +16,7 @@ coverage:

# Matches 'omit:' in .coveragerc
ignore:
- "Tests/32bit_segfault_check.py"
- "Tests/bench_cffi_access.py"
- "Tests/check_*.py"
- "Tests/createfontdatachunk.py"
13 changes: 10 additions & 3 deletions docs/installation.rst
Expand Up @@ -285,8 +285,11 @@ Many of Pillow's features require external libraries:

.. tab:: Windows using MSYS2/MinGW

To build Pillow using MSYS2, make sure you run the **MSYS2 MinGW 64-bit** console,
*not* **MSYS2** directly.
To build Pillow using MSYS2, make sure you run the **MSYS2 MinGW 32-bit** or
**MSYS2 MinGW 64-bit** console, *not* **MSYS2** directly.

The following instructions target the 64-bit build, for 32-bit
replace all occurrences of ``mingw-w64-x86_64-`` with ``mingw-w64-i686-``.

Make sure you have Python and GCC installed::

Expand Down Expand Up @@ -336,6 +339,8 @@ Many of Pillow's features require external libraries:
pkg install -y python ndk-sysroot clang make \
libjpeg-turbo

This has been tested within the Termux app on ChromeOS, on x86.

Installing
^^^^^^^^^^

Expand Down Expand Up @@ -448,7 +453,7 @@ These platforms are built and tested for every change.
+----------------------------------+----------------------------+---------------------+
| Debian 11 Bullseye | 3.9 | x86-64 |
+----------------------------------+----------------------------+---------------------+
| Debian 12 Bookworm | 3.11 | x86-64 |
| Debian 12 Bookworm | 3.11 | x86, x86-64 |
+----------------------------------+----------------------------+---------------------+
| Fedora 37 | 3.11 | x86-64 |
+----------------------------------+----------------------------+---------------------+
Expand All @@ -472,6 +477,8 @@ These platforms are built and tested for every change.
| Windows Server 2022 | 3.8, 3.9, 3.10, 3.11, | x86-64 |
| | 3.12, PyPy3 | |
| +----------------------------+---------------------+
| | 3.11 | x86 |
| +----------------------------+---------------------+
| | 3.9 (MinGW) | x86-64 |
| +----------------------------+---------------------+
| | 3.8, 3.9 (Cygwin) | x86-64 |
Expand Down
18 changes: 5 additions & 13 deletions docs/releasenotes/10.0.0.rst
Expand Up @@ -4,11 +4,6 @@
Backwards Incompatible Changes
==============================

32-bit support
^^^^^^^^^^^^^^

32-bit architecture is no longer supported and 32-bit wheels are no longer provided.

Categories
^^^^^^^^^^

Expand Down Expand Up @@ -129,14 +124,6 @@ Image.coerce_e

This undocumented method has been removed.

Deprecations
============

TODO
^^^^

TODO

API Changes
===========

Expand Down Expand Up @@ -165,6 +152,11 @@ TODO
Other Changes
=============

32-bit wheels
^^^^^^^^^^^^^

32-bit wheels are no longer provided.

Support display_jpeg() in IPython
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
20 changes: 13 additions & 7 deletions setup.py
Expand Up @@ -153,13 +153,16 @@ def _find_library_dirs_ldconfig():

ldconfig = "ldconfig" if shutil.which("ldconfig") else "/sbin/ldconfig"
if sys.platform.startswith("linux") or sys.platform.startswith("gnu"):
machine = os.uname()[4]
if struct.calcsize("l") == 4:
machine = os.uname()[4] + "-32"
else:
machine = os.uname()[4] + "-64"
mach_map = {
"x86_64": "libc6,x86-64",
"ppc64": "libc6,64bit",
"sparc64": "libc6,64bit",
"s390x": "libc6,64bit",
"ia64": "libc6,IA-64",
"x86_64-64": "libc6,x86-64",
"ppc64-64": "libc6,64bit",
"sparc64-64": "libc6,64bit",
"s390x-64": "libc6,64bit",
"ia64-64": "libc6,IA-64",
}
abi_type = mach_map.get(machine, "libc6")

Expand Down Expand Up @@ -581,7 +584,10 @@ def build_extensions(self):
# user libs are at $PREFIX/lib
_add_directory(
library_dirs,
os.path.join(os.environ["ANDROID_ROOT"], "lib64"),
os.path.join(
os.environ["ANDROID_ROOT"],
"lib" if struct.calcsize("l") == 4 else "lib64",
),
)

elif sys.platform.startswith("netbsd"):
Expand Down
2 changes: 1 addition & 1 deletion src/libImaging/ImagingUtils.h
Expand Up @@ -30,7 +30,7 @@
/* This is to work around a bug in GCC prior 4.9 in 64 bit mode.
GCC generates code with partial dependency which is 3 times slower.
See: https://stackoverflow.com/a/26588074/253146 */
#if defined(__SSE__) && !defined(__NO_INLINE__) && \
#if defined(__x86_64__) && defined(__SSE__) && !defined(__NO_INLINE__) && \
!defined(__clang__) && defined(GCC_VERSION) && (GCC_VERSION < 40900)
static float __attribute__((always_inline)) inline _i2f(int v) {
float x;
Expand Down
6 changes: 3 additions & 3 deletions winbuild/build.rst
Expand Up @@ -27,7 +27,7 @@ Download and install:
* `Ninja <https://ninja-build.org/>`_
(optional, use ``--nmake`` if not available; bundled in Visual Studio CMake component)

* x64: `Netwide Assembler (NASM) <https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D>`_
* x86/x64: `Netwide Assembler (NASM) <https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D>`_

Any version of Visual Studio 2017 or newer should be supported,
including Visual Studio 2017 Community, or Build Tools for Visual Studio 2019.
Expand All @@ -42,7 +42,7 @@ Run ``build_prepare.py`` to configure the build::

usage: winbuild\build_prepare.py [-h] [-v] [-d PILLOW_BUILD]
[--depends PILLOW_DEPS]
[--architecture {x64,ARM64}]
[--architecture {x86,x64,ARM64}]
[--python PYTHON] [--executable EXECUTABLE]
[--nmake] [--no-imagequant] [--no-fribidi]

Expand All @@ -56,7 +56,7 @@ Run ``build_prepare.py`` to configure the build::
--depends PILLOW_DEPS
directory used to store cached dependencies (default:
'winbuild\depends')
--architecture {x64,ARM64}
--architecture {x86,x64,ARM64}
build architecture (default: same as host Python)
--python PYTHON Python install directory (default: use host Python)
--executable EXECUTABLE
Expand Down
8 changes: 7 additions & 1 deletion winbuild/build_prepare.py
Expand Up @@ -3,6 +3,7 @@
import platform
import re
import shutil
import struct
import subprocess
import sys

Expand Down Expand Up @@ -97,6 +98,7 @@ def cmd_msbuild(
SF_PROJECTS = "https://sourceforge.net/projects"

architectures = {
"x86": {"vcvars_arch": "x86", "msbuild_arch": "Win32"},
"x64": {"vcvars_arch": "x86_amd64", "msbuild_arch": "x64"},
"ARM64": {"vcvars_arch": "x86_arm64", "msbuild_arch": "ARM64"},
}
Expand Down Expand Up @@ -609,7 +611,11 @@ def build_pillow():
choices=architectures,
default=os.environ.get(
"ARCHITECTURE",
"ARM64" if platform.machine() == "ARM64" else "x64",
(
"ARM64"
if platform.machine() == "ARM64"
else ("x86" if struct.calcsize("P") == 4 else "x64")
),
),
help="build architecture (default: same as host Python)",
)
Expand Down