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 automatically on the source files of my software project?
可以使用包含“你使用什么”的工具来检测不需要的标题。我正在为我的c++软件项目使用CMake。我如何指示CMake在我的软件项目的源文件上自动运行包含-什么-你使用?
4 个解决方案
#1
42
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 3.3引入了新的目标属性CXX_INCLUDE_WHAT_YOU_USE,可以将其设置为程序包含的-what-you-use的路径。例如这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
能够构建文件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
如果您想传递自定义选项来包含您使用的内容,比如mapping_file,您可以通过它来实现
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})
#2
18
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.
如果您无法访问CMake 3.3,那么您可以使用一个名为iwyu_tool的python工具。py可以做你想做的。
It works by parsing a clang compilation database, which is easily produced with CMake.
它通过解析clang编译数据库来工作,该数据库很容易使用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:
假设您的项目已经有一个CMake build dir,您首先需要告诉CMake生成编译数据库:
$ 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.
这会生成一个名为compile_commands的文件。json包含对项目中的每个对象文件的编译器调用。您不需要重新构建项目。
You can now run include-what-you-use
on your project by running the python tool on your build directory:
现在,您可以在您的构建目录上运行python工具,从而在项目上运行包含的内容:
$ 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.
以下代码片段可用于向cmake项目添加iwyu目标。
# 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.
要使上述任何一种方法正常工作,您所使用的二进制代码都需要在您的路径中。
#3
3
You can also enable it globally outside the cmake script by setting the cmake variable:
您还可以通过设置cmake变量在cmake脚本之外的全局启用它:
cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir>
It will then call it on each CXX target.
然后在每个CXX目标上调用它。
#4
2
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:
我扩展了Alastair Harrison的源代码,以创建一个可重用的解决方案。我想到了下面的方法,它应该适用于所有CMake版本:
File iwyu.cmake
:
文件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
:
文件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,如下所示,在调用所有目标时运行include-what-you-use:
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.
编辑2015-08-19:CMake属性
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.
编辑2015-09-30:输出错误,因为我的include-what-you-use安装坏了。include-what-you-use iwyu_tool。py文件必须在与clang、clang+等相同的目录中。
#1
42
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 3.3引入了新的目标属性CXX_INCLUDE_WHAT_YOU_USE,可以将其设置为程序包含的-what-you-use的路径。例如这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
能够构建文件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
如果您想传递自定义选项来包含您使用的内容,比如mapping_file,您可以通过它来实现
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})
#2
18
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.
如果您无法访问CMake 3.3,那么您可以使用一个名为iwyu_tool的python工具。py可以做你想做的。
It works by parsing a clang compilation database, which is easily produced with CMake.
它通过解析clang编译数据库来工作,该数据库很容易使用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:
假设您的项目已经有一个CMake build dir,您首先需要告诉CMake生成编译数据库:
$ 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.
这会生成一个名为compile_commands的文件。json包含对项目中的每个对象文件的编译器调用。您不需要重新构建项目。
You can now run include-what-you-use
on your project by running the python tool on your build directory:
现在,您可以在您的构建目录上运行python工具,从而在项目上运行包含的内容:
$ 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.
以下代码片段可用于向cmake项目添加iwyu目标。
# 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.
要使上述任何一种方法正常工作,您所使用的二进制代码都需要在您的路径中。
#3
3
You can also enable it globally outside the cmake script by setting the cmake variable:
您还可以通过设置cmake变量在cmake脚本之外的全局启用它:
cmake -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="iwyu" <builddir>
It will then call it on each CXX target.
然后在每个CXX目标上调用它。
#4
2
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:
我扩展了Alastair Harrison的源代码,以创建一个可重用的解决方案。我想到了下面的方法,它应该适用于所有CMake版本:
File iwyu.cmake
:
文件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
:
文件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,如下所示,在调用所有目标时运行include-what-you-use:
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.
编辑2015-08-19:CMake属性
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.
编辑2015-09-30:输出错误,因为我的include-what-you-use安装坏了。include-what-you-use iwyu_tool。py文件必须在与clang、clang+等相同的目录中。