Repository navigation
Don't fetch a dependency another package already provided - #89
Merged
Merged
Conversation
get_dependencies() decided whether a dependency was already resolved by
testing TARGET ${NWX_DEP_TARGET_<name>}, which defaults to the bare dep
name. For third-party packages that name is usually not a target that
exists -- pybind11 defines pybind11::pybind11, Catch2 defines
Catch2::Catch2 (and CMake target names are case-sensitive, so even
"Catch2" would not match "catch2"). The check therefore never fired for
either, which is why every configure logs "Fetching dependency: pybind11"
four or five times.
That was noise, not breakage, while FetchContent_MakeAvailable() was the
only way those packages entered a build: it dedups against its own
earlier population. Declaring real dependencies in the generated
<name>Config.cmake files removed that guarantee. pluginplayConfig.cmake
now calls nwx_config_find_dependency(pybind11), so resolving pluginplay
from its installed wheel find_package()es pybind11 and creates
pybind11::pybind11 et al. as IMPORTED targets. The subsequent
get_dependencies(pybind11) missed them, fell through to
FetchContent_MakeAvailable(), and add_subdirectory()'d pybind11's own
CMakeLists over the top -- which dies re-creating targets that already
exist:
add_library cannot create ALIAS target "pybind11::pybind11_headers"
because another target with the same name already exists
This is the failure on every test_cmake_build leg of NWChemEx/SCF#75,
where the integration-testing step pip installs the published ecosystem
before configuring.
Fixed in two parts. The dep files now name the target they actually
provide via _gd_target_<name>. get_dependencies() re-checks after the
include() -- the earliest point at which that name is known, since the
existing check runs before it and, on a first call, has no cache entry
to consult anyway -- and skips the fetch when the target is already
there.
Verified against the real published wheels (nwchemex-pluginplay 1.0.65,
pybind11 3.1.0) with get_dependencies(pluginplay pybind11): unpatched
fails with exactly the error above, patched logs "pybind11: already
provided (pybind11::pybind11)" and configures clean. Also confirmed the
no-wheel path still fetches both packages normally and that a repeated
get_dependencies(pybind11) short-circuits.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
🚀 [bumpr] Bumped! |
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.
The bug
get_dependencies()decided whether a dependency was already resolved by testingTARGET ${NWX_DEP_TARGET_<name>}, which defaults to the bare dep name. Forthird-party packages that name is usually not a target that exists:
TARGET <bare name>pybind11pybind11::pybind11,pybind11::headers,pybind11_headerscatch2Catch2,Catch2::Catch2(names are case-sensitive)So the short-circuit never fired for either — which is why every configure logs
-- Fetching dependency: pybind11four or five times.That was noise, not breakage, while
FetchContent_MakeAvailable()was the only waythose packages entered a build: it dedups against its own earlier population.
#87/#88 removed that guarantee. Now that the generated
<name>Config.cmakefiles declare their real dependencies,
pluginplayConfig.cmakecallsnwx_config_find_dependency(pybind11)— so resolving pluginplay from its installedwheel
find_package()es pybind11 and createspybind11::pybind11et al. asIMPORTED targets. The subsequent
get_dependencies(pybind11)missed them, fellthrough to
FetchContent_MakeAvailable(), andadd_subdirectory()'d pybind11's ownCMakeLists over the top:
...plus eight more from
pybind11Common.cmake. This is the failure on everytest_cmake_buildleg of NWChemEx/SCF#75, whose integration-testing step pipinstalls the published ecosystem before configuring.
The fix
Two parts:
dependencies/pybind11.cmakeanddependencies/catch2.cmakedeclare the targetthey actually provide via
_gd_target_<name>.get_dependencies()re-checks after theinclude()— the earliest point atwhich that name is known, since the existing check runs before it and, on a first
call, has no cache entry to consult anyway — and skips the fetch when the target
already exists.
Part 2 is load-bearing on its own: with only part 1, the first
get_dependencies(pybind11)in a configure still fetched, because the pre-include()check has nothing to test yet. I verified that intermediate state failed before
adding it.
Catch2 is fixed alongside as the same latent defect. Nothing
find_package()esCatch2 ahead of
get_dependencies()today — it is test-only and so never appears inan installed target's
INTERFACE_LINK_LIBRARIES— so it relies onFetchContent_MakeAvailable()'s dedup exactly the way pybind11 used to.Verification
Against the real published wheels (
nwchemex-pluginplay 1.0.65,pybind11 3.1.0)with
get_dependencies(pluginplay pybind11), which is the SCF path:CMakeLists.txt:280,pybind11Common.cmake:68/75/82/112/121/146), byte-identical to the SCF#75 CI log.-- pybind11: already provided (pybind11::pybind11), configures clean.Also confirmed:
get_dependencies(pybind11)short-circuits via the existing cache check;nwx_ecosystem_dependencyonly sets_gd_target_<name>in its installed-wheel branch, where it already sets_gd_uses_fc FALSE.🤖 Generated with Claude Code