Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ on:
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
Expand All @@ -32,21 +33,35 @@ jobs:
brew untap aws/tap || true
brew install bison flex

- name: Install bison/flex (Windows)
if: runner.os == 'Windows'
# windows-latest ships MSYS2 pre-installed at C:\msys64 (not on
# PATH). Its bison (3.8.2+) satisfies the submodule grammar's
# %require "3.8" -- the Chocolatey winflexbison3 package is stuck
# on bison 3.7.4 and fails that check. The submodule's own
# CMakeLists.txt WIN32 block points BISON_EXECUTABLE/
# FLEX_EXECUTABLE straight at the MSYS2 binaries.
run: C:\msys64\usr\bin\bash.exe -lc "pacman -Sy --noconfirm bison flex"

- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release

# --config/-C Release: a no-op on the single-config generators
# Linux/macOS use (CMAKE_BUILD_TYPE already picked the config), but
# required on Windows's default multi-config Visual Studio
# generator, which ignores CMAKE_BUILD_TYPE entirely.
- name: Build
run: cmake --build build -j
run: cmake --build build --config Release -j

# Bytecode VM on (the default as of the Phase 5 rollout decision --
# see evaluator.hpp's own bytecodeVmEnabled() comment) and off
# (OSCAD_BYTECODE_VM=0), so a regression in either the compiled or
# the interpreted path fails CI, not just whichever happens to be
# default at the time.
- name: Test (bytecode VM on, the default)
run: ctest --test-dir build --output-on-failure
run: ctest --test-dir build --output-on-failure -C Release

- name: Test (bytecode VM off)
run: ctest --test-dir build --output-on-failure
run: ctest --test-dir build --output-on-failure -C Release
env:
OSCAD_BYTECODE_VM: "0"
28 changes: 28 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# ponytail: MSVC always reports __cplusplus as 199711L regardless of the
# real /std: level unless this flag is passed (a long-standing legacy-
# compatibility quirk) -- set it at the outer-project level too (the
# submodule's own CMakeLists.txt sets it for its own targets, but that
# add_compile_options call is directory-scoped and doesn't reach this
# project's own src/tools/tests targets). Several dependencies here
# (nlohmann_json, Manifold, Boost.Polygon) branch on __cplusplus.
if(MSVC)
add_compile_options(/Zc:__cplusplus)
# MSVC's <cmath> only defines M_PI et al. when this is set before the
# first include -- a command-line define guarantees that regardless of
# each translation unit's own include order. Unix libcs define these
# unconditionally (a POSIX extension our code already relies on), so no
# equivalent is needed there.
add_compile_definitions(_USE_MATH_DEFINES)
endif()

add_subdirectory(external/openscad_cpp_parser)

# openscad_cpp_parser's own src/CMakeLists.txt exposes its public headers via
Expand All @@ -24,6 +41,17 @@ include(FetchContent)
# shows single-threaded Boolean ops are a bottleneck. MANIFOLD_CROSS_SECTION
# stays at its own default (ON) -- 2D CrossSection support is needed from
# Phase 3 onward.
#
# BUILD_SHARED_LIBS off: Manifold's own CMakeLists.txt defaults this ON,
# which builds manifold.dll/manifoldc.dll instead of static libs. Harmless
# on Linux/macOS (CMake gives build-tree executables an automatic rpath to
# find a build-tree .so/.dylib), but Windows has no rpath equivalent -- a
# DLL must be either next to the .exe or on PATH, neither of which is true
# for a FetchContent dependency built into its own build/_deps/ tree, so
# every test/CLI executable failed to even start (STATUS_DLL_NOT_FOUND).
# Forcing this off, matching the existing MANIFOLD_TEST override pattern,
# fixes Windows and is a no-op everywhere else this project already worked.
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(MANIFOLD_TEST OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
manifold
Expand Down
1 change: 1 addition & 0 deletions include/openscad_cpp_evaluator/scope_trail.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <unordered_set>
Expand Down
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ target_include_directories(openscad_cpp_evaluator PUBLIC
target_include_directories(openscad_cpp_evaluator PRIVATE ${stb_SOURCE_DIR} ${CMAKE_BINARY_DIR}/generated)

target_link_libraries(openscad_cpp_evaluator PUBLIC openscad_cpp_parser manifold Boost::polygon)
target_compile_options(openscad_cpp_evaluator PRIVATE -Wall -Wextra)
target_compile_options(openscad_cpp_evaluator PRIVATE
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra>
)
1 change: 1 addition & 0 deletions tests/test_cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ TEST(CliDebugRepl, SetOverridesVariableOnResume) {
double v;
while (ls >> v) maxCoord = std::max(maxCoord, std::fabs(v));
}
in.close(); // Windows can't remove() a file while it's still open.
EXPECT_DOUBLE_EQ(maxCoord, 2.0); // would be 10.0 without the override
std::filesystem::remove(src);
std::filesystem::remove(out);
Expand Down
13 changes: 9 additions & 4 deletions tests/test_export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <gtest/gtest.h>

Expand All @@ -15,6 +16,10 @@ using namespace oscadeval::test;

namespace {

std::filesystem::path tempPath(const std::string& name) {
return std::filesystem::temp_directory_path() / ("oscad_eval_test_" + name);
}

std::vector<ColoredBody> evalToBodies(const std::string& code) {
auto ast = parseSrc(code);
auto scope = oscad::buildScopes(ast);
Expand Down Expand Up @@ -55,7 +60,7 @@ StlSummary readStl(const std::string& path) {

TEST(ExportStl, WritesCorrectTriangleCountAndHeader) {
std::vector<ColoredBody> bodies = evalToBodies("cube(2);");
const std::string path = "/tmp/oscad_eval_test_cube.stl";
const std::string path = tempPath("cube.stl").string();
writeStl(path, bodies);

StlSummary s = readStl(path);
Expand All @@ -67,7 +72,7 @@ TEST(ExportStl, WritesCorrectTriangleCountAndHeader) {

TEST(ExportStl, TranslatedCubeBoundsMatch) {
std::vector<ColoredBody> bodies = evalToBodies("translate([1,0,0]) cube(2);");
const std::string path = "/tmp/oscad_eval_test_translate.stl";
const std::string path = tempPath("translate.stl").string();
writeStl(path, bodies);

StlSummary s = readStl(path);
Expand All @@ -78,7 +83,7 @@ TEST(ExportStl, TranslatedCubeBoundsMatch) {

TEST(ExportStl, NoGeometryThrows) {
std::vector<ColoredBody> empty;
EXPECT_THROW(writeStl("/tmp/oscad_eval_test_empty.stl", empty), std::runtime_error);
EXPECT_THROW(writeStl(tempPath("empty.stl").string(), empty), std::runtime_error);
}

// -- toRenderableBodies (Phase 6) ------------------------------------------
Expand All @@ -101,7 +106,7 @@ TEST(ToRenderableBodies, ThinExtrudesABareTopLevel2dShapeSoItCanExportAsStl) {
manifold::Box bbox = renderable[0].body->BoundingBox();
EXPECT_NEAR(bbox.max.z - bbox.min.z, 1e-3, 1e-9);

const std::string path = "/tmp/oscad_eval_test_flat_preview.stl";
const std::string path = tempPath("flat_preview.stl").string();
writeStl(path, renderable);
StlSummary s = readStl(path);
EXPECT_GT(s.triangleCount, 0u);
Expand Down