cmakeiwyuinclude-what-you-use

Using IWYU fix_includes.py with CMake - more friendly instuctions


I have problem running tool fix_includes.py that automatically fixes up source files based on the include-what-you-use recommendations.

I have configured IWYU tool accordingly to the documentation:

mkdir build && cd build
cmake -G "Unix Makefiles" -DCMAKE_PREFIX_PATH=/usr/lib/llvm 10/lib/clang/10.0.0
make
sudo make install
cmake_minimum_required(VERSION 3.16.3)
set(CMAKE_CXX_STANDARD 17)
project(using_mocks_with_di_proj LANGUAGES CXX)

option(USE_IWYU "Enable include-what-you-use reports during build" ON)

if(USE_IWYU)
    find_program(IWYU_PATH NAMES include-what-you-use iwyu)
    if(NOT IWYU_PATH)
        message(FATAL_ERROR "Could not find the program include-what-you-use")
    endif()
    message("Found IWYU ${IWYU_PATH}")
    set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
    set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
endif()

set(PROJ_DIR ${PROJECT_SOURCE_DIR})

add_subdirectory(app)
add_subdirectory(src)

And it produces report while building:

[ 20%] Building CXX object src/Car/CMakeFiles/Car.dir/src/Car.cpp.o
Warning: include-what-you-use reported diagnostics:

/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/inc/Car.h should add these lines:
class MotorIf;

/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/inc/Car.h should remove these lines:
- #include "MotorIf.h"  // lines 2-2

The full include-list for /home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/inc/Car.h:
class MotorIf;
---

/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/src/Car.cpp should add these lines:
#include "inc/MotorIf.h"  // for MotorIf

/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/src/Car.cpp should remove these lines:

The full include-list for /home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/src/Car.cpp:
#include "inc/Car.h"
#include <iostream>       // for basic_ostream::operator<<, operator<<, endl
#include "inc/MotorIf.h"  // for MotorIf
---

[ 40%] Building CXX object src/Car/CMakeFiles/Car.dir/src/CarMotor.cpp.o
[ 60%] Linking CXX static library libCar.a
make[3]: Leaving directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build'
[ 60%] Built target Car
make[3]: Entering directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build'
Scanning dependencies of target Executable
make[3]: Leaving directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build'
make[3]: Entering directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build'
[ 80%] Building CXX object app/CMakeFiles/Executable.dir/main.cpp.o
Warning: include-what-you-use reported diagnostics:

/home/kpolok/worksapce/projects/using_iwyu_proj/app/main.cpp should add these lines:

/home/kpolok/worksapce/projects/using_iwyu_proj/app/main.cpp should remove these lines:
- #include <vector>  // lines 2-2

The full include-list for /home/kpolok/worksapce/projects/using_iwyu_proj/app/main.cpp:
#include <iostream>        // for operator<<, endl, basic_ostream, cout, ost...
#include "inc/Car.h"       // for Car
#include "inc/CarMotor.h"  // for CarMotor

That part went pretty smooth, but now i want to use the script fix_includes.py. So I once more followed the documentation and invoked this commands in my project root /home/kpolok/worksapce/projects/using_iwyu_proj:

make -k CXX=/usr/bin/iwyu/build/bin/include-what-you-use CXXFLAGS="-Xiwyu --error_always" 2> ./err.txt
python3 /usr/bin/iwyu/include-what-you-use/fix_includes.py < ./err.txt

But after first command I get:

rm -rf build
mkdir build
cmake -S . -B ./build/
-- The CXX compiler identification is unknown
-- Check for working CXX compiler: /usr/bin/iwyu/build/bin/include-what-you-use
-- Check for working CXX compiler: /usr/bin/iwyu/build/bin/include-what-you-use -- broken
CMake Error at /usr/share/cmake-3.16/Modules/CMakeTestCXXCompiler.cmake:53 (message):
  The C++ compiler

    "/usr/bin/iwyu/build/bin/include-what-you-use"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: /home/kpolok/worksapce/projects/using_iwyu_proj/build/CMakeFiles/CMakeTmp
    
    Run Build Command(s):/usr/bin/make cmTC_d324c/fast && make[1]: Entering directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build/CMakeFiles/CMakeTmp'
    /usr/bin/make -f CMakeFiles/cmTC_d324c.dir/build.make CMakeFiles/cmTC_d324c.dir/build
    make[2]: Entering directory '/home/kpolok/worksapce/projects/using_iwyu_proj/build/CMakeFiles/CMakeTmp'
    Building CXX object CMakeFiles/cmTC_d324c.dir/testCXXCompiler.cxx.o
...
 CMake will not be able to correctly generate this project.
 Call Stack (most recent call first):
 CMakeLists.txt:3 (project)

By the way, the Makefile in my project root looks like this:

all: prepare configure build_project

prepare:
    rm -rf build
    mkdir build

configure:
    cmake -S . -B ./build/

build_project:
    cmake --build ./build/

I'm quite new to cmake/clang stuff so I don't know what I'm doing wrong. I suppose that those commands should be invoked somewhere else?But exactly where? Maybe something else is off?

Btw IMO the instructions I found in IWYU documentations aren't really clear.


Solution

  • As @Friedrich mentioned, I was confusing make with cmake (in fact, I was blindly following the IWYU documentation, without trying to understand, what I was actually doing). The solution to the problem is easy. So, during the build process, CMake already generates the report required by the fix_includes.py script by utilizing the CMAKE_CXX_INCLUDE_WHAT_YOU_USE variable.

    option(USE_IWYU "Enable include-what-you-use reports during build" ON)
    
    if(USE_IWYU)
        find_program(IWYU_PATH NAMES include-what-you-use iwyu)
        if(NOT IWYU_PATH)
            message(FATAL_ERROR "Could not find the program include-what-you-use")
        endif()
        message("Found IWYU ${IWYU_PATH}")
        set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
    endif()
    

    I just needed to separate IWYU report from the build logs part:

    if(USE_IWYU)
        find_program(IWYU_PATH NAMES include-what-you-use iwyu)
        if(NOT IWYU_PATH)
            message(FATAL_ERROR "Could not find the program include-what-you-use")
        endif()
        message("Found IWYU ${IWYU_PATH}")
        set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${IWYU_PATH} CXXFLAGS="-Xiwyu --error_always")
    endif()
    

    Thanks to --error_always, IWYU report parts are treated as errors. Now I need to collect this report e.g. by redirecting it to separate file:

    build_project:
        cmake --build ./build/ 2> report.txt
    

    This is the part of my Makefile that triggers cmake build process. All that's left is to run the fix_includes.py:

    using_iwyu_proj$ python3 /usr/bin/iwyu/include-what-you-use/fix_includes.py < report.txt
    >>> Fixing #includes in '/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/inc/Car.h'
    >>> Fixing #includes in '/home/kpolok/worksapce/projects/using_iwyu_proj/src/Car/src/Car.cpp'
    >>> Fixing #includes in '/home/kpolok/worksapce/projects/using_iwyu_proj/app/main.cpp'
    IWYU edited 3 files on your behalf.