Files
OrcaSlicer/scripts/CAD/build-gui.sh
T
Tommaso Bianchi 13d5eac891 Move the Design-tab scripts into scripts/CAD/ and name them by role
Requested by SoftFever on PR #15238: ten of these had accumulated loose in
scripts/ next to ~20 unrelated upstream ones, with names that only meant
something to whoever wrote them. They now sit in scripts/CAD/, mirroring the
src/libslic3r/CAD/ and src/slic3r/GUI/CAD/ split, and the verb in the name is
the role: build- produces a binary, start- brings something up, run- runs a
suite, check- asserts one thing against a live app.

  kernel-test.sh        -> CAD/run-kernel-tests.sh
  ladder-all.sh         -> CAD/run-all-checks.sh
  sketch-ladder.py      -> CAD/check-sketch-engine.py
  ladder-corpus.py      -> CAD/check-sketch-engine-corpus.py
  gui-ladder.py         -> CAD/check-gui-sketching.py
  offer-ladder.py       -> CAD/check-gui-context-menu.py
  mcp-sketch-smoke.py   -> CAD/check-mcp-sketch.py
  rig-build.sh          -> CAD/build-gui.sh
  docker-iter-build.sh  -> CAD/build-gui-incremental.sh
  gui-session.sh        -> CAD/start-headless-gui.sh

"Ladder" was the worst of them: it named the shape of the test (rungs of
increasing difficulty) rather than what the test proves, so nothing in the
directory listing told you which one needed a GPU and which was pure kernel.

Every reference rewritten -- the docs, the cross-calls between the scripts,
Dockerfile.deps, and the container-side /OrcaSlicer/scripts paths. The three
shell scripts resolve REPO relative to themselves and now sit one level
deeper, so that walk went from /.. to /../.. . The copies these push into a
container's /tmp were renamed to match, or the container would have kept the
old names alive.

Two runtime paths deliberately NOT renamed. /tmp/orca-rig-build.lock is a
cross-fork contract -- both forks take the same lock so two concurrent builds
serialise instead of OOMing the box, and renaming it on one side silently
removes that guard. /tmp/gui-session.log is a runtime artefact, not a script.

Added scripts/CAD/README.md: what each script proves, what it needs, and the
two constraints that have each cost a session (never build inside the GUI
container; a window manager is required or synthetic keys are ignored).

On CI, which was the other half of the request: the kernel suite is already
there and always has been. The cases are registered in
tests/libslic3r/CMakeLists.txt under if (SLIC3R_CAD), which defaults ON and no
workflow turns off, so they build into libslic3r_tests and run under ctest on
every platform via unit_tests.yml -- like any other unit test, needing no new
job. They have simply never been seen to run, because the workflows on this PR
are still awaiting maintainer approval. run-kernel-tests.sh is the local loop
over the same cases, and it is the only script here CI could run: the other
six need an OpenGL canvas and synthetic input.

Verified: scripts/CAD/run-kernel-tests.sh from its new location, all tests
passed, 2562 assertions in 190 test cases.
2026-08-28 19:34:03 +02:00

