Skip to content

Commit 40f1197

Browse files
committed
Refactor CMake dependency provider to preserve CONFIG flag and handle OPTIONAL_COMPONENTS
- Updated the _cpp_library_track_find_package function to ensure the CONFIG flag is preserved when merging calls without COMPONENTS. - Enhanced handling of OPTIONAL_COMPONENTS to avoid duplication and ensure they are correctly merged from both old and new calls. - Added tests to verify the preservation of the CONFIG flag and the correct merging of dependencies. These changes improve the reliability and correctness of the CMake dependency management for the cpp-library.
1 parent 89eeddd commit 40f1197

3 files changed

Lines changed: 99 additions & 41 deletions

File tree

cmake/cpp-library-dependency-provider.cmake

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,36 @@ function(_cpp_library_track_find_package package_name)
126126
list(JOIN MERGED_COMPONENTS " " MERGED_COMPONENTS_STR)
127127
string(APPEND FIND_DEP_CALL " COMPONENTS ${MERGED_COMPONENTS_STR}")
128128

129-
# Add OPTIONAL_COMPONENTS if present in either old or new
130-
set(OPT_COMPONENTS ${FP_OPTIONAL_COMPONENTS})
131-
if(EXISTING_CALL MATCHES "OPTIONAL_COMPONENTS +([^ ]+( +[^ ]+)*)")
132-
string(REGEX REPLACE " +" ";" EXISTING_OPT "${CMAKE_MATCH_1}")
133-
foreach(comp IN LISTS EXISTING_OPT)
134-
if(NOT comp IN_LIST OPT_COMPONENTS)
135-
list(APPEND OPT_COMPONENTS "${comp}")
136-
endif()
137-
endforeach()
138-
endif()
139-
if(OPT_COMPONENTS)
140-
list(JOIN OPT_COMPONENTS " " OPT_COMPONENTS_STR)
141-
string(APPEND FIND_DEP_CALL " OPTIONAL_COMPONENTS ${OPT_COMPONENTS_STR}")
142-
endif()
143-
144-
# Preserve CONFIG flag if present in either
145-
if(EXISTING_CALL MATCHES "CONFIG" OR FP_CONFIG OR FP_NO_MODULE)
146-
if(NOT FIND_DEP_CALL MATCHES "CONFIG")
147-
string(APPEND FIND_DEP_CALL " CONFIG")
129+
message(DEBUG "cpp-library: Merged find_package(${package_name}) components: ${MERGED_COMPONENTS_STR}")
130+
endif()
131+
132+
# Preserve OPTIONAL_COMPONENTS if present in either old or new
133+
# This must be done outside the MERGED_COMPONENTS block to handle cases
134+
# where there are no regular COMPONENTS but OPTIONAL_COMPONENTS exist
135+
set(OPT_COMPONENTS ${FP_OPTIONAL_COMPONENTS})
136+
if(EXISTING_CALL MATCHES "OPTIONAL_COMPONENTS +([^ ]+( +[^ ]+)*)")
137+
string(REGEX REPLACE " +" ";" EXISTING_OPT "${CMAKE_MATCH_1}")
138+
foreach(comp IN LISTS EXISTING_OPT)
139+
if(NOT comp IN_LIST OPT_COMPONENTS)
140+
list(APPEND OPT_COMPONENTS "${comp}")
148141
endif()
149-
endif()
142+
endforeach()
143+
endif()
144+
if(OPT_COMPONENTS)
145+
# Remove existing OPTIONAL_COMPONENTS to avoid duplication
146+
string(REGEX REPLACE " OPTIONAL_COMPONENTS.*$" "" FIND_DEP_CALL "${FIND_DEP_CALL}")
147+
list(JOIN OPT_COMPONENTS " " OPT_COMPONENTS_STR)
148+
string(APPEND FIND_DEP_CALL " OPTIONAL_COMPONENTS ${OPT_COMPONENTS_STR}")
150149
endif()
151150

