What did you do?
Built Pillow from source on a Linux system where image libraries are available primarily as static archives. In this environment, libtiff.a is available and its pkg-config metadata is provided as libtiff-4.pc. The pkg-config file includes private dependencies needed for static linking, for example zstd/lzma/jpeg/zlib via Libs.private / Requires.private.
A representative static pkg-config result is equivalent to:
pkg-config --libs --static libtiff-4
which includes transitive dependencies such as -lzstd, -llzma, -ljpeg, and -lz.
What did you expect to happen?
When Pillow chooses to build TIFF support against a static libtiff.a, the Pillow extension should also link the static private dependencies reported by pkg-config for libtiff-4.
Alternatively, if those static dependencies cannot be resolved, the build should fail clearly instead of producing an extension with unresolved symbols.
What actually happened?
Pillow built successfully, but importing PIL.Image failed at runtime with an unresolved symbol from one of libtiff's private static dependencies:
ImportError: .../_imaging.cpython-312-...so: undefined symbol: ZSTD_compressStream
Inspection showed TIFF symbols were included in the Pillow imaging extension, but zstd symbols remained unresolved. Rebuilding the same Pillow source with TIFF disabled made the build import cleanly, which points to the static libtiff link path rather than Pillow generally.
What are your OS, Python and Pillow versions?
- OS: custom Linux distribution / source-built userland
- Python: 3.12
- Pillow: 12.2.0
Additional context
This looks like Pillow may be finding/using libtiff.a directly but not using pkg-config --libs --static libtiff-4 or otherwise not honoring the private dependencies from libtiff-4.pc.
The practical workaround was:
python -m pip install /path/to/Pillow-source.tar.gz -C tiff=disable
but that disables TIFF support entirely. Ideally static TIFF support should either link the transitive static dependencies or fail during build with a clear diagnostic.
What did you do?
Built Pillow from source on a Linux system where image libraries are available primarily as static archives. In this environment,
libtiff.ais available and its pkg-config metadata is provided aslibtiff-4.pc. The pkg-config file includes private dependencies needed for static linking, for example zstd/lzma/jpeg/zlib viaLibs.private/Requires.private.A representative static pkg-config result is equivalent to:
which includes transitive dependencies such as
-lzstd,-llzma,-ljpeg, and-lz.What did you expect to happen?
When Pillow chooses to build TIFF support against a static
libtiff.a, the Pillow extension should also link the static private dependencies reported by pkg-config forlibtiff-4.Alternatively, if those static dependencies cannot be resolved, the build should fail clearly instead of producing an extension with unresolved symbols.
What actually happened?
Pillow built successfully, but importing
PIL.Imagefailed at runtime with an unresolved symbol from one of libtiff's private static dependencies:Inspection showed TIFF symbols were included in the Pillow imaging extension, but zstd symbols remained unresolved. Rebuilding the same Pillow source with TIFF disabled made the build import cleanly, which points to the static libtiff link path rather than Pillow generally.
What are your OS, Python and Pillow versions?
Additional context
This looks like Pillow may be finding/using
libtiff.adirectly but not usingpkg-config --libs --static libtiff-4or otherwise not honoring the private dependencies fromlibtiff-4.pc.The practical workaround was:
but that disables TIFF support entirely. Ideally static TIFF support should either link the transitive static dependencies or fail during build with a clear diagnostic.