mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 14:15:02 +00:00
3.5 KiB
3.5 KiB
Macro Policy
Philosophy
This codebase enforces a "no macros" culture both socially and mechanically. Macros are banned except in strictly whitelisted headers. This is how large, sane codebases survive.
Why Ban Macros?
- Type safety: Macros don't respect C++ types and can cause subtle bugs
- Debuggability: Macros are preprocessor text substitution, making debugging difficult
- Scope pollution: Macros don't respect namespaces and can collide globally
- IDE support: Tools struggle with macros (no refactoring, poor code navigation)
- Maintainability: Modern C++ has better alternatives (constexpr, templates, inline functions)
Enforcement Mechanisms
1. Compiler Warnings
The build system enables strict warnings:
- Clang/GCC:
-Wmacro-redefined,-Wreserved-id-macro - MSVC:
/we4005(macro redefinition as error)
These catch accidental macro redefinitions and reserved identifier usage.
2. Static Analysis (clang-tidy)
cppcoreguidelines-macro-usage check is enabled with:
- Only CAPS_CASE macros trigger warnings (CheckCapsOnly)
- Whitelisted pattern:
^SDL3CPP_.*_HPP$|^SDL_MAIN_HANDLED$
This allows include guards and necessary SDK configuration while rejecting everything else.
3. CI Enforcement
The scripts/check_macros.sh script runs in CI and rejects any #define outside the whitelist.
Current whitelist (include guards and SDK config only):
- All
.hppheader files (for include guards matchingSDL3CPP_*_HPP) src/app/sdl_macros.hpp(forSDL_MAIN_HANDLEDconfiguration)
4. Pre-commit Hook (Optional)
Run the macro check locally before committing:
./scripts/check_macros.sh
What to Use Instead
| ❌ Don't Use | ✅ Use Instead |
|---|---|
#define PI 3.14159 |
constexpr double pi = 3.14159; |
#define MAX(a,b) ((a)>(b)?(a):(b)) |
template<typename T> constexpr T max(T a, T b) { return a > b ? a : b; } or std::max() |
#define INLINE |
inline keyword |
#define DEBUG_LOG(x) ... |
inline void debug_log(...) with if constexpr |
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
template<typename T, size_t N> constexpr size_t array_size(T(&)[N]) { return N; } or std::size() |
Exceptions (Whitelisted)
The only allowed macros are:
- Include guards:
SDL3CPP_*_HPPpattern - SDL configuration:
SDL_MAIN_HANDLED(required by SDL3)
If you believe you need a macro:
- First, try
constexpr,inline, or templates - If absolutely necessary, propose adding it to the whitelist with justification
- Update
scripts/check_macros.shwhitelist - Update
.clang-tidyAllowedRegexp pattern
Running Checks Locally
# Check macro policy
./scripts/check_macros.sh
# Run clang-tidy
cmake -B build -DENABLE_CLANG_TIDY=ON
cmake --build build
# Build with warnings
cmake -B build
cmake --build build
CI Integration
The CI pipeline automatically:
- Runs
scripts/check_macros.shon every build - Enables clang-tidy checks (when configured)
- Compiles with strict macro-related warnings
Build will fail if:
- New
#defineappears in non-whitelisted files - Macros are redefined
- Reserved identifier macros are used