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

Enable libtiff Win32 I/O correctly #5243

Closed
wants to merge 2 commits into from

Conversation

kmilos
Copy link
Contributor

@kmilos kmilos commented Feb 2, 2021

Fixes #4237 (for Pillow static builds and wheels)

NB: Requires all downstream projects to synchronize and rebuild.

This is a follow-up to #4890

Changes proposed in this pull request:

  • Default to USE_WIN32_FILEIO for internal NMake builds (now in sync w/ Cmake and autotools; see upstream report comment)
  • Append USE_WIN32_FILEIO for all Windows builds, not just MinGW

@kmilos
Copy link
Contributor Author

kmilos commented Feb 2, 2021

I presume this fails because libtiff itself is not built as part of CI?

@hugovk
Copy link
Member

hugovk commented Feb 2, 2021

Built for Windows:

- name: Build dependencies / LibTiff
if: steps.build-cache.outputs.cache-hit != 'true'
run: "& winbuild\\build\\build_dep_libtiff.cmd"

Except installed by pacman for Windows / MSYS MinGW:

${{ matrix.package }}-libtiff \

@nulano
Copy link
Contributor

nulano commented Feb 2, 2021

LibTIFF was not rebuilt due to the build cache - the tiff.opt file is not part of the cache key, as I assumed any changes there would be in parallel with updating build_prepare.py (changing libtiff versions) or at least .github/workflows/test-windows.yml (e.g. changing the VS version). If you update either of those files the CI should re-run.

xref actions/cache#2

@nulano
Copy link
Contributor

nulano commented Feb 2, 2021

For reference, looks like this is related to conda-forge/poppler-feedstock#73 (comment), conda-forge/libtiff-feedstock#62.

@kmilos
Copy link
Contributor Author

kmilos commented Feb 2, 2021

Correct, trying to figure out what is a consistent way of building libtiff and Pillow on Windows across the board...

OTOH, @cgohlke imagecodecs seems to assume Unix I/O always (ctypedef void* thandle_t), so this PR might actually hurt? (This should already be a problem on MinGW...)

@nulano
Copy link
Contributor

nulano commented Feb 2, 2021

OTOH, @cgohlke imagecodecs seems to assume Unix I/O always (ctypedef void* thandle_t), so this PR might actually hurt? (This should already be a problem on MinGW...)

Windows guarantees sizeof(HFILE)==sizeof(DECLARE_HANDLE(...))==sizeof(void*) so that by itself is not a problem. The problematic function is actually TIFFFdOpen which takes an int with unix I/O, but HFILE with win32 I/O. However, using this function requires obtaining a raw file handle in Python code, so it might not actually be commonly used. I would expect TIFFOpen, which just takes a filename, is used a lot more often.

@kmilos
Copy link
Contributor Author

kmilos commented Feb 2, 2021

AFAICT we don't have HFILE in this case but the DECLARE_HANDLE(thandle_t) macro.

imagecodecs indeed actually uses only TIFFClientOpen so I guess that is safe?

@nulano
Copy link
Contributor

nulano commented Feb 2, 2021

AFAICT we don't have HFILE in this case but the DECLARE_HANDLE(thandle_t) macro.

Oh right, but HFILE is defined as DECLARE_HANDLE(HFILE) in the WinAPI headers, so that is also the same size as all other HANDLEs on Windows (although only the bottom 32-bits are in use for compatibility with WoW).

imagecodecs indeed actually uses only TIFFClientOpen so I guess that is safe?

TIFFFdOpen is implemented by calling TIFFClientOpen with a set of windows- or unix-specific callbacks; imagecodecs provides its own callbacks so it is safe to use it with either version.