99 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Rebuild the GUI binary the design rig launches — in a THROWAWAY container, writing into the
# same build-cache volume the rig's long-lived GUI container reads from.
#
# NEVER build inside the GUI container (snaporca-gui / orcacad-gui). Its baked /OrcaSlicer tree
# is the Jun-13 Snapmaker-derived source, so a `cmake .` in there silently reconfigures the
# shared build dir as project(Snapmaker_Orca) and this fork's targets vanish. That is Trap 1 of
# five; all of them, with symptoms and exact recovery commands, are in docs/rig_build_traps.md.
# Read that file before debugging a configure or link failure this script reports.
#
# Usage:
# scripts/CAD/build-gui.sh # configure + build the fork's GUI target
# DRY_RUN=1 scripts/CAD/build-gui.sh # print the resolved fork identity and exit, no container
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# Fork identity is DERIVED from the repo, never hardcoded, so this file is byte-identical in
# both forks and cannot be mirrored into the wrong one. Pointing a fork at the other fork's
# image or volume is not a slow failure: with the wrong image CMake dies at configure, and with
# the wrong volume the two forks silently trade build artefacts.
PROJECT="$(sed -n 's/^project(\([A-Za-z_0-9]*\)).*/\1/p' "$REPO/CMakeLists.txt" | head -1)"
case "$PROJECT" in
Snapmaker_Orca) PREFIX=snaporca; BIN=snapmaker-orca ;;
OrcaSlicer) PREFIX=orcacad; BIN=orca-slicer ;;
*) echo "FATAL: unrecognised project($PROJECT) in $REPO/CMakeLists.txt" >&2; exit 2 ;;
esac
TARGET="$PROJECT"
IMAGE="${PREFIX}-deps"
BUILD_VOL="${PREFIX}_buildcache"
echo "REPO=$REPO PROJECT=$PROJECT IMAGE=$IMAGE BUILD_VOL=$BUILD_VOL TARGET=$TARGET BIN=$BIN"
if [ -n "${DRY_RUN:-}" ]; then
echo "DRY_RUN: resolution only, no container started"
exit 0
fi
# Three memory bounds. On 2026-08-21 both forks ran this script at the same time, each with
# ninja -j$(nproc)=16: ~36 cc1plus holding 42 GB of a 62 GB box -> global OOM at 21:05, a
# 2h28m kill storm, ssh unreachable, lightdm destroyed, 2946 session kill events. Neither
# build produced a single object. The bounds, weakest to strongest:
# flock — the lock path is shared by both forks on purpose, so they SERIALISE instead of
# summing. Peak is one build's worth no matter who else starts one.
# -j12 — measured 1.17 GB average per cc1plus in the incident dump, so 12 in flight
# is ~14 GB typical and leaves the box usable. JOBS=n overrides.
# --memory — the actual guarantee. A runaway build hits its own cgroup limit and dies alone;
# the host never reaches global OOM again, whatever -j or flock do.
# --memory-swap equal to --memory forbids swap, which is what made ssh hang.
JOBS="${JOBS:-12}"
MEM="${MEM:-40g}"
LOCK=/tmp/orca-rig-build.lock
exec 9>"$LOCK"
if ! flock -n 9; then
echo "another fork's build-gui holds $LOCK — waiting (this is the OOM guard, not a hang)"
flock 9
fi
# Every one of these mounts covers a trap, none is decorative:
# CMakeLists.txt + cmake/ carry the SLIC3R_CAD gate — inherit the baked copies and the cache
# says SLIC3R_CAD=ON while -DSLIC3R_CAD is never defined, so every #ifdef block compiles out.
# deps_src/ carries pybind11, which the image predates.
# src/, resources/, localization/, version.inc are the code under test.
rc=0
docker run --rm \
--memory="$MEM" --memory-swap="$MEM" \
-v "$REPO/src":/OrcaSlicer/src \
-v "$REPO/resources":/OrcaSlicer/resources \
-v "$REPO/cmake":/OrcaSlicer/cmake \
-v "$REPO/deps_src":/OrcaSlicer/deps_src \
-v "$REPO/localization":/OrcaSlicer/localization \
-v "$REPO/CMakeLists.txt":/OrcaSlicer/CMakeLists.txt \
-v "$REPO/version.inc":/OrcaSlicer/version.inc \
-v "$BUILD_VOL":/OrcaSlicer/build \
"$IMAGE" bash -lc "
cd /OrcaSlicer/build || exit 1
cmake . > /tmp/cfg.log 2>&1 || { echo 'CONFIGURE FAILED'; tail -25 /tmp/cfg.log; exit 1; }
# Twice, deliberately. src/libslic3r/CMakeLists.txt publishes OCCT_LIBS as CACHE INTERNAL
# at the END of its own configure, so a first pass after that list changes links the
# PREVIOUS one and drops TKBool/TKOffset — a wall of TopOpeBRepBuild undefined references
# that reads as a broken OCCT install and is not. Trap 4.
cmake . > /tmp/cfg2.log 2>&1 || { echo 'RECONFIGURE FAILED'; tail -25 /tmp/cfg2.log; exit 1; }
ninja -f build-Release.ninja -j$JOBS $TARGET > /tmp/bld.log 2>&1
rc=\$?
echo \"EXIT=\$rc\"
grep -n 'error:' /tmp/bld.log | head -20
tail -4 /tmp/bld.log
ls -la /OrcaSlicer/build/src/Release/$BIN 2>/dev/null
exit \$rc
" || rc=$?
# A target-only build writes src/Release/, but this fork's start-headless-gui.sh may default BIN to the
# PACKAGED path that only build_linux.sh refreshes — launching with the default would then run a
# stale binary. Pass BIN explicitly. See docs/rig_build_traps.md.
echo "=== launch the rig on the binary just built ==="
echo " docker exec -e BIN=/OrcaSlicer/build/src/Release/$BIN ${PREFIX}-gui /OrcaSlicer/scripts/CAD/start-headless-gui.sh"
exit "$rc"