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
18 changes: 9 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project overview

A C++20 example/learning project demonstrating modern C++ features, built with CMake and vcpkg. Dependencies: GTest, fmt, spdlog.
A native HTTP module for IIS to experiment with new ways of unit testing. C++20, built with CMake and vcpkg. Dependencies: GTest, fmt, spdlog.

## Build system

Dependencies are managed via **vcpkg**, bootstrapped automatically by the top-level `CMakeLists.txt`: if `VCPKG_ROOT` is unset, it clones vcpkg into `.vcpkg/`, bootstraps it, and installs `MODERNCPP_DEPENDENCIES` (GTest, fmt, spdlog) before `project()` is even declared. This means the *first* configure can take a while and requires network/git access; subsequent configures just auto-update the vcpkg checkout via `git pull`.
Dependencies are managed via **vcpkg**, bootstrapped automatically by the top-level `CMakeLists.txt`: if `VCPKG_ROOT` is unset, it clones vcpkg into `.vcpkg/` and bootstraps it before `project()` is even declared; the dependencies declared in `vcpkg.json` (GTest, fmt, spdlog) are then installed by vcpkg's manifest-mode resolution during configure. This means the *first* configure can take a while and requires network/git access; subsequent configures just auto-update the vcpkg checkout via `git pull`.

Building uses **CMake presets** (`CMakePresets.json`), targeting Visual Studio 2026 (`vs2026` generator) on Windows only — this project builds on Windows exclusively. Presets combine an architecture with a configuration:

Expand All @@ -32,16 +32,16 @@ ctest --preset windows-x86-64-debug

Build artifacts land in `_build/<presetName>/`.

