* Fix Publish 3MF dialog styling
Use Orca's shared checkbox widget in the Publish 3MF dialog. Keep checkbox labels clickable, preserve toggle event propagation and disabled-row state, and use Windows-only double buffering on the tab page hosts to reduce flicker during page switches.
Also align the dialog's guide-link color with existing Orca dialogs.
* Fix Publish 3MF dialog styling
Use Orca's shared checkbox widget in the Publish 3MF dialog. Keep checkbox labels clickable, preserve toggle event propagation and disabled-row state, and use Windows-only double buffering on the tab page hosts to reduce flicker during page switches.
Also align the dialog's guide-link color with existing Orca dialogs.
* match font size and left margins
---------
Co-authored-by: yw4z <ywsyildiz@gmail.com>
* init
* drop usage of StaticGroup for ExtruderGroup
* completely remove StaticGroup from project
* fix alignment of "Not installed" text
* fix crash on linux while clicking edit button
* Fix background color on macOS
---------
Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
Merged by /bot merge on behalf of @inslogic3d (id 321604763).
Grants: resources/profiles/OrcaFilamentLibrary/filament/INSLOGIC, resources/profiles/OrcaFilamentLibrary.json
Head: 22a51b32f0
libslic3r_version.h defines ORCA_CHECK_GCODE_PLACEHOLDERS from the CMake
option, 0 by default, and GCode.hpp then forces it to 1 whenever NDEBUG
is undefined. Clang reports the second definition under
-Wmacro-redefined, which is on by default, so since -Werror (#15660)
every clang Debug build fails at the libslic3r files that include
GCode.hpp. Release and RelWithDebInfo define NDEBUG and never compile
the override, which is why no CI configuration sees it. The override
dates from #3861 and has warned in every Debug build since.
Undefine the macro before overriding it. Debug builds get the same
value the redefinition already produced, so nothing else changes.
Follow-up to #15749, refs #15748.
fix(build): drop two unused lambda captures that break non-Release builds
Both handlers capture this and never use it. They sit inside
#if !BBL_RELEASE_TO_PUBLIC, which CMakeLists defines as $<CONFIG:Release>, so
the code compiles in Debug and RelWithDebInfo but not in Release. Clang warns
on an unused capture under -Wall, and since every warning became an error the
two captures fail any clang build that is not Release - an Xcode scheme on its
default Debug configuration, for instance. The CI matrix builds Release, where
the block does not exist, and GCC does not implement the warning at all, so
nothing in CI can see it.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Description
<!--
> Please provide a summary of the changes made in this PR. Include
details such as:
> * What issue does this PR address or fix?
> * What new features or enhancements does this PR introduce?
> * Are there any breaking changes or dependencies that need to be
considered?
-->
On windows, after installing and loading a plugin, if you try to
unsubscribe from a loaded plugin, and on refresh, it will be an orphaned
plugin.
# Screenshots/Recordings/Graphs
<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->
On unsubscribing from a loaded cloud plugin
<img width="1418" height="862" alt="image"
src="https://github.com/user-attachments/assets/9ba8353c-1645-4b21-86ff-2ed235f4d259"
/>
On plugin refresh
<img width="1418" height="862" alt="image"
src="https://github.com/user-attachments/assets/fd58c144-7970-4448-ba3b-e72e52980467"
/>
## Tests
<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->
<!--
> A guide for users on how to download the artifacts from this PR.
-->
[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
# Description
Adds the CI half of the profile OTA pipeline: a push-triggered workflow
that
rebuilds a vendor's binary preset cache (`<vendor>.opc`) whenever its
profile
changes on `main` / `release/*`, and publishes it as a versioned release
asset
for OrcaCloud's OTA Manager to pick up.
### `.github/workflows/post_merge_profiles.yml` (new)
Push-triggered counterpart to `check_profiles.yml` (which only gates
PRs):
- Diffs the push to find which vendors under `resources/profiles/**`
changed.
- Reads the Orca version from `version.inc` and each vendor's 4-part
`version`
from `resources/profiles/<vendor>.json` (fails the run if it isn't
`A.B.C.D`).
- Downloads the prebuilt `generate_system_cache` from this repo's
`nightly-builds` release and builds one `<vendor>.opc` per changed
vendor.
- Packages each as
`<orca_ver>_<vendor>_<profile_version>_<UTCyyyymmddHHMM>.zip` (zip root
`<vendor>.opc`) — the asset-name contract OrcaCloud's release scanner
expects.
- Uploads them to a per-Orca-version release on the profiles repo via a
scoped
GitHub App token.
It stops there: no changelog, no R2, no OTA webhook — a maintainer still
publishes from the OTA Manager. Job is guarded to
`OrcaSlicer/OrcaSlicer`;
workflow permissions are `contents: read` (the cross-repo write uses the
App
token only).
### `.github/workflows/build_orca.yml`
Two steps on the Linux leg: upload `generate_system_cache` as a CI
artifact,
and (on `main`) deploy it to the `nightly-builds` release as
`generate_system_cache_Linux_Ubuntu2404_nightly` so the workflow above
has a
tool to download. `.opc` is 64-bit little-endian and
platform-independent, so
only the Linux binary is shipped.
### `src/dev-utils/generate_system_cache.cpp`
New `-v` / `--vendor` option to generate the cache for a single vendor
(plus the
always-loaded Orca filament library) instead of all vendors, and an
error if the
named vendor produced no `.opc` (catches typos). Reuses
`PresetBundle::set_vendor_to_validate()` from #14217.
## Operational prerequisites
- Repo secrets `PROFILES_APP_ID` / `PROFILES_APP_PRIVATE_KEY` for a
GitHub App
with `contents: write` on the target profiles repo.
- `env.PROFILES_OWNER` / `env.PROFILES_REPO` in
`post_merge_profiles.yml` must
point at the production profiles repo OrcaCloud reads.
- `generate_system_cache_Linux_Ubuntu2404_nightly` only appears after
the first
post-merge nightly `build_orca` run; a profile-only push before then
fails at
the download step.
## Screenshots/Recordings/Graphs
n/a — CI only.
## Tests
Exercised end-to-end in a staging environment: per-vendor `.opc` zips
published
in the expected `<orca_ver>_<vendor>_<profile_version>_<timestamp>.zip`
layout,
and `generate_system_cache -v <vendor>` confirmed to emit only that
vendor's
`.opc`.
[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
# Description
Adds a sketch-first parametric CAD tab to the slicer: sketch → constrain
→ solid features
→ commit to plate. The feature recipe is persisted inside the 3MF, so
reopening a project
restores an editable model rather than a frozen mesh.
Opening this at @SoftFever's request, so the code is easier to read than
a fork.
**The number worth reading first:** the diff is large, but almost all of
it is new files.
Existing upstream code is touched in **23 files, +622 / -88 total**.
That is the entire
negotiable surface. The largest single one is `GLCanvas3D.cpp` at
+149/-14 (a pick path for
the CAD viewport); everything else is under 60 lines.
One thing about the raw diff: the file count includes everything new,
and the negotiable
surface is the 23 modified files above. Thanks for merging `main` in —
the branch is current
again, and I have kept building on top of it.
The regenerated i18n catalogues (`OrcaSlicer.pot`, `OrcaSlicer_it.po`,
`list.txt`) have been
kept OUT of this branch deliberately — they were 27,314 added lines of
build product standing
between you and the code. They regenerate from source with
`scripts/run_gettext.sh` whenever
you want them refreshed. A Romanian catalogue that had been riding along
was pulled out at
the same time — a translation has no business being reviewed inside a
CAD feature PR.
| | |
|---|---|
| Kernel | OCCT — already linked for STEP import. The dependency delta
is one line: `BUILD_MODULE_ModelingAlgorithms=OFF → ON`. Measured cost
in
[`docs/cad_dependency_weight.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/cad_dependency_weight.md)
|
| Constraint solver | vendored SolveSpace `libslvs` subset, 21 files /
~10k lines under `src/libslic3r/slvs/` |
| Build gate | `SLIC3R_CAD` (default ON). With it OFF the tab is not
compiled and the deps prefix matches upstream exactly |
| Persistence | CAD recipe embedded in both the 3MF and BBS-3MF writers
|
| User docs |
[`docs/design_tab.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/design_tab.md)
|
| Interaction model | object-driven — point at geometry, it offers the
verbs that apply:
[`docs/cad_ux_guidelines.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/cad_ux_guidelines.md)
|
### Why it belongs in the slicer
Every round trip through an external CAD tool costs an export, a
re-import, and the design
intent both steps discard. A part changed after slicing should come back
to its feature
history, not to a mesh. Keeping the model in the slicer preserves that
loop — nozzle
diameter, build volume and material are known at design time. Longer
argument in
[`docs/design_tab_upstream_portability.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/design_tab_upstream_portability.md).
### Two things I'd rather you hear from me than find
**Licensing.** The vendored solver is **GPL-3.0**, not LGPL
(`src/libslic3r/slvs/LICENSE`).
The combined work is distributable under AGPL-3.0 and the compatibility
argument is written
out in the portability doc, but this is a project-level decision and I
would like it
confirmed explicitly rather than assumed. If GPL-3.0 in-tree is not
acceptable, the solver
is the separable part — the timeline, features and persistence do not
depend on it.
**One CMake change is larger than it looks.** `CMakeLists.txt` is
+41/-56: it replaces a
hand-maintained list of OCCT DLLs to copy on Windows with a glob plus an
assertion that
every linked toolkit actually has a DLL. The explicit list had already
drifted from what
`libslic3r` links and shipped a portable that died at launch with `error
126`. Happy to
split that out into its own PR if you'd prefer it reviewed separately.
### Not verified
- No automated GUI test. A green kernel run says nothing about the
viewport — synthetic
clicks never drift, so the suite and the UI are two separate realities.
- Card wiring for 9 of the 16 late-wired tools has never been
click-tested.
- The click-test defect rate has not converged: one pass found nothing,
four further days
of work found five more defects. I would not present the quiet pass as
evidence of
stability.
# Screenshots/Recordings/Graphs
One part, start to finish: sketch it, feature it, print it — without
leaving the slicer.

**1. Sketch, constrained and dimensioned.** A 100 × 90 rounded rectangle
drawn straight onto
the bed, R20 corners, live dimensions, and the solver's remaining
degrees of freedom reported
in the panel. The bed is the sketch plane, so the part is sized against
the machine it will be
printed on from the first line.

**2. The feature tree is the part.** `Sketch1 → Extrude2 → Chamfer3 →
Sketch4 → Extrude5 →
Hole6 → Thread7`. Every step stays editable and re-evaluates downstream
— the modelled thread
in the boss is a real helical feature, not a texture.

**3. Committed to the plate.** The same body arrives in Prepare as
`Design Body`,
100 × 90 × 78 mm, 581,634 mm³, ready for a Sovol Zero and PETG. No
export, no re-import, no
lost design intent.

**4. Sliced.** The thread comes out as real helical toolpaths, and the
estimate is 3h26m /
134.54 g. This is the whole argument for the feature in one frame: the
geometry that was
parametric two screens ago is now G-code, and it is still parametric if
you go back.
## Tests
215 `TEST_CASE` blocks across 6 new test files, plus 2 `SCENARIO`s added
to
`tests/libslic3r/test_3mf.cpp` covering the CAD recipe's round trip
through both 3MF
writers. `scripts/kernel-test.sh` is the headless contract: it builds
only
`libslic3r_tests`, needs no display, and exit 0 means the CAD suite
passed.
Happy to slice this differently — kernel + solver first, GUI second — if
that reviews
better for you.
Merged by /bot merge on behalf of @JAYO3D-Official (id 320896770).
Grants: resources/profiles/OrcaFilamentLibrary/filament/JAYO, resources/profiles/OrcaFilamentLibrary.json
Head: fb9a6d70a0
* CLI: --inspect-paint — dump per-facet paint state as JSON
Reads the per-facet enforcer/blocker/extruder/fuzzy-skin state stored
on every ModelVolume (supported_facets / seam_facets /
mmu_segmentation_facets / fuzzy_skin_facets) and emits a structured
JSON summary to stdout. Machine-readable alternative to opening the
paint gizmos.
Per (object, volume, layer, state): facet count, surface area in
mm², and mesh-local bounding box. Empty layers collapse to
{"empty": true}. Summary at the top level rolls up totals.
One correctness detail worth calling out: FacetsAnnotation::
get_facets_strict returns an indexed_triangle_set whose `vertices`
array is the whole source mesh — only `indices` are filtered to the
painted triangles. A naive bounding_box(its) would report the whole
mesh's bbox even when only a few facets are painted. The helper
its_referenced_bbox() walks only the vertices actually indexed by
the painted triangles, so `bbox` correctly localizes the painted
region.
Rationale: every paint-driven workflow — GUI-painted .3mf verified
in CI, AI agents planning support enforcers, MMU color layout checks
— needs to know what's already painted on a model. Today that's a
GUI-only read. --inspect-paint closes that loop for scripted callers.
New file src/slic3r/Utils/PaintCLI.{hpp,cpp} (~215 lines). Depends
only on Model, TriangleMesh, TriangleSelector, FacetsAnnotation, and
nlohmann::json — all already in tree. No new dependencies, no
signature changes, no behavior change when the flag is absent.
Registered as an action (parallel to --info) so it satisfies the
"needs an action" check and bypasses the GUI fallback; control falls
through the normal post-action path to a clean exit 0.
Verification:
unpainted STL: every layer {"empty": true}, summary zero
GUI-painted .3mf: enforcer count / area / bbox match painter
clean JSON: parseable via jq
* CLI --inspect-paint: exit after printing, reject conflicting actions
- Finish like the end of CLI::run once the JSON is written, as the
tooltip says. The callback manager is Linux-only, so its use is
guarded.
- Reject actions that would otherwise be skipped without notice
(--slice, --export-3mf, ...) before loading. Load-time options such as
--uptodate are still accepted.
- Replace invalid UTF-8 in object names and paths instead of throwing.
- Report every input file as sources; inputs are merged into one model
before actions run.
* CLI --inspect-paint: reject a run without input
Without an input file or --load-assemble-list there is nothing to
inspect, and the run printed nothing and exited 0. Reject it up front
with CLI_INVALID_PARAMS, next to the other invalid-parameter checks.
The deps superbuild passes the Visual Studio generator and platform to
every sub-build but not the toolset, so build_win.bat -d -l without -x
compiled every dependency with cl even though the superbuild had been
configured with -T ClangCL; CMake replaces the forwarded
CMAKE_<LANG>_COMPILER with whatever the toolset ran. The recipes that
adapt to clang-cl then disagreed with what had been built, and
wxInspector told FindwxWidgets to look in lib/clang_x64_lib while the
cl-built wxWidgets had installed into lib/vc_x64_lib:
Could NOT find wxWidgets (missing: wxWidgets_LIBRARIES
wxWidgets_INCLUDE_DIRS core base aui propgrid)
Forward CMAKE_GENERATOR_TOOLSET as well, so the dependencies compile
with clang-cl under MSBuild the way they already do under Ninja. Four
of them need more than that:
- OpenSSL always builds with cl, and MSBuild runs its nmake steps in
the project's toolset environment, where ClangCL puts clang's include
directory first and cl trips over clang's stdint.h. The project gets
the default toolset.
- Boost.Container's dlmalloc needs -Wno-incompatible-pointer-types
under clang. boost_container links as C++, and the Visual Studio
generator writes only the link language's flags into the project, so
its C file never saw CMAKE_C_FLAGS. Under that generator the option
goes through the C++ flags as well, with the defaults kept.
- Draco's tools and NLopt's testopt compile sources their own static
library also contains. MSBuild lists libraries before objects and
lld-link resolves archive members as each input arrives, so the
library's copy is pulled in before the executable's own object and
the link fails on duplicate symbols; link.exe defers the search and
Ninja lists the objects first. Nothing uses those executables, so
they get /FORCE:MULTIPLE there.
The Ninja path is unchanged: the generated configure commands of all
29 dependencies are identical before and after. OCCT's arm64 override
to cl still applies under Ninja but not under the Visual Studio
generator, where the toolset wins; that combination never built and is
left for a follow-up.
* Toolchange Cyclic Order
* Apply cyclic order to first layer
* Unit test
* Copilot fixes
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
* ci: build Windows with build_win.bat and drop the old scripts
The deps and slicer jobs called build_release_vs.bat; they now call
build_win.bat. --deps-dir and --build-dir name the build/build-arm64
directories the cache keys and later steps already use, and the
script's own VsDevCmd call replaces the Enter-VsDevShell blocks.
With both stages configured each way into the same directory, the deps
superbuild is byte-identical and the slicer build files are
byte-identical apart from CMakeCache.txt recording how DEP_BUILD_DIR
was set.
Two changes beyond the script swap:
- The compiler is the clang-cl bundled with Visual Studio, the script's
default. The old script's bare "clang-cl" resolved to the LLVM on the
runner image's PATH, 20.1.8 on x64 and 22.1.8 on arm64; both arches
now build with the 22.1.3 VS 18.9 ships. Cached dependencies are only
rebuilt when deps/ changes, so they stay on the LLVM they were built
with; the arm64 leg already links deps built with Clang 19 into a
Clang 22 slicer.
- The deps job no longer zips the dependencies afterwards. The zip was
never uploaded and was not in the cached path.
A failed cmake --build now fails the job. The old script returned 0, so
the arm64 failure fixed in #15719 was reported as success and the
half-built dependencies were saved to the cache.
build_release.bat, build_release_vs.bat and build_release_vs2022.bat are
removed; nothing referenced them any more.
* ci: run Build all when the Windows build script changes; tests doc builds the deps
The push filter of build_all.yml never listed a build script, and CI
now depends on build_win.bat, so it and its test suite join the list
the pull_request filter already has.
tests/AGENTS.md told Windows to run build_win.bat --run-tests, which
only implies -s and stops at the dependency check on a clean checkout.
The old build_release_vs.bat tests built the dependencies first, so
the line now says -ds --run-tests.
* Run every profile maintenance job from one tool
orca_id_tool.py becomes orca_profile_tool.py, and orca_extra_profile_check.py
and orca_filament_lib.py fold into it as subcommands: check, generate-id, fix,
trim, update-index and update-snapshot. The three scripts already overlapped --
the checker imported half of its rules from the id tool, which in turn kept a
copy-pasted set of output helpers to avoid the resulting import cycle -- while
disagreeing on how a vendor is enumerated, how a JSON file is read and what the
exit code means. One file settles all three.
check, normalize, trim and update-index reproduce their predecessors exactly; normalize and
update-index were diffed byte-for-byte against the old scripts over a copy of
the whole tree. Deliberate changes: the compatible-printers check no longer
switches itself off when --check-materials is passed, an error exits 1 rather
than -1, update-index honours --profile-type and reports a profile it cannot
place instead of dropping it from the index, fix and update-index gained
--dry-run, trim keeps an unindexed file some surviving profile still inherits
from, and vendors are enumerated as directories with an index -- which is why
blacklist.json, a data file that an unscoped index rebuild once wrote four empty
list sections into, loses them here and will not collect them again. The dead
rename_filament_system() helper is gone.
The suite under scripts/tests now covers the maintenance commands too, and CI
runs it; nothing there ran in CI before. No shipped profile data changes apart
from those four keys.
* update vendor index files with "python3 ./scripts/orca_profile_tool.py update-index" and "python3 ./scripts/orca_profile_tool.py normalize"
* CLI: --ground-face-* / --lay-flat / --center-on-bed orientation primitives
Adds the CLI counterparts to the GUI's lay-flat / face-pick gizmos.
Scripted / CI / AI pipelines can now set orientation without rendering
a wxWidgets frame; today the only way is a GUI round-trip.
New CLI actions (all operate in the mesh-local frame so they compose
with prior --rotate-* / --orient flags):
--ground-largest-face 1 Auto-detect the largest planar-face
or --lay-flat 1 cluster (area-weighted), rotate so its
normal points -Z. Covers "this part has
one obvious flat side" cases.
--ground-face-normal NX,NY,NZ Pick the face whose mesh-local
normal best matches the given
vector; ground it. e.g.
`--ground-face-normal 1,0,0`
stands a part on its +X side.
--ground-face-point X,Y,Z Find the triangle containing the
given mesh-local point; ground its
face. Disambiguates when several
faces share a normal (largest
containing triangle wins).
--center-on-bed 1 Translate so the XY bounding-box
centroid lands at the bed center
(derived from printable_area).
New file `src/slic3r/Utils/MeshOrient.{hpp,cpp}`:
- collect_triangles_object / compute_face_clusters — quantize
per-triangle normals (0.001, ~0.06°) and area-weighted-average
within clusters. Same clustering logic used by lay-flat.
- apply_ground_rotation — same math as Selection::flattening_rotate
in the GUI (Selection.cpp:1432): world-space quaternion from the
transformed normal to -Z, applied as offset * new_rot * old_no_offset
on every instance of every object, then a per-instance Z-lift so the
grounded face lands at exactly 0 (avoids "No layers were detected"
from FP-error z≈-1e-9).
- ground_face_point uses a top-N cluster search + point-in-triangle
test in local space; largest-area triangle wins on ambiguity.
Rationale: without these, any CLI pipeline that needs a specific
face on the bed must either encode custom rotation math per part or
break out of the pipeline into the GUI. Both are bad for
reproducibility. The --ground-face-* triple + the largest-face
auto-mode cover essentially every orientation intent expressible
in a slicing wizard.
Scope:
- `src/slic3r/Utils/MeshOrient.{hpp,cpp}` — new, ~420 lines
- `src/slic3r/CMakeLists.txt` — 2-line registration
- `src/libslic3r/PrintConfig.cpp` — 5 new CLIMiscConfigDef entries
- `src/OrcaSlicer.cpp` — 58-line handler block + 1 include
No behaviour change when the flags are absent.
(cherry picked from commit c45a9795e1)
* CLI grounding: choose among the Lay on Face planes, per object
Addresses review:
- Move the geometry of GLGizmoFlatten::update_planes() into
libslic3r/LayOnFace and use it from the gizmo and the CLI, so the
--ground-* options pick convex-hull faces per object and instance,
with part transformations (--rotate-x/y) applied.
- Drop --center-on-bed, the --lay-flat alias and MeshOrient; make
--ground-largest-face a coBool.
- Parse --ground-face-normal and --ground-face-point strictly. A point
that only some objects contain grounds those and leaves the others.
- Fold in --inspect-mesh from #14603, reporting the same planes.
- Tests in tests/libslic3r/test_lay_on_face.cpp: bounding boxes before
and after, rotate then ground, two objects, and a ribbed part whose
parallel inner faces outsum its base.
* CLI --inspect-mesh, --ground-face-*: reject missing input and empty values
- Without an input file or --load-assemble-list, --inspect-mesh printed
nothing and exited 0. Reject it up front with CLI_INVALID_PARAMS.
- An explicit empty --ground-face-normal or --ground-face-point was
silently ignored. Only options given on the command line reach the
transforms loop, so an empty value now fails the strict parse like any
other malformed value.
# Description
Add `--strict` for CI and scripted pipelines, and a structured
`warnings`
array in `result.json`.
## `--strict`
A NON_CRITICAL slicing warning is logged and the slice succeeds: return
code
`0`, G-code written. That suits interactive use, but a pipeline then
ships a
slice with a warning nobody saw. With `--strict`, such a warning fails
the run
with `CLI_SLICING_ERROR` before the G-code is exported. Without the
flag,
nothing changes.
In FFF the warning that reaches this path is "support needed but
disabled"
(`PrintObject::generate_support_material`). `--no-check` skips that
check, so
`--strict --no-check` is rejected with `CLI_INVALID_PARAMS`.
`--strict` is read before any work, so it doesn't depend on argument
order and
`result.json` reports it for early failures as well.
## `result.json`
Two new top-level fields:
- `warnings`: `[{"class", ...details}]`. One class is wired:
`slicing_warning_non_critical` with `plate_id` and `text`, recorded
whenever
such a warning fires, with or without `--strict`. The array also fills
on
runs that succeed, so `return_code` stays the verdict.
- `strict_mode`: whether `--strict` was on.
`record_exit_reson` writes `result.json` on Linux only, so both fields
exist
only there. The non-zero exit works on every platform.
## Tests
- `tests/fff_print/test_support_material.cpp` (all platforms): an
overhang
sliced with support off raises the NON_CRITICAL support-needed status,
and
the no-check flag suppresses it.
- `tests/cli/test_cli_strict.sh` (Linux only): runs `orca-slicer`
without
flags, with `--strict`, and with `--strict --no-check`, and checks the
shell
status and `result.json` of each. It runs the built binary, so it
carries the
`RequiresApp` label, which `scripts/run_unit_tests.sh` excludes because
the
unit-test job only receives `build/tests`. Run it with
`ctest --test-dir build/tests -C Release -L RequiresApp`.
- CI: `unit_tests.yml` now passes `Release` on Linux too.
`build_linux.sh`
configures Ninja Multi-Config, and without a config ctest drops the
labels of
plain `add_test()` tests, so this test ran as "Not Run" instead of being
excluded. The docs that assumed Linux was single-config are corrected
too.
Built and run locally on Linux (GCC 14) on current `main`: both tests
pass,
and the touched files compile clean under Clang with `-Werror`.
* ci(flatpak): run the unit suite in a separate job, mirroring the other arches
Alternative to the in-job step: split build and test like the Linux/Windows/
macOS legs. The flatpak build now builds the test binaries in-sandbox (the
action's run-tests fires the module's build-only test-commands), prunes the
kept build tree to the test binaries + CTest metadata + data, and uploads it
with /app as a test asset (size reported to the run summary).
A new unit_tests_flatpak matrix job downloads that asset on a native runner,
restores the module-build symlink, and runs the suite via flatpak-builder
--run (which bind-mounts /run/build so TEST_DATA_DIR resolves) against the
GNOME SDK's bounds-checked STL. Results feed publish_test_results.
Costs a per-arch asset upload/download + a runtime install on the test
runner; the trade-off vs the in-job step is a genuine separate graph box.
* ci(flatpak): run tests via `flatpak build` to avoid rofiles-fuse
`flatpak-builder --run` sets up a rofiles-fuse overlay that this CI container
rejects (Failure spawning rofiles-fuse, exit_status: 256), even in a fresh job
with a machine-id and the runtime installed, and --disable-rofiles-fuse is not
accepted in --run mode. `flatpak build` enters the sandbox via bwrap directly,
so it sidesteps rofiles-fuse; bind-mounting the build tree at /run/build gives
the same path the compiled-in TEST_DATA_DIR expects.
* ci(flatpak): slim the test asset (strip binaries, drop source tree)
The first cut shipped ~1 GB: the test exes carried debug info (the SDK builds
with -g and only the app gets stripped) and the packaged module dir included
the whole copied source tree the tests never read at runtime. Strip the test
binaries and keep only build_flatpak/tests, tests/ (TEST_DATA_DIR) and scripts/.
The irreducible remainder is /app, which the exes link against.
* ci(flatpak): extract the test run into a reusable unit_tests_flatpak workflow
Move the flatpak test job out of build_all.yml into a reusable
unit_tests_flatpak.yml, called once per arch (Flatpak x86_64 / aarch64) the
same way the other arches call unit_tests.yml. build_all.yml keeps only the
build + asset packaging; the reusable workflow downloads the asset, runs the
suite via `flatpak build`, and uploads results as test-results-<artifact> for
publish_test_results. Drops the now-unused manifest checkout (flatpak build
does not need it).
* ci(flatpak): trim comments to the non-obvious
No behavior change.
* ci(flatpak): drop redundant caller comment
* ci(flatpak): drop redundant trim comment
* ci(flatpak): drop size-report scaffolding and redundant if-guards
* ci(flatpak): force the app module to rebuild so the test asset always exists
flatpak-builder caches modules by content hash and skips a hit, producing no
build tree and no test asset, so a re-run of the same commit would leave the
separate test job with nothing to download. Inject a per-run cache-buster into
the OrcaSlicer module's build-options (part of its cache key) so it always
rebuilds, mirroring how the other arches cache only deps and always rebuild the
app and tests. The deps modules stay cached.
* ci(flatpak): trim cache-buster comment, fix stale step name
* fix: guard H2C per-filament array reads against short config arrays
The H2C tool-ordering, wipe-tower, and g-code export paths index per-filament
config arrays by filament/tool id. A config with fewer entries than the filament
count (partial or legacy projects, minimal test configs) makes these reads run
past the end of the vector: silent under a normal STL, but UB that aborts under
the flatpak build's bounds-checked STL (_GLIBCXX_ASSERTIONS).
Route the reads through the existing clamping accessors (get_at,
get_filament_category, is_in_same_extruder) and add a small clamp helper for
filament_change_length. The guards are no-ops when the arrays are sized to the
filament count, so correctly specified configs are unaffected.
* ci(flatpak): build filament_group_tests too
The suite landed on main after this branch was cut and arrived via a later merge,
so it was missing from the target list and ctest failed the leg with
filament_group_tests_NOT_BUILT.
Not tests/all, which build_linux.sh uses: that is a Ninja subdirectory target and
this build configures with the default Makefile generator, where it does not exist.
* ci(flatpak): give the embedded-interpreter tests a valid Python home
python_test_support.hpp sets PyConfig.home to <testdir>/python when that
path resolves. WIN32/APPLE populate it with a copied bundled runtime; the
flatpak leg had no such branch, so home resolved to a directory with no
stdlib and all 21 embedded plugin tests failed at "failed to get the
Python codec of the filesystem encoding".
Symlink <testdir>/python to the bundled /app/libpython that already ships
in the flatpak (the test exe links libpython3.12.so from there via rpath),
so the interpreter initializes without duplicating the runtime.
* ci(flatpak): sync the ToolOrdering guard mirror with #14789
Match #14709's build_filament_group_context guard to the version on
#14789 (size filament_info to filament_nums, truncate filament_ids)
so the folded guard is a byte-identical mirror that drops cleanly when
#14789 merges, instead of leaving a stale hunk that conflicts on rebase.
* fix: guard WipeTower per-filament array reads against short config arrays
The BambuStudio WipeTower sync reintroduced raw per-filament array
indexing that reads out of bounds when a config leaves an array shorter
than the filament count: m_physical_extruder_map in format_line_M104/M109
(indexed even when empty), and m_filament_categories in get_wall_skip_points
and get_wall_filament_for_all_layer. Silent on a normal STL, a hard abort
under the bounds-checked STL the Flatpak build uses.
Bounds-check the physical extruder map before indexing (omitting the T
token, as the existing -1 path already does), and route the two raw
m_filament_categories reads through the clamping get_filament_category()
accessor the surrounding code already uses. No change for correctly-sized
configs.
* fix: default-initialize WallToolPathsParams fields
min_length_factor and is_top_or_bottom_layer had no default initializers, and the FillConcentric/FillConcentricInternal callers never set them, so WallToolPaths::removeSmallLines() thresholded on stack garbage. Which short extrusion lines it dropped then depended on memory layout, so concentric solid-infill output was nondeterministic between runs and across machines. Give every member a default, matching the adjacent FillParams. The perimeter path was already fine because it builds the struct via make_paths_params().
* fix: bounds-check the toolchange flush-volume and HRC per-filament lookups
GCode::set_extruder's toolchange flush-volume lookup and
GCodeProcessor::update_slice_warnings's HRC check index per-filament and
per-extruder arrays (flush_volumes_matrix, the filament map, the nozzle list)
by filament/extruder id. When a config leaves one of those arrays shorter than
the filament count (partial or legacy multi-extruder projects, minimal
configs), the reads run off the end: silent on a normal STL, a hard abort under
_GLIBCXX_ASSERTIONS.
Route both reads through bounds checks: the flush lookup falls back to no flush,
matching the existing unknown-old-filament branch beside it, and the HRC check
skips an unmapped filament, mirroring the required_nozzle_HRC guard on the line
above. When the arrays are sized to the filament count the values are unchanged,
so correctly-specified configs are unaffected.
* ci: retrigger checks
* ci: name the flatpak rebuild token after the cache it defeats
Since #15650 the Flatpak job also has a compiler cache, so a bare
"cache-buster" no longer says which cache is meant. Call it
flatpak_builder_cache_buster, and name the build-dir trim step after
the flatpak-builder cache save it keeps lean.
* ci: ship resources/profiles and resources/printers in the flatpak test asset
Two slic3rutils tests added in 4aa0e1d60b read
resources/printers/bambu_filament_ids.json through PROFILES_DIR/.., and
the asset dropped resources/ entirely, so both failed parsing an empty
stream on each Flatpak leg. Keep the two subtrees the tests reach;
test_gcodewriter's shipped-profile case stops skipping on this leg too.
* ci: restore the CRLF line endings of build_all.yml
The last merge from upstream/main rewrote the file with LF endings, which
turns the 60-line change into a whole-file diff on GitHub. Upstream has had
this file as CRLF since it was created, so put it back.
* ci: trigger Build all on changes to the unit-test workflows
The path filters only matched build_*.yml, so an edit to unit_tests.yml or
unit_tests_flatpak.yml could merge without ever running.
* ci: put a timeout on the flatpak unit-test step
Matches the 20 minutes of the regular unit-test workflow; without it a hung
test holds the runner for the six-hour job default.
VS 2026's ARM64 code generator needs about 27 GB for
_PyUnicode_ToNumeric, a switch with 1951 cases in
Objects/unicodetype_db.h; the same file takes under 1 GB on x64. The
16 GB CI runner has an 18.9 GB commit limit and only gets through when
Windows grows the pagefile on the temp disk in time, so cold arm64
dependency builds fail at random with C1002 "compiler is out of heap
space". build_release_vs.bat returns 0 on failure, so the job still
reports success and the incomplete dependencies are cached.
A property sheet compiles that one file with optimisation off on arm64;
the rest stays whole-program optimised and x64 is unchanged.
MSBuild reads it from PCbuild/msbuild.rsp, which is now written at
configure time and copied in, so a checkout path with spaces works too.