Skip to content

Add stable, linkage-agnostic CMake target names - #6600

Open
mattjala wants to merge 6 commits into
HDFGroup:developfrom
mattjala:cmake-public-targets
Open

mattjala wants to merge 6 commits into
HDFGroup:developfrom
mattjala:cmake-public-targets

Conversation

@mattjala

@mattjala mattjala commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

At present, the installed CMake package exports linkage-qualified targets (hdf5-shared, hdf5-static, hdf5_hl-shared). That pushes the implementation details of internal target naming and provided linkage onto consumers in a way we would ideally avoid.

This PR adds a new config/cmake/HDF5PublicTargets.cmake which defines stable names as ALIASes onto the concrete targets:

Target Library
hdf5::hdf5 C
hdf5::hdf5_hl High-level C
hdf5::hdf5_cpp / hdf5::hdf5_hl_cpp C++
hdf5::hdf5_fortran / hdf5::hdf5_hl_fortran Fortran

The find process in CMake then simplifies to:

find_package (HDF5 NAMES hdf5 CONFIG REQUIRED COMPONENTS C)
target_link_libraries (app PRIVATE hdf5::hdf5)

The same module now has identical names across the HDF5 build tree, add_subdirectory embeddings, and find_package() installations.

The linkage type is decided while resolving the package, by (in order of precedence):

  1. explicit static/shared component
  2. HDF5_USE_STATIC_LIBRARIES (matching FindHDF5)
  3. shared if available, static otherwise

Requesting both components will give a warning and fall back to the default.

This changeset is purely additive. The old shared/static targets, HDF5_<lang>_<LINKAGE>_LIBRARY variables, and the exported target set are unchanged, and the public names are ALIASes onto the same targets, so a project with both on its link line still gets only one library.

Nothing is deprecated yet, though we may want to do so in the future.

Partially addresses #6580

At present, the installed CMake package exports linkage-qualified targets (`hdf5-shared`,
`hdf5-static`, `hdf5_hl-shared`). That pushes the implementation
details of internal target naming and provided linkage onto consumers
in a way we would ideally avoid.

This PR adds a new  `config/cmake/HDF5PublicTargets.cmake` which defines
stable names as ALIASes onto the concrete targets:

| Target | Library |
| --- | --- |
| `hdf5::hdf5` | C |
| `hdf5::hdf5_hl` | High-level C |
| `hdf5::hdf5_cpp` / `hdf5::hdf5_hl_cpp` | C++ |
| `hdf5::hdf5_fortran` / `hdf5::hdf5_hl_fortran` | Fortran |
| `hdf5::<tool>` | each installed tool, e.g. `hdf5::h5diff` |
| `HDF5::HDF5` | aggregate of the available libraries |

The find process then simplifies to:

```cmake
find_package (HDF5 NAMES hdf5 CONFIG REQUIRED COMPONENTS C)
target_link_libraries (app PRIVATE hdf5::hdf5)
```

The same module now has identical names across the HDF5 build tree, `add_subdirectory` embeddings, and `find_package()` installations.

The linkage type is decided while resolving the package, by (in order of precedence):

1. explicit `static`/`shared` component
2. `HDF5_USE_STATIC_LIBRARIES` (matching `FindHDF5`)
3. shared if available, static otherwise

Requesting both components will give a warning and fall back to the default.

This changeset is purely additive. The old shared/static targets, `HDF5_<lang>_<LINKAGE>_LIBRARY` variables, and the exported target set are
unchanged, and the public names are ALIASes onto the same targets, so a project
with both on its link line still gets only one library.

Nothing is deprecated yet, though we may want to do so in the future.