Run a single test binary directly with GTest filters (there is currently one test target, `ModernCppTest`, registered with CTest as a single opaque test — use the binary's own filter flag to select individual cases):
Run a single test binary directly with GTest filters (there is currently one test target, `IISNativeModuleTest`, registered with CTest as a single opaque test — use the binary's own filter flag to select individual cases):

```powershell
_build\windows-x86-64-debug\test\Debug\ModernCppTest.exe --gtest_filter=TestUtils.TestSmokeGetHello
_build\windows-x86-64-debug\test\Debug\IISNativeModuleTest.exe --gtest_filter=TestUtils.TestSmokeGetHello
```

Run the app:

```powershell
_build\windows-x86-64-debug\src\Debug\ModernCppApp.exe
_build\windows-x86-64-debug\src\Debug\IISNativeModuleApp.exe
```

### Static analysis (`windows-x86-64-static-analysis` preset)
Expand All @@ -67,11 +67,11 @@ Report lands at `_build\windows-x86-64-coverage\coverage-report\index.html`.

## Architecture

- **`src/`** — the main application (`CMakeLists.txt` defines target `ModernCppApp`, project `ModernCppApp`). Sources are glob-collected (`*.cpp`/`*.h` in the directory), so **new files under `src/` are picked up automatically at the next CMake configure** — no need to edit `src/CMakeLists.txt` when adding a file there.
- **`src/`** — the main application (`CMakeLists.txt` defines target `IISNativeModuleApp`, project `IISNativeModuleApp`). Sources are glob-collected (`*.cpp`/`*.h` in the directory), so **new files under `src/` are picked up automatically at the next CMake configure** — no need to edit `src/CMakeLists.txt` when adding a file there.
- `src/controller/`, `src/model/`, `src/view/` are currently empty placeholder directories (each holds only a `.gitignore`), suggesting an intended MVC split that hasn't been built out yet.
- `src/utils/` is a separate static library target, `ModernCppUtils` (project `ModernCppUtils`), also glob-built and linked into both the app and the test binary. New utility files go here and are picked up the same way.
- `src/utils/` is a separate static library target, `IISNativeModuleUtils` (project `IISNativeModuleUtils`), also glob-built and linked into both the app and the test binary. New utility files go here and are picked up the same way.
- `src/module/` is the IIS native module itself: target `IISNativeModule`, a `SHARED` library (DLL) that exports `RegisterModule` via `iis_native_module.def`. `iis::HttpModule` (`http_module.h/.cpp`) overrides every overridable `CHttpModule` method with skeleton bodies returning `RQ_NOTIFICATION_CONTINUE`; `iis::HttpModuleFactory` creates instances; `register_module.cpp` currently subscribes to no notifications (`SetRequestNotifications(factory, 0, 0)`) — add `RQ_*` flags there as methods gain real implementations.
- **`test/`** — GTest-based tests, target/project `ModernCppTest`. Globs both `test/*.cpp` and `test/utils/*.cpp`, and links `ModernCppUtils`. `test/main.cpp` is a standard GTest `main()` running `RUN_ALL_TESTS()`. Mirror `src/utils/` layout under `test/utils/` for new utility tests (see `test/utils/smoke_test.cpp` as the existing example — one GTest `TEST` per behavior, wrapped in the same namespace as the code under test).
- **`test/`** — GTest-based tests, target/project `IISNativeModuleTest`. Globs both `test/*.cpp` and `test/utils/*.cpp`, and links `IISNativeModuleUtils`. `test/main.cpp` is a standard GTest `main()` running `RUN_ALL_TESTS()`. Mirror `src/utils/` layout under `test/utils/` for new utility tests (see `test/utils/smoke_test.cpp` as the existing example — one GTest `TEST` per behavior, wrapped in the same namespace as the code under test).
- Test includes reference library headers as `<utils/smoke.h>` because `test/CMakeLists.txt` adds `test/../src` (i.e. `src/`) to the include path — so app/test code both include utils headers via the `utils/` prefix, not relative paths.
- Because both `src/` and `src/utils/` (and `test/`) use `file(GLOB ...)`, CMake must be **re-run** (re-configure, not just rebuild) after adding or removing source files for them to be picked up — GLOB results are cached at configure time.

Expand All @@ -84,4 +84,4 @@ Report lands at `_build\windows-x86-64-coverage\coverage-report\index.html`.

- Minimum CMake version required is 4.2 (unusually new — verify your local CMake before assuming a configure failure is a code issue). CI installs `cmake >= 4.2` explicitly since GitHub-hosted runners don't have it preinstalled.
- The toolchain pins Visual Studio 2026 (`Visual Studio 18 2026`); local build presets additionally pin an exact MSVC toolset version (`14.44.35207` for build presets, `host=x64,version=14.50` for the static-analysis configure preset) — build failures on other VS/MSVC versions are expected without adjusting `CMakePresets.json`. CI sidesteps this (see above).
- `ModernCppUtils` (`src/utils/CMakeLists.txt`) is declared `add_library(... SHARED STATIC ...)` — despite the name, `STATIC` is the effective/last-wins keyword, so it builds as a static library.
- `IISNativeModuleUtils` (`src/utils/CMakeLists.txt`) is declared `add_library(... SHARED STATIC ...)` — despite the name, `STATIC` is the effective/last-wins keyword, so it builds as a static library.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ endif()
# toolchain.cmake) as part of manifest-mode dependency resolution -- no
# manual `vcpkg install` step needed.

project(ModernCppRoot LANGUAGES C CXX)
project(IISNativeModuleRoot LANGUAGES C CXX)

# Enforce C++20 for C++ targets
set(CMAKE_CXX_STANDARD 20)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# ModernCpp
# IISNativeModule
A native HTTP module for IIS to experiment new ways of unit testing
4 changes: 2 additions & 2 deletions cmake/windows-x86-32/toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR "x86")

if(NOT DEFINED ENV{VCPKG_ROOT})
get_filename_component(MODERNCPP_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${MODERNCPP_SOURCE_DIR}/.vcpkg)
get_filename_component(IISNATIVEMODULE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${IISNATIVEMODULE_SOURCE_DIR}/.vcpkg)
else()
set(VCPKG_ROOT $ENV{VCPKG_ROOT})
endif()
Expand Down
4 changes: 2 additions & 2 deletions cmake/windows-x86-64-clang/toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ set(CMAKE_C_COMPILER "$ENV{ProgramFiles}/Microsoft Visual Studio/18/Community/VC
set(CMAKE_CXX_COMPILER "$ENV{ProgramFiles}/Microsoft Visual Studio/18/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe" CACHE STRING "")

if(NOT DEFINED ENV{VCPKG_ROOT})
get_filename_component(MODERNCPP_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${MODERNCPP_SOURCE_DIR}/.vcpkg)
get_filename_component(IISNATIVEMODULE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${IISNATIVEMODULE_SOURCE_DIR}/.vcpkg)
else()
set(VCPKG_ROOT $ENV{VCPKG_ROOT})
endif()
Expand Down
4 changes: 2 additions & 2 deletions cmake/windows-x86-64-coverage/toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ set(CMAKE_C_COMPILER "$ENV{ProgramFiles}/Microsoft Visual Studio/18/Community/VC
set(CMAKE_CXX_COMPILER "$ENV{ProgramFiles}/Microsoft Visual Studio/18/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe" CACHE STRING "")

if(NOT DEFINED ENV{VCPKG_ROOT})
get_filename_component(MODERNCPP_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${MODERNCPP_SOURCE_DIR}/.vcpkg)
get_filename_component(IISNATIVEMODULE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${IISNATIVEMODULE_SOURCE_DIR}/.vcpkg)
else()
set(VCPKG_ROOT $ENV{VCPKG_ROOT})
endif()
Expand Down
22 changes: 11 additions & 11 deletions cmake/windows-x86-64-static-analysis/toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,30 @@ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
# installs under Program Files (x86) even when VS itself is installed to a
# different drive/location. Requires the "C++ Clang tools for Windows" VS
# component to be installed.
find_program(MODERNCPP_VSWHERE_EXE vswhere
find_program(IISNATIVEMODULE_VSWHERE_EXE vswhere
PATHS "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer"
)
if(NOT MODERNCPP_VSWHERE_EXE)
if(NOT IISNATIVEMODULE_VSWHERE_EXE)
message(FATAL_ERROR "vswhere.exe not found; cannot locate the Visual Studio installation.")
endif()

execute_process(
COMMAND "${MODERNCPP_VSWHERE_EXE}" -latest -property installationPath
OUTPUT_VARIABLE MODERNCPP_VS_INSTALL_PATH
COMMAND "${IISNATIVEMODULE_VSWHERE_EXE}" -latest -property installationPath
OUTPUT_VARIABLE IISNATIVEMODULE_VS_INSTALL_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)

set(MODERNCPP_CLANG_CL "${MODERNCPP_VS_INSTALL_PATH}/VC/Tools/Llvm/x64/bin/clang-cl.exe")
if(NOT EXISTS "${MODERNCPP_CLANG_CL}")
message(FATAL_ERROR "clang-cl.exe not found at ${MODERNCPP_CLANG_CL}; install the \"C++ Clang tools for Windows\" VS component.")
set(IISNATIVEMODULE_CLANG_CL "${IISNATIVEMODULE_VS_INSTALL_PATH}/VC/Tools/Llvm/x64/bin/clang-cl.exe")
if(NOT EXISTS "${IISNATIVEMODULE_CLANG_CL}")
message(FATAL_ERROR "clang-cl.exe not found at ${IISNATIVEMODULE_CLANG_CL}; install the \"C++ Clang tools for Windows\" VS component.")
endif()

set(CMAKE_C_COMPILER "${MODERNCPP_CLANG_CL}" CACHE STRING "")
set(CMAKE_CXX_COMPILER "${MODERNCPP_CLANG_CL}" CACHE STRING "")
set(CMAKE_C_COMPILER "${IISNATIVEMODULE_CLANG_CL}" CACHE STRING "")
set(CMAKE_CXX_COMPILER "${IISNATIVEMODULE_CLANG_CL}" CACHE STRING "")

if(NOT DEFINED ENV{VCPKG_ROOT})
get_filename_component(MODERNCPP_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${MODERNCPP_SOURCE_DIR}/.vcpkg)
get_filename_component(IISNATIVEMODULE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${IISNATIVEMODULE_SOURCE_DIR}/.vcpkg)
else()
set(VCPKG_ROOT $ENV{VCPKG_ROOT})
endif()
Expand Down
4 changes: 2 additions & 2 deletions cmake/windows-x86-64/toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR "x86_64")

if(NOT DEFINED ENV{VCPKG_ROOT})
get_filename_component(MODERNCPP_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${MODERNCPP_SOURCE_DIR}/.vcpkg)
get_filename_component(IISNATIVEMODULE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
set(VCPKG_ROOT ${IISNATIVEMODULE_SOURCE_DIR}/.vcpkg)
else()
set(VCPKG_ROOT $ENV{VCPKG_ROOT})
endif()
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate_coverage.bat
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ cd /d "%~dp0.."

set PRESET=windows-x86-64-coverage
set BUILD_DIR=_build\%PRESET%
set TEST_EXE=%BUILD_DIR%\test\Debug\ModernCppTest.exe
set TEST_EXE=%BUILD_DIR%\test\Debug\IISNativeModuleTest.exe
REM Must be absolute: ctest runs each test with its cwd set to the test's
REM own binary dir, not the repo root, so a relative path here would land
REM %BUILD_DIR% underneath _build\%PRESET%\test\ instead.
Expand Down
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.2)

project(ModernCppApp C CXX)
project(IISNativeModuleApp C CXX)

add_subdirectory(module)
add_subdirectory(utils)
Expand All @@ -12,7 +12,7 @@ file(GLOB SRC_FILES

add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} PRIVATE
ModernCppUtils
IISNativeModuleUtils
fmt::fmt
spdlog::spdlog
)
Expand Down
2 changes: 1 addition & 1 deletion src/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.2)

project(ModernCppUtils C CXX)
project(IISNativeModuleUtils C CXX)

file(GLOB UTILS_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
Expand Down
2 changes: 1 addition & 1 deletion src/utils/smoke.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
namespace utils {

auto Smoke::getHello() -> std::string {
return "Hello ModernCpp!";
return "Hello IISNativeModule!";
}

}
Expand Down
4 changes: 2 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.2)

project(ModernCppTest)
project(IISNativeModuleTest)

file(GLOB TEST_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
Expand All @@ -12,7 +12,7 @@ file(GLOB TEST_FILES
add_executable(${PROJECT_NAME} ${TEST_FILES})
target_link_libraries(${PROJECT_NAME} PRIVATE
GTest::gtest
ModernCppUtils
IISNativeModuleUtils
)

target_include_directories(${PROJECT_NAME} PRIVATE
Expand Down
2 changes: 1 addition & 1 deletion test/utils/smoke_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
namespace utils {
TEST(TestUtils, TestSmokeGetHello)
{
EXPECT_EQ("Hello ModernCpp!", utils::Smoke::getHello());
EXPECT_EQ("Hello IISNativeModule!", utils::Smoke::getHello());
}
}
2 changes: 1 addition & 1 deletion vcpkg.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "moderncpp",
"name": "iisnativemodule",
"version": "0.1.0",
"builtin-baseline": "d92484ed3c5020c6679d095ad3e5add907887b62",
"dependencies": [
Expand Down
Loading