Repository navigation
Make HelFEM consumable: split the library, install the diatomic headers, namespace the include root - #348
Merged
Conversation
and stop dumping generic names at the include root
Three problems, found by asking what an external project actually sees rather
than by reading CMakeLists: an install tree was built and inventoried, and a
standalone consumer was written against it.
1. THE GATE WAS ALL-OR-NOTHING, AND THE DEPENDENCY IT FORCED WAS FICTITIOUS.
add_subdirectory(src) sat inside if(HELFEM_BINARIES), so obtaining a diatomic
TwoDBasis meant building twelve executables and hard-requiring HDF5 + libxc --
both PUBLIC on helfem-common, hence inherited. The diatomic basis uses
neither. Of ~25 translation units in helfem-common exactly nine touch HDF5 or
libxc (checkpoint, dftfuncs, dftgrid*, atomdb, sadatom/*); none is in the
diatomic path, whose whole closure (gaunt, spherical_harmonics, gsz, timer,
scf_helpers, quadrature) is clean. One library mixing basis machinery with DFT
and checkpointing lets its heaviest member set everyone's requirements.
So: helfem-fem, built unconditionally, carrying the geometry machinery, with
src/ entered always and gating only the HDF5/libxc half. helfem-common keeps
the rest and links helfem-fem rather than duplicating it.
The ATOMIC basis does not join it: general/model_potential.cpp uses libxc's
XC_LDA_X for the SAP potential and atomic/TwoDBasis.h includes it. Making that
optional would let atomic follow; it is noted in src/CMakeLists.txt rather
than quietly shipped as a narrower split than intended.
2. NO DIATOMIC HEADERS WERE INSTALLED.
include/helfem/ shipped atomic/TwoDBasis.h and four general/ headers and
nothing else, so even with HELFEM_BINARIES=ON and helfem-common linked there
was no basis.h to include. The atomic side got this treatment for libatomscf;
diatomic never did. Added, preserving the source layout so the relative
include chain in basis.h resolves unchanged.
3. THE HEADER LAYOUT COULD SHADOW A SYSTEM HEADER.
libhelfem installed 37 headers FLAT into include/ -- among them math.h,
types.h, grid.h -- and handed consumers -I${prefix}/include. Since -I paths
precede system paths, a consumer's #include <math.h> resolved to HelFEM's,
which then includes <types.h> expecting its own. Everything now lands under
include/helfem/, and the 204 include lines that named those headers across 102
files were rewritten to <helfem/X.h>. include/ holds exactly one entry:
helfem/. The bare $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> entry is gone
with it -- it existed so a stale helfem.h at the binary root could be found,
which is the same shadowing in the build tree.
WHAT THE CONSUMER TEST CAUGHT
A standalone project (find_package + helfem::fem + <helfem/diatomic/basis.h>,
with no HelFEM source directory on its include path) turned up three further
packaging faults that reading the CMake would not have:
- helfemConfig.cmake required OpenOrbitalOptimizer unconditionally, though
only helfem-common uses it, so find_package failed outright on a
HELFEM_BINARIES=OFF install.
- helfem_otr was exported unconditionally, leaving
OpenTrustRegion::opentrustregion dangling in that same install.
- the export set would have published helfem::helfem-fem; EXPORT_NAME gives
consumers the helfem::fem the in-tree alias promises, with the archive
still libhelfem-fem.a.
It now builds a diatomic basis and calls coulomb()/exchange() against an
installed HELFEM_BINARIES=OFF tree:
consumer: Nbf=101 |S|=3.40e+03 |H|=3.59e+02 |J|=3.05e+04 |K|=4.34e+03
Nbf=101 is what the in-tree diatomic tests report on the same grid, so the
basis is built rather than trivially empty.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The atomic example next to it shows the radial FEM export; this one shows the other half a consumer needs, and doubles as the regression guard for the packaging. It compiles against an INSTALLED tree only -- no HelFEM source directory on the include path -- which is what makes it a test of the install layout rather than of the build tree, and is why it caught three faults the in-tree build could not see. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
install(EXPORT) refuses a target that appears more than once, and the new
helfem-fem install block listed legendre alongside the existing
helfem-common one:
CMake Error: install(EXPORT "helfemTargets" ...) includes target
"legendre" more than once in the export set.
CMake still writes usable build files after that error, so the build and
the whole test suite ran green on a tree whose configure had exited 1. I
missed it locally by discarding the configure output and separating the
commands with `;` rather than `&&` -- CI caught it as twelve missing
binaries.
Verified with every exit code checked this time: configure and build rc 0
in both HELFEM_BINARIES=ON and OFF, the executables present under
objdir/src, and the installed-tree consumer building and running.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Another project wants HelFEM's diatomic coordinate machinery and its Coulomb/exchange builders. It couldn't have them. This makes that work, and fixes two related problems found along the way.
The findings come from building an install tree and inventorying it, plus writing a standalone consumer against it — not from reading
CMakeLists.txt.1. The gate was all-or-nothing, and the dependency it forced was fictitious
add_subdirectory(src)sat insideif(HELFEM_BINARIES), so obtaining a diatomicTwoDBasismeant building twelve executables and hard-requiring HDF5 + libxc — bothPUBLIConhelfem-common, hence inherited by the consumer.The diatomic basis uses neither. Of ~25 translation units in
helfem-common, exactly nine touch HDF5 or libxc (checkpoint,dftfuncs,dftgrid*,atomdb,sadatom/*). None is in the diatomic path, whose entire closure is clean:One library mixing basis machinery with DFT and checkpointing lets its heaviest member set everyone's requirements.
So:
helfem-fem, built unconditionally, carrying the geometry machinery.src/is entered always and gates only the HDF5/libxc half.helfem-commonkeeps the rest and linkshelfem-femrather than duplicating it.The atomic basis does not join it.
general/model_potential.cppuses libxc'sXC_LDA_Xfor the SAP potential, andatomic/TwoDBasis.hincludes it. Making that optional would let atomic follow; the exclusion and its reason are recorded insrc/CMakeLists.txtrather than the split quietly shipping narrower than described.2. No diatomic headers were installed
include/helfem/shippedatomic/TwoDBasis.hand fourgeneral/headers, nothing else — so even withHELFEM_BINARIES=ONandhelfem-commonlinked, there was nobasis.hto include. The atomic side got this treatment forlibatomscf; diatomic never did. Added, preserving the source layout so the relative-include chain inbasis.hresolves unchanged.3. The header layout could shadow a system header
libhelfeminstalled 37 headers flat intoinclude/— among themmath.h,types.h,grid.h— and handed consumers-I${prefix}/include. Since-Ipaths precede system paths, a consumer's#include <math.h>resolved to HelFEM's, which then includes<types.h>expecting its own.Everything now lands under
include/helfem/, and the 204 include lines naming those headers across 102 files were rewritten to<helfem/X.h>.include/holds exactly one entry:helfem/. The bare$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>entry goes with it — it existed so a stalehelfem.hat the binary root could be found, which is the same shadowing inside the build tree.What the consumer test caught
A standalone project —
find_package+helfem::fem+<helfem/diatomic/basis.h>, with no HelFEM source directory on its include path — turned up three further packaging faults that reading the CMake would not have:helfemConfig.cmakerequiredOpenOrbitalOptimizerunconditionallyfind_package(helfem)failed outright on aHELFEM_BINARIES=OFFinstallhelfem_otrexported unconditionallyOpenTrustRegion::opentrustregionin that same installhelfem::helfem-femEXPORT_NAMEnow gives thehelfem::femthe in-tree alias promises, archive stilllibhelfem-fem.aIt is committed as
examples/diatomic_consumer.cpp, next to the existing atomic example, so the packaging has a regression guard instead of living in a scratch directory.Verification
Nbf=101is what the in-tree diatomic tests report on the same grid, so the basis is genuinely constructed rather than trivially empty. The full suite matters here because the integration cases run real SCF calculations: if any of the 204 rewritten includes had picked up a different header, the energies would have moved.🤖 Generated with Claude Code