Partially addresses HDFGroup#6580
@mattjala mattjala added this to the HDF5 2.3.0 milestone Aug 7, 2026
Copilot AI lite review requested due to automatic review settings August 7, 2026 20:15
@mattjala
mattjala requested review from hyoklee and lrknox as code owners August 7, 2026 20:15
@mattjala mattjala added the Component - Documentation Doxygen, markdown, etc. label Aug 7, 2026
@mattjala mattjala added the Component - Build CMake files label Aug 7, 2026
@github-project-automation github-project-automation Bot moved this to To be triaged in HDF5 - TRIAGE & TRACK Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Checklist

This PR touches the following areas. Each needs a sign-off
from its listed owners before merging.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes HDF5’s installed (and build-tree) CMake package interface by introducing stable, linkage-agnostic namespaced targets (e.g., hdf5::hdf5) that alias onto the existing linkage-qualified targets, so downstream consumers no longer need to encode static/shared in their link logic.

Changes:

  • Add config/cmake/HDF5PublicTargets.cmake implementing stable public targets (hdf5::…), tool targets (hdf5::<tool>), and an aggregate HDF5::HDF5.
  • Update hdf5-config.cmake.in and build-tree CMake to define these public targets consistently across install, build tree, and add_subdirectory() use.
  • Update docs/examples/changelog to recommend linking via hdf5::… targets and describe linkage selection rules.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
release_docs/CHANGELOG.md Documents the new stable public CMake targets and linkage resolution behavior.
HDF5Examples/config/cmake/HDFExampleMacros.cmake Prefer hdf5::hdf5 when available when configuring examples against external HDF5.
docs/USING_HDF5_CMake.md Updates guidance to link via hdf5::hdf5 and explains public targets + linkage selection.
config/install/hdf5-config.cmake.in Includes the new public-target module and selects linkage to bind public aliases.
config/cmake/HDF5PublicTargets.cmake New module defining the stable public aliases and aggregate target.
CMakeLists.txt Defines public aliases in the build tree (and for add_subdirectory() consumers).
CMakeInstallation.cmake Ships the new module in build/install trees alongside the generated config package.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread config/cmake/HDF5PublicTargets.cmake Outdated
Comment thread config/cmake/HDF5PublicTargets.cmake
@lrknox
lrknox removed the request for review from hyoklee August 7, 2026 20:31
@github-actions
github-actions Bot requested review from lrknox and removed request for lrknox August 7, 2026 20:44
@jhendersonHDF

Copy link
Copy Markdown
Collaborator

This is unfortunately something I also happened to be working on at the time, but let me at least list a few things that I've had to think about while moving in this direction:

  • The final target names need better integration with HDF_PACKAGE_NAMESPACE rather than being hard-coded with a namespace of hdf5::. The current situation is that a typical source build of HDF5 will result in hdf5-shared, hdf5-static, etc., in which case the single target name would be hdf5. However, if one builds in a way that uses cacheinit.cmake (which sets HDF_PACKAGE_NAMESPACE to hdf5::), the target names are hdf5::hdf5-shared, hdf5::hdf5-static, etc., in which case hdf5::hdf5 would make sense. You can see this in the .cmake files in the release binary assets, for example. I assume the purpose of HDF_PACKAGE_NAMESPACE is to allow upstream consumers of HDF5 to build it as part of their process, while choosing a final target name such as myproject::hdf5-shared (or myproject::hdf5 with these changes). To be resolved is whether it makes sense for source builds of HDF5 to have hdf5:: as the default namespace for the targets and whether that being missing from the target names was an oversight.
  • When no COMPONENTS part is specified for find_package(), the current logic in hdf5-config.cmake prefers static over shared, which is the opposite of the logic used in this PR. Personally, I have a preference toward shared -> static due to the issues that static linkage causes for plugins, but the difference between the two still needs to be resolved here and switching the order would need to be a documented change if we go that way.
  • Information about deprecations should be made immediately, but CMake makes this difficult to do in a programmatic way. A deprecation message could be set on the old targets, but since the new ALIAS targets resolve to the old targets, upstream projects would get a deprecation warning regardless of which one they linked against. This means even going with the flipped approach in the future (make hdf5::hdf5 the main library target and make hdf5-shared/hdf5-static an ALIAS for compatibility until they are removed) won't work. Also, until very recently, no properties could be set on ALIAS targets. See the discussions on https://gitlab.kitware.com/cmake/cmake/-/work_items/17824 and https://gitlab.kitware.com/cmake/cmake/-/work_items/19445.
  • This will probably need some testing to make sure the behavior between our configuration file and the FindHDF5 module is consistent. That's definitely a common pain point when it comes to calling find_package(HDF5) and not knowing how HDF5 was built and installed.

