Skip to content

Commit

Permalink
Add clang-iwyu (#7081)
Browse files Browse the repository at this point in the history
* Add iwyu

Co-authored-by: GitHub Web Flow <noreply@github.com>
  • Loading branch information
mehrdadn and web-flow committed Feb 8, 2020
1 parent f9885b8 commit ad4ac9a
Show file tree
Hide file tree
Showing 5 changed files with 373 additions and 2 deletions.
1 change: 1 addition & 0 deletions .bazelrc
Expand Up @@ -26,6 +26,7 @@ build --host_copt="-Wno-microsoft-unqualified-friend"
# This workaround is needed due to https://github.com/bazelbuild/bazel/issues/4341
build --per_file_copt="-\\.(asm|S)$,external/com_github_grpc_grpc/.*@-DGRPC_BAZEL_BUILD"
build --http_timeout_scaling=5.0
build:iwyu --experimental_action_listener=//:iwyu_cpp
# This workaround is due to an incompatibility of
# bazel_common/tools/maven/pom_file.bzl with Bazel 1.0
build --incompatible_depset_is_not_iterable=false
Expand Down
65 changes: 63 additions & 2 deletions .github/workflows/main.yml
Expand Up @@ -2,10 +2,71 @@ name: CI

env:
LLVM_VERSION_WINDOWS: 9.0.0
DEBIAN_FRONTEND: noninteractive

on: [push, pull_request]

jobs:
iwyu:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
name: [
ubuntu-clang-iwyu,
]
include:
- name: ubuntu-clang-iwyu
os: ubuntu-latest
compiler: clang
steps:
- name: Checkout repository
uses: actions/checkout@v1
with:
fetch-depth: 1
- name: Setup Bazel
shell: bash
env:
BAZEL_CACHE_CREDENTIAL_B64: ${{ secrets.BAZEL_CACHE_CREDENTIAL_B64 }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./ci/travis/install-bazel.sh
- name: Setup Clang Include-What-You-Use
shell: bash
run: |
sudo apt-get install iwyu
- name: Perform build
continue-on-error: true
shell: bash
env:
CC: ${{ matrix.compiler }}
run: |
# TODO(mehrdadn): Replace this with the same build script as below, once we factor that out
set -euo pipefail
PATH="${HOME}/bin:${PATH}"
main() {
local startflags=()
startflags+=(--batch)
startflags+=(--nodeep_execroot)
local cmdflags=()
cmdflags+=(--attempt_to_print_relative_paths)
cmdflags+=(--color=yes)
cmdflags+=(--experimental_repository_cache_hardlinks)
cmdflags+=(--experimental_ui_deduplicate)
cmdflags+=(--incompatible_strict_action_env)
cmdflags+=(--keep_going)
cmdflags+=(--per_file_copt='-\.(asm|S)$@-fansi-escape-codes')
cmdflags+=(--per_file_copt='-\.(asm|S)$@-fcolor-diagnostics')
cmdflags+=(--show_progress_rate_limit=5)
cmdflags+=(--show_task_finish)
cmdflags+=(--show_timestamps)
cmdflags+=(--symlink_prefix=/)
cmdflags+=(--verbose_failures)
local packages=()
packages+=("//:ray_pkg")
bazel "${startflags[@]}" build "${cmdflags[@]}" "${packages[@]}" "$@"
}
main --compilation_mode=fastbuild --config=iwyu "$@"
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -98,8 +159,8 @@ jobs:
cmdflags+=(--experimental_ui_deduplicate)
cmdflags+=(--incompatible_strict_action_env)
cmdflags+=(--keep_going)
cmdflags+=(--per_file_copt="-\\.(asm|S)$@-fansi-escape-codes")
cmdflags+=(--per_file_copt="-\\.(asm|S)$@-fcolor-diagnostics")
cmdflags+=(--per_file_copt='-\.(asm|S)$@-fansi-escape-codes')
cmdflags+=(--per_file_copt='-\.(asm|S)$@-fcolor-diagnostics')
cmdflags+=(--show_progress_rate_limit=5)
cmdflags+=(--show_task_finish)
cmdflags+=(--show_timestamps)
Expand Down
31 changes: 31 additions & 0 deletions BUILD.bazel
Expand Up @@ -835,6 +835,37 @@ cc_library(
],
)

filegroup(
name = "iwyu_sh",
srcs = ["ci/travis/iwyu.sh"],
)

filegroup(
name = "extra_actions_base_proto",
srcs = [
# TODO: Replace our file with the built-in copy once this issue is resolved:
# https://github.com/bazelbuild/bazel/issues/8738
"thirdparty/protobuf/extra_actions_base.proto",
#"@bazel_tools//src/main/protobuf:extra_actions_base.proto",
],
)

action_listener(
name = "iwyu_cpp",
extra_actions = [":iwyu_action"],
mnemonics = ["CppCompile"],
)

extra_action(
name = "iwyu_action",
cmd = "$(location :iwyu_sh) $(location @com_google_protobuf//:protoc) $(location :extra_actions_base_proto) --extra_action_file=$(EXTRA_ACTION_FILE)",
tools = [
":extra_actions_base_proto",
":iwyu_sh",
"@com_google_protobuf//:protoc",
],
)

cc_library(
name = "sha256",
srcs = [
Expand Down
94 changes: 94 additions & 0 deletions ci/travis/iwyu.sh
@@ -0,0 +1,94 @@
#!/usr/bin/env bash

set -euo pipefail

if [ "${OSTYPE-}" = msys ] && [ -z "${MINGW_DIR+x}" ]; then
if [ "${HOSTTYPE-}" = x86_64 ]; then
MINGW_DIR=/mingw64
elif [ "${HOSTTYPE-}" = i686 ]; then
MINGW_DIR=/mingw32
fi
fi
invoke_cc() {
local env_vars=() args=() env_parsed=0
if [ "${OSTYPE}" = msys ]; then
env_vars+=(MSYS2_ARG_CONV_EXCL="*")
fi
local arg; for arg in "$@"; do
if [ 0 -ne "${env_parsed}" ]; then
args+=("${arg}")
elif [ "${arg}" == "--" ]; then
env_parsed=1
else
if [ "${OSTYPE}" = msys ] && [ ! "${arg}" = "${arg#PATH=}" ]; then
local key="${arg%%=*}"
local value="${arg#*=}"
value="${value//'/'\\''}"
value="'${value//;/\' \'}'"
local paths; declare -a paths="(${value})"
value=""
local path; for path in "${paths[@]}"; do
if [ "${OSTYPE}" = msys ]; then
path="${path//\\//}"
fi
case "${path}" in
[a-zA-Z]:|[a-zA-Z]:/*)
local drive; drive="${path%%:*}"
path="/${drive,,}${path#*:}"
;;
*) true;;
esac
if [ -n "${value}" ]; then
value="${value}:"
fi
value="${value}${path}"
done
arg="${key}=${value}"
fi
env_vars+=("${arg}")
fi
done
local cc; cc="${args[0]}"
case "${cc##*/}" in
clang*)
{ PATH="${PATH}:/usr/bin" env -i "${env_vars[@]}" "${SHELL-/bin/bash}" -c 'iwyu -isystem "$("$1" -print-resource-dir "${@:2}")/include" "${@:2}"' exec "${args[@]}" 2>&1 || true; } | awk '
{ header = 0; }
/^(The full include-list for .*|.* should (add|remove) these lines:)$/ { keep = 1; header = 1; }
/^(The full include-list for ([^\/]*\/)*external\/.*|([^\/]*\/)*external\/.* should (add|remove) these lines:)$/ { keep = 0; header = 1; }
/^The full include-list for .*$/ { keep = 0; header = 1; }
/^---$/ { keep = 0; header = 1; }
keep { print; n += header ? 0 : 1; }
END { exit n; }
'
;;
esac
}

main() {
# Parsing might fail due to various things like aspects (e.g. BazelCcProtoAspect), but we don't want to check generated files anyway
local data="" # initialize in case next line fails
data="$(exec "$1" --decode=blaze.CppCompileInfo "$2" < "${3#*=}" 2>&-)" || true
if [ -n "${data}" ]; then
# Convert output to JSON-like format so we can parse it
data="$(exec sed -e "/^[a-zA-Z]/d" -e "s/^\(\s*\)\([0-9]\+\):\s*\(.*\)/\1[\2, \3],/g" -e "s/^\(\s*\)\([0-9]\+\)\s*{/\1[\2, /g" -e "s/^\(\s*\)}/\1],/g" <<< "${data}")"
# Turn everything into a single line by replacing newlines with a special character that should never appear in the actual stream
data="$(exec tr "\n" "\a" <<< "${data}")"
# Remove some fields that we don't want, and put back newlines we removed
data="$(exec sed -e "s/\(0x[0-9a-fA-F]*\)]\(,\a\)/\"\1\"]\2/g" -e "s/,\(\a\s*\(]\|\$\)\)/\1/g" -e "s/\a/\n/g" <<< "${data}")"
# Parse the resulting JSON and select the actual fields we're interested in
data="$(PATH="${PATH}:${MINGW_DIR-/usr}/bin" && exec jq -r '(
[]
+ [.[1:][] | select (.[0] == 6) | "\(.[1][1])=\(.[2][1])" | gsub("'\''"; "'\''\\'\'''\''") | "'\''\(.)'\''"]
+ ["--"]
+ [.[1:][] | select (.[0] == 1) | .[1] | gsub("'\''"; "'\''\\'\'''\''") | "'\''\(.)'\''"]
+ [.[1:][] | select (.[0] == 2) | .[1] ]
) | .[]' <<< "${data}")"
# On Windows, jq can insert carriage returns; remove them
data="$(exec tr -d "\r" <<< "${data}")"
# Wrap everything into a single line for passing as argument array
data="$(exec tr "\n" " " <<< "${data}")"
eval invoke_cc "${data}"
fi
}

main "$@"

0 comments on commit ad4ac9a

Please sign in to comment.