HDF5 finds the wrong zlib
Describe the bug
HDF5 uses find_package(ZLIB ... COMPONENTS ...) before it falls back to find_package(ZLIB) in CMakeFilters.cmake. The former call scans the system for a CMake config file (due to COMPONENTS). The latter call uses the builtin FindZLIB.cmake module.
Calling find_package twice is problematic because it messes up the search order: if a user configures HDF5 with CMAKE_PREFIX_PATH=/path/to/my/zlib, and this zlib does not have an associated CMake config file, HDF5 will ignore it and pick up a system zlib if it has a config file.
The problem happens for example on Fedora 40 after dnf install zlib-devel, which installs the file
/usr/lib64/cmake/ZLIB/ZLIB.cmake
which is picked up by the first find_package call. The second find_package call which would have found the intended zlib in the higher priority search directory is then ignored.
Expected behavior
As a user, if I pass -DCMAKE_PREFIX_PATH=/path/to/zlib (without cmake config file), HDF5 should use this zlib, not system zlib (with cmake config file).
Further, I would not expect HDF5 to prefer CMake config files at all, given that the promoted build system for zlib is their configure script, which obviously does not create a CMake config file.
I would strongly suggest to use one and only one find_package call, and use ZLIB_USE_STATIC_LIBS introduced in CMake 3.24 instead of rolling your own.
Platform (please complete the following information)
- HDF5 version: any version in the last decade, specifically any after 4d0187a4832a60d56bc077a43855b91b8518271c
- OS and version: any OS that has a system ZLIB.cmake, for example Fedora 40 with
zlib-develinstalled - Build system and version: CMake at any version.
Additional context Add any other context about the problem here.
I would prefer a different solution then this as this is not a guarantee for all the systems we support. CMake has a number of options to find_package:
[NO_DEFAULT_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [NO_CMAKE_PATH] [NO_SYSTEM_ENVIRONMENT_PATH] [NO_CMAKE_PACKAGE_REGISTRY] [NO_CMAKE_BUILDS_PATH] [NO_CMAKE_SYSTEM_PATH] [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY] [CMAKE_FIND_ROOT_PATH_BOTH | ONLY_CMAKE_FIND_ROOT_PATH | NO_CMAKE_FIND_ROOT_PATH])
Furthermore: `The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. This effectively “re-roots” the entire search under given locations. Paths which are descendants of the CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default the CMAKE_FIND_ROOT_PATH is empty.
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Setting CMAKE_SYSROOT also has other effects. See the documentation for that variable for more.
These variables are especially useful when cross-compiling to point to the root directory of the target environment and CMake will search there too. By default at first the directories listed in CMAKE_FIND_ROOT_PATH are searched, then the CMAKE_SYSROOT directory is searched, and then the non-rooted directories will be searched. The default behavior can be adjusted by setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE. This behavior can be manually overridden on a per-call basis. By using CMAKE_FIND_ROOT_PATH_BOTH the search order will be as described above. If NO_CMAKE_FIND_ROOT_PATH is used then CMAKE_FIND_ROOT_PATH will not be used. If ONLY_CMAKE_FIND_ROOT_PATH is used then only the re-rooted directories and directories below CMAKE_STAGING_PREFIX will be searched.`
One of these might be useful
I will be investigating all the issues with the zlib and szip functionality in the HDF5 CMake code. There are a variety of ways to build hdf5 with zlib/szip support and it's time to re-evaluate that code before the end of the year.
Any news?
In my opinion HDF5 should not decide for the user to enforce config mode search for zlib. Just do ordinary find_package. Users can pass -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON. See also #5155 where a user accidentally has a cmake config file for zlib in their search path, but they mean to link to system libz from macOS.
I second @haampie suggestion that since zlib does not ship its config.cmake (Since last week they started to provided a config file https://github.com/madler/zlib/blob/develop/zlibConfig.cmake.in) files there is no need to use the find_package(CONFIG) invocation, in fact as @haampie the basic invocation of find_package will search for the config if the module is not found.
I recommend to specify the locations of the your packages using Package_ROOT which should be understood by your ZLIB_ROOT=zlibinstallationprefix, here is an extract of the cmake findzlib:
Hints
^^^^^
A user may set ``ZLIB_ROOT`` to a zlib installation root to tell this
module where to look.
This will have a greater preference compared to CMAKE_PREFIX_PATH and avoid you to use the system zlib.
#5280 should address these concerns.