From c77917f87fd0c1da8fecd6c8d9337dcdb1ba71bf Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Mon, 22 Dec 2025 10:09:40 -0800 Subject: [PATCH 1/2] Enable install in non-top-level projects via NAMESPACE_INSTALL Installation is now enabled if either building as a top-level project or if the `${NAMESPACE}_INSTALL` variable is set to ON. Updated documentation to explain how to enable installation in non-top-level projects, improving support for package managers and advanced workflows. --- README.md | 7 +++++++ cmake/cpp-library-setup.cmake | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2c5f01e..a613347 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,12 @@ cmake --install build/install --prefix /opt/mylib ``` The `install` preset enables `CPM_USE_LOCAL_PACKAGES`, which verifies your generated Config.cmake works correctly. See the [CPM.cmake documentation](https://github.com/cpm-cmake/CPM.cmake#cpm_use_local_packages) for more about using installed packages. +By default, installation is enabled only when building as a top-level project. To enable installation in non-top-level projects (e.g., when using CPM with package managers), set `${NAMESPACE}_INSTALL=ON`: + +```bash +cmake -DSTLAB_INSTALL=ON -B build # For a library with NAMESPACE stlab +``` + **Re-exporting CPM dependencies:** When re-exporting dependencies from `CPMAddPackage`, wrap them in `BUILD_INTERFACE` to avoid export errors (CPM creates non-IMPORTED targets that can't be exported): ```cmake @@ -333,6 +339,7 @@ cpp_library_setup( - The project name is automatically taken from `PROJECT_NAME` (set by the `project()` command). You must call `project(your-library)` before `cpp_library_setup()`. - **If you specify `TESTS` or `EXAMPLES`**, call `include(CTest)` after `project()` and before `cpp_library_setup()`. - Version is automatically detected from git tags (see [Version Management](#version-management) for overrides). +- Installation is enabled by default when `PROJECT_IS_TOP_LEVEL=TRUE`. Set `${NAMESPACE}_INSTALL=ON` to enable installation in non-top-level projects. ### Target Naming diff --git a/cmake/cpp-library-setup.cmake b/cmake/cpp-library-setup.cmake index ebecfd6..b98e43b 100644 --- a/cmake/cpp-library-setup.cmake +++ b/cmake/cpp-library-setup.cmake @@ -119,8 +119,10 @@ function(_cpp_library_setup_core) endif() endif() - # Setup installation when building as top-level project - if(ARG_TOP_LEVEL) + # Setup installation when building as top-level project OR explicitly requested + # This allows package managers (vcpkg, CPM with install intent) to enable installation + # even when PROJECT_IS_TOP_LEVEL is FALSE + if(ARG_TOP_LEVEL OR ${ARG_NAMESPACE}_INSTALL) _cpp_library_setup_install( NAME "${ARG_NAME}" PACKAGE_NAME "${ARG_PACKAGE_NAME}" From 0e6c59478b2d470253aac99ba10d2841194a38e3 Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Tue, 23 Dec 2025 10:04:23 -0800 Subject: [PATCH 2/2] Add option to control installation via NAMESPACE_INSTALL Introduces a CMake option `${NAMESPACE}_INSTALL` (defaulting to `PROJECT_IS_TOP_LEVEL`) to explicitly enable or disable installation of the library. Updates documentation and refactors install logic to use this option, allowing more flexible control for both top-level and subproject builds. --- README.md | 7 ++++--- cmake/cpp-library-install.cmake | 21 +++++++++++++++++---- cmake/cpp-library-setup.cmake | 21 +++++++++------------ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index a613347..6c15678 100644 --- a/README.md +++ b/README.md @@ -171,10 +171,11 @@ cmake --install build/install --prefix /opt/mylib ``` The `install` preset enables `CPM_USE_LOCAL_PACKAGES`, which verifies your generated Config.cmake works correctly. See the [CPM.cmake documentation](https://github.com/cpm-cmake/CPM.cmake#cpm_use_local_packages) for more about using installed packages. -By default, installation is enabled only when building as a top-level project. To enable installation in non-top-level projects (e.g., when using CPM with package managers), set `${NAMESPACE}_INSTALL=ON`: +**Controlling installation**: The `${NAMESPACE}_INSTALL` option controls whether installation is enabled (defaults to `PROJECT_IS_TOP_LEVEL`). Use `-D${NAMESPACE}_INSTALL=ON/OFF` to override: ```bash -cmake -DSTLAB_INSTALL=ON -B build # For a library with NAMESPACE stlab +cmake -DSTLAB_INSTALL=OFF -B build # Disable install for top-level project +cmake -DSTLAB_INSTALL=ON -B build # Enable install for non-top-level (e.g., via CPM) ``` **Re-exporting CPM dependencies:** When re-exporting dependencies from `CPMAddPackage`, wrap them in `BUILD_INTERFACE` to avoid export errors (CPM creates non-IMPORTED targets that can't be exported): @@ -339,7 +340,7 @@ cpp_library_setup( - The project name is automatically taken from `PROJECT_NAME` (set by the `project()` command). You must call `project(your-library)` before `cpp_library_setup()`. - **If you specify `TESTS` or `EXAMPLES`**, call `include(CTest)` after `project()` and before `cpp_library_setup()`. - Version is automatically detected from git tags (see [Version Management](#version-management) for overrides). -- Installation is enabled by default when `PROJECT_IS_TOP_LEVEL=TRUE`. Set `${NAMESPACE}_INSTALL=ON` to enable installation in non-top-level projects. +- Installation is controlled by the `${NAMESPACE}_INSTALL` option, which defaults to `PROJECT_IS_TOP_LEVEL`. ### Target Naming diff --git a/cmake/cpp-library-install.cmake b/cmake/cpp-library-install.cmake index dd78ad5..374635a 100644 --- a/cmake/cpp-library-install.cmake +++ b/cmake/cpp-library-install.cmake @@ -409,6 +409,7 @@ endfunction() # - Precondition: NAME, PACKAGE_NAME, VERSION, and NAMESPACE specified; target NAME exists # - Postcondition: install rules created for target, config files, and export with NAMESPACE:: prefix # - Supports header-only (INTERFACE) and compiled libraries, uses SameMajorVersion compatibility +# - Installation can be controlled via ${NAMESPACE}_INSTALL option (defaults to PROJECT_IS_TOP_LEVEL) function(_cpp_library_setup_install) set(oneValueArgs NAME # Target name (e.g., "stlab-enum-ops") @@ -422,10 +423,6 @@ function(_cpp_library_setup_install) cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - # Include required CMake modules (deferred from top-level to avoid requiring project() before include) - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) - # Validate required arguments if(NOT ARG_NAME) message(FATAL_ERROR "_cpp_library_setup_install: NAME is required") @@ -440,6 +437,22 @@ function(_cpp_library_setup_install) message(FATAL_ERROR "_cpp_library_setup_install: NAMESPACE is required") endif() + # Define installation option with PROJECT_IS_TOP_LEVEL as default + # This allows explicit control: -D${NAMESPACE}_INSTALL=ON/OFF + # Upper-case the namespace for the option name + string(TOUPPER "${ARG_NAMESPACE}" NAMESPACE_UPPER) + option(${NAMESPACE_UPPER}_INSTALL "Enable installation of ${ARG_PACKAGE_NAME}" ${PROJECT_IS_TOP_LEVEL}) + + # Check if installation is enabled + if(NOT ${NAMESPACE_UPPER}_INSTALL) + message(STATUS "cpp-library: Installation disabled for ${ARG_PACKAGE_NAME} (${NAMESPACE_UPPER}_INSTALL=OFF)") + return() + endif() + + # Include required CMake modules (deferred from top-level to avoid requiring project() before include) + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + # Install the library target # For header-only libraries (INTERFACE), this installs the target metadata # For compiled libraries, this installs the library files and headers diff --git a/cmake/cpp-library-setup.cmake b/cmake/cpp-library-setup.cmake index b98e43b..651db62 100644 --- a/cmake/cpp-library-setup.cmake +++ b/cmake/cpp-library-setup.cmake @@ -119,18 +119,15 @@ function(_cpp_library_setup_core) endif() endif() - # Setup installation when building as top-level project OR explicitly requested - # This allows package managers (vcpkg, CPM with install intent) to enable installation - # even when PROJECT_IS_TOP_LEVEL is FALSE - if(ARG_TOP_LEVEL OR ${ARG_NAMESPACE}_INSTALL) - _cpp_library_setup_install( - NAME "${ARG_NAME}" - PACKAGE_NAME "${ARG_PACKAGE_NAME}" - VERSION "${ARG_VERSION}" - NAMESPACE "${ARG_NAMESPACE}" - HEADERS "${ARG_HEADERS}" - ) - endif() + # Setup installation (controlled by ${NAMESPACE}_INSTALL option, defaults to PROJECT_IS_TOP_LEVEL) + # The option is defined and checked inside _cpp_library_setup_install() + _cpp_library_setup_install( + NAME "${ARG_NAME}" + PACKAGE_NAME "${ARG_PACKAGE_NAME}" + VERSION "${ARG_VERSION}" + NAMESPACE "${ARG_NAMESPACE}" + HEADERS "${ARG_HEADERS}" + ) endfunction()