Skip to content

feat(lib): CMake install/export for the host C++ library (find_package + FetchContent/CPM) - #715

Open
finger563 wants to merge 2 commits into
mainfrom
feat/cmake-install
Open

feat(lib): CMake install/export for the host C++ library (find_package + FetchContent/CPM)#715
finger563 wants to merge 2 commits into
mainfrom
feat/cmake-install

Conversation

@finger563

Copy link
Copy Markdown
Contributor

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 name espp::espp:

  • find_package(espp REQUIRED) from an install tree, and
  • add_subdirectory(lib) via FetchContent / CPM from the build tree.

Changes

  • lib/CMakeLists.txt: espp::espp ALIAS (+ EXPORT_NAME espp), $<BUILD_INTERFACE>/$<INSTALL_INTERFACE> include dirs, PUBLIC cxx_std_23 + system libs. Gated all pybind11 discovery + the Python module behind a new option(ESPP_BUILD_PYTHON OFF) (if(SKBUILD OR ESPP_BUILD_PYTHON)), so a plain cmake -S lib builds 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 + installs esppConfig.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=ON to preserve their (and CI's) Python-producing behavior; the scikit-build wheel path (SKBUILD) is unaffected.

Consumer usage

find_package:

find_package(espp REQUIRED)
target_link_libraries(consumer PRIVATE espp::espp)

FetchContent / CPM (note SOURCE_SUBDIR lib, and a recursive submodule checkout is required since third-party deps are vendored):

CPMAddPackage(NAME espp GITHUB_REPOSITORY esp-cpp/espp GIT_TAG main SOURCE_SUBDIR lib)
target_link_libraries(myapp PRIVATE espp::espp)

Verification (all passed)

  • Configure + --target install to a prefix (no network) → installs libespp_pc.a, ~820 headers, and lib/cmake/espp/{esppConfig,esppConfigVersion,esppTargets,...}.cmake.
  • A find_package(espp) consumer linking espp::espp configures, builds, and runs.
  • An add_subdirectory(lib) build-tree consumer sees espp::espp and builds/runs (C++23 auto-propagates).
  • Existing pc/ test build unchanged; -DESPP_BUILD_PYTHON=ON still builds the wheel as before.

⚠️ Behavioral change to note

The Python module is now opt-in (-DESPP_BUILD_PYTHON=ON, default OFF) so a find_package consumer doesn't drag in pybind11. build.sh/build.ps1 and the CI build_libraries path were updated to pass it, and the wheel/SKBUILD path is unchanged — but this changes what a bare cmake -S lib produces 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 is Threads. Watch for ODR/header clashes if a consumer also uses one of these directly. Requires C++23.

🤖 Generated with Claude Code

…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>
Copilot AI lite review requested due to automatic review settings August 15, 2026 01:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 generate esppConfig.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.

Comment thread lib/CMakeLists.txt Outdated
Comment thread lib/CMakeLists.txt Outdated
@github-actions

Copy link
Copy Markdown

✅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>
@finger563
finger563 requested a balanced review from Copilot August 15, 2026 04:25
Comment thread lib/CMakeLists.txt

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ...) without FILES_MATCHING/PATTERN filters 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()

Comment thread lib/CMakeLists.txt

# Build and install the python package (espp/ with the _espp extension inside)
espp_install_python_module(${PROJECT_SOURCE_DIR}/pc)
if(ESPP_BUILD_PYTHON)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants