Skip to content

Commit 3a9750e

Browse files
authored
Fix #13290 (Import project: -isystem in compile_commands.json) (cppcheck-opensource#8862)
1 parent b080d6e commit 3a9750e

6 files changed

Lines changed: 434 additions & 1 deletion

File tree

man/manual-premium.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,17 @@ To ignore certain folders you can use `-i`. This will skip analysis of source fi
307307

308308
cppcheck --project=compile_commands.json -ifoo
309309

310+
### `-isystem`, `-I`, `--sysroot`
311+
312+
We have a [script](https://github.com/cppcheck-opensource/cppcheck/blob/main/tools/tweak-compile-commands.py) that tweaks compile_commands.json.
313+
314+
You can use it to:
315+
* use `--sysroot` flags in Cppcheck analysis
316+
* use `-isystem` paths in Cppcheck analysis
317+
* remove `-I` paths from the compile_commands.json
318+
319+
See [script documentation](https://github.com/cppcheck-opensource/cppcheck/blob/main/tools/tweak-compile-commands.md).
320+
310321
## Visual Studio
311322

312323
You can run Cppcheck on individual project files (`*.vcxproj`) or on a whole solution (`*.sln`) or (`*.slnx`).
@@ -1166,6 +1177,7 @@ To use a `.cfg` file shipped with Cppcheck, pass the `--library=<lib>` option. T
11661177
| `lua.cfg` | | |
11671178
| `mfc.cfg` | [MFC](https://learn.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications) | |
11681179
| `microsoft_atl.cfg` | [ATL](https://learn.microsoft.com/en-us/cpp/atl/active-template-library-atl-concepts) | |
1180+
| `microsoft_gsl.cfg` | [Microsoft.GSL](https://github.com/microsoft/gsl) | |
11691181
| `microsoft_sal.cfg` | [SAL annotations](https://learn.microsoft.com/en-us/cpp/c-runtime-library/sal-annotations) | |
11701182
| `microsoft_unittest.cfg` | [CppUnitTest](https://learn.microsoft.com/en-us/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference) | |
11711183
| `motif.cfg` | | |

man/manual.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,17 @@ To ignore certain folders you can use `-i`. This will skip analysis of source fi
308308

309309
cppcheck --project=compile_commands.json -ifoo
310310

311+
### `-isystem`, `-I`, `--sysroot`
312+
313+
We have a [script](https://github.com/cppcheck-opensource/cppcheck/blob/main/tools/tweak-compile-commands.py) that tweaks compile_commands.json.
314+
315+
You can use it to:
316+
* use `--sysroot` flags in Cppcheck analysis
317+
* use `-isystem` paths in Cppcheck analysis
318+
* remove `-I` paths from the compile_commands.json
319+
320+
See [script documentation](https://github.com/cppcheck-opensource/cppcheck/blob/main/tools/tweak-compile-commands.md).
321+
311322
## Visual Studio
312323

313324
You can run Cppcheck on individual project files (`*.vcxproj`) or on a whole solution (`*.sln`) or (`*.slnx`).

releasenotes.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Changed interface:
2020
-
2121

2222
Infrastructure & dependencies:
23-
-
23+
- compile_commands.json - flexible handling of -isystem, --sysroot and -I flags through the script tweak-compile_commands.py.
2424

2525
Other:
2626
- Added configuration file for Microsoft.GSL (Guideline Support Library).

tools/readme.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,9 @@ message.
8383

8484
Script to compare the error IDs in the expected `testrunner` output (without executing it) with the `--errorlist` output.
8585
It will report missing test coverage for an ID and missing IDs in the `--errorlist` output.
86+
87+
### * tools/tweak-compile-commands.py
88+
89+
Script to tweak `-isystem`/`--sysroot`/`-I` options in a `compile_commands.json` file, for example to make
90+
implicit `--sysroot`-relative `-isystem` paths explicit, convert `-isystem` to `-I`, or remove unwanted include
91+
paths. See `tools/tweak-compile-commands.md` for details.

tools/tweak-compile-commands.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# tweak-compile-commands.py
2+
3+
## NAME
4+
5+
tweak-compile-commands.py - tweak `-isystem`/`--sysroot`/`-I` options in a `compile_commands.json` file
6+
7+
## SYNOPSIS
8+
9+
```
10+
tools/tweak-compile-commands.py COMPILE_COMMANDS [-o OUTPUT | -i]
11+
[--isystem-to-i] [--exclude-folder FOLDER ...]
12+
[--remove-include-path PATH ...]
13+
```
14+
15+
## DESCRIPTION
16+
17+
In many cases the system headers should not be included in Cppcheck
18+
analysis, it is preferable to use `--library` instead. The headers
19+
do not provide the knowledge needed for static analysis, i.e. they
20+
can say what types the arguments to a function has but the header
21+
do not provide the semantics of the functions.
22+
23+
However sometimes you do want to include system headers in Cppcheck
24+
analysis. And you need to have handling of `--sysroot` and
25+
`-isystem`. This script will tweak the compile_commands.json file.
26+
27+
### SYSROOT
28+
29+
Example build command such as:
30+
31+
```
32+
gcc --sysroot /a/b -isystem /opt/x -c foo.c
33+
```
34+
35+
gcc searches both `/opt/x` *and* `/a/b/opt/x` for headers.
36+
37+
`tweak-compile-commands.py` rewrites each build command in a
38+
`compile_commands.json` file so this implicit behaviour is spelled out
39+
explicitly: for every command that has a `--sysroot` argument, every
40+
existing `-isystem PATH` argument gets a matching, explicit
41+
`-isystem SYSROOT/PATH` argument added right after it, and the `--sysroot`
42+
argument is then removed (it is no longer needed since the sysroot-relative
43+
paths are now spelled out explicitly). Commands without a `--sysroot`
44+
argument are left unchanged.
45+
46+
### ISYSTEM
47+
48+
The script has an option `--isystem-to-i`, this tells the script to
49+
convert `-isystem` arguments to `-I`.
50+
51+
The option `--exclude-folder` can be used to skip certain folders. Use
52+
that for a folder if Cppcheck option `--library` can be used instead.
53+
54+
### REMOVE -I
55+
56+
The script also has `--remove-include-path`, the script will remove
57+
any `-I PATH` argument whose path contains a given string. This is
58+
useful for stripping include paths that Cppcheck should not see at all.
59+
60+
## ARGUMENTS
61+
62+
`COMPILE_COMMANDS`
63+
: Path to the `compile_commands.json` file to read.
64+
65+
## OPTIONS
66+
67+
`-o OUTPUT`, `--output OUTPUT`
68+
: Write the result to `OUTPUT` instead of stdout. Cannot be combined with
69+
`-i`.
70+
71+
`-i`, `--in-place`
72+
: Overwrite `COMPILE_COMMANDS` with the result. Cannot be combined with
73+
`-o`.
74+
75+
`--isystem-to-i`
76+
: Also convert `-isystem PATH` arguments to `-I PATH`, except for paths
77+
excluded with `--exclude-folder`. Has no effect on its own if not given
78+
(the sysroot tweak still applies).
79+
80+
`--exclude-folder FOLDER`
81+
: When used with `--isystem-to-i`, keep any `-isystem` argument as
82+
`-isystem` (instead of converting it to `-I`) if `FOLDER` is one of the
83+
path's folder components (an exact match of a path segment, not a
84+
substring). May be given multiple times. Ignored if `--isystem-to-i` is
85+
not given.
86+
87+
`--remove-include-path PATH`
88+
: Remove any `-I` argument whose path contains `PATH` as a substring. May be
89+
given multiple times; a path is removed if it matches any of them.
90+
Independent of `--isystem-to-i`/`--exclude-folder`, and applies after them,
91+
so a path converted from `-isystem` to `-I` can also be removed by this
92+
option.
93+
94+
With neither `-o` nor `-i`, the resulting JSON is written to stdout, and
95+
the input file is left untouched. A summary (`tweaked N of M entries`) is
96+
always printed to stderr.
97+
98+
## EXAMPLES
99+
100+
Preview the sysroot tweak without touching any file:
101+
102+
```
103+
$ tools/tweak-compile-commands.py compile_commands.json
104+
```
105+
106+
Apply the sysroot tweak in place:
107+
108+
```
109+
$ tools/tweak-compile-commands.py -i compile_commands.json
110+
```
111+
112+
Apply the sysroot tweak and convert `-isystem` to `-I`, keeping any path
113+
that goes through a `lib1` or `lib2` folder as `-isystem`:
114+
115+
```
116+
$ tools/tweak-compile-commands.py -i compile_commands.json \
117+
--isystem-to-i --exclude-folder lib1 --exclude-folder lib2
118+
```
119+
120+
Given this input entry:
121+
122+
```json
123+
{
124+
"command": "gcc --sysroot /a/b -isystem /opt/x -isystem /path/lib1/include -c foo.c -o foo.o"
125+
}
126+
```
127+
128+
the last command above produces:
129+
130+
```json
131+
{
132+
"command": "gcc -I /opt/x -I /a/b/opt/x -isystem /path/lib1/include -isystem /a/b/path/lib1/include -c foo.c -o foo.o"
133+
}
134+
```
135+
136+
Note that `/path/lib1/include` is kept as `-isystem` (matching
137+
`--exclude-folder lib1`), and so is its sysroot-relative duplicate
138+
`/a/b/path/lib1/include`, since it also contains a `lib1` folder component.
139+
140+
Remove all `-I` include paths that go through `/path/lib1`:
141+
142+
```
143+
$ tools/tweak-compile-commands.py -i compile_commands.json \
144+
--remove-include-path /path/lib1
145+
```
146+
147+
Given this input entry:
148+
149+
```json
150+
{
151+
"command": "gcc -I /opt/x -I /path/lib1/include -c foo.c -o foo.o"
152+
}
153+
```
154+
155+
the command above produces:
156+
157+
```json
158+
{
159+
"command": "gcc -I /opt/x -c foo.c -o foo.o"
160+
}
161+
```
162+
163+
## EXIT STATUS
164+
165+
Exits with a non-zero status and a traceback if `COMPILE_COMMANDS` cannot
166+
be read or does not contain valid JSON. Otherwise exits 0, even if no
167+
entries needed changes.

0 commit comments

Comments
 (0)