The imagecodecs.libtiff.TIFFFdOpen function is not in a private module AFAICT, but this is just passing the issue one level deeper and will most-likely require patching a subset of libraries that use it depending on which version of I/O they assume is in use, if there are any such libraries. (the change is #4237 (comment))

@kmilos
Copy link
Contributor Author

kmilos commented Feb 3, 2021

TIFFFdOpen is implemented by calling TIFFClientOpen with a set of windows- or unix-specific callbacks; imagecodecs provides its own callbacks so it is safe to use it with either version.

Got it, thanks.

Back to the CI cache issue - still don't have any clues how to kickstart it and what to change in the yml files, so maintainers please feel free to modify the PR.

@hugovk
Copy link
Member

hugovk commented Feb 3, 2021

Because https://github.com/actions/cache doesn't yet have a way to clear caches, one common workaround is to include a -v1- version number in the cache key, which can be easily changed: actions/cache#2

For example:

https://github.com/hugovk/pypistats/blob/5978cf0f935053cefbd4e84736dfb0438bbe0714/.github/workflows/test.yml#L34-L42

@radarhere radarhere added the TIFF label Feb 4, 2021
@nulano
Copy link
Contributor

nulano commented Feb 7, 2021

It looks like the libtiff maintainers are soon removing have now removed NMake support entirely: https://gitlab.com/libtiff/libtiff/-/merge_requests/223

I have an old work-in-progress branch where I changed the build to use CMake, but didn't proceed due to #4237. Would it be better to switch to always use win32 io or to include the patch from conda in the CMake build?

@kmilos
Copy link
Contributor Author

kmilos commented Feb 7, 2021

Thanks for catching and sharing that.

I'm converting this PR to draft for now, as I guess it'll take some time to converge to the "best" approach.

Here's what I gathered so far:

  • MINGW uses Autotools to build libtiff for ages and Win32 I/O has been a default there like it is in Cmake now, and you @nulano have already patched Pillow to support this^
    • If MINGW ever switches to Cmake, there is no impact on Pillow as things stand
  • vcpkg ports use Cmake and Win32 I/O unless the build is for UWP (Microsoft Store)
  • conda-forge used Cmake for a while, and the Win32 I/O default was only introduced in 4.1 and broke compatibility
    • They have opted to disable it and keep 4.0.x Unix I/O to keep Pillow happy at the time
    • As a consequence poppler also had to be patched, so now they have to maintain at least two patches
    • I guess somebody needs to ping the core team on how they want to proceed
  • So far I only know of Pillow and poppler using TIFFFdOpen directly. poppler assumes Win32 I/O with any Windows build sice 2014

IMHO all Windows libtiff builds should use the default Win32 I/O, which would mean some maintenance work for conda-forge to switch or keep patching. It'd be nice to establish if there are more packages affected other than Pillow and poppler...

Ideally, libtiff should have exposed the USE_WIN32_FILEIO define publicly in tiffconf.h instead of only in the private tif_config.h, so 3rd parties can use this directly and we wouldn't have to worry about maintaining exceptions. I think I'll add this to the bug report over there.

^ Rather than hard-coding this in setup.py, is there a way to pass -DUSE_WIN32_FILEIO externally to setup.py build so any Pillow packager can easily choose without patching? I see passing defines is supported for setup.py build_ext command, but don't know setuptools well enough to know if this applies to the build command as well, I haven't seen it in its options list...

@kmilos kmilos marked this pull request as draft February 7, 2021 19:39
@kmilos
Copy link
Contributor Author

kmilos commented Feb 11, 2021

NMake removal is now merged in libtiff master, so it sounds like Pillow will likely make a switch to CMake anyway, no?

Feel free to hijack this PR for it, or close/reject until such a time comes...

@radarhere
Copy link
Member

I've added an unrelated nasm update, and the change in test-windows.yml updates the cache key, causing the Windows tests to pass.

@kmilos
Copy link
Contributor Author

kmilos commented Mar 24, 2021

Thanks, I'll remove the draft status should you want to take this for the next release.

I guess the cmake switch won't be necessary until the next libtiff version is released, which is usually a while from now...

@kmilos kmilos marked this pull request as ready for review March 24, 2021 16:09
@nulano
Copy link
Contributor

nulano commented Mar 24, 2021

I have an old work-in-progress branch where I changed the build to use CMake,

Rebased in #5359.

@hugovk
Copy link
Member

hugovk commented Apr 1, 2021

#5359 merged instead. Thanks!

@hugovk hugovk closed this Apr 1, 2021
@nulano nulano mentioned this pull request Apr 1, 2021
25 tasks
@kmilos kmilos deleted the win32_io branch May 18, 2021 08:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OSError: -2 when decoding a tiff_lzw file
4 participants