-
Notifications
You must be signed in to change notification settings - Fork 0
Adding installation support (again) #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Added cleaned up installation support, along with an overhauled readme.
This CI test added complexity without adding value. Testing find_package() is sufficient to ensure the package installs correctly.
To simplify the ci logic, I'm changing the ci.yml file to a template.
Adds conditional execution for environment setup and CMake configuration steps based on the presence of matrix.cc.
…brary into sean-parent/install
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for your work ! I am happy to participate if needed. :-)
tested on my vcpkg environment, got stuck on stlab, but otherwise promising !
|
|
||
| # Generate package config file from template | ||
| configure_file( | ||
| "${CPP_LIBRARY_ROOT}/templates/Config.cmake.in" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the delicate part (the PITA).
This would work well for enum and copy, because their only dependency is cpp_library, and it is a private dependency (no need to find_dependency it).
For stlab, it has internal (enum, copy) and external (qt, libdispatch, Threads) that are public (stlab users will need them if they want to use stlab, well, those who were used during stlab build).
the classic way is that each project will have it own tmpl, and double edit each time he modify a dependency.
this is where my previous proposal of a wrapper "get_dependency" would be handy.
It would store the public dependency, and will be used to generate the corresponding find_dependency calls.
Config.cmake.in (I use Config.tmpl.cmake to keep syntax highlights) would have @Dependencies@ that will replaced here.
If you wish, I can implement a prototype of that. Ideally _cpp_library_setup_install should be called in stlab to test it.
If you wonder in term of test and ci, this issue would have become apparent if it was used on a project with external dependencies, installed, and imported in a test project. It would have complained that Qt5, enum or something was not found and stlab link against it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't mind adding a way to specify additional dependencies that are not through CPM (e.g., qt, libdispatch). Are CPM dependencies handled correctly (modulo the above naming issue)?
I'm less thrilled with something that requires wrapping CPMAddPackage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I though about just using CPM_PACKAGES and CPM_PACKAGE_*_VERSION for theses, but there is one main issue with that, CPM does not indicate anywhere if a dependency is public or private cpp_library and enum are good 2 examples, one is for internal use only, another has to be exposed, and CPM does not have this information.
We could, of course, make workarounds, keeping a hard coded list of private deps like cpp_library. But I feel it a bit shaky.
There is also benefit that all you dependency go through the same function call, no matter the flavor.
It is up to you to decide what you prefer, I can implement it either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The public/private/interface information is provided in target_link_libraries() - in my experiments the dependency on cpp_library is not currently exported but if the other dependencies are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay - I updated the auto dependency() call generation to allow a map for custom dependency formats. This way, I'm not on the hook to keep a custom table up-to-date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So consumer will need to provide correct name for stlab dependencies ?
Sure you do not want a wrapper for dependencies ? It would solve all of this imbroglio.
Anyway, this would work, even though currently it would still generate find_dependency(stlab-copy-on-write) as stlab target name was not changed, only the package name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So consumer will need to provide correct name for stlab dependencies ?
I'm not sure what that means - where would they need to provide the name? I reviewed all the naming and made changes. If you have project(enum-ops) ... cpp_library(NAMESPACE stlab...), the package name is stlab-enum-ops both for the installed package and the generated dependency for a client. There were a few inconsistencies in this area but I think I've cleaned them all up (check the read-me and the enum-ops library branch that is using this version).
The install should correctly generate all the dependency calls.
| # - Postcondition: OUTPUT_VAR set to version string with 'v' prefix removed | ||
| function(_cpp_library_get_git_version OUTPUT_VAR) | ||
| # Try to get version from git tags | ||
| execute_process( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While unrelated with cmake install, there is a vcpkg limitation in that the .git folder is not available after extracting the sources. But vcpkg know which version get pulled;
This make the install generate a set(PACKAGE_VERSION "0.0.0")
if(DEFINED PROJECT_VERSION AND NOT PROJECT_VERSION STREQUAL "")
set(${OUTPUT_VAR} "${PROJECT_VERSION}" PARENT_SCOPE)
return()
endif()
Would solve the issue with minimal interference.
This could be done in the vcpkg port though it is a bit dirty. But i would understand if you do not which to add variables that would have such specific use cases.
In term of test and ci, this would become apparent only if the component was build through vcpkg, or any other package manager that strips the .git folder from the sources. Or in an sandboxed environment that does not have git.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another good catch - fixed (please verify).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, crap, I sent the wrong code, it is not PROJECT_VERSION, but it should be something else (anything really), I used EXTERNAL_PROJECT_VERSION.
Issue with PROJECT_VERSION is that it is overwritten by cmake during project(stlab-copy-on-write), so there is no version there.
My bad ^^'
The _cpp_library_setup_install function now requires a PACKAGE_NAME argument, ensuring correct package naming in generated CMake config files and install locations. Version detection in _cpp_library_get_git_version now prefers PROJECT_VERSION if set, improving compatibility with package managers and source archives.
Added logic to introspect INTERFACE_LINK_LIBRARIES and generate appropriate find_dependency() calls in installed CMake package config files. Updated documentation to explain dependency handling, added a helper function in cpp-library-install.cmake, and modified the config template to include generated dependencies. This ensures downstream users automatically find and link required dependencies.
Replaces usage of a 'clean' name with PACKAGE_NAME for library target aliases and CI workflow templates. Ensures consistent naming between CMake targets and package discovery, improving clarity and reducing potential mismatches.
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.
Updated internal CMake functions to require PACKAGE_NAME as a parameter instead of relying on PROJECT_NAME. This clarifies the preconditions for template and CI workflow generation, ensuring correct substitution and improving maintainability.
Ikar-Rahl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was able to test it with stlab and confirmed that it generate a config file, with some fixes as noted above.
I would suggest also reconsidering not using a dependency wrapper, but I may not have the full picture on the rational regarding that.
| # - Postcondition: OUTPUT_VAR set to version string with 'v' prefix removed | ||
| function(_cpp_library_get_git_version OUTPUT_VAR) | ||
| # Try to get version from git tags | ||
| execute_process( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, crap, I sent the wrong code, it is not PROJECT_VERSION, but it should be something else (anything really), I used EXTERNAL_PROJECT_VERSION.
Issue with PROJECT_VERSION is that it is overwritten by cmake during project(stlab-copy-on-write), so there is no version there.
My bad ^^'
The install-test job was removed from the GitHub Actions workflow because it duplicated functionality already provided by the main test job. This simplifies the workflow and reduces unnecessary runs across multiple operating systems. Also fixed a quoting issue with the install prefix on Windows.
Updated dependency mapping logic to distinguish between internal cpp-library and external dependencies, ensuring package names are collision-safe and consistent. Added support for overriding the version using the CPP_LIBRARY_VERSION variable, which is useful for package managers and CI systems without git history. Improved documentation in README.md to clarify dependency handling, target naming patterns, and version management. Refactored CMake scripts to align with these changes and updated comments for clarity.
Adds conditional steps in the CI workflow to set CC and CXX environment variables only when matrix.cc is defined. Ensures builds use the correct compiler configuration based on the matrix setup.
Clarifies that GitHub repository names must match package names, including namespace prefixes, for CPM compatibility. Updates usage examples, instructions, and project links to reflect this requirement and prevent issues with CPM's local package finding and source fetching. Repository naming requirements may be backed out if [this CPM PR](cpm-cmake/CPM.cmake#682) lands.
| add_library(${ARG_NAMESPACE}::${ARG_CLEAN_NAME} ALIAS ${ARG_NAME}) | ||
| target_include_directories(${ARG_NAME} INTERFACE | ||
| $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||
| $<INSTALL_INTERFACE:include> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Exported target name incorrect for alternative naming pattern
When using project(namespace-component) with NAMESPACE namespace, the exported target becomes namespace::namespace-component instead of namespace::component. The target is created with name ARG_NAME (which could be namespace-component), but no EXPORT_NAME property is set. When install(EXPORT) adds the NAMESPACE prefix at line 162 of cmake/cpp-library-install.cmake, it creates a double prefix. Consumers expecting namespace::component (matching the build-tree alias) will fail to link. The target needs EXPORT_NAME set to CLEAN_NAME to ensure consistent exported names regardless of project naming pattern.
|
|
||
| # Calculate clean name (without namespace prefix) for target alias | ||
| # If PROJECT_NAME starts with NAMESPACE-, strip it; otherwise use PROJECT_NAME as-is | ||
| string(REGEX REPLACE "^${ARG_NAMESPACE}-" "" CLEAN_NAME "${ARG_NAME}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Namespace not escaped in regex pattern
The namespace is used directly in a regex pattern without escaping special regex characters. If the namespace contains characters like ., +, *, or [, the regex will interpret them as metacharacters rather than literals, causing incorrect pattern matching. For example, namespace my.lib would match my-lib because . matches any character. This affects clean name calculation and could lead to incorrect target naming. The same issue exists at line 38 in _cpp_library_setup_executables.
Introduces setup.cmake, an interactive script for initializing new C++ library projects using the cpp-library template. The README is updated with detailed quick start instructions for using the script in both interactive and non-interactive modes, as well as guidance for manual setup.
| # Skip generator expressions (typically BUILD_INTERFACE dependencies) | ||
| if(LIB MATCHES "^\\$<") | ||
| continue() | ||
| endif() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Generator expressions incorrectly skipped in dependency generation
The dependency generation skips all generator expressions, including $<INSTALL_INTERFACE:...> dependencies that should be processed. This causes dependencies specified with $<INSTALL_INTERFACE:package::target> to be omitted from the generated find_dependency() calls in the package config file, breaking downstream builds that rely on those dependencies. Only $<BUILD_INTERFACE:...> should be skipped, while $<INSTALL_INTERFACE:...> content needs extraction and processing.
| set(DEPENDENCY_LINES "") | ||
| endif() | ||
|
|
||
| set(${OUTPUT_VAR} "${DEPENDENCY_LINES}" PARENT_SCOPE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Multiple find_dependency calls for same package with components
When a library links against multiple components of the same package (e.g., Qt5::Core and Qt5::Widgets), the dependency generation creates separate find_dependency() calls for each component instead of merging them into a single call with multiple components. This generates find_dependency(Qt5 COMPONENTS Core) followed by find_dependency(Qt5 COMPONENTS Widgets), which may fail or behave unexpectedly. The correct output should be a single find_dependency(Qt5 COMPONENTS Core Widgets) call.
Added cleaned up installation support, along with an overhauled readme.
Note
Adds full CMake install/package config generation with dependency mapping, generates CI workflows with install verification, introduces an interactive setup script, and significantly expands the README and presets.
cmake/cpp-library-install.cmaketo install targets (HEADER-ONLY and compiled), generateConfig.cmake/version files, and auto-derivefind_dependency()fromINTERFACE_LINK_LIBRARIES(withcpp_library_map_dependency). Updatestemplates/Config.cmake.inaccordingly._cpp_library_get_git_versionsupportsCPP_LIBRARY_VERSION; targets addINSTALL_INTERFACE:include; install step wired into_cpp_library_setup_core; cleaner alias name handling; improved exec setup linking.cmake/cpp-library-ci.cmakeand templatetemplates/.github/workflows/ci.yml.in; copy step now configures workflow withPACKAGE_NAME. Removes static workflow template.installconfigure/build presets intemplates/CMakePresets.json.setup.cmaketo scaffold projects (dirs, CPM, sample files, CMakeLists, git init)..vscode/settings.json; tweak recommended extensions template.Written by Cursor Bugbot for commit f13bae3. This will update automatically on new commits. Configure here.