diff --git a/CMakeLists.txt b/CMakeLists.txt index 692077e6465..bfe68b3144c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ if(CLANG_TIDY) ) message(STATUS "Using clang-tidy from: ${CLANG_TIDY_EXE}") endif() +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/iwyu.cmake) if(SAN OR TSAN) find_program(LLVM_SYMBOLIZER NAMES "llvm-symbolizer") diff --git a/cmake/iwyu.cmake b/cmake/iwyu.cmake new file mode 100644 index 00000000000..52ac969f50b --- /dev/null +++ b/cmake/iwyu.cmake @@ -0,0 +1,50 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache 2.0 License. + +option(INCLUDE_WHAT_YOU_USE "Run include-what-you-use on the codebase" OFF) +set( + IWYU_MAPPING_DIR + "" + CACHE PATH + "Directory containing include-what-you-use mapping files" +) + +if(NOT INCLUDE_WHAT_YOU_USE) + return() +endif() + +find_program(IWYU_EXE NAMES "include-what-you-use" "iwyu") +if(NOT IWYU_EXE) + message(FATAL_ERROR "include-what-you-use requested but not found") +endif() + +# -w suppresses compiler warnings so CI logs focus on IWYU findings. +# --error=1 selects IWYU's standard non-zero failure code, so any suggestion +# fails the build and enforces direct includes. +set(IWYU_COMMAND "${IWYU_EXE}" "-w" "-Xiwyu" "--error=1") +get_filename_component(IWYU_BIN_DIR "${IWYU_EXE}" DIRECTORY) +set( + IWYU_MAPPING_DIRS + "${IWYU_MAPPING_DIR}" + "${IWYU_BIN_DIR}/../share/include-what-you-use" + "/usr/local/share/include-what-you-use" + "/usr/share/include-what-you-use" +) +set(IWYU_LIBCXX_MAPPING_FOUND OFF) +foreach(IWYU_MAPPING_CANDIDATE_DIR ${IWYU_MAPPING_DIRS}) + if(EXISTS "${IWYU_MAPPING_CANDIDATE_DIR}/libcxx.imp") + list( + APPEND IWYU_COMMAND + "-Xiwyu" + "--mapping_file=${IWYU_MAPPING_CANDIDATE_DIR}/libcxx.imp" + ) + set(IWYU_LIBCXX_MAPPING_FOUND ON) + break() + endif() +endforeach() +if(NOT IWYU_LIBCXX_MAPPING_FOUND) + message(WARNING "include-what-you-use libcxx.imp mapping file not found") +endif() + +set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_COMMAND}) +message(STATUS "Using include-what-you-use from: ${IWYU_EXE}") diff --git a/scripts/ci-checks.sh b/scripts/ci-checks.sh index f3036923655..da34824988b 100755 --- a/scripts/ci-checks.sh +++ b/scripts/ci-checks.sh @@ -39,6 +39,7 @@ CHECKS=( "Shell scripts:shellcheck-checks.sh" "TODOs:todo-checks.sh" "Includes:includes-checks.sh" + "Include what you use:iwyu-checks.sh" "Release notes:release-notes-checks.sh" "Non-ASCII characters:ascii-checks.sh" "C/C++ format:cpp-format-checks.sh" diff --git a/scripts/iwyu-checks.sh b/scripts/iwyu-checks.sh new file mode 100755 index 00000000000..d2198c6b12c --- /dev/null +++ b/scripts/iwyu-checks.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Apache 2.0 License. + +# Checks C/C++ include hygiene with include-what-you-use. +# Pass -f for interface consistency, but no auto-fix is available. + +set -e +set -u +set -o pipefail + +FIX=0 +if [ "${1:-}" = "-f" ]; then + # ci-checks.sh passes -f to every check; IWYU has no safe auto-fix mode, so + # this script treats it as a request to run the check normally. + FIX=1 + shift +fi + +if [ "$#" -ne 0 ]; then + echo "Usage: $0 [-f]" + exit 1 +fi + +if [ "$FIX" -ne 0 ]; then + echo "include-what-you-use checks do not support auto-fix; running checks only" +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +ROOT_DIR=$( dirname "$SCRIPT_DIR" ) +BUILD_DIR=${CCF_IWYU_BUILD_DIR:-"$ROOT_DIR/build-iwyu"} +NPROC=$(nproc 2>/dev/null || echo 4) + +cmake \ + -S "$ROOT_DIR" \ + -B "$BUILD_DIR" \ + -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DBUILD_END_TO_END_TESTS=OFF \ + -DCOMPILE_TARGET=virtual \ + -DINCLUDE_WHAT_YOU_USE=ON + +cmake --build "$BUILD_DIR" --parallel "$NPROC" +echo "include-what-you-use checks passed" diff --git a/scripts/setup-ci.sh b/scripts/setup-ci.sh index 3f32d60846e..64279327df0 100755 --- a/scripts/setup-ci.sh +++ b/scripts/setup-ci.sh @@ -54,6 +54,7 @@ install_build_dependencies() { tdnf --snapshottime=$SOURCE_DATE_EPOCH -y install \ build-essential \ clang \ + include-what-you-use \ cmake \ ninja-build \ which \ diff --git a/scripts/setup-dev.sh b/scripts/setup-dev.sh index c2533de03fd..e83cf37dd41 100755 --- a/scripts/setup-dev.sh +++ b/scripts/setup-dev.sh @@ -40,6 +40,7 @@ retry() { install_dev_dependencies() { tdnf -y install \ clang-tools-extra \ + include-what-you-use \ python-pip \ jq \ tar \