Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/package-consumer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ jobs:
- name: Materialize the packages this workspace consumes
shell: bash
# The libraries this repository no longer builds -- usd-motion-plugins'
# motionCore, motionSampling and motionRecording -- are declared by
# motionCore, motionRetarget, motionSampling and motionUsd -- are declared by
# digest in the descriptors and resolved like OpenUSD: as a prefix the
# consumer is handed. Pulled here rather than by the driver, because a
# lane that reaches the network from inside a consumer fixture would be
Expand Down
151 changes: 151 additions & 0 deletions .github/workflows/plain-cmake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Hand-authored (not generated by `ost ci generate`), and it has to be: the one
# thing this lane exists to prove is that the build needs no `ost` at all.
#
# OpenUSD 26.08 install + `cmake --install` of usd-motion-plugins
# -> cmake -> cmake --build -> ctest
#
# is this repository's plain-CMake contract (docs/reference/
# SUPPORTED_CONFIGURATIONS.md, "Plain CMake"), and every other lane here runs
# after `ost` has materialized the dependencies and activated the runtime. That
# activation can hide a real defect, and did: the published execMotion library
# opens only when the platform loader path names OpenUSD, which `ost test` sets
# and the suites' own environment did not (cmake/UsdVrmExecMotion.cmake). This
# lane found it on its first local run.
#
# WHAT IT COPIES: NOTHING. Every input is read from the file that already pins it
# (scripts/plain_cmake_inputs.py): the OpenUSD install is the Linux workspace
# cell's `runtime_artifact` in openstrata.ci.yaml, fetched by digest over HTTPS
# and extracted -- an ordinary OpenUSD prefix; the usd-motion-plugins commit is
# the one the pinned packages' SLSA provenance names, and it is built from
# source and installed with plain CMake; execMotion is execVrm's pinned bundle.
# When the pins move, this lane moves with them.
#
# One platform on purpose. What is proved is the dependency contract, not
# platform coverage -- the ost lanes carry three platforms.
#
# Fork-PR safety: this workflow never publishes, never promotes, and uses no
# secrets. Every artifact it reads is public.
name: plain cmake

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

env:
# The ost cell whose runtime this lane mirrors.
CELL: workspace-pr-linux

jobs:
plain-cmake:
name: plain CMake, no ost (linux)
runs-on: ubuntu-24.04
steps:
- name: Check out the repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Refuse to run with ost on PATH
shell: bash
run: |
if command -v ost; then
echo "::error title=plain cmake::ost is on PATH; this lane must not be able to call it"
exit 1
fi

- name: Check the CMake dependency boundary
# Static, before anything is fetched: a member reaching a package it
# may not, or the root resolving one for it, fails in seconds.
shell: bash
run: |
python3 scripts/check_cmake_boundaries.py --selftest
python3 scripts/check_cmake_boundaries.py

- name: Fetch the OpenUSD install the CI contract pins
id: openusd
shell: bash
run: python3 scripts/plain_cmake_inputs.py openusd --cell "$CELL" --out "$RUNNER_TEMP/openusd" | tee -a "$GITHUB_OUTPUT"

- name: Install the Python this OpenUSD was built against, and the host packages
id: python
# AN OPENUSD INSTALL IS NOT RELOCATABLE ACROSS PYTHONS. Its CMake
# package names the Python it was built against by absolute path:
# pxrConfig.cmake defaults Python3_LIBRARY/_INCLUDE_DIR to it, and
# pxrTargets.cmake bakes its include directory into the
# INTERFACE_INCLUDE_DIRECTORIES of gf, usd and the rest -- here
# /usr/include/python3.13, the Ubuntu 24.04 + deadsnakes Python the
# runtime's producer used. `ost` rewrites those paths when it
# materializes the runtime; this lane does not, so it provides that
# Python where the install expects it, as someone who built OpenUSD on
# their own host has it. (setup-python's interpreter lives elsewhere,
# and the configure then fails at generate time on a non-existent
# include directory even with every Python3_* hint defined.)
#
# MaterialX 1.39.5 (OpenUSD 26.08) exports find_dependency(X11) on
# Linux; that list is the cell's `host_packages`.
shell: bash
env:
PYTHON_VERSION: ${{ steps.openusd.outputs.python }}
HOST_PACKAGES_APT: ${{ steps.openusd.outputs.apt }}
run: |
set -euo pipefail
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y --no-install-recommends ninja-build \
"python${PYTHON_VERSION}" "python${PYTHON_VERSION}-dev" $HOST_PACKAGES_APT
echo "python-path=/usr/bin/python${PYTHON_VERSION}" | tee -a "$GITHUB_OUTPUT"