@Growl1234

Growl1234 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

I'm not quite sure if we really need to introduce additional workflow to handle this. Ideally the implementation should be clean, and I don't think the targets like hdf5::hdf5 should be designed as an alias of targets hdf5-shared etc (there should not have been hdf5-shared and hdf5-static targets from the first time). That said, correct me if I missed something.

@Growl1234

Growl1234 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

The final target names need better integration with HDF_PACKAGE_NAMESPACE rather than being hard-coded with a namespace of hdf5::.

Personally I would say let's use the hdf5:: namespace and revise HDF_PACKAGE_NAMESPACE from HDF5 side. That said, I wonder if there are really two slightly different contracts here.

For an installed HDF5 package consumed through find_package(hdf5 CONFIG), I think having a stable canonical interface such as hdf5::hdf5 is important; otherwise the public target name depends on how HDF5 itself happened to be configured. It would also make the Config package inconsistent with FindHDF5, which already exposes hdf5::hdf5, hdf5::hdf5_fortran, etc.

On the other hand, for HDF5 embedded through add_subdirectory() / HDF5_EXTERNALLY_CONFIGURED, allowing a parent project to select something such as myproject::hdf5 might make sense. So perhaps HDF_PACKAGE_NAMESPACE should remain relevant to that integration/internal export interface, while the installed standalone package exposes stable canonical HDF5 targets. I don't think we necessarily need to change all of the internal/source-build target naming just to establish the installed public API.

@github-actions
github-actions Bot removed the request for review from gheber August 10, 2026 15:28
@github-actions
github-actions Bot removed the request for review from jhendersonHDF August 10, 2026 15:28
@mattjala

Copy link
Copy Markdown
Contributor Author

I've looked into it, and I'm leaning towards deprecating or removing HDF_PACKAGE_NAMESPACE.

From what I can tell, it's not common convention to expose project-level CMake namespacing decisions like this to consumers at all. Other C libraries that use CMake (SDL3, zstd, json-c, netCDF-C, curl) all hardcode their namespace.

I went looking for anyone actually using HDF_PACKAGE_NAMESPACE, and most of the results are forks or vendored copies of HDF5. Excluding those, there are two external consumers, and both set it to hdf5:: anyway:

  • vcpkg passes -DHDF_PACKAGE_NAMESPACE:STRING=hdf5::
  • cbflib sets it to hdf5:: while embedding with HDF5_EXTERNALLY_CONFIGURED ON

VTK doesn't use the variable at all despite being the kind of consumer it seems to have been designed for. When VTK builds against an external HDF5 it just consumes hdf5::hdf5 and hdf5::hdf5_hl from FindHDF5. When it vendors HDF5, it sets HDF5_EXTERNALLY_CONFIGURED and renames the whole thing into its own namespace as VTK::hdf5 / vtkhdf5 via vtk.module. The namespace prefix wouldn't have even helped them, because their goal in doing the renaming seems to be keeping their embedded copy from colliding with any other HDF5 in the same build or process. HDF_PACKAGE_NAMESPACE also leaves the installed library as libhdf5.so, so it would still collide on disk with a system HDF5, and it does nothing about the C symbols.

