Add MANIFOLD_NO_IOSTREAM build-time option (#1690)
Strips iostream- and filesystem-using bits from the public API and tests, for freestanding/embedded consumers (e.g., wasm32-unknown-unknown via wasm-cxx-shim). Default OFF. When ON, defines MANIFOLD_NO_IOSTREAM and MANIFOLD_NO_FILESYSTEM as PUBLIC compile defs on manifold, gates iostream-using TESTs at compile time, and triggers CLIPPER2_NO_IOSTREAM=ON for the bundled Clipper2 via a carry-patch tracking AngusJohnson/Clipper2#1094 (drops once that lands and the SHA pin moves past it). Incompatible with MANIFOLD_DEBUG / MANIFOLD_TIMING (FATAL_ERROR). Discussion: https://github.com/elalish/manifold/discussions/1046 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
5f95a3ac0e
commit
e73c0781ac
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -124,6 +124,14 @@ CMake flags (usage e.g. `-DMANIFOLD_DEBUG=ON`):
|
||||
See profiling section below.
|
||||
- `ASSIMP_ENABLE=[<OFF>, ON]`: Enable integration with assimp, which is needed for some of the utilities in `extras`.
|
||||
- `MANIFOLD_STRICT=[<OFF>, ON]`: Treat compile warnings as fatal build errors.
|
||||
- `MANIFOLD_NO_IOSTREAM=[<OFF>, 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=[<OFF>, ON]`: Use builtin version of tbb.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
#include "manifold/manifoldc.h"
|
||||
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
#include <sstream>
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -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=<SOURCE_DIR>
|
||||
-P ${CMAKE_CURRENT_LIST_DIR}/patches/apply-clipper2-patch.cmake
|
||||
)
|
||||
FetchContent_MakeAvailable(Clipper2)
|
||||
set_property(
|
||||
|
||||
@@ -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}
|
||||
$<$<BOOL:${CLIPPER2_HI_PRECISION}>:CLIPPER2_HI_PRECISION>
|
||||
+ $<$<BOOL:${CLIPPER2_NO_IOSTREAM}>: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}
|
||||
$<$<BOOL:${CLIPPER2_HI_PRECISION}>:CLIPPER2_HI_PRECISION>
|
||||
+ $<$<BOOL:${CLIPPER2_NO_IOSTREAM}>: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 <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
+#ifndef CLIPPER2_NO_IOSTREAM
|
||||
#include <iostream>
|
||||
+#endif
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
@@ -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<T>& rect) {
|
||||
os << "(" << rect.left << "," << rect.top << "," << rect.right << "," << rect.bottom << ") ";
|
||||
return os;
|
||||
}
|
||||
+#endif
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
@@ -498,6 +506,7 @@ namespace Clipper2Lib
|
||||
return Rect<T>(xmin, ymin, xmax, ymax);
|
||||
}
|
||||
|
||||
+#ifndef CLIPPER2_NO_IOSTREAM
|
||||
template <typename T>
|
||||
std::ostream& operator << (std::ostream& outstream, const Path<T>& path)
|
||||
{
|
||||
@@ -518,6 +527,7 @@ namespace Clipper2Lib
|
||||
outstream << p;
|
||||
return outstream;
|
||||
}
|
||||
+#endif
|
||||
|
||||
|
||||
template <typename T1, typename T2>
|
||||
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<typename T, typename U>
|
||||
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)
|
||||
{
|
||||
@@ -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=<path> -DSOURCE_DIR=<src> -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()
|
||||
@@ -273,8 +273,10 @@ using MeshGL = MeshGLP<float>;
|
||||
*/
|
||||
using MeshGL64 = MeshGLP<double, uint64_t>;
|
||||
|
||||
#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.
|
||||
|
||||
@@ -80,6 +80,7 @@ set(
|
||||
MANIFOLD_ASSERT
|
||||
MANIFOLD_TIMING
|
||||
MANIFOLD_CROSS_SECTION
|
||||
MANIFOLD_NO_IOSTREAM
|
||||
TRACY_ENABLE
|
||||
TRACY_MEMORY_USAGE
|
||||
)
|
||||
@@ -94,6 +95,16 @@ else()
|
||||
target_compile_definitions(manifold PUBLIC MANIFOLD_PAR=-1)
|
||||
endif()
|
||||
|
||||
# MANIFOLD_NO_IOSTREAM also defines MANIFOLD_NO_FILESYSTEM (the two
|
||||
# track together in practice — `<filesystem>` paths are only useful
|
||||
# if you can `<fstream>` 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()
|
||||
|
||||
target_include_directories(
|
||||
manifold
|
||||
PUBLIC
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
#include <iomanip>
|
||||
#endif
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#include "csg_tree.h"
|
||||
#include "disjoint_sets.h"
|
||||
@@ -61,6 +65,7 @@ int GetLabels(std::vector<int>& components,
|
||||
return uf.connectedComponents(components);
|
||||
}
|
||||
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
template <typename T>
|
||||
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<double> epsilon) {
|
||||
@@ -860,4 +867,5 @@ bool Manifold::WriteOBJ(std::ostream& stream) const {
|
||||
stream << *this->GetCsgLeafNode().GetImpl();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
} // namespace manifold
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "manifold/manifoldc.h"
|
||||
|
||||
#include <cmath>
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
#include <fstream>
|
||||
#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);
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#include "manifold/polygon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef MANIFOLD_NO_IOSTREAM
|
||||
#include <fstream>
|
||||
#endif
|
||||
#include <limits>
|
||||
|
||||
#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
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <algorithm>
|
||||
#ifndef MANIFOLD_NO_FILESYSTEM
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user