📋 Table of Contents
- What Are Contracts?
- Introduction
- Understanding the HPX Module Structure
- CMake Integration and Build System Design
- Testing Strategy: Multi-Mode Validation
- Technical Challenges and Solutions
- Development Environment Setup
- Results and Impact
- Real-World Usage Examples
- Lessons Learned
- Future Directions
- Acknowledgments
- Conclusion
What Are Contracts?
According to the C++26 Contracts proposal P2900R14, "The primary goal of this facility is to enable identifying, in code, when a program is correct or incorrect in ways that does not, just by being used, change whether a program is correct or incorrect."
Contracts are used to clearly state what each function expects and guarantees. They help make assumptions in the code explicit and catch mistakes early. By adding preconditions, postconditions, and contract assertions, we can:
- Detect when a function is called with invalid data or ends in an incorrect state
- Make the purpose and correct use of functions easier to understand
- Improve debugging and maintenance without changing runtime behavior
Overall, contracts in HPX can help ensure that its components work together safely and consistently in parallel execution.
Introduction
This summer, I had the opportunity to work on implementing C++26 contracts support for HPX (High Performance ParalleX) as part of Google Summer of Code. My goal was to create a contracts module that could use native C++26 contract syntax when available, but fall back to regular assertions when the compiler doesn't support contracts yet. Later, we decided to also include an option of upgrading regular assertions to contract assertions.
Understanding the HPX Module Structure
First, I needed to understand how HPX structures its modules. HPX follows a clean separation of concerns with modules located in libs/core/ and libs/full/. Each module maintains a consistent structure:
libs/core/contracts/ ├── CMakeLists.txt # Module configuration ├── include/hpx/ │ ├── contracts.hpp # Public API header │ └── modules/contracts.hpp # Implementation header ├── tests/ │ ├── unit/ # Unit tests │ ├── performance/ # Performance tests │ └── regressions/ # Regression tests ├── docs/ │ └── index.rst # Sphinx documentation └── README.md # Quick reference
This structure ensures that each module is self-contained, testable, and follows HPX's documentation standards.
Header File Architecture and Design Logic
The contracts module follows HPX's dual-header pattern with specific design considerations:
Public API Header: include/hpx/contracts.hpp
This is the user-facing header that provides a clean, simple interface:
// include/hpx/contracts.hpp #pragma once #include <hpx/modules/contracts.hpp> // Simple forwarding header that includes the implementation // This separation allows for future API evolution without breaking user code
Implementation Header: include/hpx/modules/contracts.hpp
This contains the actual implementation with sophisticated conditional compilation logic:
// include/hpx/modules/contracts.hpp
#pragma once
#include <hpx/config.hpp>
#include <hpx/assert.hpp> // Crucial: HPX_ASSERT must be defined first
// Contract implementation: automatically selects native C++26 contracts
// or falls back to HPX_ASSERT based on compiler capabilities
#ifdef HPX_HAVE_CONTRACTS
#if HPX_HAVE_NATIVE_CONTRACTS
// Native C++26 contracts mode
#define HPX_PRE(x) pre(x)
#define HPX_CONTRACT_ASSERT(x) contract_assert(x)
#define HPX_POST(x) post(x)
#else
// Fallback mode: PRE/POST become no-ops, CONTRACT_ASSERT maps to assertions
#pragma message("HPX Contracts: Using assertion fallback mode. " \
"HPX_PRE/HPX_POST are no-ops, HPX_CONTRACT_ASSERT maps to HPX_ASSERT.")
#define HPX_PRE(x)
#define HPX_CONTRACT_ASSERT(x) HPX_ASSERT((x))
#define HPX_POST(x)
#endif
#else
// Contracts disabled: PRE/POST are no-ops, CONTRACT_ASSERT remains available
#define HPX_PRE(x)
#define HPX_CONTRACT_ASSERT(x) HPX_ASSERT((x))
#define HPX_POST(x)
#endif
#ifdef HPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS
// Override HPX_ASSERT to use contract assertions
#define HPX_ASSERT(x) HPX_CONTRACT_ASSERT(x)
#endif
Design Logic and Decision Tree
The header implements a sophisticated decision tree based on three key factors:
- User Configuration: HPX_HAVE_CONTRACTS (set by CMake)
- Compiler Capability: HPX_HAVE_NATIVE_CONTRACTS (detected by CMake)
- Enhancement Mode: HPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS flag
Decision Matrix: ┌─────────────────┬──────────────────┬─────────────────┬────────────────────────┐ │ HPX_HAVE_ │ HPX_HAVE_NATIVE_ │ Enhancement │ Result │ │ CONTRACTS │ CONTRACTS │ Mode │ │ ├─────────────────┼──────────────────┼─────────────────┼────────────────────────┤ │ ON │ YES │ OFF │ Native C++26 contracts │ │ ON │ YES │ ON │ Native + Enhanced │ │ ON │ NO │ ANY │ Assertion fallback │ │ OFF │ NO │ ANY │ Debug assert │ └─────────────────┴──────────────────┴─────────────────┴────────────────────────┘ Note: HPX_HAVE_NATIVE_CONTRACTS is determined by CMake's compiler capability detection. When Enhancement Mode is ON but native contracts are unavailable, CMake issues a warning that enhanced assertions provide no actual benefits.
CMake Integration and Build System Design
The contracts module integrates deeply with HPX's CMake build system, providing multiple configuration options and automatic compiler detection.
CMake Configuration Options
The module introduces CMake variables that control contract behavior:
# Primary contract control -DHPX_WITH_CONTRACTS=ON|OFF # Enable/disable contracts module # Contract enhancement options -DHPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS=ON|OFF # Upgrade existing assertions # Contract evaluation behavior requires experimental compiler support # Example for Clang with contracts: -DCMAKE_CXX_STANDARD=26 -DCMAKE_CXX_FLAGS="-fcontracts -fcontract-evaluation-semantic=enforce"
Automatic Compiler Detection Logic
The build system automatically detects compiler contract support using CMake's add_hpx_config_test in the test configuration and sets the HPX_HAVE_NATIVE_CONTRACTS configuration variable:
# In libs/core/contracts/tests/unit/CMakeLists.txt
# Detect if __cpp_contracts is available at configure time
add_hpx_config_test(
HPX_HAVE_NATIVE_CONTRACTS
SOURCE "
#ifndef __cpp_contracts
#error No native contracts support
#endif
int main() { return 0; }
"
)
Complete Build Command Examples
Here are comprehensive examples of how to build HPX with different contract configurations:
Example 1: Future C++26 Standard Build
cmake /path/to/hpx -GNinja \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_STANDARD=26 \ -DHPX_WITH_CONTRACTS=ON \ -DHPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS=ON \ -DHPX_WITH_TESTS=ON \ -DHPX_WITH_EXAMPLES=ON \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_FLAGS="-fcontract-evaluation-semantic=enforce" # This configuration (for future C++26 compilers): # - Enables contracts module # - Uses standard C++26 contract syntax (no experimental flags needed) # - Only evaluation semantic flag needed to control contract behavior # - Upgrades all HPX_ASSERT calls to contract assertions
Example 2: Current Experimental Build (EricWF's Clang fork)
cmake /path/to/hpx -GNinja \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_STANDARD=23 \ -DHPX_WITH_CONTRACTS=ON \ -DHPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS=ON \ -DHPX_WITH_TESTS=ON \ -DHPX_WITH_EXAMPLES=ON \ -DCMAKE_CXX_COMPILER=/opt/clang-nightly/bin/clang++ \ -DCMAKE_CXX_FLAGS="-stdlib=libc++ -fcontracts -fcontract-evaluation-semantic=enforce" # This configuration (for current experimental Clang): # - Uses EricWF's experimental Clang with contracts support # - Requires -fcontracts flag to enable experimental contracts # - Needs -stdlib=libc++ for proper standard library support # - Falls back to assertions when contracts fail to link
EricWF's Clang fork Contract Flags
The experimental Clang nightly build supports these contract-specific options:
- Enable contracts: -std=c++23 -fcontracts -stdlib=libc++
- Control evaluation behavior: -fcontract-evaluation-semantic=<ignore|observe|enforce|quick_enforce>
- Configure standard library contract behavior: -fcontract-group-evaluation-semantic=std=<...>
Example 3: Production Build with Assertion Fallback
cmake /path/to/hpx -GNinja \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_STANDARD=23 \ -DHPX_WITH_CONTRACTS=ON \ -DHPX_HAVE_ASSERTS_AS_CONTRACT_ASSERTS=OFF \ -DHPX_WITH_TESTS=OFF \ -DHPX_WITH_EXAMPLES=OFF \ -DCMAKE_CXX_COMPILER=g++ # This configuration: # - Uses standard GCC (no contract support) # - Contracts automatically fall back to assertions # - Optimized for production with minimal overhead # - Contracts provide documentation value and debugging aid
Example 4: Release for Maximum Performance
cmake /path/to/hpx -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_STANDARD=20 \ -DHPX_WITH_CONTRACTS=OFF \ -DHPX_WITH_TESTS=OFF \ -DCMAKE_CXX_COMPILER=g++ \ -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG" # This configuration: # - Completely disables contracts and assertions # - Maximum performance for production deployment
CMake Module Integration
The contracts module's CMakeLists.txt shows how it integrates with HPX's build system:
# libs/core/contracts/CMakeLists.txt
# Define the module headers
set(contracts_headers
hpx/contracts.hpp hpx/modules/contracts.hpp
)
# Create the module target using HPX's module system
add_hpx_module(
core contracts
GLOBAL_HEADER_GEN OFF
SOURCES ${contracts_sources}
HEADERS ${contracts_headers}
COMPAT_HEADERS ${contracts_compat_headers}
MODULE_DEPENDENCIES hpx_config hpx_preprocessor hpx_assertion
CMAKE_SUBDIRS examples tests
)
# Contract-specific configuration is handled through HPX's config system
# HPX_HAVE_CONTRACTS and related variables are set by the main build
# HPX_HAVE_NATIVE_CONTRACTS is detected in the test CMakeLists.txt
Integration with User Projects
When users build their own projects against HPX with contracts, they can leverage the same system:
# User's CMakeLists.txt
find_package(HPX REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app HPX::hpx)
# If HPX was built with contracts support, this automatically enables:
# - Contract macros (HPX_PRE, HPX_POST, HPX_CONTRACT_ASSERT)
# - Fallback behavior based on compiler capabilities
# User code can now use contracts:
# void my_function(int x) HPX_PRE(x > 0) HPX_POST(r: r >= x) {
# return x + 1;
# }
Testing Strategy: Multi-Mode Validation
Testing a system that behaves differently based on compiler capabilities required a sophisticated approach. I implemented automatic test mode detection using CMake:
Compiler Capability Detection
# Detection happens in the test CMakeLists.txt
add_hpx_config_test(
HPX_HAVE_NATIVE_CONTRACTS
SOURCE "
#ifndef __cpp_contracts
#error No native contracts support
#endif
int main() { return 0; }
"
)
Conditional Test Generation
Based on the detection results, different test suites are built:
Declaration Tests (Native C++26 mode):
int factorial(int n) HPX_PRE(n >= 0) HPX_POST(r: r > 0) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
Fallback Tests (Assertion mode):
int main(){
HPX_PRE(true); //no-op in fallback mode
HPX_POST(true);
HPX_CONTRACT_ASSERT(true); //Maps to HPX_ASSERT in fallback mode
// Add a failing assertion to test WILL_FAIL behavior
HPX_CONTRACT_ASSERT(false); // This should abort in Debug mode
HPX_TEST(true);
return hpx::util::report_errors();
}
Disabled Tests: Verify that preconditions and postconditions become no-ops while contract assertions remain functional.
Test Categories by Design
Each test category validates different aspects:
- Success tests: Verify contracts work correctly when conditions are met
- Failure tests: Ensure proper violation handling (these tests are expected to fail)
- Syntax tests: Validate that C++26 contract syntax compiles correctly
Running Contract Tests
To run the contract tests specifically, use these commands:
# Run all contract module tests ninja tests.unit.modules.contracts # Run contract tests with verbose output ctest -R contract -V
These commands will execute the appropriate test suite based on your compiler capabilities and build configuration, whether using native C++26 contracts or assertion fallback mode.
Advanced Testing Infrastructure
The testing system automatically generates different test suites based on detected compiler capabilities:
Automatic Test Configuration
# CMake test generation logic from actual implementation
if(HPX_HAVE_NATIVE_CONTRACTS)
message(STATUS "HPX Contracts: Native C++26 contracts detected - building declaration tests")
# Declaration contracts tests (C++26 declaration syntax)
set(contract_tests
declaration_contracts_succeed
declaration_contracts_fail_pre
declaration_contracts_fail_post
declaration_contracts_fail_contract_assert
)
foreach(test ${contract_tests})
add_hpx_executable(
${test}_test INTERNAL_FLAGS
SOURCES ${test}.cpp
NOLIBS
DEPENDENCIES hpx_core
EXCLUDE_FROM_ALL
FOLDER "Tests/Unit/Modules/Core/Contracts/"
)
add_hpx_unit_test("modules.contracts" ${test})
endforeach()
else()
message(STATUS "HPX Contracts: Fallback mode detected - building fallback tests")
# Fallback contracts tests (simple syntax for fallback mode)
set(contract_tests
fallback_contracts_succeed
fallback_contracts_fail
)
foreach(test ${contract_tests})
add_hpx_executable(
${test}_test INTERNAL_FLAGS
SOURCES ${test}.cpp
NOLIBS
DEPENDENCIES hpx_core
EXCLUDE_FROM_ALL
FOLDER "Tests/Unit/Modules/Core/Contracts/"
)
add_hpx_unit_test("modules.contracts" ${test})
endforeach()
endif()
Example Test Files
The actual test files in the repository are simpler than complex examples might suggest. The testing focuses on basic contract functionality and mode detection rather than elaborate scenarios.
Technical Challenges and Solutions
Challenge 1: Development Environment Limitations
Working on Windows with experimental compiler builds presented immediate challenges. Building LLVM from source required extensive memory (16GB+) and long build times, which were not feasible on my development machine.
Solution: Used mentor-provided dockerized development environment with pre-built EricWF's experimental Clang, ensuring reproducible builds across different platforms.
Challenge 2: Contract Linking Errors
Early testing revealed linker errors when using contract violations: undefined reference to '__handle_contract_violation_v3'. The experimental runtime support was incomplete.
Solution: Implemented intelligent fallback system that gracefully degrades to assertion-based contracts when native contract runtime support fails to link properly.
Challenge 3: Multi-Mode Compatibility
The module needed to work seamlessly across different compiler capabilities and configuration combinations without breaking existing HPX code.
Solution: Designed layered configuration system with automatic capability detection and adaptive macro definitions that maintain compatibility across all modes.
Development Environment Setup
Development was conducted using Windows Subsystem for Linux (WSL) to access a Linux-like environment. The process involved:
- HPX Environment Verification: Built and tested standard HPX examples to ensure proper setup
- Experimental Compiler Access: Used pre-built Docker container with EricWF's experimental Clang
- Contract Integration Testing: Validated contract syntax compilation and identified linking limitations
- Module Implementation: Added HPX_WITH_CONTRACTS configuration and implemented the contracts module
The final working environment was preserved in a Docker image for reproducible development and testing.
Results and Impact
The contracts module successfully delivers on all its goals:
Real-World Usage Examples
The module enables contract specifications in user code. Here's a simple example of how it works:
// Basic usage example
#include <hpx/contracts.hpp>
int safe_divide(int a, int b)
HPX_PRE(b != 0) // Precondition: no division by zero
HPX_POST(r: r == a / b) // Postcondition: verify result
{
return a / b;
}
void process_data(std::vector<int>& data, size_t index) {
HPX_CONTRACT_ASSERT(index < data.size()); // Contract assertion
data[index] *= 2;
}
The behavior adapts automatically based on compiler support and configuration:
- Native Mode: Uses real C++26 contract syntax when available
- Fallback Mode: HPX_PRE/HPX_POST become no-ops, HPX_CONTRACT_ASSERT maps to HPX_ASSERT
- Disabled Mode: Pre/post conditions become no-ops for performance
Lessons Learned
This project taught me several valuable lessons:
- Experimental Features Need Robust Fallbacks: Working with pre-standard features requires careful planning for compatibility and graceful degradation.
- Documentation During Development: Writing clear documentation as you develop improves the design itself - not just the end result.
- HPX Codebase Architecture: Gained familiarity with HPX's module structure and implementation patterns.
- Advanced CMake Understanding: Learned in-depth CMake configuration, feature detection, and build system integration.
- Cross-Compiler Development: Experience building with different compilers and handling experimental features.
- Build System Clarity: Better understanding of compiling, linking, and runtime behavior distinctions.
- Feature Testing: Learned proper feature detection techniques and header file organization.
- Containerized Development: Practical Docker usage for reproducible development environments.
Configuration System Insights
I learned how HPX's configuration system works through practical implementation:
# Build files generate defines.hpp with configuration hpx_build_clang_nightly/libs/core/config/include/hpx/config/defines.hpp: #define HPX_HAVE_CONTRACTS # Source includes the configuration ./libs/core/config/include/hpx/config.hpp: #include <hpx/config/defines.hpp> # Convention: HPX_HAVE_FEATURE for capability flags
Future Directions
This contracts module provides a foundation for further development in HPX:
Immediate Enhancements
- Guard Solution for Postconditions: Implementing a guard mechanism to better mimic postconditions in fallback mode
- Library Hardening: One of the future goals is systematic library hardening using contracts
Algorithm Hardening
The next major goal is implementing algorithm hardening for HPX's parallel algorithms, similar to the approach described in P3471R2. This would involve adding contract-based safety checks to algorithms like:
- Small vector operations
- Sorting algorithms
- Copy and move operations
- Other parallel algorithm implementations
Long-term Benefits
- Foundation for systematic safety improvements across HPX
- Experience with contract-based programming in high-performance parallel code
- Preparation for eventual C++26 standard adoption
Acknowledgments
This project would not have been possible without the support and guidance of many individuals:
Mentors: Panagiotis Syskakis and Isidoros Tsaousis-Seiras provided invaluable guidance throughout the development process, helping navigate both technical challenges and project planning.
HPX Community: Special thanks to Hartmut Kaiser and the entire HPX community for creating such a welcoming environment and providing crucial insights into HPX's architecture and design philosophy.
Google Summer of Code: Thank you to the Google Summer of Code program for providing this incredible opportunity to contribute to open-source software and advance the state of C++ parallel programming.
Special Recognition: EricWF for providing the experimental Clang builds that made native contract testing possible during this early phase of C++26 development.
Conclusion
The HPX contracts module successfully implements C++26 contract support with intelligent fallback behavior. The implementation handles the transition from experimental contract syntax to standardized C++26 contracts through a layered configuration system that adapts to compiler capabilities.
The module integrates cleanly with HPX's existing build system and maintains backward compatibility. By providing native contract support when available and appropriate fallback behavior (no-ops for HPX_PRE/HPX_POST, assertion mapping for HPX_CONTRACT_ASSERT), it offers a practical path forward as C++26 contracts become more widely available. The implementation is available for testing and integration into the main HPX codebase.