(Notably, the renaming contract that VTK needs is already handled by other variables. CMakeLists.txt:153-162 documents am embedding case with Paraview using HDF5_EXTERNALLY_CONFIGURED and HDF5_EXTERNAL_LIB_PREFIX, with no use of HDF_PACKAGE_NAMESPACE.)

I think we should keep the exported linkage-qualified target names for now, deprecate and eventually remove HDF_PACKAGE_NAMESPACE, and have the hdf5:: namespace be the standard going forward.

@jhendersonHDF

jhendersonHDF commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Attempting to collect thoughts together into a single reply (apologies for the length and intermixing of text).

I'm not quite sure if we really need to introduce additional workflow to handle this. Ideally the implementation should be clean, and I don't think the targets like hdf5::hdf5 should be designed as an alias of targets hdf5-shared etc (there should not have been hdf5-shared and hdf5-static targets from the first time). That said, correct me if I missed something.

This would generally be ideal yes, but would also involve changes that I wouldn't necessarily be comfortable with in a minor release of HDF5. Using aliases for now is a relatively small change that slowly moves toward removing the old names. Interestingly, the targets used to be hdf5, hdf5_tools, etc. around the time that CMake support was first added to HDF5, but that appears to have changed over time.

Personally I would say let's use the hdf5:: namespace and revise HDF_PACKAGE_NAMESPACE from HDF5 side. That said, I wonder if there are really two slightly different contracts here.

For an installed HDF5 package consumed through find_package(hdf5 CONFIG), I think having a stable canonical interface such as hdf5::hdf5 is important; otherwise the public target name depends on how HDF5 itself happened to be configured. It would also make the Config package inconsistent with FindHDF5, which already exposes hdf5::hdf5, hdf5::hdf5_fortran, etc.

To be clear on this point, I do believe that a stable namespace should be used on the installed targets going forward. It's likely that hdf5:: will be used (as in this PR), but I want to be a bit pedantic here and steer away from thinking too much about being compatible with the FindHDF5 module. While it's a nice convenience, the FindHDF5 module already defers to HDF5's configuration file if it can find one and there are still going to be some compatibility issues for a while after these changes are released. There are essentially three find_package() cases here:

  • An HDF5 1.14.6 or earlier installation is found:
    • The main target name could be hdf5::hdf5 (if HDF5 was built with Autotools), hdf5-shared (if HDF5 was built from source using CMake in a default way) or hdf5::hdf5-shared (if using an HDF5 binary or HDF5 was built from source using CMake in a way that adds in the namespace)
  • An HDF5 2.0.0 - 2.2.X installation is found:
    • Since Autotools support was dropped, the main target name could be hdf5-shared (if HDF5 was built from source using CMake in a default way) or hdf5::hdf5-shared (if using an HDF5 binary or HDF5 was built from source using CMake in a way that adds in the namespace)
  • An HDF5 2.3.0+ installation is found (with these changes):
    • The main target name should just be hdf5::hdf5 (or whatever is settled on)

So unless a package specifically requests version 2.3.0 or newer when calling find_package(), there is still some compatibility logic needed to select the right CMake target to use. And if version 2.3.0 or newer is requested, a CMake project should only be concerned about the target names that HDF5's configuration file provides, since the FindHDF5 module should be deferring to that anyway (though I believe I've seen some cases where this seems to be buggy).

On the other hand, for HDF5 embedded through add_subdirectory() / HDF5_EXTERNALLY_CONFIGURED, allowing a parent project to select something such as myproject::hdf5 might make sense. So perhaps HDF_PACKAGE_NAMESPACE should remain relevant to that integration/internal export interface, while the installed standalone package exposes stable canonical HDF5 targets. I don't think we necessarily need to change all of the internal/source-build target naming just to establish the installed public API.

This is what I see as being the intent behind HDF_PACKAGE_NAMESPACE. For those building HDF5 with FetchContent and similar, having a cache variable for the namespace just makes it easier to change that as desired. However, I think changing the target namespace could apply to both the build tree targets and installed targets, depending on the exact use case.

