Skip to content
Open
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
5 changes: 5 additions & 0 deletions .config/git-hooks/git-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "lib/git-hooks.schema.json",
"version": 1,
"hooks": {}
}
66 changes: 48 additions & 18 deletions .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ defaults:
run:
shell: bash

env:
# Use a recent stable vcpkg baseline from official Microsoft repo
VCPKG_COMMIT: de46587b4beaa638743916fe5674825cecfb48b3

jobs:
build-linux:
runs-on: ubuntu-latest
strategy:
fail-fast: false
fail-fast: true
matrix:
MH_STUFF_COMPILE_LIBRARY: [true, false]
compiler:
Expand All @@ -31,14 +27,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}

- name: Install compilers and tools
run: |
sudo apt-get update
sudo apt-get install -y ${{ matrix.compiler.deps }} ninja-build
sudo apt-get install -y ${{ matrix.compiler.deps }} ninja-build libcurl4-openssl-dev
pip3 install gcovr

echo "Ensuring programs work..."
Expand All @@ -61,7 +53,6 @@ jobs:
cmake --version

cmake -G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
-DMH_STUFF_COMPILE_LIBRARY=${{ matrix.MH_STUFF_COMPILE_LIBRARY }} \
../

Expand Down Expand Up @@ -133,15 +124,54 @@ jobs:
# port-name: mh-stuff
# workflow-pat: ${{ secrets.WORKFLOW_PAT }}

sanitizers:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
sanitizer:
- name: asan
flags: -fsanitize=address -fno-omit-frame-pointer
- name: tsan
flags: -fsanitize=thread
- name: ubsan
flags: -fsanitize=undefined -fno-omit-frame-pointer

steps:
- uses: actions/checkout@v4

- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y clang-15 libc++-15-dev libc++abi-15-dev ninja-build libcurl4-openssl-dev

- name: Build with ${{ matrix.sanitizer.name }}
env:
CXX: clang++-15
CXXFLAGS: ${{ matrix.sanitizer.flags }} -g -O1
run: |
mkdir build
cd build
cmake -G Ninja -DMH_STUFF_COMPILE_LIBRARY=ON ../
cmake --build .

- name: Run tests with ${{ matrix.sanitizer.name }}
env:
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
TSAN_OPTIONS: abort_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:abort_on_error=1
run: |
cd build
ctest --output-on-failure