- name: Resolve the usd-motion-plugins commit the pinned packages were built from
id: motion
shell: bash
run: python3 scripts/plain_cmake_inputs.py motion-source --target "${{ steps.openusd.outputs.target }}" | tee -a "$GITHUB_OUTPUT"

- name: Check out usd-motion-plugins at that commit
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: ${{ steps.motion.outputs.repository }}
ref: ${{ steps.motion.outputs.revision }}
path: _deps/usd-motion-plugins

- name: Build and install usd-motion-plugins with plain CMake
shell: bash
# Python3_EXECUTABLE: pxrConfig.cmake would otherwise default it to the
# producer's own interpreter path, which this host does not have.
run: |
set -euo pipefail
cmake -S _deps/usd-motion-plugins -B "$RUNNER_TEMP/build-motion" -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$RUNNER_TEMP/openusd" \
-DPython3_EXECUTABLE="${{ steps.python.outputs.python-path }}" \
-DCMAKE_INSTALL_PREFIX="$RUNNER_TEMP/motion" \
-DUSDMOTION_BUILD_TESTS=OFF \
-DUSDMOTION_BUILD_EXEC_MOTION=OFF
cmake --build "$RUNNER_TEMP/build-motion" --parallel
cmake --install "$RUNNER_TEMP/build-motion"

- name: Check the installed motion packages know no VRM
shell: bash
run: python3 scripts/check_cmake_boundaries.py --motion-include "$RUNNER_TEMP/motion/include"

- name: Fetch the execMotion bundle execVrm pins
id: exec-motion
shell: bash
run: python3 scripts/plain_cmake_inputs.py bundle --id execMotion --target "${{ steps.openusd.outputs.target }}" --out "$RUNNER_TEMP/execMotion" | tee -a "$GITHUB_OUTPUT"

- name: Configure usd-vrm-plugins
shell: bash
run: |
cmake -S . -B build-plain -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
"-DCMAKE_PREFIX_PATH=$RUNNER_TEMP/openusd;$RUNNER_TEMP/motion" \
-DPython3_EXECUTABLE="${{ steps.python.outputs.python-path }}" \
-DUSDVRM_EXEC_MOTION_ROOT="${{ steps.exec-motion.outputs.root }}"

- name: Build
shell: bash
run: cmake --build build-plain --parallel

- name: Test
shell: bash
run: ctest --test-dir build-plain --output-on-failure --parallel 4
69 changes: 69 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,67 @@ Current schema contract version: **1**.

## [Unreleased]

### Added

