From 766ddeac1a01e3dabee9112aaa94d9e051d6b82d Mon Sep 17 00:00:00 2001 From: Nitish Singh <93253740+nitishhsinghhh@users.noreply.github.com> Date: Sat, 30 May 2026 01:18:30 +0530 Subject: [PATCH 1/3] feat: add automated clang-format integration and modernize native orchestration pipeline --- .../CaseConversionAPI/CppLib/CMakeLists.txt | 91 +++++++++++++++---- .../CppLib/CMakeListsLocalApp.txt | 44 +++++++++ .../CppLib/Scripts/Dockerfile | 46 ++++++++-- .../Scripts/orchestrate-native-docker.sh | 65 +++++++++---- .../CppLib/Scripts/orchestrate-native.sh | 27 +++++- .../CppLib/Scripts/run-local-context.sh | 33 ++++++- .../CppLib/include/Client.hpp | 2 +- .../CppLib/include/ConversionResult.hpp | 88 +++++++++--------- .../CppLib/include/ProcessStringDLL.hpp | 7 +- .../Tests/CppTests/AdvStrTestDLL.cpp | 9 +- .../AdvancedStringConversionTests.cpp | 10 +- .../Tests/CppTests/StringConversionTests.cpp | 80 +++++++++------- README.md | 90 +++++++++++++++++- 13 files changed, 454 insertions(+), 138 deletions(-) diff --git a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt index b22b4ed..e092cfb 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt @@ -1,11 +1,55 @@ +# ----------------------------------------------------------------------------- +# CMake Configuration - Hardware-Aware Case Conversion Engine +# Project : StringConversion +# Component : Cross-Platform Native Core + GoogleTest Harness +# Architecture : Static Core + Shared DLL Bridge + CLI + Test Runtime +# ----------------------------------------------------------------------------- +# VERSION HISTORY +# Version | Date | Author | Description +# --------|------------|---------------|---------------------------------------- +# 1.0.0 | 2026-04-14 | Nitish Singh | Initial native orchestration baseline. +# 1.1.0 | 2026-05-09 | Nitish Singh | Added Apple Silicon optimization flags +# | and AddressSanitizer integration. +# 1.2.0 | 2026-05-20 | Nitish Singh | Added Windows MinGW static runtime +# | linking for containerized execution. +# 1.3.0 | 2026-05-28 | Nitish Singh | Added clang-format automation target +# | and cross-platform formatting support. +# ----------------------------------------------------------------------------- +# BUILD STRATEGY +# * Static Core Library : Shared reusable conversion engine +# * Shared DLL Bridge : .NET interoperability export layer +# * CLI Runtime : Standalone native execution target +# * GoogleTest Harness : Integrated validation framework +# * MinGW Static Linking : Portable Windows runtime generation +# * Clang-Format Integration : Automated source formatting pipeline +# * AddressSanitizer Support : Native debug-time memory diagnostics +# ----------------------------------------------------------------------------- + cmake_minimum_required(VERSION 3.14) if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) endif() -# Add this near the top, after project() -if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE) +# 1. Initialize the project profile first so system variables exist +project(StringConversion) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +enable_testing() + +# 2. Apply explicit static linking constraints globally for cross-compilation +if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + # Force underlying components to compile with matching runtime definitions + set(gtest_force_shared_crt OFF CACHE BOOL "" FORCE) +else() + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +# 3. Restrict AddressSanitizer strictly to native explicit Debug builds +if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") message(STATUS "Enabling AddressSanitizer for Debug build") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g") @@ -14,17 +58,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT CMAKE_BUILD_TYPE) endif() endif() -project(StringConversion) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -enable_testing() - # --------------------------- # Global Settings # --------------------------- include_directories(include) -# Required for linking static code into a shared library on some platforms set(CMAKE_POSITION_INDEPENDENT_CODE ON) # --------------------------- @@ -54,20 +91,14 @@ target_include_directories(StringConversionLib PUBLIC include) # --------------------------- # 2. The Bridge DLL: ProcessStringDLL (SHARED) # --------------------------- -# This creates the actual file (libProcessStringDLL.dylib / .so) for .NET add_library(ProcessStringDLL SHARED src/ProcessStringDLL.cpp) - -# This tells the compiler "We are BUILDING the DLL, not using it" target_compile_definitions(ProcessStringDLL PRIVATE PROCESSSTRING_EXPORTS) -# This silences the 'strcpy' warning (C4996) seen in your logs if(WIN32) target_compile_definitions(ProcessStringDLL PRIVATE _CRT_SECURE_NO_WARNINGS) endif() target_link_libraries(ProcessStringDLL PRIVATE StringConversionLib) - -# Ensure the "lib" prefix is consistent for your scripts set_target_properties(ProcessStringDLL PROPERTIES PREFIX "lib") # --------------------------- @@ -80,8 +111,6 @@ target_link_libraries(app StringConversionLib) # 4. GoogleTest Setup # --------------------------- include(FetchContent) -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/main.zip @@ -97,4 +126,30 @@ add_executable(runTests ) target_link_libraries(runTests StringConversionLib gtest gtest_main) -add_test(NAME AllTests COMMAND runTests) \ No newline at end of file +# Force the test runner to link dependencies statically under MinGW +if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_options(runTests PRIVATE "-static" "-static-libgcc" "-static-libstdc++") +endif() + +add_test(NAME AllTests COMMAND runTests) + +# --------------------------- +# 6. Code Formatting (Clang-Format Automation) +# --------------------------- +find_program(CLANG_FORMAT_EXE + NAMES clang-format + HINTS /opt/homebrew/bin /usr/local/bin +) + +if(CLANG_FORMAT_EXE) + message(STATUS "Found clang-format: ${CLANG_FORMAT_EXE}") + file(GLOB_RECURSE ALL_FORMAT_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp" + "${PROJECT_SOURCE_DIR}/../Tests/CppTests/*.cpp" + ) + add_custom_target(format + COMMAND ${CLANG_FORMAT_EXE} -i -style=LLVM ${ALL_FORMAT_FILES} + COMMENT "Auto-formatting all C++ engine source..." + ) +endif() \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt b/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt index b7a1450..2f24f35 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeListsLocalApp.txt @@ -1,3 +1,24 @@ +# ----------------------------------------------------------------------------- +# CMake Configuration - StringConversion Native Engine +# Project : StringConversion +# Component : Core Library + CLI + GoogleTest Validation +# ----------------------------------------------------------------------------- +# VERSION HISTORY +# Version | Date | Author | Description +# --------|------------|---------------|---------------------------------------- +# 1.0.0 | 2026-04-14 | Nitish Singh | Initial native CMake orchestration +# | with GoogleTest integration. +# 1.1.0 | 2026-05-28 | Nitish Singh | Added automated clang-format target +# | for recursive source/test formatting. +# ----------------------------------------------------------------------------- +# BUILD ARCHITECTURE +# * Static Core Library : Shared string conversion engine +# * CLI Runtime : Native executable entry point +# * GoogleTest Integration : Unit + advanced validation suite +# * Clang-Format Automation : Consistent code-style enforcement +# * Recursive Source Discovery : Automated formatting coverage +# ----------------------------------------------------------------------------- + cmake_minimum_required(VERSION 3.14) cmake_policy(SET CMP0135 NEW) @@ -77,4 +98,27 @@ target_link_libraries(runTests StringConversionLib gtest gtest_main) # --------------------------- add_test(NAME AllTests COMMAND runTests) +# =================================================================== +# 6. Code Formatting (Clang-Format Automation) +# =================================================================== +find_program(CLANG_FORMAT_EXE + NAMES clang-format + HINTS /opt/homebrew/bin /usr/local/bin +) +if(CLANG_FORMAT_EXE) + message(STATUS "Found clang-format: ${CLANG_FORMAT_EXE}") + + file(GLOB_RECURSE ALL_FORMAT_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp" + "${PROJECT_SOURCE_DIR}/../Tests/CppTests/*.cpp" + ) + + add_custom_target(format + COMMAND ${CLANG_FORMAT_EXE} -i -style=LLVM ${ALL_FORMAT_FILES} + COMMENT "Auto-formatting C++ engine, application, and test suites..." + ) +else() + message(WARNING "clang-format executable not found. 'format' target will not be available.") +endif() \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile b/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile index bc4e094..c0a75d9 100644 --- a/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile +++ b/Backend/CaseConversionAPI/CppLib/Scripts/Dockerfile @@ -9,6 +9,9 @@ # --------|------------|--------------|---------------------------------------- # 1.0.0 | 2026-05-14 | Nitish Singh | Initial Orchestration Layer. # 1.1.0 | 2026-05-14 | Nitish Singh | Integrated MinGW-w64 for Windows cross-builds. +# 1.2.0 | 2026-05-30 | Nitish Singh | Added Wine + Xvfb validation pipeline for +# | Windows GoogleTest execution inside Linux +# | containers with cross-platform verification. # ----------------------------------------------------------------------------- # ARCHITECTURAL STRATEGY: # * Headless Build Vessel: Designed to output binaries, not to run as a service. @@ -16,19 +19,24 @@ # * Artifact Extraction: Exposes the build directory for host-side consumption. # ----------------------------------------------------------------------------- -# --- STAGE 1: Build Environment (Native Toolchains Only) --- -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env +ARG TARGET_PLATFORM=linux/amd64 +FROM --platform=${TARGET_PLATFORM} mcr.microsoft.com/dotnet/sdk:8.0 AS build-env -# Install C++ Native Toolchains (GCC for Linux, MinGW for Windows) -RUN apt-get update && apt-get install -y \ +# Install C++ Native Toolchains, Wine, and Xvfb for testing +RUN dpkg --add-architecture i386 && \ + apt-get update && apt-get install -y \ build-essential \ cmake \ mingw-w64 \ + wine \ + wine32 \ + wine64 \ + xvfb \ && rm -rf /var/lib/apt/lists/* WORKDIR /src -# Copy the entire repo context to preserve script and source paths +# Copy the entire repo context COPY . . # Ensure orchestrator script is executable @@ -40,14 +48,38 @@ RUN ./Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh ubuntu-late # --- STEP 2: Build Windows Artifacts (.dll via MinGW) --- RUN ./Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh windows-latest +# --- STEP 3: Verification Layer (Internal Tests) --- +WORKDIR /src/Backend/CaseConversionAPI/CppLib/build/windows-latest + +ENV WINEPREFIX=/root/.wine +ENV WINEARCH=win64 +ENV WINEDEBUG=-all +ENV WINEDLLOVERRIDES="mscoree,mshtml=" + +# Run Windows test suite via Wine +# Using absolute path to /usr/bin/xvfb-run ensures command execution +RUN echo "===== Running Windows GoogleTests via Wine =====" && \ + /usr/bin/xvfb-run --server-args="-screen 0 1024x768x24" \ + /usr/lib/wine/wine64 ./runTests.exe --gtest_color=yes 2>&1 | tee gtest_internal.log && \ + echo "===== Windows GoogleTests Passed =====" \ + || { \ + echo "=== WINDOWS GOOGLETEST CRASH LOG ==="; \ + cat gtest_internal.log; \ + exit 1; \ + } + +# Reset context for artifact extraction +WORKDIR /src + # ----------------------------------------------------------------------------- # STAGE 2: Export Layer (Minimal Delivery Vessel) # ----------------------------------------------------------------------------- -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +# Re-import target architecture variable for the final runtime stage context +ARG TARGET_PLATFORM=linux/amd64 +FROM --platform=${TARGET_PLATFORM} mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app # Export the raw C++ build artifacts for the host to extract via 'docker cp' -# This bypasses managed code publish to focus on native binary delivery. COPY --from=build-env /src/Backend/CaseConversionAPI/CppLib/build /src/Backend/CaseConversionAPI/CppLib/build # Note: No ENTRYPOINT defined as this container is utilized as an artifact source. \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh index 05b7f78..fea0cd6 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native-docker.sh @@ -1,11 +1,21 @@ #!/bin/bash #*********************************************************************/ # Master Native Orchestrator: C++ Core (The Big Three) */ -# Version : 1.0 */ +# Version : 1.2 */ # */ # Purpose : Coordinates Local (macOS) and Dockerized (Linux/Win) */ -# builds to generate a unified multi-platform binary set.*/ -# Location : backend/CaseConversionAPI/CppLib/Scripts/master-build.sh*/ +# builds to generate a unified multi-platform binary */ +# set. */ +# */ +# Features : */ +# * Native macOS build + execution */ +# * Linux cross-build orchestration */ +# * Windows MinGW-w64 cross-compilation */ +# * Dockerized GoogleTest validation */ +# * Automated artifact extraction + synchronization */ +# */ +# Location : Backend/CaseConversionAPI/CppLib/Scripts/ */ +# orchestrate-native-docker.sh */ # */ # Revision History: */ # ------------------------------------------------------------------ */ @@ -13,6 +23,14 @@ # ------------------------------------------------------------------ */ # 1.0 2026-05-14 Nitish Singh Initial Master Orchestrator*/ # with Docker extraction. */ +# 1.1 2026-05-16 Nitish Singh Added backend root path */ +# normalization and improved */ +# Docker context handling. */ +# 1.2 2026-05-20 Nitish Singh Added containerized */ +# GoogleTest execution for */ +# Linux runtime validation */ +# and automated artifact */ +# synchronization pipeline. */ #*********************************************************************/ set -euo pipefail @@ -25,7 +43,7 @@ REPO_ROOT=$(realpath "$BACKEND_ROOT/..") # Configuration DOCKERFILE_PATH="$BACKEND_ROOT/CaseConversionAPI/CppLib/Scripts/Dockerfile" DIST_DIR="$BACKEND_ROOT/CaseConversionAPI/CppLib/build" -NATIVE_SCRIPT_REL="backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh" +NATIVE_SCRIPT_REL="Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh" log_info() { echo -e "\033[0;34m[$(date +'%T')] [INFO]\033[0m $1"; } log_success() { echo -e "\033[0;32m[$(date +'%T')] [SUCCESS]\033[0m $1"; } @@ -38,7 +56,6 @@ cd "$REPO_ROOT" if [[ "$(uname)" == "Darwin" ]]; then log_info "MacOS detected. Running local native build & tests..." - # Execute native script with the macos-latest target if bash "$NATIVE_SCRIPT_REL" macos-latest; then log_success "MacOS Local Build & Testing Complete." else @@ -52,41 +69,49 @@ fi # --- STEP 2: DOCKER CROSS-BUILD (LINUX & WINDOWS) --- log_info "Initiating Docker Build for Linux (.so) and Windows (.dll)..." -# Build the native-only Docker image -if docker build -t cpp-native-cross -f "$DOCKERFILE_PATH" .; then +if docker build \ + --progress=plain \ + --platform linux/amd64 \ + -t cpp-native-cross \ + -f "$DOCKERFILE_PATH" .; then + + # 1. Run Linux Tests + log_info "Running C++ Core GoogleTest suite inside Linux Container Environment..." + if docker run --rm cpp-native-cross /src/Backend/CaseConversionAPI/CppLib/build/ubuntu-latest/runTests; then + log_success "Linux (Ubuntu) Container Core Tests Passed Successfully." + else + log_error "Linux Core Tests Failed within the container context." + exit 1 + fi + + # 3. Extract and Sync Artifacts log_info "Extracting virtual artifacts from Docker..." - CONTAINER_ID=$(docker create cpp-native-cross) TEMP_EXTRACT="$DIST_DIR/docker_temp" mkdir -p "$TEMP_EXTRACT" - - # Copy the internal build directory to local temp - # The dot at the end ensures we copy contents of 'build' - docker cp "$CONTAINER_ID:/src/backend/CaseConversionAPI/CppLib/build/." "$TEMP_EXTRACT/" - - # Cleanup Docker immediately + + docker cp "$CONTAINER_ID:/src/Backend/CaseConversionAPI/CppLib/build/." "$TEMP_EXTRACT/" docker rm "$CONTAINER_ID" - docker rmi cpp-native-cross - # --- STEP 3: SYNC VIRTUAL ARTIFACTS --- log_info "Syncing cross-platform target folders..." - - # Target: ubuntu-latest + + # Sync Linux if [ -d "$TEMP_EXTRACT/ubuntu-latest" ]; then mkdir -p "$DIST_DIR/ubuntu-latest" cp "$TEMP_EXTRACT/ubuntu-latest/libProcessStringDLL.so" "$DIST_DIR/ubuntu-latest/" log_success "Artifact Secured: ubuntu-latest/libProcessStringDLL.so" fi - # Target: windows-latest + # Sync Windows if [ -d "$TEMP_EXTRACT/windows-latest" ]; then mkdir -p "$DIST_DIR/windows-latest" cp "$TEMP_EXTRACT/windows-latest/libProcessStringDLL.dll" "$DIST_DIR/windows-latest/" log_success "Artifact Secured: windows-latest/libProcessStringDLL.dll" fi - # Final Cleanup + # 4. Final Cleanup rm -rf "$TEMP_EXTRACT" + docker rmi cpp-native-cross else log_error "Docker build failed. Check Dockerfile and native toolchains." exit 1 diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh index 3381bb5..b7b71e6 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/orchestrate-native.sh @@ -1,9 +1,19 @@ #!/bin/bash #*********************************************************************/ # Utility Script - C++ Core Orchestration (Monorepo) */ -# Version : 1.5 */ +# Version : 1.6 */ # */ # Purpose : Configures, builds, and executes C++ logic & tests. */ +# */ +# Features : */ +# * Matrix OS orchestration */ +# * Dynamic build path synchronization */ +# * MinGW Windows cross-compilation */ +# * Apple Silicon optimization support */ +# * Automated GoogleTest execution */ +# * Parallelized multi-core compilation */ +# * Pre-build clang-format automation */ +# */ # Location : CppLib/Scripts/orchestrate-native.sh */ # */ # Revision History: */ @@ -19,6 +29,10 @@ # 1.5 2026-05-16 Nitish Singh Standardized logging, */ # execution context validation*/ # and dynamic path handling. */ +# 1.6 2026-05-28 Nitish Singh Added automated pre-build */ +# clang-format execution with */ +# controlled non-fatal */ +# formatting fallback logic. */ #*********************************************************************/ set -euo pipefail @@ -124,6 +138,17 @@ fi # Modern CMake build cmake -S "$CPP_ROOT" -B "$BUILD_DIR" "${CMAKE_ARGS[@]}" +# Temporarily drop strict exit tracking to execute target code formatting safely +set +e +log_info "Executing shared framework auto-formatting via clang-format..." +cmake --build "$BUILD_DIR" --target format +if [ $? -eq 0 ]; then + log_success "Workspace formatting complete." +else + log_warn "Formatting target encountered an initialization anomaly or was skipped; proceeding." +fi +set -e # Re-engage strict execution tracking for compilation safety + log_info "Utilizing $NUM_CORES cores for parallel build..." cmake --build "$BUILD_DIR" --config Release --parallel "$NUM_CORES" diff --git a/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh b/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh index 74ef91b..8efda95 100755 --- a/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh +++ b/Backend/CaseConversionAPI/CppLib/Scripts/run-local-context.sh @@ -1,10 +1,19 @@ #!/bin/bash #*********************************************************************/ # Utility Script - Local CLI App Runner (macOS Optimized) */ -# Version : 1.3 */ +# Version : 1.4 */ # */ # Purpose : Temporarily swaps CMakeLists to build/run the CLI app */ -# without modifying the main project architecture. */ +# without modifying the main project architecture. */ +# */ +# Features : */ +# * Dynamic workspace synchronization */ +# * Safe CMakeLists backup/restore workflow */ +# * Apple Silicon (M-Series) optimization */ +# * Automated clang-format integration */ +# * Parallelized multi-core compilation */ +# * Execution context validation + cleanup */ +# */ # Location : backend/CaseConversionAPI/CppLib/Scripts/run-local.sh */ # */ # Revision History: */ @@ -14,9 +23,14 @@ # 1.0 2026-04-16 Nitish Singh Initial Swap Logic Script */ # 1.1 2026-04-16 Nitish Singh Added Absolute Path Trap */ # 1.2 2026-05-09 Nitish Singh Optimized for M2 P-Cores */ -# and enhanced error cleanup. * -# 1.3 2026-05-16 Nitish Singh Added execution context */ +# and enhanced error cleanup. */ +# 1.3 2026-05-16 Nitish Singh Added execution context */ # validation and dynamic path */ +# synchronization. */ +# 1.4 2026-05-28 Nitish Singh Added automated clang-format*/ +# execution with isolated */ +# non-fatal formatter */ +# fallback handling. */ #*********************************************************************/ set -euo pipefail @@ -94,6 +108,17 @@ cmake -S "$CPP_ROOT" -B "$BUILD_DIR" \ -DUSE_PCORES=ON \ -DCMAKE_OSX_ARCHITECTURES=arm64 +# Temporarily disable strict exit-on-error for the formatter target +set +e +log_info "Executing source workspace auto-formatting via clang-format..." +cmake --build "$BUILD_DIR" --target format +if [ $? -eq 0 ]; then + log_success "Workspace formatting complete." +else + log_warn "Formatting target encountered an initialization anomaly; proceeding to compilation." +fi +set -e # Re-enable strict error tracking for compilation safety + log_info "Utilizing $NUM_CORES cores for parallel compilation..." cmake --build "$BUILD_DIR" --config Release --parallel "$NUM_CORES" diff --git a/Backend/CaseConversionAPI/CppLib/include/Client.hpp b/Backend/CaseConversionAPI/CppLib/include/Client.hpp index d2c80fe..16b60ae 100644 --- a/Backend/CaseConversionAPI/CppLib/include/Client.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/Client.hpp @@ -72,7 +72,7 @@ class Client { */ ConversionResult execute(const std::string &input) const; - void setTraceId(const std::string& traceId); + void setTraceId(const std::string &traceId); }; #endif // CLIENT_HPP \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp b/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp index 470b953..de4a58d 100644 --- a/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/ConversionResult.hpp @@ -55,60 +55,60 @@ */ class ConversionResult { private: - /// Pointer to heap-allocated C-style string - char* data; + /// Pointer to heap-allocated C-style string + char *data; public: - /** - * @brief Constructs a ConversionResult from input string. - * @param input Null-terminated C-string to copy. - */ - explicit ConversionResult(const char* input); + /** + * @brief Constructs a ConversionResult from input string. + * @param input Null-terminated C-string to copy. + */ + explicit ConversionResult(const char *input); - /** - * @brief Destructor releases allocated memory. - */ - ~ConversionResult(); + /** + * @brief Destructor releases allocated memory. + */ + ~ConversionResult(); - /*****************************************************************/ - /* Rule of 5: Copy Semantics */ - /*****************************************************************/ + /*****************************************************************/ + /* Rule of 5: Copy Semantics */ + /*****************************************************************/ - /** - * @brief Copy constructor (deep copy). - * @param other Source object to copy from. - */ - ConversionResult(const ConversionResult& other); + /** + * @brief Copy constructor (deep copy). + * @param other Source object to copy from. + */ + ConversionResult(const ConversionResult &other); - /** - * @brief Copy assignment operator (deep copy). - * @param other Source object to assign from. - * @return Reference to current object. - */ - ConversionResult& operator=(const ConversionResult& other); + /** + * @brief Copy assignment operator (deep copy). + * @param other Source object to assign from. + * @return Reference to current object. + */ + ConversionResult &operator=(const ConversionResult &other); - /*****************************************************************/ - /* Rule of 5: Move Semantics (Performance Optimization) */ - /*****************************************************************/ + /*****************************************************************/ + /* Rule of 5: Move Semantics (Performance Optimization) */ + /*****************************************************************/ - /** - * @brief Move constructor (transfers ownership). - * @param other Source object to move from. - */ - ConversionResult(ConversionResult&& other) noexcept; + /** + * @brief Move constructor (transfers ownership). + * @param other Source object to move from. + */ + ConversionResult(ConversionResult &&other) noexcept; - /** - * @brief Move assignment operator (transfers ownership). - * @param other Source object to move from. - * @return Reference to current object. - */ - ConversionResult& operator=(ConversionResult&& other) noexcept; + /** + * @brief Move assignment operator (transfers ownership). + * @param other Source object to move from. + * @return Reference to current object. + */ + ConversionResult &operator=(ConversionResult &&other) noexcept; - /** - * @brief Returns the underlying C-style string. - * @return Pointer to null-terminated string. - */ - [[nodiscard]] const char* get_c_str() const; + /** + * @brief Returns the underlying C-style string. + * @return Pointer to null-terminated string. + */ + [[nodiscard]] const char *get_c_str() const; }; #endif // CONVERSION_RESULT_HPP \ No newline at end of file diff --git a/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp b/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp index 87cad93..0d0e4c1 100644 --- a/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp +++ b/Backend/CaseConversionAPI/CppLib/include/ProcessStringDLL.hpp @@ -35,8 +35,8 @@ #define PROCESSSTRINGDLL_HPP /*********************************************************************/ -/* Platform-Specific API Macros */ -/* */ +/* Platform-Specific API Macros */ +/* */ /* Configures symbol visibility for the dynamic linker. */ /* - Windows: Uses __declspec to manage DLL export/import tables. */ /* - macOS/Linux: Uses visibility attributes to ensure P/Invoke */ @@ -68,7 +68,8 @@ extern "C" { * @return C-string result (valid until next call). Caller must free using * freeString. */ -API const char *processStringDLL(const char *input, int len, int choice, const char *traceId); +API const char *processStringDLL(const char *input, int len, int choice, + const char *traceId); /** * @brief Frees memory allocated by processStringDLL diff --git a/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp b/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp index 6814aba..9a084f0 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/AdvStrTestDLL.cpp @@ -104,7 +104,8 @@ #include "StringConversionFactory.hpp" extern "C" { -char *processStringDLL(const char *input, int len, int choice, const char *traceId); +char *processStringDLL(const char *input, int len, int choice, + const char *traceId); void freeString(char *str); } @@ -254,9 +255,9 @@ TEST(ProcessStringDLL, MultipleCalls) { // 5. MEMORY MANAGEMENT TESTS FOR DLL // ============================================================ -TEST(ProcessStringDLL, MemoryNotNull) { - const char *result = processStringDLL("hello", 4, 4, "test-trace-id"); +TEST(ProcessStringDLL, MemoryNotNull) { + const char *result = processStringDLL("hello", 4, 4, "test-trace-id"); ASSERT_NE(result, nullptr); // Cast to char* if your freeString expects it, or keep it consistent - freeString(const_cast(result)); + freeString(const_cast(result)); } \ No newline at end of file diff --git a/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp b/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp index 843117a..3adb15a 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/AdvancedStringConversionTests.cpp @@ -132,7 +132,8 @@ TEST(ProcessStringTest, ProcessStringAlternating) { std::string input = "Hello World!"; int choice = 1; // Alternating case - std::string output = ConversionResult(processString(input, choice)).get_c_str(); + std::string output = + ConversionResult(processString(input, choice)).get_c_str(); logConversion("ProcessString Alternating", input, output); @@ -143,7 +144,8 @@ TEST(ProcessStringTest, ProcessStringReverse) { std::string input = "Hello World!"; int choice = 7; // Reverse - std::string output = ConversionResult(processString(input, choice)).get_c_str(); + std::string output = + ConversionResult(processString(input, choice)).get_c_str(); logConversion("ProcessString Reverse", input, output); @@ -175,8 +177,8 @@ TEST(UpperCasePerformanceTest, LargeInput) { std::string largeInput(1'000'000, 'a'); auto start = std::chrono::high_resolution_clock::now(); - auto resultObj = converter.convert(largeInput); - const char* resultStr = resultObj.get_c_str(); + auto resultObj = converter.convert(largeInput); + const char *resultStr = resultObj.get_c_str(); auto end = std::chrono::high_resolution_clock::now(); auto duration = diff --git a/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp b/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp index 51120ab..e945757 100644 --- a/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp +++ b/Backend/CaseConversionAPI/Tests/CppTests/StringConversionTests.cpp @@ -33,11 +33,11 @@ // Core Interfaces #include "Client.hpp" +#include "ConversionResult.hpp" #include "IStringConversion.hpp" #include "ProcessString.hpp" #include "StringConversionFactory.hpp" #include "TestHelpers.hpp" -#include "ConversionResult.hpp" // Basic Conversions #include "AlternatingCaseConversion.hpp" @@ -114,12 +114,14 @@ TEST(InvertWordsConversionTest, Basic) { TEST(KebabCaseConversionTest, Basic) { KebabCaseConversion conv; - EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), "hello-world-example"); + EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), + "hello-world-example"); } TEST(SnakeCaseConversionTest, Basic) { SnakeCaseConversion conv; - EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), "hello_world_example"); + EXPECT_STREQ(conv.convert("Hello World Example").get_c_str(), + "hello_world_example"); } TEST(RemoveSpacesConversionTest, Basic) { @@ -136,7 +138,7 @@ TEST(LeetSpeakConversionTest, Basic) { LeetSpeakConversion conv; EXPECT_STREQ(conv.convert("Hello").get_c_str(), "H3ll0"); EXPECT_STREQ(conv.convert("Testing").get_c_str(), - "73571ng"); // ensure mapping matches implementation + "73571ng"); // ensure mapping matches implementation } // @@ -237,47 +239,63 @@ TEST(ClientTest, NoStrategySet) { TEST(ProcessStringTest, BasicFlow) { EXPECT_STREQ(processString("hello world", - static_cast(ConversionChoice::Alternating)).get_c_str(), - "HeLlO WoRlD"); + static_cast(ConversionChoice::Alternating)) + .get_c_str(), + "HeLlO WoRlD"); EXPECT_STREQ(processString("hello world", - static_cast(ConversionChoice::Capitalize)).get_c_str(), - "Hello World"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Lower)).get_c_str(), - "hello"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Upper)).get_c_str(), - "HELLO"); - EXPECT_STREQ(processString("hELLO wORLD", - static_cast(ConversionChoice::Sentence)).get_c_str(), - "Hello world"); - EXPECT_STREQ(processString("HeLLo", static_cast(ConversionChoice::Toggle)).get_c_str(), - "hEllO"); - EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Reverse)).get_c_str(), - "olleH"); + static_cast(ConversionChoice::Capitalize)) + .get_c_str(), + "Hello World"); + EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Lower)) + .get_c_str(), + "hello"); + EXPECT_STREQ(processString("Hello", static_cast(ConversionChoice::Upper)) + .get_c_str(), + "HELLO"); + EXPECT_STREQ( + processString("hELLO wORLD", static_cast(ConversionChoice::Sentence)) + .get_c_str(), + "Hello world"); + EXPECT_STREQ( + processString("HeLLo", static_cast(ConversionChoice::Toggle)) + .get_c_str(), + "hEllO"); + EXPECT_STREQ( + processString("Hello", static_cast(ConversionChoice::Reverse)) + .get_c_str(), + "olleH"); } TEST(ProcessStringTest, AdvancedChoices) { EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::RemoveVowels)).get_c_str(), - "Hll Wrld"); + static_cast(ConversionChoice::RemoveVowels)) + .get_c_str(), + "Hll Wrld"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::RemoveSpaces)).get_c_str(), - "HelloWorld"); + static_cast(ConversionChoice::RemoveSpaces)) + .get_c_str(), + "HelloWorld"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::InvertWords)).get_c_str(), - "olleH dlroW"); + static_cast(ConversionChoice::InvertWords)) + .get_c_str(), + "olleH dlroW"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::SnakeCase)).get_c_str(), - "hello_world"); + static_cast(ConversionChoice::SnakeCase)) + .get_c_str(), + "hello_world"); EXPECT_STREQ(processString("Hello World", - static_cast(ConversionChoice::KebabCase)).get_c_str(), - "hello-world"); + static_cast(ConversionChoice::KebabCase)) + .get_c_str(), + "hello-world"); EXPECT_STREQ( - processString("Test", static_cast(ConversionChoice::LeetSpeak)).get_c_str(), + processString("Test", static_cast(ConversionChoice::LeetSpeak)) + .get_c_str(), "7357"); } TEST(ProcessStringTest, InvalidChoice) { - EXPECT_STREQ(processString("Hello", 99).get_c_str(), "hello"); // invalid choice falls back + EXPECT_STREQ(processString("Hello", 99).get_c_str(), + "hello"); // invalid choice falls back } // diff --git a/README.md b/README.md index a22f173..3fe0a35 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ This project is a high-concurrency, cross-platform string processing and spell-c * [Key Performance Drivers](#key-performance-drivers) * [9. The Challenge of Native Compilation on Apple Silicon](#9-the-challenge-of-native-compilation-on-apple-silicon) * [10. Automated PR Workflow (Local Orchestration)](#10-automated-pr-workflow-local-orchestration) + * [11. Cross-Platform Build Engineering and Validation](#11-cross-platform-build-engineering-and-validation) * [Quick Start](#quick-start) * [Run the Load-Balanced Cluster](#run-the-load-balanced-cluster) * [Project Timeline and Roadmap](#project-timeline-and-roadmap) @@ -564,6 +565,93 @@ The script automatically blocks upstream merging until all checks return healthy ./scripts/gh-automate.sh "" ``` +### 11. Cross-Platform Build Engineering and Validation + +Beyond application-level functionality, the platform emphasizes deterministic cross-platform native build engineering and runtime verification across heterogeneous operating systems and toolchains. + +The native orchestration pipeline is designed to validate not only successful compilation, but also runtime compatibility, artifact integrity, and execution correctness across all supported targets. + +#### Multi-Platform Native Validation + +The build system produces and validates platform-native shared libraries for: + +| Platform | Artifact | Toolchain | +| -------- | -------- | ----------------------- | +| macOS | `.dylib` | Clang / Apple SDK | +| Linux | `.so` | GCC / CMake | +| Windows | `.dll` | MinGW Cross-Compilation | + +To ensure runtime correctness rather than simple compilation success, Windows-native GoogleTest executables are executed through Wine-based compatibility validation directly from Linux container environments. + +```Bash +===== Running Windows GoogleTests via Wine ===== +wine64 ./runTests.exe +``` + +This validation layer confirms: + +* successful PE executable generation +* runtime dependency correctness +* exported symbol integrity +* cross-platform ABI compatibility +* automated Windows test execution + +This approach provides significantly stronger guarantees than cross-compilation alone by validating the produced Windows binaries under execution conditions rather than merely verifying linker success. + +#### Deterministic Containerized Toolchains + +Linux and Windows builds are isolated within Dockerized cross-compilation environments to ensure reproducibility and eliminate host-environment drift. + +Key engineering characteristics include: + +* deterministic Docker-based build environments +* isolated cross-platform toolchains +* automated artifact extraction +* parallelized native compilation +* structured logging pipelines +* failure-aware orchestration +* reproducible CI/CD execution paths + +The orchestration layer separates: + +* local host compilation responsibilities +* Docker-based cross-platform builds +* artifact synchronization +* runtime validation +* binary extraction workflows + +This separation enables consistent multi-platform binary generation while preserving clean environmental boundaries between host and containerized toolchains. + +#### Runtime Verification & Observability + +The platform incorporates explicit runtime validation and observability throughout the native build lifecycle. + +Engineering considerations include: + +* GoogleTest integration across all targets +* structured build and execution logging +* runtime test output propagation +* failure-state visibility +* environment verification +* automated validation orchestration + +During implementation, additional attention was required to expose suppressed runtime logs generated inside Docker BuildKit execution layers. This ensured native test execution output remained observable during CI/CD operations and improved debugging visibility for containerized builds. + +#### Engineering Focus + +The broader objective of the build pipeline is not only portability, but operational reliability and delivery-system ownership. + +The project emphasizes: + +* systems-level engineering +* infrastructure-aware development +* cross-platform runtime behavior +* deterministic deployment workflows +* practical DevEx tooling +* automated verification pipelines + +Rather than treating native compilation as an isolated build step, the platform approaches compilation, validation, testing, orchestration, and artifact lifecycle management as a unified engineering system. + --- ## Quick Start @@ -658,4 +746,4 @@ This project follows Semantic Versioning (SemVer) and utilizes an automated CI/C * Cross-Platform Artifact Distribution: The release pipeline produces platform-specific native binaries (.dll, .so, .dylib) alongside containerized deployment artifacts, enabling consistent runtime behavior across macOS, Linux, and Windows environments. -[Read the Full Release & Versioning Guide →](Docs/releases/RELEASING.md) +[Read the Full Release & Versioning Guide →](Docs/releases/RELEASING.md) \ No newline at end of file From 2b06a05fb61d68aae24f55cda80094ccaa988f8c Mon Sep 17 00:00:00 2001 From: Nitish Singh <93253740+nitishhsinghhh@users.noreply.github.com> Date: Sat, 30 May 2026 01:23:42 +0530 Subject: [PATCH 2/3] Consistent MSVC runtime everywhere. --- Backend/CaseConversionAPI/CppLib/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt index e092cfb..f4d3ec4 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt @@ -27,6 +27,8 @@ cmake_minimum_required(VERSION 3.14) +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) endif() From 9d2b0eeca663e3213869fc3f981857de69387da0 Mon Sep 17 00:00:00 2001 From: Nitish Singh <93253740+nitishhsinghhh@users.noreply.github.com> Date: Sat, 30 May 2026 01:40:14 +0530 Subject: [PATCH 3/3] Consistent MSVC runtime everywhere. --- .../CaseConversionAPI/CppLib/CMakeLists.txt | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt index f4d3ec4..76cace3 100644 --- a/Backend/CaseConversionAPI/CppLib/CMakeLists.txt +++ b/Backend/CaseConversionAPI/CppLib/CMakeLists.txt @@ -41,17 +41,31 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) enable_testing() # 2. Apply explicit static linking constraints globally for cross-compilation -if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") - # Force underlying components to compile with matching runtime definitions - set(gtest_force_shared_crt OFF CACHE BOOL "" FORCE) -else() +# -------------------------------------------------------- +# Runtime / Linking Strategy +# -------------------------------------------------------- + +if(MSVC) + + # Using dynamic MSVC runtime consistently across all targets + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + + # GoogleTest must match the same runtime model set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +elseif(MINGW) + + # MinGW-specific static runtime linking + set(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + + set(CMAKE_SHARED_LINKER_FLAGS + "${CMAKE_SHARED_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + endif() # 3. Restrict AddressSanitizer strictly to native explicit Debug builds -if(CMAKE_BUILD_TYPE STREQUAL "Debug") +if(CMAKE_BUILD_TYPE MATCHES Debug) if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") message(STATUS "Enabling AddressSanitizer for Debug build") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g") @@ -96,10 +110,6 @@ target_include_directories(StringConversionLib PUBLIC include) add_library(ProcessStringDLL SHARED src/ProcessStringDLL.cpp) target_compile_definitions(ProcessStringDLL PRIVATE PROCESSSTRING_EXPORTS) -if(WIN32) - target_compile_definitions(ProcessStringDLL PRIVATE _CRT_SECURE_NO_WARNINGS) -endif() - target_link_libraries(ProcessStringDLL PRIVATE StringConversionLib) set_target_properties(ProcessStringDLL PROPERTIES PREFIX "lib") @@ -129,8 +139,12 @@ add_executable(runTests target_link_libraries(runTests StringConversionLib gtest gtest_main) # Force the test runner to link dependencies statically under MinGW -if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_options(runTests PRIVATE "-static" "-static-libgcc" "-static-libstdc++") +if(MINGW) + target_link_options(runTests PRIVATE + "-static" + "-static-libgcc" + "-static-libstdc++" + ) endif() add_test(NAME AllTests COMMAND runTests)