Skip to content

Allow CMake 3.x with zlib 1.3.2#80

Open
TheNicker wants to merge 2 commits into
agruzdev:masterfrom
TheNicker:cmake3
Open

Allow CMake 3.x with zlib 1.3.2#80
TheNicker wants to merge 2 commits into
agruzdev:masterfrom
TheNicker:cmake3

Conversation

@TheNicker
Copy link
Copy Markdown

@TheNicker TheNicker commented May 14, 2026

Summary

Fixes #77.

This PR contains two separate zlib-related fixes.

First, the project currently requires CMake 4.2 because that version's FindZLIB module recognizes zlib 1.3.2's Windows static library names, zs.lib and zsd.lib. That lookup detail is local to the bundled zlib dependency, so this PR keeps the CMake minimum in the 3.x line and passes the exact zlib library path to downstream dependency builds that call find_package(ZLIB).

Second, clean Ninja builds need the installed zlib static library to be declared as an ExternalProject byproduct. This issue is independent of CMake 4.2's ability to find zlib: even when the correct zlib library path is known, Ninja still needs a build rule that says the zlib install step produces that file before FreeImage links against it.

Changes

  • Change the top-level CMake requirement to 3.28...4.2.
  • Keep zlib 1.3.2 and its zs / zsd Windows static library naming.
  • Reuse the known zlib library path from dependency.zlib.cmake.
  • Pass ZLIB_LIBRARY to PNG, TIFF, HEIF, and JPEG XL dependency builds.
  • Declare the installed zlib static library as an ExternalProject INSTALL_BYPRODUCTS output so Ninja can order clean builds correctly.

@agruzdev
Copy link
Copy Markdown
Owner

agruzdev commented May 25, 2026

Hello!

As I remember, I spent some time to make sure that PNG, TIFF and others find correct zlib via default FindZLIB. So these changes are workarounds to make the old FindZLIB work with latest zlib. I hope, I understood correctly.

Could you please clatify why cmake 3.28 is necessary? It's quite an old version.

@TheNicker
Copy link
Copy Markdown
Author

TheNicker commented May 25, 2026

This PR solves two separate CMake/zlib problems:

1. Restores the project to a CMake 3.x minimum

The project was raised to:

cmake_minimum_required(VERSION 4.2)

mainly because CMake 4.2’s FindZLIB recognizes zlib 1.3.2’s Windows static library names, zs.lib and zsd.lib.

This PR changes that to:

cmake_minimum_required(VERSION 3.28...4.2)

Lowering the minimum required CMake version makes the project easier to integrate for a wider range of consumers, especially environments pinned to CMake 3.x by their OS image, CI image, package manager, or
corporate toolchain.

This is a balance between universality and available CMake features. The older the minimum version we can honestly support without compromising the project, the better, because it keeps the project usable in
more environments. In this case, the newer FindZLIB behavior is useful, but not important enough to justify losing compatibility with otherwise capable CMake 3.x environments. Since FreeImageRe builds and
controls its bundled zlib dependency, it can pass the known zlib library path directly instead of requiring every consumer to upgrade to CMake 4.2 just for that lookup behavior.

The 3.28 lower bound is the repo’s current effective lower bound because cmake/external_project_common.cmake already requires CMake 3.28 for FetchContent_Declare(... EXCLUDE_FROM_ALL), which is used by cmake/
dependency.raw.cmake. Even so, CMake 3.28 is already a reasonably conservative minimum today because it is around 2.5 years old.

Ideally, we want the supported CMake range to stay as broad as possible: keep the lower bound as low as the project can honestly support, and keep the upper policy range as high as the project has been checked
against. In this PR, 3.28...4.2 is conservative because 3.28 matches the repo’s current effective minimum and 4.2 matches the CMake version the project already targeted.

Longer term, after this PR lands, the upper policy version should ideally be raised to the latest CMake version after validating the project against it. One practical way to do that is to add a CI job that
installs the latest CMake instead of only ~4.2.0. That would continuously verify that the project still works with current CMake behavior and would catch future pull requests that introduce compatibility
issues with newer CMake versions early.

