From cac4573c726c8033aa0c16e1215dcef5a7249eb3 Mon Sep 17 00:00:00 2001 From: Zeerek Date: Thu, 13 Aug 2026 13:39:44 -0700 Subject: [PATCH] build both the ROS2 package and a plain CMake configuration find_package(ament_cmake QUIET) selects the branch, so one CMakeLists serves colcon and the wheel build. Under ament the library stays SHARED and is exported to downstream packages; without it the library is STATIC and position-independent, so the pybind11 module is self-contained and a wheel ships a single .so. Install, export and ament_package() calls move under the ament guard, and the wheel path installs the extension at the root. Drops the pybind11_vendor lookup for a direct pybind11 CONFIG lookup (vendor is a ROS2 package and is unavailable off-distro), the LINK_OPTIONS "" workaround, and the -Wl,-no-undefined link option that the static/pybind combination cannot satisfy. cmake_minimum_required rises to 3.15 to match what scikit-build-core requires. package.xml promotes pybind11_vendor to a full depend, adds python3-numpy and ament_cmake_test, and refreshes the description and maintainer. CI gains a standalone_cmake job so the non-ament path is actually exercised; CMAKE_DISABLE_FIND_PACKAGE_ament_cmake forces that branch even on a ROS2 runner. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/build.yml | 23 ++++++++- CMakeLists.txt | 95 +++++++++++++++++++------------------ package.xml | 9 ++-- 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0bb56a4..b5726c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,11 +27,30 @@ jobs: ROS_DISTRO: ${{ matrix.ros }} PIP_BREAK_SYSTEM_PACKAGES: 1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: ros-tooling/action-ros-ci@v0.4 with: target-ros2-distro: ${{ matrix.ros }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v6 with: name: colcon-logs-${{ matrix.ros }} path: ros_ws/log + + standalone_cmake: + runs-on: ubuntu-latest + name: Standalone CMake + ctest + steps: + - uses: actions/checkout@v5 + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake g++ catch2 pybind11-dev python3-dev + - name: Configure + # CMAKE_DISABLE_FIND_PACKAGE_ament_cmake forces the non-ament branch. + run: > + cmake -S . -B build -DBUILD_TESTING=ON + -DCMAKE_DISABLE_FIND_PACKAGE_ament_cmake=ON + - name: Build + run: cmake --build build -j + - name: Test + run: ctest --test-dir build --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 708f9e5..ed5b7d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.15) project(polymath_kinematics) if(NOT CMAKE_CXX_STANDARD) @@ -20,7 +20,6 @@ if(NOT CMAKE_CXX_STANDARD) endif() if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic -Werror) - add_link_options(-Wl,-no-undefined) endif() # Ubuntu detection (override with -DBUILD_JAMMY=ON/OFF) @@ -43,15 +42,21 @@ if(NOT DEFINED BUILD_JAMMY) endif() endif() -# Find packages -find_package(ament_cmake REQUIRED) -find_package(ament_cmake_python REQUIRED) +# Find packages. ament_cmake is QUIET so the wheel build (no ROS2) falls +# through to a plain CMake configuration. +find_package(ament_cmake QUIET) find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) -find_package(pybind11_vendor REQUIRED) -find_package(pybind11 REQUIRED) +find_package(pybind11 CONFIG REQUIRED) -# C++ library with all kinematic models -add_library(polymath_kinematics SHARED +# C++ library with all kinematic models. SHARED under ROS2 (ament exports a +# linkable .so to downstream packages); STATIC under wheel builds so the +# pybind11 module is self-contained and the wheel ships a single .so. +if(ament_cmake_FOUND) + set(_polymath_kinematics_lib_type SHARED) +else() + set(_polymath_kinematics_lib_type STATIC) +endif() +add_library(polymath_kinematics ${_polymath_kinematics_lib_type} src/articulated_model.cpp src/articulated_projector.cpp src/bicycle_model.cpp @@ -63,41 +68,37 @@ target_include_directories(polymath_kinematics PUBLIC $ $ ) +set_target_properties(polymath_kinematics PROPERTIES POSITION_INDEPENDENT_CODE ON) # Python bindings -set(PYBIND_TARGET polymath_kinematics_cpp) -pybind11_add_module(${PYBIND_TARGET} - src/kinematics_pybind.cpp -) -set_target_properties(${PYBIND_TARGET} PROPERTIES LINK_OPTIONS "") -target_link_libraries(${PYBIND_TARGET} PRIVATE polymath_kinematics) -_ament_cmake_python_register_environment_hook() -install(TARGETS ${PYBIND_TARGET} DESTINATION "${PYTHON_INSTALL_DIR}") +pybind11_add_module(polymath_kinematics_cpp src/kinematics_pybind.cpp) +target_link_libraries(polymath_kinematics_cpp PRIVATE polymath_kinematics) -# Install C++ library -install( - TARGETS polymath_kinematics - EXPORT ${PROJECT_NAME}_TARGETS - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION lib/${PROJECT_NAME} -) -install( - EXPORT ${PROJECT_NAME}_TARGETS - NAMESPACE ${PROJECT_NAME}:: - DESTINATION share/${PROJECT_NAME}/cmake -) -install( - DIRECTORY include/ - DESTINATION include/ -) +if(ament_cmake_FOUND) + find_package(ament_cmake_python REQUIRED) -# Python module -ament_python_install_package(${PROJECT_NAME}) + install( + TARGETS polymath_kinematics + EXPORT ${PROJECT_NAME}_TARGETS + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib/${PROJECT_NAME} + ) + install( + EXPORT ${PROJECT_NAME}_TARGETS + NAMESPACE ${PROJECT_NAME}:: + DESTINATION share/${PROJECT_NAME}/cmake + ) + install(DIRECTORY include/ DESTINATION include/) + + ament_python_install_package(${PROJECT_NAME}) + install(TARGETS polymath_kinematics_cpp DESTINATION "${PYTHON_INSTALL_DIR}") +else() + # Wheel build: scikit-build-core installs the extension at the wheel root. + install(TARGETS polymath_kinematics_cpp DESTINATION .) +endif() -# Testing if(BUILD_TESTING) - find_package(ament_cmake_pytest REQUIRED) include(CTest) if(BUILD_JAMMY) @@ -126,12 +127,16 @@ if(BUILD_TESTING) add_kinematics_catch2_test(test_bicycle_projector test/test_bicycle_projector.cpp) add_kinematics_catch2_test(test_articulated_projector test/test_articulated_projector.cpp) add_kinematics_catch2_test(test_differential_drive_projector test/test_differential_drive_projector.cpp) - ament_add_pytest_test(test_python_bindings test) -endif() -# Export targets -ament_export_targets(${PROJECT_NAME}_TARGETS HAS_LIBRARY_TARGET) -ament_export_include_directories(include) -ament_export_libraries(polymath_kinematics) + if(ament_cmake_FOUND) + find_package(ament_cmake_pytest REQUIRED) + ament_add_pytest_test(test_python_bindings test) + endif() +endif() -ament_package() +if(ament_cmake_FOUND) + ament_export_targets(${PROJECT_NAME}_TARGETS HAS_LIBRARY_TARGET) + ament_export_include_directories(include) + ament_export_libraries(polymath_kinematics) + ament_package() +endif() diff --git a/package.xml b/package.xml index 0019e51..8615ed8 100644 --- a/package.xml +++ b/package.xml @@ -3,16 +3,19 @@ polymath_kinematics 0.1.0 - Simple mixed C++/Python kinematics library - Polymath Robotics + Mixed C++/Python kinematics library for vehicle models + Polymath Engineering Apache-2.0 + Zeerek Ahmad ament_cmake ament_cmake_python - pybind11_vendor + pybind11_vendor + python3-numpy ament_cmake_pytest + ament_cmake_test catch2