feat(lib): CMake install/export for the host C++ library (find_package + FetchContent/CPM) - #715
feat(lib): CMake install/export for the host C++ library (find_package + FetchContent/CPM)#715finger563 wants to merge 2 commits into
Conversation
…e + FetchContent) Give the cross-platform host C++ library a proper, modern CMake package so a separate project can consume it two ways with the SAME link name espp::espp: - find_package(espp REQUIRED) from an installed tree, and - FetchContent / CPM add_subdirectory(lib) from the build tree. Changes: - espp_pc gets target-based usage requirements: every include dir espp.cmake collects is exposed as $<BUILD_INTERFACE:...>, plus $<INSTALL_INTERFACE:include>, and cxx_std_23 + system link deps (pthread / ws2_32,winmm,iphlpapi) are PUBLIC so they propagate to consumers. - Namespaced ALIAS espp::espp for build-tree consumers, and EXPORT_NAME espp so the installed/exported target is also espp::espp (archive stays libespp_pc.a). - New espp_install_cmake_package() (in espp.cmake) installs the target via EXPORT esppTargets, the public headers (merged flat into <prefix>/include, mirroring lib/pc/include), esppTargets.cmake, and generated esppConfig.cmake / esppConfigVersion.cmake (SameMajorVersion) under lib/cmake/espp. All third-party deps are vendored (headers installed + objects in the .a); the only non-bundled PUBLIC dep is Threads, resolved via find_dependency(Threads) in the config. - Gate the python bindings behind option ESPP_BUILD_PYTHON (default OFF) so a plain `cmake -S lib` yields just the C++ lib + install/export with no pybind11 dependency. build.sh / build.ps1 pass -DESPP_BUILD_PYTHON=ON to preserve their behavior (this is what build_libraries CI publishes to lib/pc); the scikit-build wheel path (SKBUILD) is unaffected. The legacy lib/pc install (used by the pc/ test build and CI artifacts) is kept unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds a modern CMake install + export for the host C++ library so external consumers can use a consistent espp::espp target via either find_package(espp) (install-tree) or add_subdirectory(lib) (build-tree), while making Python bindings opt-in by default.
Changes:
- Introduces
espp_install_cmake_package()to install/export targets and generateesppConfig.cmake+ version files. - Adds a namespaced build-tree alias (
espp::espp) and install-tree export name (EXPORT_NAME espp), plus modern usage requirements (BUILD/INSTALL interface include dirs, PUBLIC C++23 + system libs). - Gates pybind11 discovery and the Python module build behind
ESPP_BUILD_PYTHON(default OFF), updating build scripts to pass-DESPP_BUILD_PYTHON=ON.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/CMakeLists.txt | Adds espp::espp alias + export name, modern install/export wiring, and makes Python bindings opt-in. |
| lib/espp.cmake | Adds helper to install targets/headers and generate package config + version files. |
| lib/cmake/esppConfig.cmake.in | New package config template to load exported targets and declare Threads dependency. |
| lib/build.sh | Forces Python bindings ON for the legacy build script behavior. |
| lib/build.ps1 | Forces Python bindings ON for the legacy build script behavior on Windows. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
✅Static analysis result - no issues found! ✅ |
…uild.sh doesn't write /usr/local The build_libraries CI job (build_linux + build_macos) failed because lib/build.sh runs `cmake --build . --target install` with no CMAKE_INSTALL_PREFIX. The newly added standard install/export (espp_install_cmake_package) therefore fired during the plain build.sh install and tried to write the export into the default system prefix (/usr/local), exiting 2. - Add option(ESPP_INSTALL ... OFF). The standard install/export (find_package(espp) / espp::espp) now only runs when ESPP_INSTALL=ON. build.sh leaves it OFF, so it installs ONLY the legacy lib/pc artifacts and never touches /usr/local. A real consumer opts in with `-DESPP_INSTALL=ON -DCMAKE_INSTALL_PREFIX=<prefix>`. - Guard the legacy lib/pc install (which writes into the espp SOURCE tree) behind `if(PROJECT_IS_TOP_LEVEL OR ESPP_BUILD_PYTHON)` so a FetchContent/CPM consumer's `cmake --install` no longer mutates the espp source tree. Bump cmake_minimum_required to 3.21 for a reliable PROJECT_IS_TOP_LEVEL. - Fix the misleading top-of-file status message: report C++-only by default and only mention Python bindings when SKBUILD/ESPP_BUILD_PYTHON is set. Verified: build.sh succeeds with zero /usr/local install lines and populates lib/pc; `-DESPP_INSTALL=ON` installs a find_package-able package that a separate consumer configures, builds, links (espp::espp), and runs against. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
lib/espp.cmake:225
- Using
install(DIRECTORY ...)withoutFILES_MATCHING/PATTERNfilters will copy everything under those include roots into the install prefix (potentially including non-header files like docs, tests, licenses, or build files if any vendored include roots aren’t strictly header-only). To keep installs lean and predictable, restrict this to header patterns (e.g.,*.h,*.hpp,*.inl) and/or add explicit excludes for common non-header directories/files.
foreach(_inc IN LISTS ESPP_INCLUDES ESPP_EXTERNAL_INCLUDES ESPP_EXTERNAL_INCLUDES_SEPARATE)
install(DIRECTORY ${_inc}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endforeach()
|
|
||
| # Build and install the python package (espp/ with the _espp extension inside) | ||
| espp_install_python_module(${PROJECT_SOURCE_DIR}/pc) | ||
| if(ESPP_BUILD_PYTHON) |
What & why
The host C++ library under
lib/had no consumable install. This adds a proper modern-CMake install + export so an external project can use it two ways with the same link nameespp::espp:find_package(espp REQUIRED)from an install tree, andadd_subdirectory(lib)via FetchContent / CPM from the build tree.Changes
lib/CMakeLists.txt:espp::esppALIAS (+EXPORT_NAME espp),$<BUILD_INTERFACE>/$<INSTALL_INTERFACE>include dirs, PUBLICcxx_std_23+ system libs. Gated all pybind11 discovery + the Python module behind a newoption(ESPP_BUILD_PYTHON OFF)(if(SKBUILD OR ESPP_BUILD_PYTHON)), so a plaincmake -S libbuilds only the C++ lib + export with no pybind11/network dependency.lib/espp.cmake:espp_install_cmake_package()—install(TARGETS ... EXPORT esppTargets), installs public headers,install(EXPORT ... NAMESPACE espp::), generates + installsesppConfig.cmake+esppConfigVersion.cmake(SameMajorVersion).lib/cmake/esppConfig.cmake.in:@PACKAGE_INIT@,find_dependency(Threads), include targets,check_required_components.lib/build.sh/build.ps1: pass-DESPP_BUILD_PYTHON=ONto preserve their (and CI's) Python-producing behavior; the scikit-build wheel path (SKBUILD) is unaffected.Consumer usage
find_package:FetchContent / CPM (note
SOURCE_SUBDIR lib, and a recursive submodule checkout is required since third-party deps are vendored):Verification (all passed)
--target installto a prefix (no network) → installslibespp_pc.a, ~820 headers, andlib/cmake/espp/{esppConfig,esppConfigVersion,esppTargets,...}.cmake.find_package(espp)consumer linkingespp::esppconfigures, builds, and runs.add_subdirectory(lib)build-tree consumer seesespp::esppand builds/runs (C++23 auto-propagates).pc/test build unchanged;-DESPP_BUILD_PYTHON=ONstill builds the wheel as before.The Python module is now opt-in (
-DESPP_BUILD_PYTHON=ON, default OFF) so afind_packageconsumer doesn't drag in pybind11.build.sh/build.ps1and the CIbuild_librariespath were updated to pass it, and the wheel/SKBUILDpath is unchanged — but this changes what a barecmake -S libproduces by default.Caveats
Third-party deps (reflect-cpp, magic_enum, tabulate, fmt, alpaca, cli, csv2, hid-rp, cdr) are vendored submodules — headers installed, objects bundled into
libespp_pc.a; only external transitive dep isThreads. Watch for ODR/header clashes if a consumer also uses one of these directly. Requires C++23.🤖 Generated with Claude Code