2. Fixes the zlib Ninja build ordering issue

Without declaring the installed zlib library as an ExternalProject byproduct, Ninja can fail because FreeImage.dll depends on dependencies/zlib/install/lib/zs.lib, but Ninja has no rule saying the zlib install
step produces it.

Example failed workflow/job:
https://github.com/agruzdev/FreeImageRe/actions/runs/26415065354/job/77757650810

This PR fixes that by adding INSTALL_BYPRODUCTS for the platform-specific zlib static library. This should allow the new Ninja-based Windows 2025 / VS 2026 workflow to get past the zlib failure; that workflow
should probably be merged as well and should pass successfully once the remaining same-class ExternalProject byproduct issues are addressed.

It also passes the known ZLIB_LIBRARY path into PNG, TIFF, HEIF, and JPEG XL, so those dependency builds do not rely on newer FindZLIB behavior to find the bundled zlib.

@agruzdev
Copy link
Copy Markdown
Owner

TL;DR

@TheNicker
Copy link
Copy Markdown
Author

@agruzdev
Copy link
Copy Markdown
Owner

agruzdev commented May 25, 2026

I'm not sure, why zs.lib is missing. FreeImage depends on the LibZLIB target, that depends on ZLIB ExternalProject. So build order is correct. I would like to debug it locally on my PC and see why it happens.
And why all other dependecies work without INSTALL_BYPRODUCTS then?

@TheNicker
Copy link
Copy Markdown
Author

Changed ubuntu generator to ninja, same failure: https://github.com/agruzdev/FreeImageRe/actions/runs/26418525102/job/77768083518

Seems like MSBuild uses a higher level project-level dependency management: it builds the whole ZLIB project first, so the installed zlib library already exists by the time FreeImage links.

Ninja uses stricter, explicit file-level dependency management: if FreeImage links against the installed zlib library, Ninja needs a rule that says which build step produces that file, hence INSTALL_BYPRODUCTS

I wonder if it'll happen with more generators 🤔

TheNicker added 2 commits May 29, 2026 20:38
The zlib external project links FreeImage against the installed static library, but Ninja needs that generated file declared on the install step. Record the platform-specific zlib library name and expose it through INSTALL_BYPRODUCTS while still deriving ZLIB_ROOT from the ExternalProject install directory.
@agruzdev
Copy link
Copy Markdown
Owner

I've made draft of ninja generator support ( #85 ), but will need time to test it a bit more

@TheNicker
Copy link
Copy Markdown
Author

TheNicker commented May 31, 2026

#85 seems like a workaround by essentially bypassing Ninja build graph.
Wrong library can be linked if it's in the search path, and I'm not sure relinks would be reliable since Ninja doesn't know that building zs.lib is needed for FreeImageRe.

I believe BUILD_BYPRODUCTS came to solve these scenarios.
Or better yet, to no use external projects - #81 (comment) if possible.

@agruzdev
Copy link
Copy Markdown
Owner

Yeah, I understand that hard to control what actual library is linked, but find_package is used by all dependencies anyway... and this way code is shorter and simpler than with BUILD_BYPRODUCTS.

Yes, still need to solve issue with using external libs...

@TheNicker
Copy link
Copy Markdown
Author

I don't think there's a more correct way to handle this than declaring the installed library as an ExternalProject byproduct. CMake explicitly documents Ninja as needing generated byproducts to be declared, so this is not just a workaround for one generator or an implementation detail.

CMake documents INSTALL_BYPRODUCTS (https://cmake.org/cmake/help/latest/module/ExternalProject.html#install-step-options) as the way to declare files produced by an ExternalProject install step, and says this may be required “to explicitly declare dependencies when using the Ninja generator.” The BYPRODUCTS docs (https://cmake.org/cmake/help/latest/command/add_custom_command.html#command:add_custom_command) explain why: “Ninja requires a build rule for any generated file on which another rule depends.”

If the repeated byproduct declarations feel too verbose, I think the right fix is to wrap that pattern in a small helper. The build graph still needs to describe the real generated files; correctness there is more important than making the dependency declarations shorter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revert the CMake minimum back to 3.x.

2 participants