Skip to content

Commit 39419e2

Browse files
committed
Add custom dependency mapping for CMake package generation
Introduces the cpp_library_map_dependency() function to allow custom find_dependency() calls for specific targets, such as Qt components requiring COMPONENTS syntax. Updates documentation and dependency generation logic to prioritize custom mappings, improving flexibility for complex dependencies in installed CMake package config files.
1 parent c1bce1c commit 39419e2

File tree

2 files changed

+86
-15
lines changed

2 files changed

+86
-15
lines changed

README.md

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,35 @@ find_dependency(Threads)
156156
include("${CMAKE_CURRENT_LIST_DIR}/my-libTargets.cmake")
157157
```
158158

159-
**Supported dependency patterns:**
159+
**Default dependency handling:**
160160

161-
- **CPM/Internal dependencies** (`namespace::target`): Automatically mapped to their package names (e.g., `stlab::copy-on-write``find_dependency(copy-on-write)`)
162-
- **Threading** (`Threads::Threads`): Generates `find_dependency(Threads)`
163-
- **Qt libraries** (`Qt5::Core`, `Qt6::Widgets`): Generates `find_dependency(Qt5 COMPONENTS Core)` with proper components
164-
- **Generic packages** (`PackageName::Target`): Generates `find_dependency(PackageName)`
161+
- **cpp-library dependencies** (matching your project's `NAMESPACE`): Automatically mapped to their package names (e.g., `stlab::copy-on-write``find_dependency(copy-on-write)`)
162+
- **Other packages**: Uses the package name only by default (e.g., `PackageName::Target``find_dependency(PackageName)`)
163+
164+
**Custom dependency mappings:**
165+
166+
For dependencies that require special `find_dependency()` syntax (e.g., Qt with COMPONENTS), use `cpp_library_map_dependency()` to specify the exact call:
167+
168+
```cmake
169+
# Map Qt components to use COMPONENTS syntax
170+
cpp_library_map_dependency("Qt5::Core" "Qt5 COMPONENTS Core")
171+
cpp_library_map_dependency("Qt5::Widgets" "Qt5 COMPONENTS Widgets")
172+
173+
# Then link as usual
174+
target_link_libraries(my-lib INTERFACE
175+
Qt5::Core
176+
Qt5::Widgets
177+
Threads::Threads # Works automatically, no mapping needed
178+
)
179+
```
180+
181+
The generated config file will use your custom mappings where specified:
182+
183+
```cmake
184+
find_dependency(Qt5 COMPONENTS Core)
185+
find_dependency(Qt5 COMPONENTS Widgets)
186+
find_dependency(Threads) # Automatic from Threads::Threads
187+
```
165188

166189
### Updating cpp-library
167190

@@ -259,6 +282,44 @@ cpp_library_setup(
259282

260283
Results in `namespace-library` and `namespace::library` targets.
261284

285+
### `cpp_library_map_dependency`
286+
287+
```cmake
288+
cpp_library_map_dependency(target find_dependency_call)
289+
```
290+
291+
Registers a custom dependency mapping for `find_dependency()` generation in installed CMake package config files.
292+
293+
**Parameters:**
294+
295+
- `target`: The namespaced target (e.g., `"Qt5::Core"`, `"Threads::Threads"`)
296+
- `find_dependency_call`: The exact arguments to pass to `find_dependency()` (e.g., `"Qt5 COMPONENTS Core"`, `"Threads"`)
297+
298+
**When to use:**
299+
300+
- Dependencies requiring `COMPONENTS` syntax (e.g., Qt)
301+
- Dependencies requiring `OPTIONAL_COMPONENTS` or other special arguments
302+
- Dependencies where the target name pattern doesn't match the desired `find_dependency()` call
303+
304+
**Note:** Most common dependencies like `Threads::Threads`, `Boost::filesystem`, etc. work automatically with the default behavior and don't need mapping.
305+
306+
**Example:**
307+
308+
```cmake
309+
# Register mappings for dependencies needing special syntax
310+
cpp_library_map_dependency("Qt5::Core" "Qt5 COMPONENTS Core")
311+
cpp_library_map_dependency("Qt5::Widgets" "Qt5 COMPONENTS Widgets")
312+
313+
# Then link normally
314+
target_link_libraries(my-target INTERFACE
315+
Qt5::Core
316+
Qt5::Widgets
317+
Threads::Threads # No mapping needed
318+
)
319+
```
320+
321+
See [Dependency Handling in Installed Packages](#dependency-handling-in-installed-packages) for more details.
322+
262323
### Path Conventions
263324

264325
The template uses consistent path conventions for all file specifications:

cmake/cpp-library-install.cmake

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,19 @@
1212
include(GNUInstallDirs)
1313
include(CMakePackageConfigHelpers)
1414

15+
# Registers a custom dependency mapping for find_dependency() generation
16+
# - Precondition: TARGET is a namespaced target (e.g., "Qt5::Core", "Qt5::Widgets")
17+
# - Postcondition: FIND_DEPENDENCY_CALL stored for TARGET, used in package config generation
18+
# - Example: cpp_library_map_dependency("Qt5::Core" "Qt5 COMPONENTS Core")
19+
function(cpp_library_map_dependency TARGET FIND_DEPENDENCY_CALL)
20+
set_property(GLOBAL PROPERTY _CPP_LIBRARY_DEPENDENCY_MAP_${TARGET} "${FIND_DEPENDENCY_CALL}")
21+
endfunction()
22+
1523
# Generates find_dependency() calls for target's INTERFACE link libraries
1624
# - Precondition: TARGET_NAME specifies existing target with INTERFACE_LINK_LIBRARIES
1725
# - Postcondition: OUTPUT_VAR contains newline-separated find_dependency() calls for public dependencies
18-
# - Handles common patterns: namespace::target from CPM, Qt5/Qt6::Component, Threads::Threads, etc.
26+
# - Uses cpp_library_map_dependency() mappings if registered, otherwise uses defaults
27+
# - Automatically handles cpp-library dependencies (matching NAMESPACE)
1928
function(_cpp_library_generate_dependencies OUTPUT_VAR TARGET_NAME NAMESPACE)
2029
get_target_property(LINK_LIBS ${TARGET_NAME} INTERFACE_LINK_LIBRARIES)
2130

@@ -37,17 +46,18 @@ function(_cpp_library_generate_dependencies OUTPUT_VAR TARGET_NAME NAMESPACE)
3746
set(PKG_NAME "${CMAKE_MATCH_1}")
3847
set(COMPONENT "${CMAKE_MATCH_2}")
3948

40-
# Determine find_dependency() call based on package pattern
41-
if(PKG_NAME STREQUAL NAMESPACE)
42-
# Internal dependency: use component as package name (e.g., stlab::copy-on-write → copy-on-write)
49+
# Check for custom mapping first
50+
get_property(CUSTOM_MAPPING GLOBAL PROPERTY _CPP_LIBRARY_DEPENDENCY_MAP_${LIB})
51+
52+
if(CUSTOM_MAPPING)
53+
# Use custom mapping (e.g., "Qt5 COMPONENTS Core" for Qt5::Core)
54+
list(APPEND DEPENDENCY_LIST "find_dependency(${CUSTOM_MAPPING})")
55+
elseif(PKG_NAME STREQUAL NAMESPACE)
56+
# Internal cpp-library dependency: use component as package name
57+
# (e.g., stlab::copy-on-write → find_dependency(copy-on-write))
4358
list(APPEND DEPENDENCY_LIST "find_dependency(${COMPONENT})")
44-
elseif(PKG_NAME STREQUAL "Threads")
45-
list(APPEND DEPENDENCY_LIST "find_dependency(Threads)")
46-
elseif(PKG_NAME MATCHES "^Qt[56]$")
47-
# Qt with component (e.g., Qt5::Core → find_dependency(Qt5 COMPONENTS Core))
48-
list(APPEND DEPENDENCY_LIST "find_dependency(${PKG_NAME} COMPONENTS ${COMPONENT})")
4959
else()
50-
# Generic package (e.g., libdispatch::libdispatch → libdispatch)
60+
# Default: use package name only (e.g., libdispatch::libdispatch → find_dependency(libdispatch))
5161
list(APPEND DEPENDENCY_LIST "find_dependency(${PKG_NAME})")
5262
endif()
5363
endif()

0 commit comments

Comments
 (0)