web-dev-qa-db-fra.com

Comment utiliser l'outil include-what-you-use avec CMake pour détecter les en-têtes inutilisés?

L'outil include-what-you-use peut être utilisé pour détecter les en-têtes inutiles. J'utilise CMake pour mon projet logiciel C++. Comment puis-je demander à CMake d'exécuter automatiquement include-what-you-use sur les fichiers source de mon projet logiciel?

44
Erik Sjölund

CMake 3. a introduit la nouvelle propriété cible CXX_INCLUDE_WHAT_YOU_USE qui peut être définie sur le chemin du programme include-what-you-use . Par exemple, ceci 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})

est capable de construire le fichier main.cc

#include <iostream>
#include <vector>

int main() {
  std::cout << "Hello World!" << std::endl;
  return 0;
}

et en même temps include-what-you-use donne un avertissement indiquant que le vecteur d'en-tête inclus n'est pas nécessaire.

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$

Si vous souhaitez transmettre des options personnalisées à include-what-you-use, comme par exemple --mapping_file vous pouvez le faire 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})
51
Erik Sjölund

Si vous n'avez pas accès à CMake 3.3, include-what-you-use est livré avec un outil python appelé iwyu_tool.py qui peut faire ce que vous voulez.

Il fonctionne en analysant une base de données de compilation clang, qui est facilement produite avec CMake.

Exécution manuelle de l'outil

En supposant que vous avez déjà un répertoire de compilation CMake pour votre projet, vous devez d'abord dire à CMake de produire la base de données de compilation:

$ cd build
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .

Cela génère un fichier, compile_commands.json contenant les invocations du compilateur pour chaque fichier objet de votre projet. Vous n'avez pas besoin de reconstruire le projet.

Vous pouvez maintenant exécuter include-what-you-use sur votre projet en exécutant l'outil python sur votre répertoire de construction:

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

Ajouter une cible personnalisée à votre projet cmake

L'extrait suivant peut être utilisé pour ajouter une cible iwyu à un projet cmake.

# 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()

Remarques

Le include-what-you-use le binaire doit être sur votre chemin pour que tout ce qui précède fonctionne correctement.

23
Alastair Harrison

Vous pouvez également l'activer globalement en dehors du script cmake en définissant la variable cmake:

cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir> 

Il l'appellera ensuite sur chaque cible CXX.

6
user7159222

J'ai étendu le code source d'Alastair Harrison, afin de créer une solution réutilisable. J'ai trouvé ce qui suit qui devrait fonctionner avec les versions all CMake :

Fichier 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 <[email protected]>

#===============================================================================
# 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()

Fichier 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()

Appelez CMake comme suit pour exécuter include-what-you-use when la cible all est invoquée:

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

La sortie doit être la suivante:

-- 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: L'approche avec la propriété CMake <LANG>_INCLUDE_WHAT_YOU_USE n'a pas fonctionné pour moi avec CMake version 3.3.1. J'ai donc mis à jour la solution.

Edit 2015-09-30: La sortie était incorrecte, car mon installation avec ce que vous utilisez a été interrompue. Le include-what-you-use et iwyu_tool.py les fichiers doivent se trouver dans le même répertoire que clang, clang++, etc.

2
Florian Wolters