Skip to content

build: make cloudini_lib embeddable with add_subdirectory / FetchContent - #142

Merged
facontidavide merged 3 commits into
mainfrom
fix/subproject-build
Sep 20, 2026
Merged

facontidavide merged 3 commits into
mainfrom
fix/subproject-build

Conversation

@facontidavide

@facontidavide facontidavide commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

Makes cloudini_lib safe to embed with add_subdirectory() / FetchContent. Found while embedding it in pj_bridge, which currently needs ~45 lines of workarounds; against this branch that block shrinks to:

FetchContent_Declare(cloudini URL ... SOURCE_SUBDIR cloudini_lib)
set(CLOUDINI_FORCE_VENDORED_DEPS OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(cloudini)
target_link_libraries(my_target PRIVATE cloudini::cloudini_lib)

(verified locally: pj_bridge builds against this branch with exactly that, 303 tests pass, static link, nothing of Cloudini installed, parent build type untouched).

What leaked into the parent, and the fix

Each item was reproduced first with the new consumer project cloudini_lib/test/subproject, which embeds the library like a parent would and fails at configure time if something leaks. It now runs in the Ubuntu CI job.

Problem when embedded Fix
find_package(zstd CONFIG) fails with "Some (but not all) targets in this export set were already defined" when the parent already defined zstd::libzstd_shared (e.g. from a Find module) zstd and lz4 lookups reuse existing targets instead of looking the package up again
In a ROS parent, the inherited ament_cmake_FOUND turned the embedded library into a SHARED ament package with its own ament_package() ament is only considered when Cloudini is the top-level project
CMAKE_BUILD_TYPE=Release forced into the parent's cache; include(CTest) defined BUILD_TESTING there top-level only
Tests, tools, benchmarks, PCL and install rules on by default; PCL became a PUBLIC link dependency of the parent defaults follow "is top-level"; new options CLOUDINI_WITH_PCL and CLOUDINI_INSTALL
data_path.hpp written to the parent's ${CMAKE_BINARY_DIR}/include, colliding with a parent file of the same name ${CMAKE_CURRENT_BINARY_DIR}/include
cloudini::cloudini_lib only existed after install alias always defined, so consumers use one name for installed and embedded builds

Top-level detection uses CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR because PROJECT_IS_TOP_LEVEL needs CMake 3.21 and the project supports 3.16.

Also fixed: missing Threads dependency

PointcloudEncoder uses std::thread, but cloudini_lib did not link Threads::Threads. A static consumer on an older glibc (conda sysroot) failed with undefined reference to pthread_create — the new consumer test caught this in a RoboStack environment. Now linked PUBLIC, with find_dependency(Threads) in the package config and ament_export_dependencies(... Threads).

Top-level behaviour is unchanged — verified

  • standalone: defaults to Release, tools built, 26/26 tests, cmake --install produces the same package files, and a find_package(cloudini_lib) consumer links against the installed static library
  • ament/colcon (RoboStack Humble): still builds libcloudini_lib.so and exports its targets
  • embedded: plain Ubuntu and RoboStack Humble, configure + build + run + install (only the parent's own binary is installed)

Version 1.3.1

The version is set to 1.3.1 everywhere it is declared: project(cloudini_lib VERSION ...) (it was still 1.2.4 in the 1.3.0 release, so find_package(cloudini_lib 1.3) failed against a 1.3.0 install), both package.xml files, conda/recipe.yaml, and a 1.3.1 section in both changelogs. This branch also contains a merge of main (#141).

After tagging 1.3.1: refresh sha256 in conda/recipe.yaml — it is still the 1.2.4 tarball's hash and is marked STALE (CI is unaffected, it builds the recipe from the checkout). cloudini_foxglove/package.json (1.2.2) is versioned separately and was left alone.

Not changed

The ament install still exports cloudini_lib::cloudini_lib while the standalone install exports cloudini::cloudini_lib; unifying them would break cloudini_ros, so it is not part of this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01711BZcEtp3KsoF9uZHNFME

facontidavide and others added 3 commits September 20, 2026 21:17
Embedded in another project, cloudini_lib leaked into its parent. Each item was
reproduced with the new consumer project in test/subproject (now run in CI):

- find_package(zstd CONFIG) clashed with zstd targets the parent had already
  defined ('some (but not all) targets in this export set were already
  defined'). zstd and lz4 lookups now reuse existing targets.
- In a ROS parent, the inherited ament_cmake result turned the embedded library
  into a SHARED ament package with its own ament_package().
- CMAKE_BUILD_TYPE=Release was forced into the parent's cache; include(CTest)
  defined BUILD_TESTING there; tests, tools, benchmarks, PCL and install rules
  were on by default; data_path.hpp was written to the parent's
  CMAKE_BINARY_DIR/include.
- No cloudini::cloudini_lib target existed in-tree, only after install.

When not top-level, only the static library is built. New options
CLOUDINI_WITH_PCL and CLOUDINI_INSTALL (default: ON when top-level), and the
cloudini::cloudini_lib alias is always defined. Top-level behaviour is
unchanged (standalone, installed package and ament builds verified).

Also: cloudini_lib uses std::thread but did not link Threads::Threads, so a
static consumer failed with 'undefined reference to pthread_create' on older
glibc (conda sysroot). Linked PUBLIC and declared in the package config.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01711BZcEtp3KsoF9uZHNFME
CMake project (was still 1.2.4), both package.xml files, the conda recipe and
the changelogs. The recipe's sha256 can only be refreshed once the 1.3.1 tag
exists; it is marked as stale.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01711BZcEtp3KsoF9uZHNFME
@facontidavide
facontidavide merged commit 57531db into main Sep 20, 2026
6 checks passed
@facontidavide
facontidavide deleted the fix/subproject-build branch September 20, 2026 20:05
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.

1 participant