Skip to content

Commit 77e5150

Browse files
authored
Merge pull request #16 from stlab/sean-parent/fixes
Improved install support, including support for BUILD_INTERFACE
2 parents dbb8921 + 2e9b271 commit 77e5150

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ The library will be automatically fetched and built as part of your project.
190190

191191
#### Installation (optional)
192192

193-
Installation is optional and typically not required when using CPM. If you need to install your library (e.g., for system-wide deployment or use with a package manager) use:
193+
Installation is optional and typically not required when using CPM. If you need to install your library (e.g., for system-wide deployment or use with a package manager):
194194

195195
```bash
196196
# Build and install to default system location
@@ -202,8 +202,48 @@ cmake --install build/default
202202
cmake --install build/default --prefix /opt/mylib
203203
```
204204

205+
**Testing your installation:**
206+
207+
Use the `install` preset to verify that installed packages can be found correctly:
208+
209+
```bash
210+
# Build with CPM_USE_LOCAL_PACKAGES to test finding installed dependencies
211+
cmake --preset=install
212+
cmake --build --preset=install
213+
214+
# Install and test
215+
cmake --install build/install --prefix /tmp/test-install
216+
CMAKE_PREFIX_PATH=/tmp/test-install cmake --preset=install
217+
```
218+
219+
The `install` preset enables `CPM_USE_LOCAL_PACKAGES`, which makes CPM call `find_package()` first before fetching. This verifies your generated Config.cmake works correctly.
220+
205221
For information about using installed packages with `find_package()`, see the [CPM.cmake documentation](https://github.com/cpm-cmake/CPM.cmake) about [controlling how dependencies are found](https://github.com/cpm-cmake/CPM.cmake#cpm_use_local_packages).
206222

223+
**Re-exporting dependencies from external packages:**
224+
225+
When your library re-exports dependencies (via `INTERFACE` linkage) that come from CPMAddPackage, you must wrap them in `BUILD_INTERFACE` to avoid CMake export errors:
226+
227+
```cmake
228+
# Correct: Wrap CPM-fetched dependencies in BUILD_INTERFACE
229+
CPMAddPackage("gh:other-org/some-package@1.0.0")
230+
target_link_libraries(my-library INTERFACE $<BUILD_INTERFACE:other::package>)
231+
```
232+
233+
**Why this is needed:** CPMAddPackage creates regular (non-IMPORTED) targets in your build tree. When CMake exports your library, it sees these dependencies but cannot include them in your export set (they belong to a different package). The `BUILD_INTERFACE` wrapper tells CMake:
234+
- Use this dependency during build
235+
- Don't include it in the export
236+
- Let consumers find it themselves via `find_dependency()` in the generated Config.cmake
237+
238+
cpp-library automatically extracts dependencies from `BUILD_INTERFACE` expressions and generates the appropriate `find_dependency()` calls in your package configuration.
239+
240+
**When BUILD_INTERFACE is NOT needed:**
241+
- Dependencies from `find_package()` (already IMPORTED targets)
242+
- System libraries like `Threads::Threads`
243+
- Internal (PRIVATE) dependencies (not applicable to INTERFACE libraries)
244+
245+
This is a standard CMake pattern for re-exporting external package dependencies, not specific to cpp-library.
246+
207247
#### Dependency Handling in Installed Packages
208248

209249
cpp-library automatically generates `find_dependency()` calls in the installed CMake package configuration. Call `cpp_library_enable_dependency_tracking()` before `project()`:
@@ -470,6 +510,8 @@ cpp-library generates a `CMakePresets.json` file with the following configuratio
470510

471511
All presets automatically configure `CPM_SOURCE_CACHE` to `${sourceDir}/.cache/cpm` for faster dependency resolution. You can override this by setting the `CPM_SOURCE_CACHE` environment variable.
472512

513+
**Best Practice:** Set `CPM_SOURCE_CACHE` in presets or via environment variable/command line, not in CMakeLists.txt. Setting it in CMakeLists.txt with `FORCE` can override parent project settings when used as a subdirectory, and prevents users from configuring it themselves.
514+
473515
### Version Management
474516

475517
Version is automatically detected from git tags:

cmake/cpp-library-install.cmake

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,23 @@ function(_cpp_library_generate_dependencies OUTPUT_VAR TARGET_NAME NAMESPACE)
5656

5757
# Process each linked library
5858
foreach(LIB IN LISTS LINK_LIBS)
59-
# Skip generator expressions (typically BUILD_INTERFACE dependencies)
60-
if(LIB MATCHES "^\\$<")
59+
# Handle BUILD_INTERFACE generator expressions
60+
# When re-exporting dependencies from external packages, they must be wrapped in BUILD_INTERFACE
61+
# to avoid CMake export errors, but we still want to track them for find_dependency()
62+
if(LIB MATCHES "^\\$<BUILD_INTERFACE:([^>]+)>$")
63+
set(EXTRACTED_TARGET "${CMAKE_MATCH_1}")
64+
# Only process if it's a namespaced target (external dependency)
65+
# Non-namespaced targets in BUILD_INTERFACE are local build targets
66+
if(EXTRACTED_TARGET MATCHES "::")
67+
set(LIB "${EXTRACTED_TARGET}")
68+
message(DEBUG "cpp-library: Extracted ${LIB} from BUILD_INTERFACE generator expression")
69+
else()
70+
# Skip non-namespaced BUILD_INTERFACE targets (local build targets)
71+
message(DEBUG "cpp-library: Skipping non-namespaced BUILD_INTERFACE target: ${EXTRACTED_TARGET}")
72+
continue()
73+
endif()
74+
elseif(LIB MATCHES "^\\$<")
75+
# Skip other generator expressions (INSTALL_INTERFACE, etc.)
6176
continue()
6277
endif()
6378

templates/.github/workflows/ci.yml.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
runs-on: ${{ matrix.os }}
3535

3636
steps:
37-
- uses: actions/checkout@v5
37+
- uses: actions/checkout@v6
3838

3939
- name: Configure CMake
4040
run: cmake --preset=test

templates/CMakePresets.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,30 @@
7373
"CPP_LIBRARY_FORCE_INIT": "ON",
7474
"CPM_SOURCE_CACHE": "${sourceDir}/.cache/cpm"
7575
}
76+
},
77+
{
78+
"name": "install",
79+
"displayName": "Install Configuration",
80+
"description": "Release build for installation with CPM_USE_LOCAL_PACKAGES enabled for testing installed packages",
81+
"binaryDir": "${sourceDir}/build/install",
82+
"generator": "Ninja",
83+
"cacheVariables": {
84+
"CMAKE_BUILD_TYPE": "Release",
85+
"BUILD_TESTING": "OFF",
86+
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
87+
"CMAKE_CXX_EXTENSIONS": "OFF",
88+
"CPM_USE_LOCAL_PACKAGES": "ON",
89+
"CPM_SOURCE_CACHE": "${sourceDir}/.cache/cpm"
90+
}
7691
}
7792
],
7893
"buildPresets": [
7994
{ "name": "default", "displayName": "Default Build", "configurePreset": "default" },
8095
{ "name": "test", "displayName": "Build Tests", "configurePreset": "test" },
8196
{ "name": "docs", "displayName": "Build Docs", "configurePreset": "docs", "targets": "docs" },
8297
{ "name": "clang-tidy", "displayName": "Build with Clang-Tidy", "configurePreset": "clang-tidy" },
83-
{ "name": "init", "displayName": "Initialize Templates", "configurePreset": "init" }
98+
{ "name": "init", "displayName": "Initialize Templates", "configurePreset": "init" },
99+
{ "name": "install", "displayName": "Build for Installation", "configurePreset": "install" }
84100
],
85101
"testPresets": [
86102
{ "name": "test", "displayName": "Run All Tests", "configurePreset": "test", "output": { "outputOnFailure": true } },

0 commit comments

Comments
 (0)