#!/usr/bin/env bash # # Run the include-what-you-use tool (iwyu) on a file in the webrtc source # directory. # # The script uses a subsequent grep pass to remove #include files # that are problematic to include. # # In order to handle include paths correctly, you need to provide # a compile DB (aka compile_commands.json). # You can create it in one of the following ways: # "gn gen --export-compile-commands path/to/out" # "tools/clang/scripts/generate_compdb.py -p path/to/out > compile_commands.json" # If "out/Default" exists, the script will attempt to generate it for you. # # To get iwyu on Debian/glinux, do "sudo apt-get install iwyu". # Debug level, also controlled by the "-d" argument. # Set this to 1 to get more debug information. # Set this to 2 to also get a dump of the iwyu tool output. DEBUG=0 set -e if [ $DEBUG -gt 0 ]; then set -x fi error() { echo "$*" >&2 exit 1 } find_alternates() { for name in "$@" do name_path=$(which "${name}") if [ ! -z "${name_path}" ]; then echo ${name_path} return 0 fi done error "Could not find any of the tools '$@' in PATH." return 1 } IWYU_TOOL=$(find_alternates iwyu_tool iwyu_tool.py) FIX_INCLUDE=$(find_alternates fix_include fix_includes.py) FIX_INCLUDE_ARGS='' IWYU_TOOL_DIR="${IWYU_TOOL_DIR:-tools_webrtc/iwyu}" COMPILE_COMMANDS='' usage() { echo "Usage: $0 [ -c compile-commands-file.json ] [-r] file.cc" echo "Runs the IWYU and fix-include on a CC file and its associated .h file" echo "Arguments:" echo " -c compile-commands: Compiler command file" echo " -r : Remove non-required includes from .h file" echo " -d : Set debug level to " echo " -h : Print this help message" echo "(default command file: out/Default/compile_commands.json - this" echo "will be generated if not present" } while getopts 'c:d:rh' opts; do case "${opts}" in c) COMPILE_COMMANDS="${OPTARG}" ;; r) FIX_INCLUDE_ARGS="${FIX_INCLUDE_ARGS} --nosafe_headers" ;; d) DEBUG=${OPTARG};if [ $DEBUG -gt 0 ]; then set -x; fi ;; h) usage; exit 1 ;; *) error "Unexpected option ${opts}" ;; esac done shift $(expr $OPTIND - 1 ) if [[ -z "$COMPILE_COMMANDS" ]]; then if [ -d "out/Default" ]; then if [ ! -f "out/Default/compile_commands.json" ]; then gn gen --export-compile-commands out/Default fi COMPILE_COMMANDS="out/Default/compile_commands.json" else error "compile_commands.json must be passed." fi fi FILE="$1" if [ ! -f $FILE_CC ]; then error "File $FILE is not found" fi # Find the .h file that IWYU will modify, if any. FILE_CC=$FILE if [ -f $(dirname $FILE)/$(basename -s .cc $FILE).h ]; then FILE_H=$(dirname $FILE)/$(basename -s .cc $FILE).h else FILE_H="" fi tmpfile=$(realpath $(mktemp iwyu.XXXXXXX)) trap 'rm -f -- "${tmpfile}"' EXIT # IWYU has a confusing set of exit codes. Discard it. "$IWYU_TOOL" -p "$COMPILE_COMMANDS" "$FILE_CC" -- -Xiwyu --no_fwd_decls \ -Xiwyu --mapping_file=../../$IWYU_TOOL_DIR/mappings.imp \ >& ${tmpfile} || echo "IWYU done, code $?" if grep 'fatal error' ${tmpfile}; then echo "iwyu run failed" cat ${tmpfile} exit 1 else if [ $DEBUG -gt 1 ]; then cat ${tmpfile} fi # In compile_commands.json, the file name is recorded # as a relative path to the build directory. pushd "$(dirname "$COMPILE_COMMANDS")" || error "pushd failed" "$FIX_INCLUDE" $FIX_INCLUDE_ARGS < ${tmpfile} || echo "Some files modified" popd fi grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE_CC > $FILE_CC.new mv $FILE_CC.new $FILE_CC if [ -n "$FILE_H" ]; then grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE_H > $FILE_H.new mv $FILE_H.new $FILE_H fi echo "Finished. Check diff, compile and git cl format before uploading."