all-checks-passed:
if: always()
needs: [build-linux]
needs: [build-linux, sanitizers]
runs-on: ubuntu-latest
steps:
- name: Verify all checks passed
run: |
if [[ "${{ needs.build-linux.result }}" != "success" ]]; then
echo "build-linux failed: ${{ needs.build-linux.result }}"
exit 1
fi
echo "All checks passed!"
if: ${{ !(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}
run: echo "All checks passed!"
- name: Fail if any check failed
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: exit 1
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ out_test_linux/
CMakeSettings.json
out_test/
build/
.claude/
.cache/
Empty file removed .gitmodules
Empty file.
108 changes: 108 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is **mh_stuff**, a C++20 utility library containing reusable components for system programming. The library operates in either header-only mode or as a compiled static/shared library, with minimal interdependencies between modules to support selective usage.

**Important**: This library experiences significant API churn with no stability guarantees. It's designed for the author's personal projects and regular structural changes should be expected.

## Build and Test Commands

This project uses CMake with CPM (CMake Package Manager) for dependency management and Just for build task automation. The main dependencies are `mh-cmake-common` for build utilities and `Catch2` for testing.

### Building the Project

```bash
# Using justfile (recommended)
just build

# Or using CMake presets directly
cmake --preset default
cmake --build --preset default

# Or standard CMake build
mkdir build && cd build
cmake .. -G Ninja
cmake --build .
```

### Running Tests

The project uses Catch2 for testing:

```bash
# Using justfile (recommended)
just test

# Or using CMake presets
ctest --preset default

# Or from build directory
cd build && ctest --output-on-failure

# Or run the test executable directly
./build/mh_stuff_tests
```

### Build Configuration Options

- `MH_STUFF_BUILD_SHARED_LIBS=ON/OFF` - Build as shared library instead of static
- `MH_STUFF_COMPILE_LIBRARY=ON/OFF` - Compile implementations vs header-only mode
- `BUILD_TESTING=ON/OFF` - Enable/disable test compilation

## Architecture Overview

### Module Organization

The library is organized into logical modules under `cpp/include/mh/`:

- **`coroutine/`** - C++20 coroutine infrastructure including `task<T>` for async operations
- **`error/`** - Error handling with `mh_ensure()` assertions and `expected<T,E>` monadic error types
- **`concurrency/`** - Thread pools, async operations, and synchronization primitives
- **`io/`** - Platform-agnostic async I/O with `source`/`sink` abstractions
- **`memory/`** - Smart pointers, buffers, and memory management utilities
- **`text/`** - String processing, formatting (fmtlib/std::format), and text utilities
- **`data/`** - Data structures like `lazy<T>`, optional references, and bit manipulation
- **`process/`** - Process management and async process I/O
- **`math/`** - Mathematical utilities including interpolation and random number generation
- **`reflection/`** - Compile-time reflection for enums and structs

### Key Design Patterns

1. **Header-Only with Selective Compilation**: `.hpp` files contain interfaces, `.inl` files contain implementations that can be compiled into a library or included directly
2. **C++20 Coroutine-Based Async**: The `task<T>` type provides future-like semantics with coroutine support for async operations
3. **Platform Abstraction**: Cross-platform code with platform-specific implementations hidden behind clean interfaces
4. **Compile-Time Feature Detection**: Extensive use of `__has_include` and feature test macros for conditional compilation
5. **RAII and Exception Safety**: Strong exception safety guarantees throughout with automatic resource management

### Build System Notes

- Uses CPM (CMake Package Manager) for automatic dependency fetching (Catch2 testing framework)
- Automatically generates a library.cpp file from all .inl files when in compiled library mode
- Tests include compile-time verification that all headers can be included independently
- Supports coverage reporting with gcov/gcovr on GCC/Clang

### Important Compile-Time Configurations

- `MH_COMPILE_LIBRARY` - Controls whether implementations are compiled into a library or included header-only
- `MH_COROUTINES_SUPPORTED` - Enables C++20 coroutine functionality
- `MH_FORMATTER` - Selects formatting backend (fmtlib, std::format, or none)
- `MH_BROKEN_UNICODE=1` - Forced workaround for compiler Unicode issues

## Development Guidelines

- This library requires C++20 and uses modern C++ features extensively
- Platform support includes Windows (MSVC), Linux (GCC), and macOS (Clang)
- Code follows RAII principles with move semantics preferred over copying
- Exception safety is critical - all code should provide strong exception safety guarantees
- The library is designed for zero-overhead abstractions with extensive use of `constexpr`

## Testing

Tests are located in the `test/` directory and use Catch2. The build system:
- Automatically discovers all `*_test.cpp` files
- Creates a unified test executable `mh_stuff_tests`
- Includes compile-time tests to verify all headers can be included independently
- Conditionally excludes platform-specific tests (e.g., `io_getopt_test.cpp` on systems without getopt)
46 changes: 3 additions & 43 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ add_library(${PROJECT_NAME} ${MH_INTERFACE_OR_EMPTY}
)
add_library(mh::stuff ALIAS ${PROJECT_NAME})

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/mh-cmake-common")
include(mh-BasicInstall)
include(mh-CheckCoroutineSupport)

if (MH_STUFF_COMPILE_LIBRARY)
find_package(CURL REQUIRED)

Expand Down Expand Up @@ -85,9 +81,6 @@ else()
)
endif()

mh_check_cxx_coroutine_support(SUPPORTS_COROUTINES COROUTINES_FLAGS)
target_compile_options(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE} ${COROUTINES_FLAGS})

target_include_directories(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE}
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/cpp/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
Expand All @@ -112,6 +105,7 @@ endif()

if (CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
target_compile_options(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE} -pthread)
target_compile_options(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE} -Wno-missing-field-initializers)
target_link_options(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE} -pthread)
endif()

Expand All @@ -135,6 +129,8 @@ message(STATUS "Forcing MH_BROKEN_UNICODE=1 to work around compiler Unicode issu
if (NOT DEFINED BUILD_TESTING)
if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(BUILD_TESTING ON)
# Define MH_STUFF_STANDALONE_BUILD when building as main project
target_compile_definitions(${PROJECT_NAME} ${MH_PUBLIC_OR_INTERFACE} "MH_STUFF_STANDALONE_BUILD")
else()
set(BUILD_TESTING OFF)
endif()
Expand All @@ -146,40 +142,4 @@ if (BUILD_TESTING)
add_subdirectory("test")
endif()

mh_basic_install(
PROJ_INCLUDE_DIRS "cpp/include/"
)

###########################################
# "install" is intended for vcpkg support #
###########################################
# include(CMakePackageConfigHelpers)
# configure_package_config_file(
# cmake/config.cmake.in
# "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
# INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}"
# )

# include(GNUInstallDirs)

# write_basic_package_version_file(
# "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
# VERSION ${PROJECT_VERSION}
# COMPATIBILITY SameMajorVersion
# )

# install(
# FILES
# "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
# "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
# DESTINATION
# "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}"
# )

# install(TARGETS stuff EXPORT ${PROJECT_NAME}_targets)
# install(DIRECTORY cpp/include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# install(
# EXPORT ${PROJECT_NAME}_targets
# NAMESPACE mh::
# DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}"
# )
Loading
Loading