diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..67cae40 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.25) + +project(FESA VERSION 0.1.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +include(cmake/FesaDependencies.cmake) + +enable_testing() + +add_subdirectory(src/fesa) +add_subdirectory(tests) diff --git a/cmake/FesaDependencies.cmake b/cmake/FesaDependencies.cmake new file mode 100644 index 0000000..0944d96 --- /dev/null +++ b/cmake/FesaDependencies.cmake @@ -0,0 +1,71 @@ +set( + FESA_GTEST_SOURCE_DIR + "" + CACHE PATH + "Path to the approved local GoogleTest source checkout" +) + +if(NOT FESA_GTEST_SOURCE_DIR) + message(FATAL_ERROR "FESA_GTEST_SOURCE_DIR must name a local GoogleTest source checkout") +endif() + +get_filename_component( + _fesa_gtest_source_dir + "${FESA_GTEST_SOURCE_DIR}" + ABSOLUTE + BASE_DIR "${CMAKE_SOURCE_DIR}" +) + +if(NOT EXISTS "${_fesa_gtest_source_dir}/CMakeLists.txt") + message( + FATAL_ERROR + "FESA_GTEST_SOURCE_DIR does not contain a GoogleTest CMakeLists.txt: " + "${_fesa_gtest_source_dir}" + ) +endif() + +# Keep GoogleTest on the same MSVC runtime as FESA without changing its source tree. +set(gtest_force_shared_crt ON CACHE BOOL "Use the shared MSVC runtime for GoogleTest" FORCE) +add_subdirectory( + "${_fesa_gtest_source_dir}" + "${CMAKE_BINARY_DIR}/_deps/googletest-build" + EXCLUDE_FROM_ALL +) + +find_package(MKL CONFIG REQUIRED) +find_package(TBB CONFIG REQUIRED COMPONENTS tbb) +find_package(HDF5 CONFIG REQUIRED) + +if(NOT TARGET MKL::MKL) + message(FATAL_ERROR "The oneMKL CONFIG package did not define MKL::MKL") +endif() + +if(NOT TARGET TBB::tbb) + message(FATAL_ERROR "The oneTBB CONFIG package did not define TBB::tbb") +endif() + +if(TARGET hdf5::hdf5-static) + set(_fesa_hdf5_target hdf5::hdf5-static) +elseif(TARGET hdf5::hdf5-shared) + set(_fesa_hdf5_target hdf5::hdf5-shared) +elseif(TARGET HDF5::HDF5) + set(_fesa_hdf5_target HDF5::HDF5) +else() + message(FATAL_ERROR "The HDF5 CONFIG package did not define a supported C target") +endif() + +# Stable FESA-owned targets keep package-specific target names out of later modules. +add_library(fesa_dependency_mkl INTERFACE) +target_link_libraries(fesa_dependency_mkl INTERFACE MKL::MKL) +add_library(Fesa::MKL ALIAS fesa_dependency_mkl) + +add_library(fesa_dependency_tbb INTERFACE) +target_link_libraries(fesa_dependency_tbb INTERFACE TBB::tbb) +add_library(Fesa::TBB ALIAS fesa_dependency_tbb) + +add_library(fesa_dependency_hdf5 INTERFACE) +target_link_libraries(fesa_dependency_hdf5 INTERFACE "${_fesa_hdf5_target}") +add_library(Fesa::HDF5 ALIAS fesa_dependency_hdf5) + +unset(_fesa_gtest_source_dir) +unset(_fesa_hdf5_target) diff --git a/docs/implementation-plans/linear-static-3d-euler-beam-implementation-report.md b/docs/implementation-plans/linear-static-3d-euler-beam-implementation-report.md new file mode 100644 index 0000000..d457e4a --- /dev/null +++ b/docs/implementation-plans/linear-static-3d-euler-beam-implementation-report.md @@ -0,0 +1,47 @@ +# Linear Static 3D Euler Beam Implementation Report + +## Metadata + +- feature_id: `linear-static-3d-euler-beam` +- source_plan: `docs/implementation-plans/linear-static-3d-euler-beam.md` +- source_design: `docs/superpowers/specs/2026-08-08-linear-static-3d-euler-beam-design.md` +- status: `in-progress` +- owner_agent: `implementation-agent` +- validation_environment: `Windows, MSVC 19.51.36252, Visual Studio 18 2026, x64 Debug` +- report_started: `2026-08-09` + +## Step 7 — cmake-test-foundation + +- task_id: `TASK-07` +- status: `completed` +- changed_files: `CMakeLists.txt`, `cmake/FesaDependencies.cmake`, + `include/fesa/build_info.hpp`, `src/fesa/build_info.cpp`, + `src/fesa/CMakeLists.txt`, `tests/CMakeLists.txt`, + `tests/unit/build_info_test.cpp`, + `docs/implementation-plans/linear-static-3d-euler-beam-implementation-report.md` +- requirement_ids: `FESA-REQ-LS3DEB-030`, `FESA-REQ-LS3DEB-034` +- test_ids: `T07-BUILD-001`, `T07-BUILD-002` + +| stage | exact command | exit_code | expected_or_observed_result | evidence_tail | +| --- | --- | ---: | --- | --- | +| RED | Temporarily move `include/fesa/build_info.hpp` to `.harness/build_info.hpp.red-backup`; run `cmake --build .harness/build --config Debug --target fesa_unit_tests`; restore the header in `finally` | 1 | Build fails because the public API is unavailable | `build_info.cpp(1,10): error C1083: 'fesa/build_info.hpp': No such file or directory` | +| GREEN | `cmake --build .harness/build --config Debug --target fesa_tests`; `ctest --test-dir .harness/build -C Debug -R BuildInfo --output-on-failure` | 0 | Foundation target builds and both named BuildInfo tests pass | `BuildInfo.VersionIsStableAndNonEmpty` and `BuildInfo.PublicHeaderHasNoBackendDependency`: 2/2 passed | +| VERIFY-configure | `cmake -S . -B .harness/build -A x64 -DFESA_GTEST_SOURCE_DIR=C:/git/googletest "-DMKL_DIR=C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl" "-DTBB_DIR=C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb" "-DHDF5_DIR=C:/Program Files/HDF_Group/HDF5/2.1.1/cmake"` | 0 | MSVC x64 Debug build tree generated and dependencies resolved | Visual Studio 18 2026; MSVC 19.51.36252; MKL 2026.1; TBB and HDF5 CONFIG packages resolved | +| VERIFY-build | `cmake --build .harness/build --config Debug` | 0 | FESA and GoogleTest targets build without FESA warnings | `fesa_solver.lib` and `fesa_unit_tests.exe` built; no warning emitted under FESA `/W4 /WX` | +| VERIFY-discovery | `ctest --test-dir .harness/build -C Debug --show-only=json-v1` | 0 | CTest discovers at least one test | 2 tests discovered, both carrying `linear-static-3d-euler-beam` and `unit` labels | +| VERIFY-full | `ctest --test-dir .harness/build -C Debug --output-on-failure` | 0 | Full suite has zero failures | 2/2 tests passed | + +- contract_checks: GoogleTest revision + `04ee1b4f2aefdffb0135d7cf2a2c519fe50dabe4`; no default + `C:/git/googletest` path in production CMake; `/W4 /WX` is private to + `fesa_solver`; public BuildInfo header exposes only `std::string_view`. +- generated_evidence: `.harness/build/src/fesa/Debug/fesa_solver.lib`, + `.harness/build/tests/Debug/fesa_unit_tests.exe` +- environment_note: Native Codex Windows workspace sandboxes stalled in the + CMake compiler-id `cl.exe` child process. The identical approved configure, + build, and CTest commands were therefore executed by the root session's + authorized unrestricted shell; the same configure completed in 7.9 seconds. +- reference_diff: unchanged +- handoff: `fesa_solver`, `fesa_unit_tests`, `fesa_tests`, normalized + `Fesa::MKL`, `Fesa::TBB`, `Fesa::HDF5`, and `solverVersion()` are available + to Step 8. diff --git a/include/fesa/build_info.hpp b/include/fesa/build_info.hpp new file mode 100644 index 0000000..545b906 --- /dev/null +++ b/include/fesa/build_info.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace fesa { + +// Returns the stable solver version written to externally visible result metadata. +std::string_view solverVersion() noexcept; + +} // namespace fesa diff --git a/src/fesa/CMakeLists.txt b/src/fesa/CMakeLists.txt new file mode 100644 index 0000000..6a78be9 --- /dev/null +++ b/src/fesa/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library( + fesa_solver + STATIC + build_info.cpp +) + +target_include_directories( + fesa_solver + PUBLIC + "${PROJECT_SOURCE_DIR}/include" +) + +# Product warnings are strict without imposing FESA policy on external targets. +target_compile_options( + fesa_solver + PRIVATE + $<$:/W4 /WX> +) diff --git a/src/fesa/build_info.cpp b/src/fesa/build_info.cpp new file mode 100644 index 0000000..2cac255 --- /dev/null +++ b/src/fesa/build_info.cpp @@ -0,0 +1,10 @@ +#include "fesa/build_info.hpp" + +namespace fesa { + +std::string_view solverVersion() noexcept { + // Keep this value stable until a reviewed solver release changes the metadata contract. + return "0.1.0"; +} + +} // namespace fesa diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..30ee1f3 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,21 @@ +include(GoogleTest) + +add_executable( + fesa_unit_tests + unit/build_info_test.cpp +) + +target_link_libraries( + fesa_unit_tests + PRIVATE + fesa_solver + GTest::gtest_main +) + +gtest_discover_tests( + fesa_unit_tests + PROPERTIES + LABELS "linear-static-3d-euler-beam;unit" +) + +add_custom_target(fesa_tests DEPENDS fesa_unit_tests) diff --git a/tests/unit/build_info_test.cpp b/tests/unit/build_info_test.cpp new file mode 100644 index 0000000..d3579d4 --- /dev/null +++ b/tests/unit/build_info_test.cpp @@ -0,0 +1,27 @@ +#include "fesa/build_info.hpp" + +#include + +#include +#include +#include +#include + +TEST(BuildInfo, VersionIsStableAndNonEmpty) { + const std::string_view first = fesa::solverVersion(); + const std::string_view second = fesa::solverVersion(); + + EXPECT_FALSE(first.empty()); + EXPECT_EQ(first, second); + EXPECT_TRUE(std::regex_match( + std::string(first), std::regex{R"(^[0-9]+\.[0-9]+\.[0-9]+$)"})); +} + +TEST(BuildInfo, PublicHeaderHasNoBackendDependency) { + static_assert( + std::is_same_v, + "The public BuildInfo API must use only a standard-library value type."); + static_assert(noexcept(fesa::solverVersion())); + + SUCCEED(); +}