diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 37f3893332..97314233a7 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -6,6 +6,9 @@ on: - 'docs/**' jobs: + # --------------------------------------------------------------------------- + # GUI builds + # --------------------------------------------------------------------------- mac-gui: uses: ./.github/workflows/reusable-build.yml with: @@ -16,12 +19,25 @@ jobs: build-with-python: true artifact-name: SCIRunMacInstaller - mac-headless: + mac-gui-26: uses: ./.github/workflows/reusable-build.yml with: - runner: macOS-latest - variant: headless - build-testing: true + runner: macos-26 + qt-version: '6.10.2' + scirun-qt-min-version: '6.3.1' + variant: gui + build-with-python: true + artifact-name: SCIRunMacInstaller-26 + + mac-gui-26-intel: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macos-26-intel + qt-version: '6.10.2' + scirun-qt-min-version: '6.3.1' + variant: gui + build-with-python: true + artifact-name: SCIRunMacInstaller-26-intel mac-gui-nonpython: uses: ./.github/workflows/reusable-build.yml @@ -43,3 +59,68 @@ jobs: variant: gui with-ospray: true artifact-name: SCIRunMacOsprayInstaller + + # --------------------------------------------------------------------------- + # Headless builds (with testing enabled) + # --------------------------------------------------------------------------- + mac-headless: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-latest + variant: headless + build-testing: true + + mac-headless-14-arm: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-14 + variant: headless + build-testing: true + + mac-headless-14-arm-slim: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-14 + variant: headless + build-testing: true + build-with-python: false + run-unit-tests: true + + mac-headless-15-arm: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-15 + variant: headless + build-testing: true + + mac-headless-15-arm-slim: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-15 + variant: headless + build-testing: true + build-with-python: false + run-unit-tests: true + + mac-headless-15-intel: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-15-intel + variant: headless + build-testing: true + + mac-headless-15-intel-slim: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-15-intel + variant: headless + build-testing: true + build-with-python: false + run-unit-tests: true + + mac-headless-26: + uses: ./.github/workflows/reusable-build.yml + with: + runner: macOS-26 + variant: headless + build-testing: true diff --git a/shapeworks-ci-caching.html b/shapeworks-ci-caching.html new file mode 100644 index 0000000000..191e924be4 --- /dev/null +++ b/shapeworks-ci-caching.html @@ -0,0 +1,189 @@ + + + + + +ShapeWorks CI Caching — and what SCIRun should copy + + + +
+ +
+

CI Engineering Notes

+

How ShapeWorks caches C++ builds in CI

+

A breakdown of the caching strategy in SCIInstitute/shapeworks — what's actually doing the work, what's dead code, and which pattern SCIRun should adopt (it currently caches nothing).

+
+ +
+

ShapeWorks has two layers of caching in its GitHub Actions workflows, but only one is wired into the active pipeline. Knowing which is which matters before copying anything.

+ + + + + + + + + + + + + + + + + + + +
LayerWhat it cachesMechanismStatus
Dependency cacheCompiled 3rd-party C++ libs (ITK, VTK, OpenVDB, etc.)GitHub-native actions/cacheActive — the real win
ccache (per-object compiler cache).o files from their own sourcescp to a self-hosted SSH hostLegacy / dormant
+ +
+
+

🟢 Layer 1 — Dependencies

+

The multi-hour build of ITK/VTK/OpenVDB is cached and reused across every PR and commit. Re-runs only when the dependency build scripts change. This is what keeps their CI fast.

+
+
+

🟡 Layer 2 — ccache

+

A self-hosted scp-tarball scheme. Despite the scripts in the repo, no current workflow calls it and CMake is never told to use it. Effectively dead code from the self-hosted-runner era.

+
+
+
+ +
+

1 Dependency caching — the part that matters

+

Every workflow (build-linux, mac-arm64, mac-intel, windows, linux-debug) uses the same split restore / save pattern:

+ +
- name: Restore Dependencies Cache
+  id: cache-deps-restore
+  uses: actions/cache/restore@v3
+  with:
+    path: /github/home/install        # ~/install on mac, C:\deps on windows
+    key: ${{ runner.os }}-deps-${{ hashFiles(
+      '.github/workflows/Dockerfile',
+      '.github/workflows/gha_deps.sh',
+      'install_shapeworks.sh',
+      'python_requirements.txt',
+      'build_dependencies.sh') }}
+
+- name: Build Dependencies
+  if: steps.cache-deps-restore.outputs.cache-hit != 'true'   # skip on hit
+  run: .github/workflows/gha_deps.sh
+
+- name: Save Dependencies Cache
+  if: steps.cache-deps-restore.outputs.cache-hit != 'true'   # save only on miss
+  uses: actions/cache/save@v3
+  with:
+    path: ...
+    key: ...   # same key
+ +
+
restore@v3pull cache by key
+
+
build (if miss)gated on cache-hit
+
+
save@v3 (if miss)store for next run
+
+ +

Why it works

+
    +
  1. The key hashes the dependency recipe, not the source. It's keyed on the build scripts (build_dependencies.sh, gha_deps.sh, install_shapeworks.sh, requirements files, Dockerfile) — not on the project's .cpp/.h files. So the expensive third-party build is reused across every PR and commit, and only re-runs when someone actually changes how dependencies are built.
  2. +
  3. Split restore + save (not the combined actions/cache@v3), with both the build step and the save step gated on cache-hit != 'true' — the standard "only rebuild on a miss" pattern.
  4. +
  5. Per-variant keys so caches don't collide: -arm64-, -intel-, -deps-debug-, plus osx${MACOSX_DEPLOYMENT_TARGET} and the Linux Docker image hash.
  6. +
  7. A second internal guard: gha_deps.sh itself short-circuits with if [ -d ${DEP_PATH} ] before building anything.
  8. +
+ +
+

Takeaway

+

Cache the output of the expensive, slow-changing thing (third-party deps), keyed on the files that define how it's built. Everything else recompiles cheaply each run.

+
+
+ +
+

2 ccache — don't copy this one

+

common.sh, restore_caches.sh, and store_ccache.sh implement a self-hosted scheme: scp ccache / conda / dep tarballs (pigz tar.gz, or 7z on Windows) to and from a secret SSH host (secrets.SSH_HOST). common.sh sets USE_CCACHE=ON for mac/linux.

+ +
+

But it's effectively dead code

+

Grepping the actual workflow YAMLs, the only ccache reference is brew install ccache in the two Mac jobs. No step calls restore_caches.sh / store_ccache.sh, and CMake is never told to use it (CMAKE_CXX_COMPILER_LAUNCHER=ccache is absent). These scripts are leftovers from an older self-hosted-runner era, superseded by actions/cache.

+
+
+ +
+

3 What this means for SCIRun

+

SCIRun's nine workflows (ccpp.yml, mac.yml, windows.yml, reusable-build.yml, …) use zero caching today — every CI run rebuilds everything from scratch, including the Superbuild externals.

+ +
+

Highest-leverage change

+

Copy the ShapeWorks dependency-cache pattern: cache SCIRun's Superbuild / externals output, keyed on the toolchain + Superbuild CMake files, using the same restore → (build if miss) → save shape.

+
+ + + +

This is especially relevant given SCIRun's C++ modernization work is currently gated on new CI testing jobs landing — faster CI directly unblocks that.

+
+ + + +
+ +