¿Cómo puedo usar la herramienta ‘Incluye lo que usas’ junto con CMake para detectar encabezados no utilizados?

7 minutos de lectura

Avatar de usuario de Erik Sjölund
Erik Sjolund

La herramienta Incluye lo que usas se puede utilizar para detectar encabezados innecesarios. estoy usando CHacer para mi proyecto de software C++. ¿Cómo puedo indicarle a CMake que ejecute Incluya lo que usa automáticamente en los archivos fuente de mi proyecto de software?

  • Necesitaba usar include-what-you-use en mi proyecto CMake. Cuando descubrí esta forma de hacerlo, pensé que era una buena idea documentarlo como una pregunta de stackoverflow para otros. Se recomiendan las auto-respuestas de acuerdo con la documentación.

    – Erik Sjolund

    20 de junio de 2015 a las 15:28

  • Incluso hay una casilla de verificación “Responde tu propia pregunta” cuando haces una pregunta.

    – Timmmmm

    25 de mayo de 2017 a las 10:23

Avatar de usuario de Erik Sjölund
Erik Sjolund

CMake 3.3 introdujo la nueva propiedad de destino CXX_INCLUDE_QUÉ_USTED_UTILIZA que se puede establecer en la ruta del programa include-what-you-use. por ejemplo esto 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 REQUIRED)

# If using CGAL<3.18, you remove REQUIRED and use
# 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})

es capaz de construir el archivo principal.cc

#include <iostream>
#include <vector>

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

y al mismo tiempo tener include-what-you-use dar una advertencia de que el encabezado incluido vector no es necesario.

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 desea pasar opciones personalizadas a include-what-you-usecomo por ejemplo --mapping_file puedes hacerlo a través de

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})

  • En mi máquina, iwyu nunca emite ninguna advertencia sobre los extras incluidos :/

    – Mcandre

    29 ago 2021 a las 21:10

Avatar de usuario de Alastair Harrison
alastair harrison

Si no tiene acceso a CMake 3.3, include-what-you-use viene con una herramienta de Python llamada iwyu_tool.py que puede hacer lo que quieras.

Funciona analizando una base de datos de compilación JSON, que se produce fácilmente con CMake (ver más abajo).

Ejecutar la herramienta manualmente

Suponiendo que ya tiene un directorio de compilación de CMake para su proyecto, primero debe decirle a CMake que produzca la base de datos de compilación:

cd build
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .

Esto genera un archivo, compile_commands.json que contiene invocaciones de compilador para cada archivo de objeto en su proyecto. No es necesario reconstruir el proyecto.

Ahora puedes ejecutar include-what-you-use en su proyecto ejecutando la herramienta Python en su directorio de compilación:

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

Agregar un objetivo personalizado a su proyecto CMake

El siguiente fragmento se puede utilizar para agregar un iwyu destino a un proyecto de 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()

notas

El include-what-you-use el binario debe estar en su camino para que cualquiera de los anteriores funcione correctamente.

Por defecto, iwyu_tool.py es de subproceso único, lo que puede ser lento para proyectos grandes. Puedes usar el --jobs argumento para aumentar el número de archivos de origen que se procesarán en paralelo.

  • no puedo encontrar iwyu_tool.py en la última fuente. cual seria el equivalente de eso?

    – bysreg

    26 de noviembre de 2016 a las 16:49

  • @bysreg ¿Estás hablando de include-what-you-use-0.7.src.tar.gz descargado de http://include-what-you-use.org/downloads/? iwyu_tool.py parece estar todavía allí, aunque está profundamente anidado en la estructura del directorio. Alternativamente, simplemente descargue el script desde el página de github.

    -Alastair Harrison

    27 de noviembre de 2016 a las 9:30


  • ah tienes razon Estaba usando la rama clang 3.4 y no tiene ese iwyu_tool.py. Ese archivo solo existe desde clang 3.6 en adelante. ¡Gracias por la ayuda!

    – bysreg

    27 de noviembre de 2016 a las 18:39

  • Tenga en cuenta que ejecutar la herramienta de esta manera no aprovecha ningún paralelismo como el que normalmente obtiene con make -j.

    -Paul Brannan

    26 de marzo de 2017 a las 16:35

  • Se llama iwyu_tool y no iwyu-tool. Es posible que desee corregir su respuesta u otros pueden encontrarse en una situación similar a la que tuve cuando busqué este último y no pude encontrar esa herramienta en ninguna parte.

    – josé

    10 de agosto de 2017 a las 18:28

avatar de usuario de user7159222
usuario7159222

También puede habilitarlo globalmente fuera del script CMake configurando la variable CMake:

cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir>

Luego lo llamará en cada objetivo CXX.

Avatar de usuario de Florian Wolters
Florian Wolters

Extendí el código fuente de Alastair Harrison para crear una solución reutilizable. Se me ocurrió lo siguiente que debería funcionar con todo CHacer versiones:

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

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

Invocar CHacer de la siguiente manera para ejecutar incluye-lo-que-usas cuando el all se invoca el objetivo:

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

La salida debe ser la siguiente:

-- 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

¿Ha sido útil esta solución?