#!/usr/bin/env bash # # Run the include-cleaner tool (iwyu replacement) on a file in the webrtc source # directory. # # # 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. # # clang-include-cleaner is built as part of the "clangd" package in our # LLVM build. # Example .gclient file: # solutions = [ # { # "name": "src", # "url": "https://webrtc.googlesource.com/src.git", # "deps_file": "DEPS", # "managed": False, # "custom_deps": {}, # "custom_vars" : { # "checkout_clangd": True, # "download_remoteexec_cfg" : True, # } # }, # ] CLEANER=third_party/llvm-build/Release+Asserts/bin/clang-include-cleaner if [ ! -x $CLEANER ]; then echo "clang-include-cleaner not found" echo -n "Add '\"checkout_clangd\": True' to 'custom_vars' in your" echo ".gclient file and run 'gclient sync'." exit 1 fi # 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 } WORKDIR=out/Default usage() { echo "Usage: $0 [-r] file.cc [file2.cc ...]" echo "Runs the include-cleaner tool on a list of files" echo "Arguments:" echo " -n : Just print changes, don't do them" echo " -c : Just return non-zero exit code if there are changes, don't do them" echo " -r : Remove non-required includes from .h file" echo " -d : Set debug level to " echo " -w : Specify the workdir (out/Default if not specified)" echo " -h : Print this help message" } COMMAND=" --edit" INCLUDE_ARGS="" CHECK_MODE=false while getopts 'd:rncw:h' opts; do case "${opts}" in n) COMMAND=" --print=changes" ;; c) COMMAND=" --print=changes" ; CHECK_MODE=true ;; r) INCLUDE_ARGS=" --remove" ;; d) DEBUG=${OPTARG};if [ $DEBUG -gt 0 ]; then set -x; fi ;; w) WORKDIR=${OPTARG} ;; h) usage; exit 1 ;; *) error "Unexpected option ${opts}" ;; esac done shift $(expr $OPTIND - 1 ) if [[ -z "$COMPILE_COMMANDS" ]]; then if [ -d "$WORKDIR" ]; then if [ ! -f "$WORKDIR/compile_commands.json" ]; then echo "Generating compile commands file" tools/clang/scripts/generate_compdb.py -p $WORKDIR > $WORKDIR/compile_commands.json fi COMPILE_COMMANDS="$WORKDIR/compile_commands.json" else error "Could not generate $WORKDIR/compile_commands.json." fi fi # To get a list of files in a commit: git diff-tree --no-commit-id --name-only -r HEAD for FILE in "$@" do if [ -z $FILE ] || [ ! -f $FILE ]; then usage error "File $FILE is not found" fi done HAS_OUTPUT=false for FILE in "$@" do # Run the command in $WORKDIR because of this reported issue: # https://github.com/llvm/llvm-project/issues/110843 cd $WORKDIR OUTPUT=$(../../$CLEANER $INCLUDE_ARGS $COMMAND ../../$FILE) cd - # include-cleaner does not support custom mappings for certain deps # this ensures that the gtest/gmock deps it inserts are replaced # with the right paths for those includes. # Since sed inplace argument acts differently between GNU/BSD based systems # we handle this here. case "$(uname -s)" in Linux*) INPLACE_ARG=( -i );; Darwin*) INPLACE_ARG=( -i '' );; *) INPLACE_ARG=( -i ) esac for INCLUDE in "gtest" "gmock"; do if grep -q "#include \"test\/${INCLUDE}\.h\"" $FILE; then OUTPUT=${OUTPUT//"+ \"${INCLUDE}"\/"${INCLUDE}.h\""/} sed "${INPLACE_ARG[@]}" -e "/#include \"${INCLUDE}\/${INCLUDE}\.h\"/d" $FILE else sed "${INPLACE_ARG[@]}" -e "s@^#include \"${INCLUDE}\/${INCLUDE}\.h@#include \"test\/${INCLUDE}\.h@g" $FILE fi done echo "${OUTPUT}" HAS_OUTPUT=$HAS_OUTPUT || [[ ! -z $OUTPUT ]] done echo "Finished. Check diff, compile, gn gen --check (tools_webrtc/gn_check_autofix.py can fix most of the issues)" echo "and git cl format before uploading." # Return a non-zero exit code if running with "CHECK_MODE" # and there are changes to apply. if $CHECK_MODE && [[ ! -z $OUTPUT ]]; then exit 1 fi