- **A plain-CMake lane with no `ost` in it** —
[`.github/workflows/plain-cmake.yml`](.github/workflows/plain-cmake.yml).
On Linux it builds and tests the workspace from an OpenUSD 26.08 install
and a `cmake --install` of `usd-motion-plugins`, and refuses to run if
`ost` is on `PATH`. It copies no pin.
[`scripts/plain_cmake_inputs.py`](scripts/plain_cmake_inputs.py) reads the
OpenUSD archive from the Linux workspace cell in `openstrata.ci.yaml` and
the `execMotion` bundle from `execVrm`'s descriptor, and fetches both by
digest. It builds `usd-motion-plugins` from the commit that the pinned
packages' SLSA provenance names, so the lane moves when the pins move.
Measured locally in a clean `ubuntu:24.04` container: 40/40, the same suite
that `ost test` runs. The lane installs deadsnakes' `python3.13-dev`, not
setup-python, because an OpenUSD install's CMake package names its build
Python by absolute path, in `pxrConfig.cmake` and in `pxrTargets.cmake`'s
include directories. `ost` rewrites those paths when it materializes a
runtime; a plain build has to supply that Python where the install expects
it (docs/reference/SUPPORTED_CONFIGURATIONS.md, "Plain CMake").
- **A CMake dependency-boundary audit**:
[`scripts/check_cmake_boundaries.py`](scripts/check_cmake_boundaries.py),
registered as `workspace_cmake_boundaries` plus a self-test and run first in
the plain lane. It checks the build graph and needs no build. It fails on:
- a source tree of another repository (`add_subdirectory` out of the repo,
`FetchContent`, `ExternalProject`);
- a `usd-motion-plugins` identity built here;
- the root resolving a consumed package;
- a member reaching a package that WORKSPACE.md §2 does not allow it. The
VRM importer may reach no motion package, and the `.vrma` importer may
reach neither `vrmRig` nor `motionRetarget`;
- a member whose resolved, linked and included packages are not the same
set;
- a descriptor whose `requires.libraries` disagrees with its CMake.

Given an installed `usd-motion-plugins` `include/`, it also fails on any
code there that knows VRM. Against `main` before this change it reports 17
violations.

### Changed

- **The root `CMakeLists.txt` resolves no consumed package.** Each member
resolves what it links through `usdvrm_consume_package()`
([`cmake/UsdVrmConsumedPackage.cmake`](cmake/UsdVrmConsumedPackage.cmake)).
The root used to `find_package` all five motion packages up front. That
made every configure require every package, including `motionRecording`,
which nothing here includes. Each member now configures and builds on its
own against a prefix holding only its own packages. `usdVrmFileFormat`,
`usdVrmPackageResolver`, `vrmSchema` and `vrmContainer` need no motion
package at all.
- **`execVrm` no longer links `motionSampling` or `motionRecording`**, and its
descriptor no longer pins them. Both were carried from MIG-1, when
`motionRuntime` became two packages, but no source here includes either.
`motionRecording` is no longer consumed by this workspace.
- **`motion_retarget` links `motionCore` by name**, because it includes a
`motionCore/` header. It used to reach that package only through
`motionRetarget`'s link line.
- **`usdvrm_baseline` asks whether it is in the root build**
(`USDVRM_COMPOSED_BUILD`). It used to ask whether `motionCore`'s target was
visible. That check stood in for the real question and would have silently
dropped the gate once the root stopped resolving packages.

- **Every `usd-motion-plugins` pin is v0.5.1**, the release that pushed
`execMotion` and the CLIs to its registry as well as the libraries. The five
library pins in `vrmRig`, `execVrm`, `usdVrmaFileFormat` and
Expand Down Expand Up @@ -327,6 +386,16 @@ Current schema contract version: **1**.

### Fixed

- **Suites that load the consumed `execMotion` now set the loader path**
(`USDVRM_EXEC_MOTION_ENV`,
[`cmake/UsdVrmExecMotion.cmake`](cmake/UsdVrmExecMotion.cmake)). The
published library's `RUNPATH` points at the producer's CI checkout. It
therefore opens only when `LD_LIBRARY_PATH` names OpenUSD, which `ost test`
sets by activating the runtime and a plain CTest run did not. On Linux
outside `ost`, `execVrm_diagnostics` and `workspace_exec_driver` failed:
the plugin never loaded, and the computations came back empty. The plain
lane found this on its first run.