152-
message(DEBUG "cpp-library: Merged find_package(${package_name}) components: ${MERGED_COMPONENTS_STR}")
151+
# Preserve CONFIG flag if present in either old or new call
152+
# This must be done outside the MERGED_COMPONENTS block to handle cases
153+
# where neither call has COMPONENTS but one has CONFIG
154+
if(EXISTING_CALL MATCHES "CONFIG" OR FP_CONFIG OR FP_NO_MODULE)
155+
if(NOT FIND_DEP_CALL MATCHES "CONFIG")
156+
string(APPEND FIND_DEP_CALL " CONFIG")
157+
endif()
158+
endif()
153159
endif()
154160

155161
# Store the dependency information globally

tests/install/test_dependency_provider.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,15 @@ mock_target_links(test28_target "Qt6::Core" "Qt6::Widgets")
119119
_cpp_library_generate_dependencies(RESULT test28_target "mylib")
120120
verify_output("${RESULT}" "find_dependency(Qt6 6.5.0 COMPONENTS Core Widgets)" "Test 28")
121121

122+
# Test 29: CONFIG flag preserved when neither call has COMPONENTS (bug fix verification)
123+
run_test("CONFIG preserved without components - first call has CONFIG")
124+
# Simulate what the provider would track after merging two calls:
125+
# First: find_package(MyPkg 1.0 CONFIG), Second: find_package(MyPkg 1.0)
126+
# The fix ensures CONFIG is preserved even without COMPONENTS
127+
set_property(GLOBAL PROPERTY "_CPP_LIBRARY_TRACKED_DEP_MyPkg" "MyPkg 1.0.0 CONFIG")
128+
set_property(GLOBAL APPEND PROPERTY _CPP_LIBRARY_ALL_TRACKED_DEPS "MyPkg")
129+
set_property(GLOBAL PROPERTY _CPP_LIBRARY_PROVIDER_INSTALLED TRUE)
130+
mock_target_links(test29_target "MyPkg::MyPkg")
131+
_cpp_library_generate_dependencies(RESULT test29_target "mylib")
132+
verify_output("${RESULT}" "find_dependency(MyPkg 1.0.0 CONFIG)" "Test 29")
133+

tests/install/test_provider_merge.cmake

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,33 @@ function(_cpp_library_track_find_package package_name)
7777
set(FIND_DEP_CALL "${BASE_CALL}")
7878
list(JOIN MERGED_COMPONENTS " " MERGED_COMPONENTS_STR)
7979
string(APPEND FIND_DEP_CALL " COMPONENTS ${MERGED_COMPONENTS_STR}")
80-
81-
# Add OPTIONAL_COMPONENTS if present in either old or new
82-
set(OPT_COMPONENTS ${FP_OPTIONAL_COMPONENTS})
83-
if(EXISTING_CALL MATCHES "OPTIONAL_COMPONENTS +([^ ]+( +[^ ]+)*)")
84-
string(REGEX REPLACE " +" ";" EXISTING_OPT "${CMAKE_MATCH_1}")
85-
foreach(comp IN LISTS EXISTING_OPT)
86-
if(NOT comp IN_LIST OPT_COMPONENTS)
87-
list(APPEND OPT_COMPONENTS "${comp}")
88-
endif()
89-
endforeach()
90-
endif()
91-
if(OPT_COMPONENTS)
92-
list(JOIN OPT_COMPONENTS " " OPT_COMPONENTS_STR)
93-
string(APPEND FIND_DEP_CALL " OPTIONAL_COMPONENTS ${OPT_COMPONENTS_STR}")
94-
endif()
95-
96-
# Preserve CONFIG flag if present in either
97-
if(EXISTING_CALL MATCHES "CONFIG" OR FP_CONFIG OR FP_NO_MODULE)
98-
if(NOT FIND_DEP_CALL MATCHES "CONFIG")
99-
string(APPEND FIND_DEP_CALL " CONFIG")
80+
endif()
81+
82+
# Preserve OPTIONAL_COMPONENTS if present in either old or new
83+
# This must be done outside the MERGED_COMPONENTS block to handle cases
84+
# where there are no regular COMPONENTS but OPTIONAL_COMPONENTS exist
85+
set(OPT_COMPONENTS ${FP_OPTIONAL_COMPONENTS})
86+
if(EXISTING_CALL MATCHES "OPTIONAL_COMPONENTS +([^ ]+( +[^ ]+)*)")
87+
string(REGEX REPLACE " +" ";" EXISTING_OPT "${CMAKE_MATCH_1}")
88+
foreach(comp IN LISTS EXISTING_OPT)
89+
if(NOT comp IN_LIST OPT_COMPONENTS)
90+
list(APPEND OPT_COMPONENTS "${comp}")
10091
endif()
92+
endforeach()
93+
endif()
94+
if(OPT_COMPONENTS)
95+
# Remove existing OPTIONAL_COMPONENTS to avoid duplication
96+
string(REGEX REPLACE " OPTIONAL_COMPONENTS.*$" "" FIND_DEP_CALL "${FIND_DEP_CALL}")
97+
list(JOIN OPT_COMPONENTS " " OPT_COMPONENTS_STR)
98+
string(APPEND FIND_DEP_CALL " OPTIONAL_COMPONENTS ${OPT_COMPONENTS_STR}")
99+
endif()
100+
101+
# Preserve CONFIG flag if present in either old or new call
102+
# This must be done outside the MERGED_COMPONENTS block to handle cases
103+
# where neither call has COMPONENTS but one has CONFIG
104+
if(EXISTING_CALL MATCHES "CONFIG" OR FP_CONFIG OR FP_NO_MODULE)
105+
if(NOT FIND_DEP_CALL MATCHES "CONFIG")
106+
string(APPEND FIND_DEP_CALL " CONFIG")
101107
endif()
102108
endif()
103109
endif()
@@ -175,6 +181,40 @@ else()
175181
message(FATAL_ERROR "✗ FAIL: Expected '${EXPECTED3}' but got '${DEDUP_CALL}'")
176182
endif()
177183

