diff --git a/CHANGELOG.md b/CHANGELOG.md index cfeff97..fcac0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ combination in CI: | Shim version | manifold | Clipper2 | Patches shipped | |-----------------------|-----------------------------------------------|----------------------------------------------|-----------------------| +| v0.4.0 | `3ce9622b` (master, includes elalish/manifold#1690) | inherits manifold's pin (manifold owns the FetchContent_Declare) | 0 | | v0.4.0-alpha.1 | `5f95a3ac` (master + vendored elalish/manifold#1690) | inherits manifold's pin (manifold owns the FetchContent_Declare) | 1 (verbatim diff of #1690) | | v0.3.0 | `v3.4.1` | `46f639177fe418f9689e8ddb74f08a870c71f5b4` | 0001 + 0002 + 0003 | | v0.2.0 | `v3.4.1` | `46f639177fe418f9689e8ddb74f08a870c71f5b4` | 0001 + 0002 + 0003 (carried in `test/manifold-link/patches/`; helper not yet present) | @@ -22,7 +23,7 @@ combination in CI: Consumers calling `wasm_cxx_shim_add_manifold()` (introduced in v0.3.0) with no arguments get the row matching their installed shim version. Pinning to other refs is supported via `MANIFOLD_GIT_TAG` / -`CLIPPER2_GIT_TAG` / `EXTRA_*_PATCHES` parameters; see +`EXTRA_MANIFOLD_PATCHES` parameters; see `cmake/WasmCxxShimManifold.cmake`. When upstream PRs land for the carry-patches, the corresponding patch @@ -33,7 +34,36 @@ version where the macro guard appears natively. ## Unreleased -(no changes since v0.4.0-alpha.1) +(no changes since v0.4.0) + +## v0.4.0 — manifold #1690 merged upstream, carry-patch dropped (2026-05-04) + +Manifold's `MANIFOLD_NO_IOSTREAM` build option is now upstream +(merged in [elalish/manifold#1690][pr1690]). The shim drops its +single carry-patch entirely and bumps the manifold pin to a master +commit past the merge. From here, the helper is just a thin wrapper +that sets `MANIFOLD_NO_IOSTREAM=ON` and lets manifold's own option +chain propagate the macros. + +[pr1690]: https://github.com/elalish/manifold/pull/1690 + +### Removed + +- `cmake/manifold-patches/0001-manifold-no-iostream.patch` and the + whole `cmake/manifold-patches/` directory. The vendored #1690 diff + is no longer needed; manifold owns the option upstream. +- `SKIP_BUILTIN_PATCHES` argument from + `wasm_cxx_shim_add_manifold()`. There are no builtin patches to + skip. Callers that were passing it can drop the argument; callers + using `EXTRA_MANIFOLD_PATCHES` continue to work unchanged. +- The `install(DIRECTORY .../manifold-patches ...)` rule (the + directory no longer exists). + +### Changed + +- Default `MANIFOLD_GIT_TAG` bumped to `3ce9622b` (upstream master + HEAD at release time, includes #1690 + one downstream commit). +- Helper smoke test updated for the new file layout. ## v0.4.0-alpha.1 — manifold pin bump + #1690 carry-patch (2026-05-03) diff --git a/CLAUDE.md b/CLAUDE.md index 5ce28cd..aacfb77 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -352,9 +352,8 @@ them. - **`CMAKE_CURRENT_LIST_DIR` inside a function body resolves to the *caller's* location, not the module's.** When writing a CMake helper module that needs to find files it ships alongside (e.g., - `WasmCxxShimManifold.cmake` resolving its sibling - `manifold-patches/` directory), capture the path at module - load-time, OUTSIDE any function: + shipped data, vendored patches, generated configs), capture the + path at module load-time, OUTSIDE any function: ```cmake # at module top-level set(_helper_dir "${CMAKE_CURRENT_LIST_DIR}") diff --git a/CMakeLists.txt b/CMakeLists.txt index c13dd92..5167335 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,14 +120,6 @@ install(FILES DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wasm-cxx-shim ) -# Integration-helper patches. Installed alongside the helper module -# so that wasm_cxx_shim_add_manifold()'s ${CMAKE_CURRENT_LIST_DIR}/ -# manifold-patches/ resolution works uniformly in source + install -# trees. -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/manifold-patches - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wasm-cxx-shim -) - # Install the toolchain file as a convenience for downstream consumers # building C++ libraries against this shim. They pass it as # `-DCMAKE_TOOLCHAIN_FILE=${prefix}/share/wasm-cxx-shim/toolchain-wasm32.cmake`. diff --git a/cmake/WasmCxxShimManifold.cmake b/cmake/WasmCxxShimManifold.cmake index 07d8b23..1b13079 100644 --- a/cmake/WasmCxxShimManifold.cmake +++ b/cmake/WasmCxxShimManifold.cmake @@ -3,8 +3,8 @@ # Helper for consumers building manifold (elalish/manifold) on top of # wasm-cxx-shim for the wasm32-unknown-unknown target. Captures the # high-change-rate parts of the integration cocktail (FetchContent -# pin, the iostream-stripping carry-patch, manifold's CMake options) -# that drift fast across manifold versions. Lower-change-rate parts +# pin, manifold's CMake options) that drift fast across manifold +# versions. Lower-change-rate parts # (the libc++ `__config_site` override, the `` stub header, # and `libcxx-extras.cpp`) stay scoped under the shim's # `test/manifold-link/` for libc++-source-drift insulation reasons @@ -24,8 +24,7 @@ # # wasm_cxx_shim_add_manifold( # MANIFOLD_GIT_TAG # tag or SHA; default = shim's tested pin -# EXTRA_MANIFOLD_PATCHES

... # additional patches to apply -# SKIP_BUILTIN_PATCHES # opt out of the shipped #1690 carry-patch +# EXTRA_MANIFOLD_PATCHES

... # caller-supplied patches to apply # ) # # After the call, the `manifold`, `manifoldc`, and `Clipper2` CMake @@ -49,35 +48,26 @@ # # --- # -# The shipped carry-patch is the verbatim diff of elalish/manifold#1690 -# (adds `MANIFOLD_NO_IOSTREAM` build option + Clipper2 tracking patch) -# against the upstream master commit pinned below. Once #1690 lands and -# the pin moves past it, the patch drops entirely. Until then, this -# helper bakes #1690's design into the shim — manifold's option chain -# does the work, the shim just sets the option ON and lets manifold -# propagate `MANIFOLD_NO_IOSTREAM` / `MANIFOLD_NO_FILESYSTEM` / -# `CLIPPER2_NO_IOSTREAM` as PUBLIC compile defs. +# Manifold's `MANIFOLD_NO_IOSTREAM` option (added upstream in #1690) +# does the work: defining it ON propagates `MANIFOLD_NO_IOSTREAM` / +# `MANIFOLD_NO_FILESYSTEM` / `CLIPPER2_NO_IOSTREAM` as PUBLIC compile +# defs through manifold's and Clipper2's targets. The shim just sets +# the option ON. No carry-patches are shipped for default-pin builds. include_guard(GLOBAL) -# Resolve our own location so the helper finds its shipped patch -# regardless of whether it's loaded from the source tree or from an -# installed package config dir. -set(_wasm_cxx_shim_manifold_helper_dir "${CMAKE_CURRENT_LIST_DIR}") - # Tested-pin default. Bumped when the shim cuts a new release that # verifies a new manifold combination. Source of truth: this file. # Changes here must be paired with a CHANGELOG.md entry + a version -# bump (and re-rolling the carry-patch if upstream master moved -# beneath #1690's diff context). +# bump. set(_wasm_cxx_shim_manifold_default_manifold_tag - "5f95a3ac0e906f596bb2d27a52d005ef60de58f3" + "3ce9622b" CACHE STRING "Default manifold pin used by wasm_cxx_shim_add_manifold()") function(wasm_cxx_shim_add_manifold) cmake_parse_arguments(_WCSAM - "SKIP_BUILTIN_PATCHES" + "" "MANIFOLD_GIT_TAG" "EXTRA_MANIFOLD_PATCHES" ${ARGN}) @@ -91,31 +81,21 @@ function(wasm_cxx_shim_add_manifold) set(_WCSAM_MANIFOLD_GIT_TAG "${_wasm_cxx_shim_manifold_default_manifold_tag}") endif() - # Builtin patch (the vendored #1690 diff) plus user extras. - set(_manifold_patches "") - if(NOT _WCSAM_SKIP_BUILTIN_PATCHES) - list(APPEND _manifold_patches - "${_wasm_cxx_shim_manifold_helper_dir}/manifold-patches/0001-manifold-no-iostream.patch") - endif() - list(APPEND _manifold_patches ${_WCSAM_EXTRA_MANIFOLD_PATCHES}) - include(FetchContent) - # Manifold owns its Clipper2 declaration (manifoldDeps.cmake). - # With the #1690 carry-patch applied, that declaration also - # carries a Clipper2 carry-patch tracking AngusJohnson/Clipper2#1094, - # and sets CLIPPER2_NO_IOSTREAM=ON when MANIFOLD_NO_IOSTREAM is on. - # We don't pre-declare Clipper2 here. + # Manifold owns its Clipper2 declaration (manifoldDeps.cmake) and + # propagates CLIPPER2_NO_IOSTREAM=ON to the bundled Clipper2 when + # MANIFOLD_NO_IOSTREAM is on. We don't pre-declare Clipper2 here. set(_manifold_decl_args GIT_REPOSITORY https://github.com/elalish/manifold.git GIT_TAG ${_WCSAM_MANIFOLD_GIT_TAG} UPDATE_DISCONNECTED TRUE) - if(_manifold_patches) + if(_WCSAM_EXTRA_MANIFOLD_PATCHES) # `git apply` flag set matches manifold-csg's proven recipe: # --ignore-whitespace + --whitespace=nowarn for cross-platform # robustness (CRLF, mixed indentation). list(APPEND _manifold_decl_args - PATCH_COMMAND git apply --ignore-whitespace --whitespace=nowarn ${_manifold_patches}) + PATCH_COMMAND git apply --ignore-whitespace --whitespace=nowarn ${_WCSAM_EXTRA_MANIFOLD_PATCHES}) endif() FetchContent_Declare(manifold ${_manifold_decl_args}) diff --git a/cmake/check-manifold-helper.cmake b/cmake/check-manifold-helper.cmake index 88ad59d..80be484 100644 --- a/cmake/check-manifold-helper.cmake +++ b/cmake/check-manifold-helper.cmake @@ -37,13 +37,5 @@ if(NOT _wasm_cxx_shim_manifold_default_manifold_tag) message(FATAL_ERROR "default manifold tag is empty") endif() -# Shipped carry-patch must resolve. Catches "file moved" / "captured -# the wrong CMAKE_CURRENT_LIST_DIR" / "install rule missed a file". -set(_p "${_wasm_cxx_shim_manifold_helper_dir}/manifold-patches/0001-manifold-no-iostream.patch") -if(NOT EXISTS "${_p}") - message(FATAL_ERROR "shipped patch missing: ${_p}") -endif() - message(STATUS - "helper API smoke OK: default manifold pin=${_wasm_cxx_shim_manifold_default_manifold_tag}, " - "carry-patch resolved") + "helper API smoke OK: default manifold pin=${_wasm_cxx_shim_manifold_default_manifold_tag}") diff --git a/cmake/manifold-patches/0001-manifold-no-iostream.patch b/cmake/manifold-patches/0001-manifold-no-iostream.patch deleted file mode 100644 index be928f9..0000000 --- a/cmake/manifold-patches/0001-manifold-no-iostream.patch +++ /dev/null @@ -1,784 +0,0 @@ -Carry-patch: vendored verbatim diff of elalish/manifold#1690 against -manifold master, providing a `MANIFOLD_NO_IOSTREAM` build option that -strips iostream- and filesystem-using bits from the public API and -tests, plus a tracking patch for AngusJohnson/Clipper2#1094 that -adds the matching `CLIPPER2_NO_IOSTREAM` macro guards in Clipper2. - -When MANIFOLD_NO_IOSTREAM=ON, manifold defines MANIFOLD_NO_IOSTREAM -and MANIFOLD_NO_FILESYSTEM as PUBLIC compile defs on the manifold -target, and sets CLIPPER2_NO_IOSTREAM=ON so the bundled Clipper2 -inherits the same. - -Generated against manifold SHA 5f95a3ac0e906f596bb2d27a52d005ef60de58f3 -(upstream/master HEAD at the time of vendoring). Drops once #1690 -lands and the shim's manifold pin moves past it. - -Apply with: git apply --ignore-whitespace --whitespace=nowarn - 0001-manifold-no-iostream.patch - -diff --git a/.gitattributes b/.gitattributes -new file mode 100644 -index 00000000..888e025b ---- /dev/null -+++ b/.gitattributes -@@ -0,0 +1,4 @@ -+# Carry-patches must keep LF line endings even when checked out on -+# Windows with default core.autocrlf=true; otherwise `git apply` -+# refuses them on EOL mismatch with the (non-CRLF) target tree. -+*.patch text eol=lf -diff --git a/.github/workflows/manifold.yml b/.github/workflows/manifold.yml -index 2df52438..f2603709 100644 ---- a/.github/workflows/manifold.yml -+++ b/.github/workflows/manifold.yml -@@ -175,6 +175,40 @@ jobs: - sudo cmake --install build - ./scripts/test-cmake.sh - -+ build_no_iostream: -+ name: NO_IOSTREAM (clang) -+ timeout-minutes: 20 -+ runs-on: ubuntu-latest -+ steps: -+ - uses: actions/checkout@v6 -+ - name: Install apt packages -+ uses: awalsh128/cache-apt-pkgs-action@v1.6.0 -+ with: -+ packages: cmake clang libgtest-dev -+ - name: Configure + build with MANIFOLD_NO_IOSTREAM=ON, MANIFOLD_TEST=ON -+ run: | -+ cmake \ -+ -DCMAKE_BUILD_TYPE=Release \ -+ -DCMAKE_C_COMPILER=clang \ -+ -DCMAKE_CXX_COMPILER=clang++ \ -+ -DMANIFOLD_NO_IOSTREAM=ON \ -+ -DMANIFOLD_USE_BUILTIN_CLIPPER2=ON \ -+ -DMANIFOLD_STRICT=ON \ -+ -DMANIFOLD_TEST=ON \ -+ -DMANIFOLD_PYBIND=OFF \ -+ . -B build -+ cmake --build build -+ - name: Run manifold_test (iostream-using TESTs are gated out) -+ run: ./build/test/manifold_test -+ - name: Verify conflict guard fires (NO_IOSTREAM + DEBUG) -+ run: | -+ if cmake -DMANIFOLD_NO_IOSTREAM=ON -DMANIFOLD_DEBUG=ON \ -+ -DMANIFOLD_USE_BUILTIN_CLIPPER2=ON \ -+ . -B /tmp/conflict-debug 2>&1; then -+ echo "FAIL: configure should have failed for NO_IOSTREAM + DEBUG" -+ exit 1 -+ fi -+ - build_gcc_codecov: - name: code coverage - timeout-minutes: 45 -diff --git a/CMakeLists.txt b/CMakeLists.txt -index e83223eb..1b543ffb 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -42,6 +42,11 @@ option(MANIFOLD_DEBUG "Enable debug tracing/timing" OFF) - option(MANIFOLD_ASSERT "Enable assertions - requires MANIFOLD_DEBUG" OFF) - option(MANIFOLD_TIMING "Enable Boolean3 phase timing without debug overhead" OFF) - option(MANIFOLD_STRICT "Treat compile warnings as fatal build errors" OFF) -+option( -+ MANIFOLD_NO_IOSTREAM -+ "Strip iostream- and filesystem-using bits from the public API and tests; useful for freestanding/embedded builds. When ON, defines both MANIFOLD_NO_IOSTREAM and MANIFOLD_NO_FILESYSTEM." -+ OFF -+) - option( - MANIFOLD_DOWNLOADS - "Allow Manifold build to download missing dependencies" -@@ -100,6 +105,19 @@ mark_as_advanced(TRACY_MEMORY_USAGE) - mark_as_advanced(MANIFOLD_FUZZ) - mark_as_advanced(ASSIMP_ENABLE) - -+# MANIFOLD_NO_IOSTREAM strips iostream- and filesystem-using bits -+# from the public API and from the test files that use them. -+# Incompatible with options that emit diagnostic output via iostream: -+# MANIFOLD_DEBUG and MANIFOLD_TIMING (both use std::cout). -+# MANIFOLD_TEST=ON is supported — iostream-using TEST(...) blocks -+# in manifold_test/polygon_test/manifoldc_test are gated out under -+# the macro; the test executable still builds and runs the rest. -+if(MANIFOLD_NO_IOSTREAM AND (MANIFOLD_DEBUG OR MANIFOLD_TIMING)) -+ message(FATAL_ERROR -+ "MANIFOLD_NO_IOSTREAM is incompatible with MANIFOLD_DEBUG / MANIFOLD_TIMING " -+ "(those options use std::cout for diagnostic output).") -+endif() -+ - # Always build position independent code for relocatability - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -diff --git a/README.md b/README.md -index e6d33464..5f6ddd8b 100644 ---- a/README.md -+++ b/README.md -@@ -124,6 +124,14 @@ CMake flags (usage e.g. `-DMANIFOLD_DEBUG=ON`): - See profiling section below. - - `ASSIMP_ENABLE=[, ON]`: Enable integration with assimp, which is needed for some of the utilities in `extras`. - - `MANIFOLD_STRICT=[, ON]`: Treat compile warnings as fatal build errors. -+- `MANIFOLD_NO_IOSTREAM=[, ON]`: Strip iostream- and filesystem-using -+ bits from the public API and tests; useful for freestanding/embedded -+ builds (e.g., `wasm32-unknown-unknown`). Defines both -+ `MANIFOLD_NO_IOSTREAM` and `MANIFOLD_NO_FILESYSTEM` as PUBLIC compile -+ definitions. The test suite still builds + runs — iostream-using -+ TESTs in `manifold_test`/`polygon_test`/`manifoldc_test` are gated -+ out under the macro. Incompatible with `MANIFOLD_DEBUG` / -+ `MANIFOLD_TIMING` (which use `std::cout` for diagnostic output). - - Dependency version override: - - `MANIFOLD_USE_BUILTIN_TBB=[, ON]`: Use builtin version of tbb. -diff --git a/bindings/c/CMakeLists.txt b/bindings/c/CMakeLists.txt -index 66158cc6..1641f636 100644 ---- a/bindings/c/CMakeLists.txt -+++ b/bindings/c/CMakeLists.txt -@@ -43,3 +43,14 @@ install( - FILES include/manifold/manifoldc.h include/manifold/types.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/manifold - ) -+ -+# Always-on build-time check: compiles manifold/manifoldc.h with -+# MANIFOLD_NO_IOSTREAM defined. Mirrors src/no_iostream_check.cpp's -+# role for the C++ public header. -+add_library(manifoldc_no_iostream_check OBJECT no_iostream_check.cpp) -+target_link_libraries(manifoldc_no_iostream_check PRIVATE manifoldc) -+if(NOT MANIFOLD_NO_IOSTREAM) -+ target_compile_definitions( -+ manifoldc_no_iostream_check PRIVATE MANIFOLD_NO_IOSTREAM -+ ) -+endif() -diff --git a/bindings/c/include/manifold/manifoldc.h b/bindings/c/include/manifold/manifoldc.h -index 608f6eb1..08ee60d2 100644 ---- a/bindings/c/include/manifold/manifoldc.h -+++ b/bindings/c/include/manifold/manifoldc.h -@@ -542,6 +542,7 @@ void manifold_delete_rect(ManifoldRect* b); - void manifold_delete_triangulation(ManifoldTriangulation* m); - void manifold_delete_execution_context(ManifoldExecutionContext* ctx); - -+#ifndef MANIFOLD_NO_IOSTREAM - // MeshIO / Export - - // Import a manifold from a Wavefront obj file. -@@ -570,6 +571,7 @@ void manifold_write_obj(ManifoldManifold* manifold, - // passing additional data into the callback. - void manifold_meshgl64_write_obj(ManifoldMeshGL64* mesh, - void (*callback)(char*, void*), void* args); -+#endif - #ifdef __cplusplus - } - #endif -diff --git a/bindings/c/manifoldc.cpp b/bindings/c/manifoldc.cpp -index f411de7b..3e6d3fd7 100644 ---- a/bindings/c/manifoldc.cpp -+++ b/bindings/c/manifoldc.cpp -@@ -14,7 +14,9 @@ - - #include "manifold/manifoldc.h" - -+#ifndef MANIFOLD_NO_IOSTREAM - #include -+#endif - #include - - #include "conv.h" -@@ -1048,6 +1050,7 @@ void manifold_destruct_execution_context(ManifoldExecutionContext* ctx) { - - // IO - -+#ifndef MANIFOLD_NO_IOSTREAM - ManifoldManifold* manifold_read_obj(void* mem, char* obj_file) { - std::istringstream iss(obj_file); - Manifold m = Manifold::ReadOBJ(iss); -@@ -1075,6 +1078,7 @@ void manifold_meshgl64_write_obj(ManifoldMeshGL64* mesh, - WriteOBJ(ss, *m); - callback(ss.str().data(), args); - } -+#endif - - #ifdef __cplusplus - } -diff --git a/bindings/c/no_iostream_check.cpp b/bindings/c/no_iostream_check.cpp -new file mode 100644 -index 00000000..455c39e0 ---- /dev/null -+++ b/bindings/c/no_iostream_check.cpp -@@ -0,0 +1,19 @@ -+// Copyright 2026 The Manifold Authors. -+// -+// Licensed under the Apache License, Version 2.0 (the "License"); -+// you may not use this file except in compliance with the License. -+// You may obtain a copy of the License at -+// -+// https://www.apache.org/licenses/LICENSE-2.0 -+// -+// Unless required by applicable law or agreed to in writing, software -+// distributed under the License is distributed on an "AS IS" BASIS, -+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+// See the License for the specific language governing permissions and -+// limitations under the License. -+// -+// Build-time check: compiles manifold/manifoldc.h with MANIFOLD_NO_IOSTREAM -+// defined. Fails the build if iostream usage creeps into the C-API -+// header outside the macro guards. -+ -+#include "manifold/manifoldc.h" -diff --git a/cmake/manifoldDeps.cmake b/cmake/manifoldDeps.cmake -index bf51371a..78ba8f07 100644 ---- a/cmake/manifoldDeps.cmake -+++ b/cmake/manifoldDeps.cmake -@@ -119,6 +119,22 @@ if(MANIFOLD_CROSS_SECTION) - CACHE BOOL - "Preempt cache default of USINGZ (we only use 2d)" - ) -+ # When manifold is built with MANIFOLD_NO_IOSTREAM, also strip -+ # iostream from the bundled Clipper2 — manifold doesn't call any -+ # of Clipper2's stream operators internally, so passing this -+ # through is safe regardless. The CLIPPER2_NO_IOSTREAM macro is -+ # added by the carry-patch below; once Clipper2#1094 lands and -+ # the SHA pin moves past it, the patch drops and the option is -+ # honored natively. -+ if(MANIFOLD_NO_IOSTREAM) -+ set( -+ CLIPPER2_NO_IOSTREAM -+ ON -+ CACHE BOOL -+ "Strip iostream-using overloads from Clipper2 (set by manifold when MANIFOLD_NO_IOSTREAM=ON)" -+ FORCE -+ ) -+ endif() - FetchContent_Declare( - Clipper2 - GIT_REPOSITORY https://github.com/AngusJohnson/Clipper2.git -@@ -127,6 +143,20 @@ if(MANIFOLD_CROSS_SECTION) - GIT_PROGRESS TRUE - SOURCE_SUBDIR - CPP -+ # Disable Windows autocrlf on the clone so the carry-patch (which -+ # is LF-only) applies cleanly. Default core.autocrlf=true on -+ # Windows would convert all LFs to CRLFs in the working tree, and -+ # `git apply` then fails on the line-ending mismatch. -+ GIT_CONFIG -+ core.autocrlf=false -+ # Carry-patch: tracks AngusJohnson/Clipper2#1094 (CLIPPER2_NO_IOSTREAM -+ # macro guards). Drops once that PR lands and the SHA pin moves past -+ # it. Applied via wrapper script so re-configures (which re-trigger -+ # PATCH_COMMAND) don't fail when the patch is already applied. -+ PATCH_COMMAND ${CMAKE_COMMAND} -+ -DPATCH_FILE=${CMAKE_CURRENT_LIST_DIR}/patches/0001-clipper2-no-iostream.patch -+ -DSOURCE_DIR= -+ -P ${CMAKE_CURRENT_LIST_DIR}/patches/apply-clipper2-patch.cmake - ) - FetchContent_MakeAvailable(Clipper2) - set_property( -diff --git a/cmake/patches/0001-clipper2-no-iostream.patch b/cmake/patches/0001-clipper2-no-iostream.patch -new file mode 100644 -index 00000000..4f4c7819 ---- /dev/null -+++ b/cmake/patches/0001-clipper2-no-iostream.patch -@@ -0,0 +1,153 @@ -+Carry-patch: add a CLIPPER2_NO_IOSTREAM build option (off by default) -+that strips iostream-using overloads from Clipper2's public headers, -+and propagate the macro through Clipper2's PUBLIC compile definitions -+so consumers see it. Lets manifold pass MANIFOLD_NO_IOSTREAM=ON -+through to the bundled Clipper2 (e.g., for wasm32-unknown-unknown -+consumers via the wasm-cxx-shim integration). -+ -+Tracks AngusJohnson/Clipper2#1094 — once that lands and manifold's -+Clipper2 SHA pin moves past it, this patch drops. -+ -+Generated against Clipper2 SHA 46f639177fe418f9689e8ddb74f08a870c71f5b4 -+(the SHA manifoldDeps.cmake currently pins). The headers at this SHA -+are byte-identical to upstream main, so the patch tracks #1094's diff -+exactly. -+ -+Apply with: git apply -p1 0001-clipper2-no-iostream.patch -+ -+ -+diff --git a/CPP/CMakeLists.txt b/CPP/CMakeLists.txt -+index 7642e86..b327296 100644 -+--- a/CPP/CMakeLists.txt -++++ b/CPP/CMakeLists.txt -+@@ -17,6 +17,7 @@ option(CLIPPER2_HI_PRECISION "Caution: enabling this will compromise performance -+ option(CLIPPER2_UTILS "Build utilities" ON) -+ option(CLIPPER2_EXAMPLES "Build examples" ON) -+ option(CLIPPER2_TESTS "Build tests" ON) -++option(CLIPPER2_NO_IOSTREAM "Disable iostream-using header overloads" OFF) -+ option(USE_EXTERNAL_GTEST "Use system-wide installed GoogleTest" OFF) -+ option(USE_EXTERNAL_GBENCHMARK "Use the googlebenchmark" OFF) -+ option(BUILD_SHARED_LIBS "Build shared libs" OFF) -+@@ -69,6 +70,7 @@ if (NOT (CLIPPER2_USINGZ STREQUAL "ONLY")) -+ Clipper2 PUBLIC -+ CLIPPER2_MAX_DECIMAL_PRECISION=${CLIPPER2_MAX_DECIMAL_PRECISION} -+ $<$:CLIPPER2_HI_PRECISION> -++ $<$:CLIPPER2_NO_IOSTREAM> -+ ) -+ -+ target_include_directories( -+@@ -95,6 +97,7 @@ if (NOT (CLIPPER2_USINGZ STREQUAL "OFF")) -+ USINGZ -+ CLIPPER2_MAX_DECIMAL_PRECISION=${CLIPPER2_MAX_DECIMAL_PRECISION} -+ $<$:CLIPPER2_HI_PRECISION> -++ $<$:CLIPPER2_NO_IOSTREAM> -+ ) -+ target_include_directories( -+ Clipper2Z PUBLIC -+diff --git a/CPP/Clipper2Lib/include/clipper2/clipper.core.h b/CPP/Clipper2Lib/include/clipper2/clipper.core.h -+index 99a5205..d3af0a0 100644 -+--- a/CPP/Clipper2Lib/include/clipper2/clipper.core.h -++++ b/CPP/Clipper2Lib/include/clipper2/clipper.core.h -+@@ -14,7 +14,9 @@ -+ #include -+ #include -+ #include -++#ifndef CLIPPER2_NO_IOSTREAM -+ #include -++#endif -+ #include -+ #include -+ #include -+@@ -166,11 +168,13 @@ namespace Clipper2Lib -+ -+ void SetZ(const z_type z_value) { z = z_value; } -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ friend std::ostream& operator<<(std::ostream& os, const Point& point) -+ { -+ os << point.x << "," << point.y << "," << point.z; -+ return os; -+ } -++#endif -+ -+ #else -+ -+@@ -203,11 +207,13 @@ namespace Clipper2Lib -+ return Point(x * scale, y * scale); -+ } -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ friend std::ostream& operator<<(std::ostream& os, const Point& point) -+ { -+ os << point.x << "," << point.y; -+ return os; -+ } -++#endif -+ #endif -+ -+ friend bool operator==(const Point& a, const Point& b) -+@@ -396,10 +402,12 @@ namespace Clipper2Lib -+ return result; -+ } -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ friend std::ostream& operator<<(std::ostream& os, const Rect& rect) { -+ os << "(" << rect.left << "," << rect.top << "," << rect.right << "," << rect.bottom << ") "; -+ return os; -+ } -++#endif -+ }; -+ -+ template -+@@ -498,6 +506,7 @@ namespace Clipper2Lib -+ return Rect(xmin, ymin, xmax, ymax); -+ } -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ template -+ std::ostream& operator << (std::ostream& outstream, const Path& path) -+ { -+@@ -518,6 +527,7 @@ namespace Clipper2Lib -+ outstream << p; -+ return outstream; -+ } -++#endif -+ -+ -+ template -+diff --git a/CPP/Clipper2Lib/include/clipper2/clipper.h b/CPP/Clipper2Lib/include/clipper2/clipper.h -+index fe1e299..deb1f7b 100644 -+--- a/CPP/Clipper2Lib/include/clipper2/clipper.h -++++ b/CPP/Clipper2Lib/include/clipper2/clipper.h -+@@ -309,6 +309,7 @@ namespace Clipper2Lib { -+ return true; -+ } -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ static void OutlinePolyPath(std::ostream& os, -+ size_t idx, bool isHole, size_t count, const std::string& preamble) -+ { -+@@ -338,6 +339,7 @@ namespace Clipper2Lib { -+ if (pp.Child(i)->Count()) -+ details::OutlinePolyPathD(os, *pp.Child(i), i, preamble + " "); -+ } -++#endif -+ -+ template -+ inline constexpr void MakePathGeneric(const T an_array, -+@@ -377,6 +379,7 @@ namespace Clipper2Lib { -+ -+ } // end details namespace -+ -++#ifndef CLIPPER2_NO_IOSTREAM -+ inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp) -+ { -+ std::string plural = (pp.Count() == 1) ? " polygon." : " polygons."; -+@@ -399,6 +402,7 @@ namespace Clipper2Lib { -+ if (!pp.Level()) os << std::endl; -+ return os; -+ } -++#endif -+ -+ inline Paths64 PolyTreeToPaths64(const PolyTree64& polytree) -+ { -diff --git a/cmake/patches/apply-clipper2-patch.cmake b/cmake/patches/apply-clipper2-patch.cmake -new file mode 100644 -index 00000000..31518fcd ---- /dev/null -+++ b/cmake/patches/apply-clipper2-patch.cmake -@@ -0,0 +1,32 @@ -+# Idempotent application of the Clipper2 carry-patch. Runs as the -+# PATCH_COMMAND of FetchContent_Declare(Clipper2 ...). Re-runs of -+# `cmake` (e.g., when CMakeLists.txt files in the parent project -+# are edited) reinvoke the patch step; without this idempotency -+# wrapper, `git apply` fails on already-patched files. -+# -+# Invoked via: cmake -DPATCH_FILE= -DSOURCE_DIR= -P this.cmake -+ -+if(NOT PATCH_FILE OR NOT SOURCE_DIR) -+ message(FATAL_ERROR "PATCH_FILE and SOURCE_DIR are required") -+endif() -+ -+# `git apply --reverse --check` succeeds iff the patch is already applied. -+execute_process( -+ COMMAND git apply --reverse --check --ignore-whitespace --whitespace=nowarn "${PATCH_FILE}" -+ WORKING_DIRECTORY "${SOURCE_DIR}" -+ RESULT_VARIABLE _already_applied -+ OUTPUT_QUIET -+ ERROR_QUIET -+) -+if(_already_applied EQUAL 0) -+ return() -+endif() -+ -+execute_process( -+ COMMAND git apply --ignore-whitespace --whitespace=nowarn "${PATCH_FILE}" -+ WORKING_DIRECTORY "${SOURCE_DIR}" -+ RESULT_VARIABLE _apply_result -+) -+if(NOT _apply_result EQUAL 0) -+ message(FATAL_ERROR "Failed to apply Clipper2 carry-patch: ${PATCH_FILE}") -+endif() -diff --git a/include/manifold/manifold.h b/include/manifold/manifold.h -index 20f7c0c0..80c49765 100644 ---- a/include/manifold/manifold.h -+++ b/include/manifold/manifold.h -@@ -273,8 +273,10 @@ using MeshGL = MeshGLP; - */ - using MeshGL64 = MeshGLP; - -+#ifndef MANIFOLD_NO_IOSTREAM - MeshGL64 ReadOBJ(std::istream& stream); - bool WriteOBJ(std::ostream& stream, const MeshGL64& mesh); -+#endif - - /** - * @brief This library's internal representation of an oriented, 2-manifold, -@@ -517,8 +519,10 @@ class Manifold { - * ofile.close(); - * @endcode - */ -+#ifndef MANIFOLD_NO_IOSTREAM - static Manifold ReadOBJ(std::istream& stream); - bool WriteOBJ(std::ostream& stream) const; -+#endif - - /** @name Testing Hooks - * These are just for internal testing. -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index d9bf8963..67cdecb4 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -80,6 +80,7 @@ set( - MANIFOLD_ASSERT - MANIFOLD_TIMING - MANIFOLD_CROSS_SECTION -+ MANIFOLD_NO_IOSTREAM - TRACY_ENABLE - TRACY_MEMORY_USAGE - ) -@@ -94,6 +95,30 @@ else() - target_compile_definitions(manifold PUBLIC MANIFOLD_PAR=-1) - endif() - -+# MANIFOLD_NO_IOSTREAM also defines MANIFOLD_NO_FILESYSTEM (the two -+# track together in practice — `` paths are only useful -+# if you can `` them, which needs iostream). Source code -+# uses the macros separately for semantic clarity (NO_IOSTREAM gates -+# the iostream-using public API; NO_FILESYSTEM gates filesystem use -+# in test_main.cpp's fixture helpers + main()). -+if(MANIFOLD_NO_IOSTREAM) -+ target_compile_definitions(manifold PUBLIC MANIFOLD_NO_FILESYSTEM) -+endif() -+ -+# Always-on build-time check: compiles manifold/manifold.h with -+# MANIFOLD_NO_IOSTREAM defined. Fails if iostream usage creeps into -+# the public header outside the macro guards. Independent of the -+# MANIFOLD_NO_IOSTREAM option's value (just inherits manifold's other -+# PUBLIC defines via target_link_libraries; sets the macro PRIVATE -+# only when the option isn't already setting it PUBLIC). -+add_library(manifold_no_iostream_check OBJECT no_iostream_check.cpp) -+target_link_libraries(manifold_no_iostream_check PRIVATE manifold) -+if(NOT MANIFOLD_NO_IOSTREAM) -+ target_compile_definitions( -+ manifold_no_iostream_check PRIVATE MANIFOLD_NO_IOSTREAM -+ ) -+endif() -+ - target_include_directories( - manifold - PUBLIC -diff --git a/src/impl.cpp b/src/impl.cpp -index ce4a2090..0dfb96a0 100644 ---- a/src/impl.cpp -+++ b/src/impl.cpp -@@ -19,11 +19,15 @@ - #include - #include - #include -+#ifndef MANIFOLD_NO_IOSTREAM - #include -+#endif - #include - #include - #include -+#ifndef MANIFOLD_NO_IOSTREAM - #include -+#endif - - #include "csg_tree.h" - #include "disjoint_sets.h" -@@ -61,6 +65,7 @@ int GetLabels(std::vector& components, - return uf.connectedComponents(components); - } - -+#ifndef MANIFOLD_NO_IOSTREAM - template - double FromChars(T buffer) { - double tmp; -@@ -69,6 +74,7 @@ double FromChars(T buffer) { - iss >> tmp; - return tmp; - } -+#endif - } // namespace - - namespace manifold { -@@ -699,6 +705,7 @@ void Manifold::Impl::IncrementMeshIDs() { - UpdateMeshID({meshIDold2new.D()})); - } - -+#ifndef MANIFOLD_NO_IOSTREAM - static std::ostream& WriteOBJWithEpsilon(std::ostream& stream, - const MeshGL64& mesh, - std::optional epsilon) { -@@ -860,4 +867,5 @@ bool Manifold::WriteOBJ(std::ostream& stream) const { - stream << *this->GetCsgLeafNode().GetImpl(); - return true; - } -+#endif - } // namespace manifold -diff --git a/src/no_iostream_check.cpp b/src/no_iostream_check.cpp -new file mode 100644 -index 00000000..0f0e4f69 ---- /dev/null -+++ b/src/no_iostream_check.cpp -@@ -0,0 +1,24 @@ -+// Copyright 2026 The Manifold Authors. -+// -+// Licensed under the Apache License, Version 2.0 (the "License"); -+// you may not use this file except in compliance with the License. -+// You may obtain a copy of the License at -+// -+// https://www.apache.org/licenses/LICENSE-2.0 -+// -+// Unless required by applicable law or agreed to in writing, software -+// distributed under the License is distributed on an "AS IS" BASIS, -+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+// See the License for the specific language governing permissions and -+// limitations under the License. -+// -+// Build-time check: compiles manifold's public header with -+// MANIFOLD_NO_IOSTREAM defined. Fails the build if iostream usage -+// creeps into the public header outside the macro guards. -+ -+#include "manifold/manifold.h" -+ -+namespace { -+manifold::MeshGL64 _force_meshgl64; -+manifold::Manifold _force_manifold; -+} // namespace -diff --git a/test/boolean_complex_test.cpp b/test/boolean_complex_test.cpp -index 2b83f0a5..b8787027 100644 ---- a/test/boolean_complex_test.cpp -+++ b/test/boolean_complex_test.cpp -@@ -1468,6 +1468,7 @@ TEST(BooleanComplex, Ring) { - EXPECT_EQ(result.Status(), Manifold::Error::NoError); - } - -+#ifndef MANIFOLD_NO_FILESYSTEM - TEST(BooleanComplex, SelfIntersect) { - ManifoldParamGuard guard; - manifold::ManifoldParams().processOverlaps = true; -@@ -1518,6 +1519,7 @@ TEST(BooleanComplex, HullMask) { - Manifold ret = body - mask; - MeshGL mesh = ret.GetMeshGL(); - } -+#endif - - TEST(BooleanComplex, LazyCollider) { - Manifold ele1 = Manifold::Cylinder(50, 50); -diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp -index e8c21be3..8ae2909f 100644 ---- a/test/manifold_test.cpp -+++ b/test/manifold_test.cpp -@@ -334,6 +334,7 @@ TEST(Manifold, ErrorPropagationSimplify) { - EXPECT_EQ(errored.Simplify().Status(), Manifold::Error::NonFiniteVertex); - } - -+#ifndef MANIFOLD_NO_IOSTREAM - TEST(Manifold, ObjRoundTrip) { - Manifold m = Manifold::Cube(); - std::stringstream ss; -@@ -343,6 +344,7 @@ TEST(Manifold, ObjRoundTrip) { - EXPECT_EQ(m2.Status(), Manifold::Error::NoError); - EXPECT_EQ(m2.Volume(), 1); - } -+#endif - - TEST(Manifold, OppositeFace) { - MeshGL gl; -diff --git a/test/manifoldc_test.cpp b/test/manifoldc_test.cpp -index e84eeda6..3a27be2f 100644 ---- a/test/manifoldc_test.cpp -+++ b/test/manifoldc_test.cpp -@@ -1,7 +1,9 @@ - #include "manifold/manifoldc.h" - - #include -+#ifndef MANIFOLD_NO_IOSTREAM - #include -+#endif - - #include "gtest/gtest.h" - #include "manifold/types.h" -@@ -140,6 +142,7 @@ TEST(CBIND, include_pt_mutates_bounds) { - free(box); - } - -+#ifndef MANIFOLD_NO_IOSTREAM - TEST(CBIND, obj_round_trip) { - ManifoldManifold* cube = - manifold_cube(alloc_manifold_buffer(), 1.0, 1.0, 1.0, 1); -@@ -162,6 +165,7 @@ TEST(CBIND, obj_round_trip) { - free(result); - free(buffer); - } -+#endif - - TEST(CBIND, level_set) { - // can't convert lambda with captures to funptr -@@ -205,6 +209,7 @@ TEST(CBIND, level_set) { - ManifoldMeshGL* sdf_mesh = - manifold_get_meshgl(alloc_meshgl_buffer(), sdf_man); - -+#ifndef MANIFOLD_NO_IOSTREAM - if (options.exportModels) { - manifold_write_obj( - sdf_man, -@@ -215,6 +220,7 @@ TEST(CBIND, level_set) { - }, - NULL); - } -+#endif - - EXPECT_EQ(manifold_status(sdf_man), MANIFOLD_NO_ERROR); - EXPECT_EQ(manifold_status(sdf_man_context), MANIFOLD_NO_ERROR); -diff --git a/test/polygon_test.cpp b/test/polygon_test.cpp -index eaf62a27..2e1824fb 100644 ---- a/test/polygon_test.cpp -+++ b/test/polygon_test.cpp -@@ -15,7 +15,9 @@ - #include "manifold/polygon.h" - - #include -+#ifndef MANIFOLD_NO_IOSTREAM - #include -+#endif - #include - - #include "test.h" -@@ -79,6 +81,7 @@ class PolygonTestFixture : public testing::Test { - void TestBody() { TestPoly(polys, expectedNumTri, epsilon); } - }; - -+#ifndef MANIFOLD_NO_IOSTREAM - void RegisterPolygonTestsFile(const std::string& filename) { - auto f = std::ifstream(filename); - EXPECT_TRUE(f.is_open()); -@@ -117,8 +120,10 @@ void RegisterPolygonTestsFile(const std::string& filename) { - } - f.close(); - } -+#endif - } // namespace - -+#ifndef MANIFOLD_NO_IOSTREAM - void RegisterPolygonTests() { - std::string files[] = {"polygon_corpus.txt", "sponge.txt", "zebra.txt", - "zebra3.txt"}; -@@ -132,3 +137,9 @@ void RegisterPolygonTests() { - for (auto f : files) RegisterPolygonTestsFile(dir + "/polygons/" + f); - #endif - } -+#else -+// Stub when MANIFOLD_NO_IOSTREAM is set: polygon corpus tests need -+// std::ifstream to load fixtures, so they're skipped. test_main.cpp -+// still calls RegisterPolygonTests(); this stub keeps the link clean. -+void RegisterPolygonTests() {} -+#endif -diff --git a/test/test_main.cpp b/test/test_main.cpp -index 39321a88..5da56b65 100644 ---- a/test/test_main.cpp -+++ b/test/test_main.cpp -@@ -12,8 +12,10 @@ - // See the License for the specific language governing permissions and - // limitations under the License. - #include -+#ifndef MANIFOLD_NO_FILESYSTEM - #include - #include -+#endif - - #include "manifold/manifold.h" - #include "test.h" -@@ -485,6 +487,7 @@ void CheckGLEquiv(const MeshGL& mgl1, const MeshGL& mgl2) { - } - } - -+#ifndef MANIFOLD_NO_FILESYSTEM - Manifold ReadTestOBJ(const std::string& filename) { - return Manifold(ReadTestMeshGL64OBJ(filename)); - } -@@ -511,3 +514,15 @@ void WriteTestOBJ(const std::string& filename, Manifold m) { - WriteOBJ(f, m.GetMeshGL64()); - f.close(); - } -+#else -+// Stub WriteTestOBJ for MANIFOLD_NO_FILESYSTEM builds: lets the -+// `if (options.exportModels) WriteTestOBJ(...)` call sites keep -+// linking. exportModels defaults false, so the runtime path is dead. -+// -+// ReadTestOBJ / ReadTestMeshGL64OBJ are deliberately NOT stubbed — -+// tests that read fixtures depend on real geometry, and a stub -+// returning an empty Manifold would silently make assertions fail -+// by construction. Callers must be compile-time gated; an unguarded -+// caller fails to link, which is the bright signal we want. -+void WriteTestOBJ(const std::string& /*filename*/, Manifold /*m*/) {} -+#endif diff --git a/test/manifold-link/README.md b/test/manifold-link/README.md index 36326cf..e48e6af 100644 --- a/test/manifold-link/README.md +++ b/test/manifold-link/README.md @@ -41,23 +41,17 @@ Each shim release verifies a specific manifold pin in CI; see `CHANGELOG.md`'s "Tested upstream combinations" table for the mapping. -## Carry-patch +## Carry-patches -Lives under [`cmake/manifold-patches/`](../../cmake/manifold-patches/) -(canonical location — alongside the `wasm_cxx_shim_add_manifold()` -helper that applies it via FetchContent's `PATCH_COMMAND`): - -- **`0001-manifold-no-iostream.patch`** — verbatim vendored diff of - [elalish/manifold#1690](https://github.com/elalish/manifold/pull/1690) - against the pinned manifold commit. Adds a `MANIFOLD_NO_IOSTREAM` - build option that strips iostream- and filesystem-using bits from - manifold's public API and tests, and propagates the matching - `CLIPPER2_NO_IOSTREAM` macro to the bundled Clipper2 (via a tracking - patch for [AngusJohnson/Clipper2#1094](https://github.com/AngusJohnson/Clipper2/pull/1094) - shipped inside #1690 itself). +None at v0.4.0+. Manifold's `MANIFOLD_NO_IOSTREAM` build option is +now upstream +([elalish/manifold#1690](https://github.com/elalish/manifold/pull/1690), +merged 2026-05-04). The helper sets the option ON; manifold owns the +rest, including the bundled Clipper2 carry-patch that mirrors +[AngusJohnson/Clipper2#1094](https://github.com/AngusJohnson/Clipper2/pull/1094). -Once #1690 lands and the shim's manifold pin moves past the merge, -this carry-patch drops entirely. +Callers can still pass `EXTRA_MANIFOLD_PATCHES` to apply their own +patches against the pinned manifold checkout if needed. ## Stub headers @@ -92,10 +86,11 @@ What it took to get green: before user `-isystem` paths, which was breaking libc++'s `` → `` resolution chain. Broadly useful — not manifold-specific. -3. **The vendored #1690 carry-patch** described above — gives manifold - a `MANIFOLD_NO_IOSTREAM` build option that propagates through to - `MANIFOLD_NO_FILESYSTEM` and `CLIPPER2_NO_IOSTREAM`, stripping - stream- and filesystem-using bits from the public API + tests. +3. **`MANIFOLD_NO_IOSTREAM=ON`** — manifold's native build option + (added in elalish/manifold#1690, merged 2026-05-04) propagates + through to `MANIFOLD_NO_FILESYSTEM` and `CLIPPER2_NO_IOSTREAM`, + stripping stream- and filesystem-using bits from the public API + + tests. 4. **Stub `include/mutex`** — no-op `std::mutex`/`recursive_mutex`/ `lock_guard`/`scoped_lock`/`unique_lock` because libc++ gates these behind `_LIBCPP_HAS_THREADS`. @@ -112,14 +107,15 @@ What it took to get green: — defaults are ON and pull in ``, googletest, etc. we don't ship. -## Upstream PR roadmap +## Upstream PR status -The single carry-patch is the verbatim diff of -[elalish/manifold#1690](https://github.com/elalish/manifold/pull/1690), -which itself contains a tracking patch for -[AngusJohnson/Clipper2#1094](https://github.com/AngusJohnson/Clipper2/pull/1094). -Once #1690 lands the patch drops and the shim just bumps the manifold -pin past the merge. +[elalish/manifold#1690](https://github.com/elalish/manifold/pull/1690) +landed 2026-05-04 — the carry-patch dropped at v0.4.0. A bundled +Clipper2 tracking patch for +[AngusJohnson/Clipper2#1094](https://github.com/AngusJohnson/Clipper2/pull/1094) +travels with the manifold pin (manifold owns it via its +`manifoldDeps.cmake` carry-patch). Drops once Clipper2 takes #1094 +and manifold's pin moves past it. ## Opt-in build diff --git a/test/manifold-tests/README.md b/test/manifold-tests/README.md index 88aff91..aaa6449 100644 --- a/test/manifold-tests/README.md +++ b/test/manifold-tests/README.md @@ -100,16 +100,14 @@ Things that may need extending when you do: headers our libcxx subset doesn't ship. Adding such a test means either patching the test source or extending the libcxx subset. -## Carry-patch dependency - -This directory inherits the carry-patch applied at the -`test/manifold-link/` level via the shared -`FetchContent_Declare(manifold ...)` call. The single carry-patch -(`cmake/manifold-patches/0001-manifold-no-iostream.patch`) provides -manifold's `MANIFOLD_NO_IOSTREAM` build option, which transitively -strips iostream/filesystem-using bits from manifold's library code, -its `test/test_main.cpp` fixture helpers, and the bundled Clipper2 -headers. Documented in `test/manifold-link/README.md`. +## Iostream/filesystem stripping + +This directory's tests build with `MANIFOLD_NO_IOSTREAM=ON` (set by +the helper, native upstream option as of manifold#1690). That +transitively strips iostream/filesystem-using bits from manifold's +library code, its `test/test_main.cpp` fixture helpers, and the +bundled Clipper2 headers. No carry-patches needed at v0.4.0+; +documented further in `test/manifold-link/README.md`. ## Build & run