- **The release lane could not package the product since MIG-4.**
`openstrata.toml`'s `release_exclude` still named `mocopi_record`,
`vmc_record` and `vrchat_osc_record`, the three adapter CLIs that left for
Expand Down
84 changes: 59 additions & 25 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@
# Top-level project for usd-vrm-plugins.
#
# This repo is dual-mode by design:
# * OpenStrata-native: `ost plugin build|test plugins/usdVrmFileFormat` drives the bundle
# * OpenStrata-native: `ost build` / `ost test` drive this file, and
# `ost plugin build|test plugins/usdVrmFileFormat` drives one bundle's
# CMakeLists.txt directly against the activated runtime's toolchain.
# * Plain CMake: anyone without OpenStrata can configure THIS file, point
# CMAKE_PREFIX_PATH at an OpenUSD install, and build every bundle. Use the
# * Plain CMake: anyone without OpenStrata can configure THIS file with an
# OpenUSD 26.08 install and a `cmake --install` of usd-motion-plugins on
# CMAKE_PREFIX_PATH, and build and test every member. Use the
# CMakePresets.json here, or:
# cmake -S . -B build -DCMAKE_PREFIX_PATH=<usd-install>
# cmake -S . -B build "-DCMAKE_PREFIX_PATH=<usd-install>;<motion-install>"
# cmake --build build --config Release
# ctest --test-dir build -C Release
# .github/workflows/plain-cmake.yml runs exactly that, with no `ost`.
#
# Each plugin under plugins/<name> is a self-contained CMake project (so `ost
# plugin build` can target it standalone) that is also add_subdirectory()-able
# from here.
# This file orchestrates and nothing else: the project and its version, the
# OpenUSD contract, the member list, and the tests that span members. A
# dependency belongs to the member that links it (cmake/UsdVrmConsumedPackage.cmake).
#
# Each member under libs/, plugins/ and tools/ is a self-contained CMake project
# (so `ost plugin build` / `ost library build` can target it standalone) that is
# also add_subdirectory()-able from here.
cmake_minimum_required(VERSION 3.22)

# Single source of truth for the release version: the repo-root VERSION file.
Expand Down Expand Up @@ -91,24 +99,25 @@ add_subdirectory("libs/vrmContainer")
find_package(pxr REQUIRED CONFIG)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/UsdVrmOpenUsd.cmake")

# The generic motion libraries are consumed, not built (MIG-1..MIG-3).
# `motionCore`, `motionSampling`, `motionRecording`, `motionRetarget` and
# `motionUsd` are published `usd-motion-plugins` artifacts, pinned by digest per target in each
# descriptor that names one; `ost` materializes them and puts
# their prefixes on CMAKE_PREFIX_PATH before this file is configured, so every
# `find_package` below resolves against a package rather than a sibling
# directory. A plain-CMake build resolves them from CMAKE_PREFIX_PATH the same
# way it resolves OpenUSD.
# The generic motion libraries are consumed, not built (MIG-1..MIG-3), and this
# file resolves none of them. `motionCore`, `motionRetarget`, `motionSampling`
# and `motionUsd` are usd-motion-plugins' installed packages: `ost`
# materializes each digest-pinned artifact and puts its prefix on
# CMAKE_PREFIX_PATH, and a plain-CMake build names a `cmake --install` of that
# repository there, the same way it names OpenUSD. Never a sibling source tree.
#
# Resolved once here, after pxr, so the composed build never asks any of their
# configs to define OpenUSD's imported targets a second time. Each member still
# guards its own `find_package` with `if(NOT TARGET ...)`, which is what keeps a
# standalone configure of that member working.
foreach(_consumed IN ITEMS motionCore motionSampling motionRecording motionRetarget motionUsd)
if(NOT TARGET ${_consumed}::${_consumed})
find_package(${_consumed} REQUIRED CONFIG)
endif()
endforeach()
# Each member resolves what it links, through usdvrm_consume_package()
# (cmake/UsdVrmConsumedPackage.cmake), so this build requires exactly the union
# of what its members use -- and a standalone configure of one member requires
# only that member's own. OpenUSD is resolved above first, so no package config
# is ever the one that defines OpenUSD's targets.
#
# Set for the members' workspace-wide tests, which need bundles a standalone
# member configure does not have. A variable rather than a target probe: a
# probe answers "which package happens to be visible here", which is not the
# question and stopped being the same answer when this file stopped resolving
# packages for its members.
set(USDVRM_COMPOSED_BUILD ON)