184+
# Test: CONFIG flag preserved when neither call has COMPONENTS
185+
message(STATUS "")
186+
message(STATUS "Test: CONFIG preserved when neither call has COMPONENTS")
187+
188+
# Clear state
189+
set_property(GLOBAL PROPERTY "_CPP_LIBRARY_TRACKED_DEP_MyPackage")
190+
set_property(GLOBAL PROPERTY _CPP_LIBRARY_ALL_TRACKED_DEPS "")
191+
192+
# First call: find_package(MyPackage 1.0 CONFIG)
193+
_cpp_library_track_find_package("MyPackage" "1.0" "CONFIG")
194+
195+
get_property(CONFIG_FIRST GLOBAL PROPERTY "_CPP_LIBRARY_TRACKED_DEP_MyPackage")
196+
message(STATUS "After first call: ${CONFIG_FIRST}")
197+
198+
# Verify CONFIG was stored
199+
set(EXPECTED_CONFIG1 "MyPackage 1.0 CONFIG")
200+
if(NOT "${CONFIG_FIRST}" STREQUAL "${EXPECTED_CONFIG1}")
201+
message(FATAL_ERROR "✗ FAIL: Expected '${EXPECTED_CONFIG1}' but got '${CONFIG_FIRST}'")
202+
endif()
203+
204+
# Second call: find_package(MyPackage 1.0) - no CONFIG flag
205+
_cpp_library_track_find_package("MyPackage" "1.0")
206+
207+
get_property(CONFIG_MERGED GLOBAL PROPERTY "_CPP_LIBRARY_TRACKED_DEP_MyPackage")
208+
message(STATUS "After second call: ${CONFIG_MERGED}")
209+
210+
# Verify CONFIG was preserved (this was the bug - it would be lost)
211+
set(EXPECTED_CONFIG2 "MyPackage 1.0 CONFIG")
212+
if("${CONFIG_MERGED}" STREQUAL "${EXPECTED_CONFIG2}")
213+
message(STATUS "✓ PASS: CONFIG flag preserved without components")
214+
else()
215+
message(FATAL_ERROR "✗ FAIL: Expected '${EXPECTED_CONFIG2}' but got '${CONFIG_MERGED}'")
216+
endif()
217+
178218
message(STATUS "")
179219
message(STATUS "===========================================")
180220
message(STATUS "All provider merging tests passed!")

0 commit comments

Comments
 (0)