From what I can tell, it's not common convention to expose project-level CMake namespacing decisions like this to consumers at all. Other C libraries that use CMake (SDL3, zstd, json-c, netCDF-C, curl) all hardcode their namespace.

Notably, this is not true for libcurl (though for reasons unrelated to this discussion); I didn't look too much into other projects.

VTK doesn't use the variable at all despite being the kind of consumer it seems to have been designed for. When VTK builds against an external HDF5 it just consumes hdf5::hdf5 and hdf5::hdf5_hl from FindHDF5. When it vendors HDF5, it sets HDF5_EXTERNALLY_CONFIGURED and renames the whole thing into its own namespace as VTK::hdf5 / vtkhdf5 via vtk.module. The namespace prefix wouldn't have even helped them, because their goal in doing the renaming seems to be keeping their embedded copy from colliding with any other HDF5 in the same build or process.

I'm not sure if VTK is a great example here, as it uses a fairly heavily modified fork of HDF5 (https://gitlab.kitware.com/third-party/hdf5/-/tree/for/vtk-20260701-2.1.1) when building, likely because the current build process of the library doesn't give them enough flexibility to build the way they want. This includes substantially reworking the build of HDF5 and namespacing the resulting targets into their own VTK:: namespace, mangling the symbol names, etc. The complexity of that process may be a bit deceptive about why HDF_PACKAGE_NAMESPACE isn't used.

HDF_PACKAGE_NAMESPACE also leaves the installed library as libhdf5.so, so it would still collide on disk with a system HDF5, and it does nothing about the C symbols.

This is mostly irrelevant, as the implicit assumption is that a project would use HDF_PACKAGE_NAMESPACE in conjunction with HDF5_EXTERNAL_LIB_PREFIX/SUFFIX if the installed library names need to be differentiated.

Comment thread config/cmake/HDF5PublicTargets.cmake Outdated
@mattjala
mattjala force-pushed the cmake-public-targets branch from 6496118 to dca2be7 Compare August 13, 2026 14:26
@github-actions github-actions Bot added the stale label Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has had no activity for 30 days and has been marked stale. Push a commit or comment to keep it open, or it will be flagged for maintainer review.

Comment thread release_docs/CHANGELOG.md

### Added stable, linkage-agnostic CMake target names to the installed package

Downstream projects can now link `hdf5::hdf5`, `hdf5::hdf5_hl`, `hdf5::hdf5_cpp`, `hdf5::hdf5_hl_cpp`, `hdf5::hdf5_fortran` and `hdf5::hdf5_hl_fortran` instead of the linkage-qualified `hdf5-shared` and `hdf5-static` targets, along with an `HDF5::HDF5` aggregate and `hdf5::<tool>` for each installed tool. The names do not encode whether the library is static or shared, so the same project file works against a static installation, a shared one, or one providing both. These are the names CMake's own `FindHDF5` module provides, so a project using them no longer needs different code depending on whether HDF5 was located through `FindHDF5` or through HDF5's `hdf5-config.cmake`, and they are defined identically when HDF5 is built as a subproject with `add_subdirectory()`. Which linkage the targets refer to is chosen while resolving the package: by a `static` or `shared` component, by `HDF5_USE_STATIC_LIBRARIES`, or by default shared-if-available and static otherwise, which is the same order the rest of the package resolution now follows (see Breaking Changes). The existing `hdf5-shared` / `hdf5-static` targets and the `HDF5_<lang>_<LINKAGE>_LIBRARY` variables are otherwise unchanged, and the public names are aliases onto those same targets, so a project naming both on its link line still gets a single library.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"both" refers to old/existing targets and new new hdf5:: targets?

@github-actions github-actions Bot removed the stale label Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component - Build CMake files Component - Documentation Doxygen, markdown, etc.

Projects

Status: To be triaged

Development

Successfully merging this pull request may close these issues.

5 participants