# What is still built here from this layer: what a VRM rig adds to the
# consumed retarget (WORKSPACE.md §2, §9.5).
Expand Down Expand Up @@ -254,7 +263,10 @@ if(USDVRM_BUILD_TESTS AND USDVRM_EXEC_MOTION_BUNDLE AND TARGET ExecVrm
elseif(USDVRM_BUILD_TESTS)
message(STATUS
"usd-vrm-plugins: no consumed execMotion or no execVrm in this build; "
"skipping the OpenExec parity cases")
"skipping the OpenExec parity cases. A plain-CMake build names an "
"extracted execMotion bundle with -DUSDVRM_EXEC_MOTION_ROOT=<dir>; "
"without one, workspace_ctest_labels reports the labels these cases "
"carry as missing")
endif()

# The live half left with MIG-4. `liveTransport`, `osc`, `motionTracking` and
Expand Down Expand Up @@ -330,6 +342,28 @@ if(USDVRM_BUILD_TESTS AND USDVRM_TEST_PYTHON)
COMMAND "${USDVRM_TEST_PYTHON}"
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/check_ctest_labels.py"
--selftest)

# The CMake dependency boundary (WORKSPACE.md §2) as the build states it:
# what each member resolves, links and includes, against what it may; the
# root resolving nothing on a member's behalf; no source tree of another
# repository. And the consumed packages this build actually resolved,
# read for any code that knows VRM -- whichever prefix they came from, the
# artifact `ost` pulled or a plain `cmake --install`.
set(_boundary_includes)
foreach(_consumed IN ITEMS motionCore motionRetarget motionSampling motionUsd)
if(TARGET ${_consumed}::${_consumed})
list(APPEND _boundary_includes --motion-include
"$<TARGET_PROPERTY:${_consumed}::${_consumed},INTERFACE_INCLUDE_DIRECTORIES>")
endif()
endforeach()
add_test(NAME workspace_cmake_boundaries
COMMAND "${USDVRM_TEST_PYTHON}"
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/check_cmake_boundaries.py"
${_boundary_includes})
add_test(NAME workspace_cmake_boundaries_selftest
COMMAND "${USDVRM_TEST_PYTHON}"
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/check_cmake_boundaries.py"
--selftest)
endif()

install(FILES
Expand Down
7 changes: 4 additions & 3 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
{
"name": "windows-msvc",
"displayName": "Windows / Visual Studio 2022 (plain CMake)",
"description": "Set USD_INSTALL_ROOT to your OpenUSD install (e.g. C:/dev/build/usd2605).",
"description": "Set USD_INSTALL_ROOT to your OpenUSD 26.08 install and USD_MOTION_PREFIX to a cmake --install of usd-motion-plugins.",
"inherits": "base",
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "$env{USD_INSTALL_ROOT}"
"CMAKE_PREFIX_PATH": "$env{USD_INSTALL_ROOT};$env{USD_MOTION_PREFIX}"
},
"condition": {
"type": "equals",
Expand All @@ -34,10 +34,11 @@
{
"name": "linux-ninja",
"displayName": "Linux / Ninja (plain CMake)",
"description": "Set USD_INSTALL_ROOT to your OpenUSD 26.08 install and USD_MOTION_PREFIX to a cmake --install of usd-motion-plugins.",
"inherits": "base",
"generator": "Ninja Multi-Config",
"cacheVariables": {
"CMAKE_PREFIX_PATH": "$env{USD_INSTALL_ROOT}"
"CMAKE_PREFIX_PATH": "$env{USD_INSTALL_ROOT};$env{USD_MOTION_PREFIX}"
},
"condition": {
"type": "equals",
Expand Down
Loading
Loading