clean-includes (5734B)
1 #!/bin/sh -e 2 # 3 # Clean up QEMU #include lines by ensuring that qemu/osdep.h 4 # is the first include listed in .c files, and no headers provided 5 # by osdep.h itself are redundantly included in either .c or .h files. 6 # 7 # Copyright (c) 2015 Linaro Limited 8 # 9 # Authors: 10 # Peter Maydell <peter.maydell@linaro.org> 11 # 12 # This work is licensed under the terms of the GNU GPL, version 2 13 # or (at your option) any later version. See the COPYING file in 14 # the top-level directory. 15 16 # Usage: 17 # clean-includes [--git subjectprefix] [--check-dup-head] file ... 18 # or 19 # clean-includes [--git subjectprefix] [--check-dup-head] --all 20 # 21 # If the --git subjectprefix option is given, then after making 22 # the changes to the files this script will create a git commit 23 # with the subject line "subjectprefix: Clean up includes" 24 # and a boilerplate commit message. 25 # 26 # If --check-dup-head is specified, additionally check for duplicate 27 # header includes. 28 # 29 # Using --all will cause clean-includes to run on the whole source 30 # tree (excluding certain directories which are known not to need 31 # handling). 32 33 # This script requires Coccinelle to be installed. 34 35 # .c files will have the osdep.h included added, and redundant 36 # includes removed. 37 # .h files will have redundant includes (including includes of osdep.h) 38 # removed. 39 # Other files (including C++ and ObjectiveC) can't be handled by this script. 40 41 # The following one-liner may be handy for finding files to run this on. 42 # However some caution is required regarding files that might be part 43 # of the guest agent or standalone tests. 44 45 # for i in $(git ls-tree --name-only HEAD) ; do test -f $i && \ 46 # grep -E '^# *include' $i | head -1 | grep 'osdep.h' ; test $? != 0 && \ 47 # echo $i ; done 48 49 50 GIT=no 51 DUPHEAD=no 52 53 # Extended regular expression defining files to ignore when using --all 54 XDIRREGEX='^(tests/tcg|tests/multiboot|pc-bios)' 55 56 while true 57 do 58 case $1 in 59 "--git") 60 if [ $# -eq 1 ]; then 61 echo "--git option requires an argument" 62 exit 1 63 fi 64 GITSUBJ="$2" 65 GIT=yes 66 shift 67 shift 68 ;; 69 "--check-dup-head") 70 DUPHEAD=yes 71 shift 72 ;; 73 "--") 74 shift 75 break 76 ;; 77 *) 78 break 79 ;; 80 esac 81 done 82 83 if [ $# -eq 0 ]; then 84 echo "Usage: clean-includes [--git subjectprefix] [--check-dup-head] [--all | foo.c ...]" 85 echo "(modifies the files in place)" 86 exit 1 87 fi 88 89 if [ "$1" = "--all" ]; then 90 # We assume there are no files in the tree with spaces in their name 91 set -- $(git ls-files '*.[ch]' | grep -E -v "$XDIRREGEX") 92 fi 93 94 # Annoyingly coccinelle won't read a scriptfile unless its 95 # name ends '.cocci', so write it out to a tempfile with the 96 # right kind of name. 97 COCCIFILE="$(mktemp --suffix=.cocci)" 98 99 trap 'rm -f -- "$COCCIFILE"' INT TERM HUP EXIT 100 101 cat >"$COCCIFILE" <<EOT 102 @@ 103 @@ 104 105 ( 106 + #include "qemu/osdep.h" 107 #include "..." 108 | 109 + #include "qemu/osdep.h" 110 #include <...> 111 ) 112 EOT 113 114 for f in "$@"; do 115 case "$f" in 116 *.c.inc) 117 # These aren't standalone C source files 118 echo "SKIPPING $f (not a standalone source file)" 119 continue 120 ;; 121 *.c) 122 MODE=c 123 ;; 124 *include/qemu/osdep.h | \ 125 *include/qemu/compiler.h | \ 126 *include/qemu/qemu-plugin.h | \ 127 *include/glib-compat.h | \ 128 *include/sysemu/os-posix.h | \ 129 *include/sysemu/os-win32.h | \ 130 *include/standard-headers/ ) 131 # Removing include lines from osdep.h itself would be counterproductive. 132 echo "SKIPPING $f (special case header)" 133 continue 134 ;; 135 *include/standard-headers/*) 136 echo "SKIPPING $f (autogenerated header)" 137 continue 138 ;; 139 *.h) 140 MODE=h 141 ;; 142 *) 143 echo "WARNING: ignoring $f (cannot handle non-C files)" 144 continue 145 ;; 146 esac 147 148 if [ "$MODE" = "c" ]; then 149 # First, use Coccinelle to add qemu/osdep.h before the first existing include 150 # (this will add two lines if the file uses both "..." and <...> #includes, 151 # but we will remove the extras in the next step) 152 spatch --in-place --no-show-diff --cocci-file "$COCCIFILE" "$f" 153 154 # Now remove any duplicate osdep.h includes 155 perl -n -i -e 'print if !/#include "qemu\/osdep.h"/ || !$n++;' "$f" 156 else 157 # Remove includes of osdep.h itself 158 perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || 159 ! (grep { $_ eq $1 } qw ("qemu/osdep.h"))' "$f" 160 fi 161 162 # Remove includes that osdep.h already provides 163 perl -n -i -e 'print if !/\s*#\s*include\s*(["<][^>"]*[">])/ || 164 ! (grep { $_ eq $1 } qw ( 165 "config-host.h" "config-target.h" "qemu/compiler.h" 166 <setjmp.h> <stdarg.h> <stddef.h> <stdbool.h> <stdint.h> <sys/types.h> 167 <stdlib.h> <stdio.h> <string.h> <strings.h> <inttypes.h> 168 <limits.h> <unistd.h> <time.h> <ctype.h> <errno.h> <fcntl.h> 169 <sys/stat.h> <sys/time.h> <assert.h> <signal.h> <glib.h> 170 <sys/stat.h> <sys/time.h> <assert.h> <signal.h> <glib.h> <sys/mman.h> 171 "sysemu/os-posix.h, sysemu/os-win32.h "glib-compat.h" 172 "qemu/typedefs.h" 173 ))' "$f" 174 175 done 176 177 if [ "$DUPHEAD" = "yes" ]; then 178 egrep "^[[:space:]]*#[[:space:]]*include" "$@" | tr -d '[:blank:]' \ 179 | sort | uniq -c | awk '{if ($1 > 1) print $0}' 180 if [ $? -eq 0 ]; then 181 echo "Found duplicate header file includes. Please check the above files manually." 182 exit 1 183 fi 184 fi 185 186 if [ "$GIT" = "yes" ]; then 187 git add -- "$@" 188 git commit --signoff -F - <<EOF 189 $GITSUBJ: Clean up includes 190 191 Clean up includes so that osdep.h is included first and headers 192 which it implies are not included manually. 193 194 This commit was created with scripts/clean-includes. 195 196 EOF 197 198 fi