]> git.ipfire.org Git - thirdparty/systemd.git/blob - coccinelle/run-coccinelle.sh
bb72a493f08f300d43355f17fc3b943298a7d326
[thirdparty/systemd.git] / coccinelle / run-coccinelle.sh
1 #!/usr/bin/env bash
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 set -e
4
5 # FIXME:
6 # - Coccinelle doesn't like our TEST() macros, which then causes name conflicts; i.e. Cocci can't process
7 # that TEST(xsetxattr) yields test_xsetxattr() and uses just xsetxattr() in this case, which then conflicts
8 # with the tested xsetxattr() function, leading up to the whole test case getting skipped due to
9 # conflicting typedefs
10 # - something keeps pulling in src/boot/efi/*.h stuff, even though it's excluded
11 # - Coccinelle has issues with some of our more complex macros
12
13 # Exclude following paths from the Coccinelle transformations
14 EXCLUDED_PATHS=(
15 "src/boot/efi/*"
16 "src/shared/linux/*"
17 "src/basic/linux/*"
18 # Symlinked to test-bus-vtable-cc.cc, which causes issues with the IN_SET macro
19 "src/libsystemd/sd-bus/test-bus-vtable.c"
20 "src/libsystemd/sd-journal/lookup3.c"
21 # Ignore man examples, as they redefine some macros we use internally, which makes Coccinelle complain
22 # and ignore code that tries to use the redefined stuff
23 "man/*"
24 )
25
26 TOP_DIR="$(git rev-parse --show-toplevel)"
27 CACHE_DIR="$(dirname "$0")/.coccinelle-cache"
28 ARGS=()
29
30 # Create an array from files tracked by git...
31 mapfile -t FILES < <(git ls-files ':/*.c')
32 # ...and filter everything that matches patterns from EXCLUDED_PATHS
33 for excl in "${EXCLUDED_PATHS[@]}"; do
34 # shellcheck disable=SC2206
35 FILES=(${FILES[@]//$excl})
36 done
37
38 case "$1" in
39 -i)
40 ARGS+=(--in-place)
41 shift
42 ;;
43 esac
44
45 if ! parallel -h >/dev/null; then
46 echo 'Please install GNU parallel (package "parallel")'
47 exit 1
48 fi
49
50 [[ ${#@} -ne 0 ]] && SCRIPTS=("$@") || SCRIPTS=("$TOP_DIR"/coccinelle/*.cocci)
51
52 mkdir -p "$CACHE_DIR"
53 echo "--x-- Using Coccinelle cache directory: $CACHE_DIR"
54 echo "--x--"
55 echo "--x-- Note: running spatch for the first time without populated cache takes"
56 echo "--x-- a _long_ time (15-30 minutes). Also, the cache is quite large"
57 echo "--x-- (~15 GiB), so make sure you have enough free space."
58 echo
59
60 for script in "${SCRIPTS[@]}"; do
61 echo "--x-- Processing $script --x--"
62 TMPFILE="$(mktemp)"
63 echo "+ spatch --sp-file $script ${ARGS[*]} ..."
64 # A couple of notes:
65 #
66 # 1) Limit this to 10 files at once, as processing the ASTs is _very_ memory hungry - e.g. with 20 files
67 # at once one spatch process can take around 2.5 GiB of RAM, which can easily eat up all available RAM
68 # when paired together with parallel
69 #
70 # 2) Make sure spatch can find our includes via -I <dir>, similarly as we do when compiling stuff
71 #
72 # 3) Make sure to include includes from includes (--recursive-includes), but use them only to get type
73 # definitions (--include-headers-for-types) - otherwise we'd start formating them as well, which might be
74 # unwanted, especially for includes we fetch verbatim from third-parties
75 #
76 # 4) Use cache, since generating the full AST is _very_ expensive, i.e. the uncached run takes 15 - 30
77 # minutes (for one rule(!)), vs 30 - 90 seconds when the cache is populated. One major downside of the
78 # cache is that it's quite big - ATTOW the cache takes around 15 GiB, but the performance boost is
79 # definitely worth it
80 parallel --halt now,fail=1 --keep-order --noswap --max-args=10 \
81 spatch --cache-prefix "$CACHE_DIR" \
82 -I src \
83 --recursive-includes \
84 --include-headers-for-types \
85 --smpl-spacing \
86 --sp-file "$script" \
87 "${ARGS[@]}" ::: "${FILES[@]}" \
88 2>"$TMPFILE" || cat "$TMPFILE"
89 rm -f "$TMPFILE"
90 echo -e "--x-- Processed $script --x--\n"
91 done