|
| 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