How to use the tool include-what-you-use together with CMake to detect unused headers?

前端 未结 4 1098
滥情空心
滥情空心 2020-12-22 22:59

The tool include-what-you-use can be used to detect unneeded headers. I am using CMake for my C++ software project. How can I instruct CMake to run include-what-you-use auto

相关标签:
4条回答
  • 2020-12-22 23:36

    You can also enable it globally outside the cmake script by setting the cmake variable:

    cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir> 
    

    It will then call it on each CXX target.

    0 讨论(0)
  • 2020-12-22 23:45

    If you don't have access to CMake 3.3, include-what-you-use comes with a python tool called iwyu_tool.py which can do what you want.

    It works by parsing a clang compilation database, which is easily produced with CMake.

    Running the tool manually

    Assuming you already have a CMake build dir for your project, you first need to tell CMake to produce the compilation database:

    $ cd build
    $ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
    

    This generates a file, compile_commands.json containing compiler invocations for every object file in your project. You don't need to rebuild the project.

    You can now run include-what-you-use on your project by running the python tool on your build directory:

    $ python /path/to/iwyu_tool.py -p .
    

    Adding a custom target to your cmake project

    The following snippet can be used to add an iwyu target to a cmake project.

    # Generate clang compilation database
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    
    find_package(PythonInterp)
    find_program(iwyu_tool_path NAMES iwyu_tool.py)
    if (iwyu_tool_path AND PYTHONINTERP_FOUND)
      add_custom_target(iwyu
        ALL      # Remove ALL if you don't iwyu to be run by default.
        COMMAND "${PYTHON_EXECUTABLE}" "${iwyu_tool_path}" -p "${CMAKE_BINARY_DIR}"
        COMMENT "Running include-what-you-use tool"
        VERBATIM
      )
    endif()
    

    Notes

    The include-what-you-use binary needs to be in your path for any of the above to work properly.

    0 讨论(0)
  • 2020-12-22 23:53

    I extended the source code from Alastair Harrison, in order to create a reusable solution. I've came up with the following that should work with all CMake versions:

    File iwyu.cmake:

    #.rst:
    # include-what-you-use (iwyu)
    # ----------------------------
    #
    # Allows to run the static code analyzer `include-what-you-use (iwyu)
    # <http://include-what-you-use.org>`_ as a custom target with the build system
    # `CMake <http://cmake.org>`_.
    #
    # .. topic:: Dependencies
    #
    #  This module requires the following *CMake* modules:
    #
    #  * ``FindPythonInterp``
    #
    # .. topic:: Contributors
    #
    #  * Florian Wolters <wolters.fl@gmail.com>
    
    #===============================================================================
    # Copyright 2015 Florian Wolters
    #
    # Distributed under the Boost Software License, Version 1.0. (See accompanying
    # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    #===============================================================================
    
    # ------------------------------------------------------------------------------
    # Include guard for this file.
    # ------------------------------------------------------------------------------
    
    if(iwyu_included)
      return()
    endif()
    
    set(iwyu_included TRUE)
    
    option(BUILD_IWYU
           "Run the include-what-you-use static analyzer on the source code of the project."
           OFF)
    
    function(iwyu_enable)
      set(iwyu_EXECUTABLE_NAME include-what-you-use)
      find_program(iwyu_EXECUTABLE ${iwyu_EXECUTABLE_NAME})
    
      if(iwyu_EXECUTABLE)
        # This is not exactly the same behavior as with CMake v3.3, since here all
        # compiled targets are analyzed.
        set(iwyu_tool_EXECUTABLE_NAME iwyu_tool.py)
    
        find_package(PythonInterp)
        find_program(iwyu_tool_EXECUTABLE ${iwyu_tool_EXECUTABLE_NAME})
    
        if(PYTHONINTERP_FOUND AND iwyu_tool_EXECUTABLE)
          set(CMAKE_EXPORT_COMPILE_COMMANDS ON PARENT_SCOPE)
    
          add_custom_target(iwyu
                            ALL
                            COMMAND "${PYTHON_EXECUTABLE}" "${iwyu_tool_EXECUTABLE}" -p "${CMAKE_BINARY_DIR}"
                            COMMENT "Running the ${iwyu_tool_EXECUTABLE_NAME} compilation database driver"
                            VERBATIM)
        else()
          message(STATUS
                  "Unable to find the Python interpreter and/or the ${iwyu_tool_EXECUTABLE_NAME} script")
        endif()
      else()
        message(STATUS "Unable to find the ${iwyu_EXECUTABLE_NAME} executable")
      endif()
    endfunction()
    

    File CMakeLists.txt:

    cmake_minimum_required(VERSION 3.0)
    
    include(iwyu.cmake)
    
    project(hello_world)
    add_executable(${PROJECT_NAME} main.cc)
    
    if(BUILD_IWYU)
      iwyu_enable()
    endif()
    

    Invoke CMake as follows to run include-what-you-use when the all target is invoked:

    cmake -DBUILD_IWYU=ON <path-to-source>
    cmake --build . --target all
    

    The output should be as follows:

    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/wolters/workspace/include-what-you-use_example/build
    [ 66%] Built target hello_world
    [100%] Running the iwyu_tool.py compilation database driver
    
    /home/wolters/workspace/include-what-you-use_example/develop/main.cc should add these lines:
    
    /home/wolters/workspace/include-what-you-use_example/develop/main.cc should remove these lines:
    - #include <vector>  // lines 1-1
    
    The full include-list for /home/wolters/workspace/include-what-you-use_example/develop/main.cc:
    #include <iostream>  // for operator<<, basic_ostream, cout, endl, ostream
    ---
    [100%] Built target iwyu
    

    Edit 2015-08-19: The approach with the CMake property <LANG>_INCLUDE_WHAT_YOU_USE did not work for me with CMake version 3.3.1. Therefore I updated the solution.

    Edit 2015-09-30: The output was wrong, since my include-what-you-use installation was broken. The include-what-you-use and iwyu_tool.py files have to be in the same directory as clang, clang++, etc.

    0 讨论(0)
  • 2020-12-22 23:54

    CMake 3.3 introduced the new target property CXX_INCLUDE_WHAT_YOU_USE that can be set to the path of the program include-what-you-use. For instance this CMakeLists.txt

    cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
    add_executable(hello main.cc)
    
    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()
    
    set_property(TARGET hello PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path})
    

    is able to build the file main.cc

    #include <iostream>
    #include <vector>
    
    int main() {
      std::cout << "Hello World!" << std::endl;
      return 0;
    }
    

    and at the same time have include-what-you-use give out a warning that the included header vector is not needed.

    user@ubuntu:/tmp$ ls ~/hello
    CMakeLists.txt  main.cc
    user@ubuntu:/tmp$ mkdir /tmp/build
    user@ubuntu:/tmp$ cd /tmp/build
    user@ubuntu:/tmp/build$ ~/cmake-3.3.0-rc2-Linux-x86_64/bin/cmake ~/hello
    -- The C compiler identification is GNU 4.9.2
    -- The CXX compiler identification is GNU 4.9.2
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /tmp/build
    user@ubuntu:/tmp/build$ make
    Scanning dependencies of target hello
    [ 50%] Building CXX object CMakeFiles/hello.dir/main.cc.o
    Warning: include-what-you-use reported diagnostics:
    
    /home/user/hello/main.cc should add these lines:
    
    /home/user/hello/main.cc should remove these lines:
    - #include <vector>  // lines 2-2
    
    The full include-list for /home/user/hello/main.cc:
    #include <iostream>  // for operator<<, basic_ostream, cout, endl, ostream
    ---
    
    [100%] Linking CXX executable hello
    [100%] Built target hello
    user@ubuntu:/tmp/build$ ./hello 
    Hello World!
    user@ubuntu:/tmp/build$
    

    If you want to pass custom options to include-what-you-use, like for instance --mapping_file you can do it via

    set(iwyu_path_and_options
        ${iwyu_path}
        -Xiwyu
        --mapping_file=${my_mapping})
    
    set_property(TARGET hello
        PROPERTY CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path_and_options})
    

    CMake 3.18 introduced the new option REQUIRED to the find_program(), so it should be possible to remove the if statement if(NOT iwyu_path) above.

    0 讨论(0)
提交回复
热议问题