Repository navigation
adding cmeel based pip installation #247
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
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
ad1a848
Add unified Python wheel configuration
TomCC7 5b0e8a6
Add cmeel split package manifests
TomCC7 04616d3
Add root CMake packaging modes
TomCC7 e4bc400
Prepare native targets for packaged RPATHs
TomCC7 18e75d6
Install core binding modules for package builds
TomCC7 80230ed
Install solver binding modules for package builds
TomCC7 67f0875
Add Python packaging structure tests
TomCC7 49fa86a
Support VCS source builds with cmeel dependencies
TomCC7 00be2a0
Fix PR CI packaging build modes
TomCC7 0ca0117
Prefer Python nanobind discovery in ROS builds
TomCC7 40fd08a
Add hpp-fcl target compatibility
TomCC7 cf83c12
Cover hpp-fcl compatibility contract
TomCC7 c1fb582
Drop Rolling from required ROS CI
TomCC7 d24724c
Revert "Drop Rolling from required ROS CI"
TomCC7 74a6093
Rename unified distribution to roboplan-dimos
TomCC7 1679617
Add PyPI release publishing workflow
TomCC7 2e449e8
Install wheel libraries under lib for auditwheel
TomCC7 2919839
Add contained Python packaging helpers
TomCC7 327a5e2
Route root CMake through packaging helpers
TomCC7 296be81
Update packaging contract checks
TomCC7 d5761fc
Add packaging-only CMake entrypoint
TomCC7 fce21c1
Point cmeel manifests at packaging entrypoint
TomCC7 3ff51f0
Centralize build tree package configs
TomCC7 13030d2
Remove root packaging superbuild
TomCC7 8cb8776
Restore core package CMake files
TomCC7 a4aa669
Restore downstream native CMake files
TomCC7 e46a136
Restore binding CMake files
TomCC7 2bbc24a
Restore package test CMake files
TomCC7 c72a9f1
Update reduced CMake contract tests
TomCC7 d31bac9
Ignore packaging helpers during colcon discovery
TomCC7 a26129d
Update Python packaging helper behavior
TomCC7 3d882bc
Document Python packaging validation
TomCC7 eaec8fa
Add stable Python 3.14 wheel support
TomCC7 6bfbe66
Rename unified distribution back to roboplan
TomCC7 6f0b17e
Split Python binding build from release publishing
TomCC7 ff91d52
Rename PyPI wheel build workflow
TomCC7 e88d08e
Simplify cmeel Python wheel controls
TomCC7 da34dbb
Document PyPI wheel build scope
TomCC7 f5160e9
Add arm and macOS PyPI wheel builds
TomCC7 7c9c95b
Set C++ standard for wheel builds
TomCC7 e4c96f0
Repair macOS wheel rpaths
TomCC7 36a6994
Run PyPI wheel builds on main pushes
TomCC7 1f73a06
Set macOS wheel deployment targets
TomCC7 f90938f
Simplify standalone binding aliases
TomCC7 02bbb24
Remove split cmeel packaging path
TomCC7 e4a2d37
Publish releases only to PyPI
TomCC7 aac3ad0
Remove stale packaging option assertions
TomCC7 3585621
Clean up unified packaging tests
TomCC7 65feae4
Apply suggestions from code review
TomCC7 690f3a4
Derive wheel version from git tags
TomCC7 287fbd6
Use project version for Python bindings
TomCC7 2774363
Fixes from testing
sea-bass File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| name: Build PyPI wheels | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
| workflow_call: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| check_version: | ||
| name: Check package version | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| version: ${{ steps.package.outputs.version }} | ||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
| - name: Read package metadata | ||
| id: package | ||
| run: | | ||
| python -m pip install --upgrade "setuptools-scm>=8" | ||
| python - <<'PY' >> "$GITHUB_OUTPUT" | ||
| import tomllib | ||
| from pathlib import Path | ||
|
|
||
| from setuptools_scm import get_version | ||
|
|
||
| pyproject = tomllib.loads(Path("pyproject.toml").read_text()) | ||
| project = pyproject["project"] | ||
| if project["name"] != "roboplan": | ||
| raise SystemExit(f"Unexpected package name: {project['name']}") | ||
| if "version" in project: | ||
| raise SystemExit("pyproject.toml must use git-derived dynamic versioning") | ||
| if project.get("dynamic") != ["version"]: | ||
| raise SystemExit("pyproject.toml must declare dynamic = ['version']") | ||
| print(f"version={get_version(root='.', local_scheme='no-local-version')}") | ||
| PY | ||
| - name: Check tag matches package version | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
| env: | ||
| PACKAGE_VERSION: ${{ steps.package.outputs.version }} | ||
| RELEASE_TAG: ${{ github.ref_name }} | ||
| run: | | ||
| if ! [[ "$RELEASE_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| echo "::error::Tag $RELEASE_TAG must use N.N.N format" | ||
| exit 1 | ||
| fi | ||
| if [ "$RELEASE_TAG" != "$PACKAGE_VERSION" ]; then | ||
| echo "::error::Tag $RELEASE_TAG does not match package version $PACKAGE_VERSION" | ||
| exit 1 | ||
| fi | ||
|
|
||
| build_sdist: | ||
| name: Build source distribution | ||
| runs-on: ubuntu-latest | ||
| needs: check_version | ||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.12" | ||
| - name: Build sdist | ||
| run: | | ||
| rm -rf dist | ||
| python -m pip install --upgrade build twine | ||
| python -m build --sdist | ||
| python -m twine check dist/*.tar.gz | ||
| - name: Upload sdist | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: python-distributions-sdist | ||
| path: dist/roboplan-*.tar.gz | ||
| if-no-files-found: error | ||
|
|
||
| build_wheels: | ||
| name: Build ${{ matrix.name }} wheels | ||
| runs-on: ${{ matrix.os }} | ||
| needs: check_version | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - name: Linux x86_64 | ||
| os: ubuntu-latest | ||
| archs: x86_64 | ||
| artifact: linux-x86_64 | ||
| extra_environment: "" | ||
| - name: Linux aarch64 | ||
| os: ubuntu-24.04-arm | ||
| archs: aarch64 | ||
| artifact: linux-aarch64 | ||
| extra_environment: "" | ||
| - name: macOS arm64 | ||
| os: macos-14 | ||
| archs: arm64 | ||
| artifact: macos-arm64 | ||
| extra_environment: "MACOSX_DEPLOYMENT_TARGET=14.0" | ||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
| - name: Build wheels | ||
| uses: pypa/cibuildwheel@v4.1.0 | ||
| env: | ||
| CIBW_ARCHS: ${{ matrix.archs }} | ||
| CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*" | ||
| CIBW_SKIP: "pp* *-musllinux*" | ||
| CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 | ||
| CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 | ||
| CIBW_ENVIRONMENT: >- | ||
| CMAKE_BUILD_PARALLEL_LEVEL=2 | ||
| MAKEFLAGS="-j2" | ||
| NINJAFLAGS="-j2" | ||
|
TomCC7 marked this conversation as resolved.
|
||
| ${{ matrix.extra_environment }} | ||
| CIBW_TEST_COMMAND: >- | ||
| python -c "import roboplan; import roboplan.core; import roboplan.filters; import roboplan.example_models; | ||
| import roboplan.simple_ik; import roboplan.optimal_ik; import roboplan.rrt; | ||
| import roboplan.toppra; import roboplan.cartesian_planning; print('roboplan imports ok')" | ||
| - name: Upload wheels | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: python-distributions-${{ matrix.artifact }} | ||
| path: wheelhouse/roboplan-*.whl | ||
| if-no-files-found: error | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - "[0-9]*.[0-9]*.[0-9]*" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build_pypi_wheels: | ||
| name: Build PyPI wheels | ||
| uses: ./.github/workflows/build-pypi-wheels.yml | ||
|
|
||
| publish_pypi: | ||
| name: Publish to PyPI | ||
| runs-on: ubuntu-latest | ||
| needs: build_pypi_wheels | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
| environment: | ||
| name: pypi | ||
| url: https://pypi.org/project/roboplan/ | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| steps: | ||
| - name: Download distributions | ||
| uses: actions/download-artifact@v5 | ||
| with: | ||
| pattern: python-distributions-* | ||
| merge-multiple: true | ||
| path: dist | ||
| - name: Check distributions | ||
| run: | | ||
| python -m pip install --upgrade twine | ||
| ls -la dist | ||
| python -m twine check dist/* | ||
| - name: Publish to PyPI | ||
| uses: pypa/gh-action-pypi-publish@release/v1 | ||
| with: | ||
| packages-dir: dist/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,5 +9,9 @@ | |
| .pixi | ||
| *.egg-info | ||
|
|
||
| # Python packaging artifacts | ||
| dist/ | ||
| wheelhouse/ | ||
|
|
||
| # Benchmarking results | ||
| pytest_benchmarks.json | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| cmake_minimum_required(VERSION 3.22) | ||
|
|
||
| set(ROBOPLAN_PACKAGING_VERSION "0.0.0") | ||
| if(DEFINED SKBUILD_PROJECT_VERSION) | ||
| set(ROBOPLAN_PACKAGING_VERSION "${SKBUILD_PROJECT_VERSION}") | ||
| endif() | ||
| project(roboplan VERSION "${ROBOPLAN_PACKAGING_VERSION}") | ||
|
|
||
| get_filename_component(ROBOPLAN_REPOSITORY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) | ||
|
|
||
| include(cmake/roboplan_python_packaging.cmake) | ||
|
|
||
| if(SKBUILD) | ||
| roboplan_configure_scikit_build_prefix() | ||
| endif() | ||
|
|
||
| roboplan_register_build_tree_packages() | ||
|
|
||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_example_models" "roboplan_example_models") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan" "roboplan") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_simple_ik" "roboplan_simple_ik") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_oink" "roboplan_oink") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_rrt" "roboplan_rrt") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_toppra" "roboplan_toppra") | ||
| add_subdirectory("${ROBOPLAN_REPOSITORY_ROOT}/roboplan_cartesian_planning" "roboplan_cartesian_planning") | ||
|
|
||
| if(SKBUILD) | ||
| roboplan_configure_unified_python_wheel() | ||
| endif() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Python packaging | ||
|
TomCC7 marked this conversation as resolved.
|
||
|
|
||
| This directory contains the PyPI/cibuildwheel-specific packaging helpers for RoboPlan. | ||
| The normal source-tree CMake build remains in the package directories. | ||
| `pyproject.toml` points `scikit-build-core` at this directory with `tool.scikit-build.cmake.source-dir`. | ||
|
|
||
| The helper CMake files cover three packaging-only concerns: | ||
|
|
||
| - expose `cmeel`'s isolated native dependency prefix to `scikit-build-core` builds; | ||
| - install the runtime native libraries that wheels need at import time; | ||
| - repair installed RPATHs with `patchelf` using checked-in CMake script templates rather than large embedded `install(CODE ...)` strings. | ||
|
|
||
| Release wheels are built with `cibuildwheel` in the [`build-pypi-wheels.yml`](../../.github/workflows/build-pypi-wheels.yml) CI workflow, and are smoke-tested by importing the `roboplan` namespace and every compiled submodule. | ||
| That workflow runs on pull requests so wheel build breakage is caught before release. | ||
| The [`release.yml`](../../.github/workflows/release.yml) workflow invokes the same build workflow from the tagged commit, downloads those fresh artifacts, and publishes them through PyPI trusted publishing. | ||
|
|
||
|
|
||
| ## Local checks | ||
|
|
||
| Run commands from the repository root. Keep native parallelism capped on small machines, matching CI: | ||
|
|
||
| ```bash | ||
| export CMAKE_BUILD_PARALLEL_LEVEL=2 | ||
| export MAKEFLAGS=-j2 | ||
| export NINJAFLAGS=-j2 | ||
| ``` | ||
|
|
||
| Source-build and import-test the unified wheel path: | ||
|
|
||
| ```bash | ||
| uv venv --seed /tmp/roboplan-wheel-check | ||
| uv pip install -v --python /tmp/roboplan-wheel-check/bin/python --no-cache . | ||
| /tmp/roboplan-wheel-check/bin/python - <<'PY' | ||
| import roboplan | ||
| import roboplan.core | ||
| import roboplan.filters | ||
| import roboplan.example_models | ||
| import roboplan.simple_ik | ||
| import roboplan.optimal_ik | ||
| import roboplan.rrt | ||
| import roboplan.toppra | ||
| import roboplan.cartesian_planning | ||
| print("roboplan imports ok") | ||
| PY | ||
| ``` | ||
|
|
||
| Check the structural packaging contract: | ||
|
|
||
| ```bash | ||
| uvx pytest tests/unified_python_package_test.py -q | ||
| ``` | ||
|
|
||
| ## Run an example against the wheel | ||
|
|
||
| To prove the wheel is usable end-to-end, install it into a fresh environment and run one of the examples. | ||
| The examples are not part of the wheel, so they pull in a few extra runtime dependencies on top of `roboplan` itself. | ||
|
|
||
| ```bash | ||
| # 1. Create an isolated environment and install the wheel we just built. | ||
| uv venv --seed /tmp/roboplan-wheel-check | ||
| uv pip install --python /tmp/roboplan-wheel-check/bin/python --no-cache . | ||
|
|
||
| # 2. Install the extra dependencies the examples need. | ||
| uv pip install --python /tmp/roboplan-wheel-check/bin/python pycollada tyro xacro viser | ||
|
|
||
| # 3. Run an example. | ||
| /tmp/roboplan-wheel-check/bin/python roboplan_examples/python/example_ik.py | ||
| ``` | ||
55 changes: 55 additions & 0 deletions
55
packaging/python/cmake/repair_unified_macos_rpaths.cmake.in
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| function(_roboplan_resolve_macos_patch_file file result) | ||
| set(_patch_file "${file}") | ||
| if(IS_SYMLINK "${_patch_file}") | ||
| file(READ_SYMLINK "${_patch_file}" _symlink_target) | ||
| if(IS_ABSOLUTE "${_symlink_target}") | ||
| set(${result} "" PARENT_SCOPE) | ||
| return() | ||
| endif() | ||
| get_filename_component(_symlink_dir "${_patch_file}" DIRECTORY) | ||
| set(_patch_file "${_symlink_dir}/${_symlink_target}") | ||
| endif() | ||
|
|
||
| set(${result} "${_patch_file}" PARENT_SCOPE) | ||
| endfunction() | ||
|
|
||
| function(_roboplan_add_macos_rpath file rpath) | ||
| _roboplan_resolve_macos_patch_file("${file}" _patch_file) | ||
| if(NOT _patch_file OR NOT EXISTS "${_patch_file}") | ||
| return() | ||
| endif() | ||
|
|
||
| execute_process( | ||
| COMMAND otool -l "${_patch_file}" | ||
| OUTPUT_VARIABLE _otool_output | ||
| ERROR_QUIET | ||
| RESULT_VARIABLE _otool_result | ||
| ) | ||
| if(NOT _otool_result EQUAL 0) | ||
| return() | ||
| endif() | ||
|
|
||
| string(FIND "${_otool_output}" "path ${rpath} (offset" _existing_rpath) | ||
| if(_existing_rpath GREATER_EQUAL 0) | ||
| return() | ||
| endif() | ||
|
|
||
| execute_process( | ||
| COMMAND chmod u+w "${_patch_file}" | ||
| COMMAND_ERROR_IS_FATAL ANY | ||
| ) | ||
| execute_process( | ||
| COMMAND "@ROBOPLAN_UNIFIED_INSTALL_NAME_TOOL@" -add_rpath "${rpath}" "${_patch_file}" | ||
| COMMAND_ERROR_IS_FATAL ANY | ||
| ) | ||
| endfunction() | ||
|
|
||
| file(GLOB_RECURSE _roboplan_extensions "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/roboplan/*.so") | ||
| foreach(_file IN LISTS _roboplan_extensions) | ||
| _roboplan_add_macos_rpath("${_file}" "@loader_path/../../lib") | ||
| endforeach() | ||
|
|
||
| file(GLOB _roboplan_libraries "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/*.dylib") | ||
| foreach(_file IN LISTS _roboplan_libraries) | ||
| _roboplan_add_macos_rpath("${_file}" "@loader_path") | ||
| endforeach() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| function(_roboplan_patch_rpath file rpath) | ||
| set(_patch_file "${file}") | ||
| if(IS_SYMLINK "${_patch_file}") | ||
| file(READ_SYMLINK "${_patch_file}" _symlink_target) | ||
| if(IS_ABSOLUTE "${_symlink_target}") | ||
| return() | ||
| endif() | ||
| get_filename_component(_symlink_dir "${_patch_file}" DIRECTORY) | ||
| set(_patch_file "${_symlink_dir}/${_symlink_target}") | ||
| endif() | ||
|
|
||
| if(EXISTS "${_patch_file}") | ||
| execute_process( | ||
| COMMAND chmod u+w "${_patch_file}" | ||
| COMMAND_ERROR_IS_FATAL ANY | ||
| ) | ||
| execute_process( | ||
| COMMAND "@ROBOPLAN_UNIFIED_PATCHELF@" --set-rpath "${rpath}" "${_patch_file}" | ||
| COMMAND_ERROR_IS_FATAL ANY | ||
| ) | ||
| endif() | ||
| endfunction() | ||
|
|
||
| file(GLOB_RECURSE _roboplan_extensions "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/roboplan/*.so") | ||
| foreach(_file IN LISTS _roboplan_extensions) | ||
| _roboplan_patch_rpath("${_file}" "$ORIGIN/../../lib:$ORIGIN/../../cmeel.prefix/lib") | ||
| endforeach() | ||
|
|
||
| file(GLOB _roboplan_libraries | ||
| "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libfilters.so*" | ||
| "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libroboplan*.so*" | ||
| ) | ||
| foreach(_file IN LISTS _roboplan_libraries) | ||
| _roboplan_patch_rpath("${_file}" "$ORIGIN:$ORIGIN/../cmeel.prefix/lib") | ||
| endforeach() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.