Skip to content

Commit 1204978

Browse files
committed
docs(clang-tidy): Add Windows build instructions and GeneralsTools mention
- Document Windows built-in approach (recommended) - Document Mac/Linux plugin approach - Add instructions for building checks into clang-tidy on Windows - Mention pre-built binaries in GeneralsTools repository
1 parent 812b398 commit 1204978

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# GeneralsGameCode Clang-Tidy Custom Checks
2+
3+
Custom clang-tidy checks for the GeneralsGameCode codebase. **This is primarily designed for Windows**, where checks are built directly into clang-tidy. Mac/Linux users can optionally use the plugin version.
4+
5+
## Quick Start
6+
7+
### Windows
8+
9+
**Option 1: Use Pre-built clang-tidy**
10+
- Precompiled binaries can be found at: https://github.com/TheSuperHackers/GeneralsTools
11+
12+
**Option 2: Build It Yourself**
13+
14+
Follow the manual steps in the [Windows: Building Checks Into clang-tidy](#windows-building-checks-into-clang-tidy) section below.
15+
16+
**Usage**
17+
```powershell
18+
llvm-project\build\bin\clang-tidy.exe -p build/clang-tidy `
19+
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' `
20+
file.cpp
21+
```
22+
23+
### macOS/Linux (Plugin Version)
24+
25+
If you prefer the plugin approach on macOS/Linux:
26+
27+
```bash
28+
# Build the plugin
29+
cd scripts/clang-tidy-plugin
30+
mkdir build && cd build
31+
cmake .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm
32+
cmake --build . --config Release
33+
34+
# Use with --load flag
35+
clang-tidy -p build/clang-tidy \
36+
--checks='-*,generals-use-is-empty' \
37+
-load scripts/clang-tidy-plugin/build/lib/libGeneralsGameCodeClangTidyPlugin.so \
38+
file.cpp
39+
```
40+
41+
**Note:** On Windows, plugin loading via `--load` is **not supported** due to DLL static initialization limitations. Windows users must use the built-in version.
42+
43+
## Checks
44+
45+
### `generals-use-is-empty`
46+
47+
Finds uses of `getLength() == 0`, `getLength() > 0`, `compare("") == 0`, or `compareNoCase("") == 0` on `AsciiString` and `UnicodeString`, and `Get_Length() == 0` on `StringClass` and `WideStringClass`, and suggests using `isEmpty()`/`Is_Empty()` or `!isEmpty()`/`!Is_Empty()` instead.
48+
49+
**Examples:**
50+
51+
```cpp
52+
// Before (AsciiString/UnicodeString)
53+
if (str.getLength() == 0) { ... }
54+
if (str.getLength() > 0) { ... }
55+
if (str.compare("") == 0) { ... }
56+
if (str.compareNoCase("") == 0) { ... }
57+
if (str.compare(AsciiString::TheEmptyString) == 0) { ... }
58+
59+
// After (AsciiString/UnicodeString)
60+
if (str.isEmpty()) { ... }
61+
if (!str.isEmpty()) { ... }
62+
if (str.isEmpty()) { ... }
63+
if (str.isEmpty()) { ... }
64+
if (str.isEmpty()) { ... }
65+
66+
// Before (StringClass/WideStringClass)
67+
if (str.Get_Length() == 0) { ... }
68+
if (str.Get_Length() > 0) { ... }
69+
70+
// After (StringClass/WideStringClass)
71+
if (str.Is_Empty()) { ... }
72+
if (!str.Is_Empty()) { ... }
73+
```
74+
75+
### `generals-use-this-instead-of-singleton`
76+
77+
Finds uses of singleton global variables (like `TheGameLogic->method()` or `TheGlobalData->member`) inside member functions of the same class type, and suggests using the member directly (e.g., `method()` or `member`) instead of the singleton reference.
78+
79+
**Examples:**
80+
81+
```cpp
82+
// Before
83+
void GameLogic::update() {
84+
UnsignedInt now = TheGameLogic->getFrame();
85+
TheGameLogic->setFrame(now + 1);
86+
TheGameLogic->m_frame = 10;
87+
}
88+
89+
// After
90+
void GameLogic::update() {
91+
UnsignedInt now = getFrame();
92+
setFrame(now + 1);
93+
m_frame = 10;
94+
}
95+
```
96+
97+
## Prerequisites
98+
99+
Before using clang-tidy, you need to generate a compile commands database:
100+
101+
```bash
102+
cmake -B build/clang-tidy -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -G Ninja
103+
```
104+
105+
This creates `build/clang-tidy/compile_commands.json` which tells clang-tidy how to compile each file.
106+
107+
## Windows: Building Checks Into clang-tidy
108+
109+
Since plugin loading via `--load` doesn't work on Windows, the checks are integrated directly into the clang-tidy source tree. This is the recommended approach for Windows.
110+
111+
### Step 1: Clone and Build LLVM
112+
113+
### Step 2: Copy Plugin Files to LLVM Source Tree
114+
115+
```powershell
116+
# Create the plugin directory in clang-tools-extra
117+
mkdir llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode
118+
119+
# Copy the plugin source files
120+
cp -r scripts\clang-tidy-plugin\*.cpp llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
121+
cp -r scripts\clang-tidy-plugin\*.h llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
122+
cp -r scripts\clang-tidy-plugin\readability llvm-project\clang-tools-extra\clang-tidy\plugins\generalsgamecode\
123+
```
124+
125+
**Important:** After copying, you need to update the include paths in the headers:
126+
- Change `#include "clang-tidy/ClangTidyCheck.h"` to `#include "../../../ClangTidyCheck.h"`
127+
- Change `#include "clang-tidy/ClangTidyModule.h"` to `#include "../../ClangTidyModule.h"`
128+
129+
### Step 3: Create CMakeLists.txt for the Module
130+
131+
Create `llvm-project/clang-tools-extra/clang-tidy/plugins/generalsgamecode/CMakeLists.txt`:
132+
133+
```cmake
134+
add_clang_library(clangTidyGeneralsGameCodeModule STATIC
135+
GeneralsGameCodeTidyModule.cpp
136+
readability/UseIsEmptyCheck.cpp
137+
readability/UseThisInsteadOfSingletonCheck.cpp
138+
139+
LINK_LIBS
140+
clangTidy
141+
clangTidyUtils
142+
)
143+
144+
clang_target_link_libraries(clangTidyGeneralsGameCodeModule
145+
PRIVATE
146+
clangAST
147+
clangASTMatchers
148+
clangBasic
149+
clangLex
150+
clangTooling
151+
)
152+
```
153+
154+
### Step 4: Register the Module
155+
156+
**Modify `llvm-project/clang-tools-extra/clang-tidy/CMakeLists.txt`:**
157+
158+
Add the subdirectory:
159+
```cmake
160+
add_subdirectory(plugins/generalsgamecode)
161+
```
162+
163+
Add to `ALL_CLANG_TIDY_CHECKS`:
164+
```cmake
165+
set(ALL_CLANG_TIDY_CHECKS
166+
...
167+
clangTidyGeneralsGameCodeModule
168+
...
169+
)
170+
```
171+
172+
**Modify `llvm-project/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h`:**
173+
174+
Add the anchor to force linker inclusion:
175+
```cpp
176+
// This anchor is used to force the linker to link the GeneralsGameCodeModule.
177+
extern volatile int GeneralsGameCodeModuleAnchorSource;
178+
static int LLVM_ATTRIBUTE_UNUSED GeneralsGameCodeModuleAnchorDestination =
179+
GeneralsGameCodeModuleAnchorSource;
180+
```
181+
182+
**Modify `llvm-project/clang-tools-extra/clang-tidy/plugins/generalsgamecode/GeneralsGameCodeTidyModule.cpp`:**
183+
184+
Ensure the anchor is defined:
185+
```cpp
186+
namespace clang::tidy {
187+
// ... module registration ...
188+
189+
// Force linker to include this module
190+
volatile int GeneralsGameCodeModuleAnchorSource = 0;
191+
}
192+
```
193+
194+
### Step 5: Rebuild clang-tidy
195+
196+
```powershell
197+
cd llvm-project\build
198+
ninja clang-tidy
199+
```
200+
201+
### Step 6: Use the Built-in Checks
202+
203+
Once rebuilt, the checks are always available - no `--load` flag needed:
204+
205+
```powershell
206+
llvm-project\build\bin\clang-tidy.exe -p build/clang-tidy `
207+
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' `
208+
file.cpp
209+
```
210+
211+
212+
## macOS/Linux: Building the Plugin
213+
214+
If you're on macOS or Linux and want to use the plugin version:
215+
216+
### Prerequisites
217+
218+
**macOS:**
219+
```bash
220+
brew install llvm@21
221+
```
222+
223+
**Linux (Ubuntu/Debian):**
224+
```bash
225+
sudo apt-get install llvm-21-dev clang-21 libclang-21-dev
226+
```
227+
228+
### Building the Plugin
229+
230+
```bash
231+
cd scripts/clang-tidy-plugin
232+
mkdir build && cd build
233+
cmake .. -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm -DClang_DIR=/path/to/clang/lib/cmake/clang
234+
cmake --build . --config Release
235+
```
236+
237+
The plugin will be built as a shared library (`.so` on Linux, `.dylib` on macOS) in the `build/lib/` directory.
238+
239+
### Using the Plugin
240+
241+
```bash
242+
clang-tidy -p build/clang-tidy \
243+
--checks='-*,generals-use-is-empty,generals-use-this-instead-of-singleton' \
244+
-load scripts/clang-tidy-plugin/build/lib/libGeneralsGameCodeClangTidyPlugin.so \
245+
file.cpp
246+
```
247+
248+
**Important:** The plugin must be built with the same LLVM version as the `clang-tidy` executable in your PATH. The CMake build will display which LLVM version it found (e.g., `Found LLVM 21.1.7`). Verify this matches your `clang-tidy --version` output.
249+
250+
- Windows plugins not working is a known limitation - see [GitHub issue #159710](https://github.com/llvm/llvm-project/issues/159710) and [LLVM Discourse discussion](https://discourse.llvm.org/t/clang-tidy-is-clang-tidy-out-of-tree-check-plugin-load-mechanism-guaranteed-to-work-with-msvc/84111)

0 commit comments

Comments
 (0)