【问题标题】:How to check each header file includes required include files?如何检查每个头文件是否包含所需的包含文件?
【发布时间】:2020-01-13 01:15:22
【问题描述】:

我正在使用 C++ 和 cmake 开发我的应用程序。

我想检查每个 C++ 头文件是否正确包含所需的包含文件。

这是一个例子:

a.hpp

inline void func_a() {
}

b.hpp

// #include "a.hpp" is missing
inline void func_b() {
    func_a();
}

main.cpp

#include "a.hpp"
#include "b.hpp"

int main() {}

演示:https://wandbox.org/permlink/kZqoNHMYARIB3bc1

b.hpp 应该包含 a.hpp。假设 b.hpp 缺少包含 a.hpp。如果 main.cpp 在 b.hpp 之前包含 a.hpp,则不会发生编译错误。如果包含顺序相反,则会发生编译错误。

我想检查一下这种问题。

我在 emacs 上使用 fly-check。它很好地检查了这个问题。我想在我的 cmake 构建系统中加入一些检查机制。

例如,如果我执行make depcheck,则检测到编译错误。

我认为如果我设置一个单独编译所有头文件但不链接的cmake目标,则会报告预期的编译错误。

到目前为止,我找不到如何设置它。

有没有办法做到这一点?或者其他实现目标的方法?

我的头文件包含政策

每个头文件都应包含包含所需元素的头文件。换句话说,每个头文件都应该单独编译。

我想要达到的目标

我想知道通过工具辅助自动检测b.hpp缺失`#include "a.hpp"的方法。该工具意味着不是编辑器。我想cmake可以做到这一点。我正在寻找方法。

【问题讨论】:

  • “我在 emacs 上使用 fly-check。它很好地检查了这个问题。” - 你确定它可以吗?它如何处理间接包含问题(当b.hpp 包含包含a.hppc.hpp 时)和私有包含问题(当不能直接包含a.hpp 而必须包含c.hpp 时)?
  • @AlanBirtles,谢谢。我会检查的。
  • @VTT,我猜 fly-check 直接在后台编译当前打开的文件。它不是从 main.cpp 编译的。因此它可以检测到 b.hpp 中缺少 func_a()。

标签: c++ cmake dependencies include


【解决方案1】:

传统的做法是将源文件添加到每个标题中。即使b.cpp 只包含这一行:

include "b.hpp" // Note, this should be the first include

这样就可以单独编译每一个cpp文件,编译成功意味着对应的头文件是自包含的。

当然,如果您已经有一个实现文件,那么移动 corresponding header to be included first 将有助于确保这一点。

【讨论】:

  • 我相信这就是天真的包括检查器所做的。编译成功并不意味着文件实际上包含了必要的包含文件,例如缺少配置包含或缺少某些模板专业化的包含会导致编译产生不正确的结果,因此检查的标头实际上不是自包含的。
  • @VTT - 可以在每一种方法的盔甲中找到缝隙。它仍然适用于非病理性病例。
  • @StoryTeller,谢谢你的回答。但我正在寻找一种自动找到这些缺失包含的方法。即使 main.cpp 意外编译成功。
【解决方案2】:

@StoryTeller 的回答

传统的做法是将源文件添加到每个标题中。

是实现目标的适当方式。它需要添加许多源文件。这是一项烦人的工作,尤其是我开发了一个只有标题的库。

如何自动化该过程?

我找到了一种方法来检查 cmake 上丢失的包含文件。策略是单独直接编译每个头文件。

这里是 CMakeLists.txt

cmake_minimum_required(VERSION 3.8.2)
project(test_checker)

add_custom_target(chkdeps)

file(GLOB HDR_ROOT "*.hpp")
FOREACH (HDR ${HDR_ROOT})
    message(STATUS "${HDR}")
    get_filename_component(HDR_WE ${HDR} NAME_WE)
    SET(CHK_TARGET "${HDR_WE}.chk")
    add_custom_target(
        ${CHK_TARGET}
        COMMAND ${CMAKE_CXX_COMPILER} -c ${HDR}
        VERBATIM
    )
    add_dependencies(chkdeps ${CHK_TARGET})
ENDFOREACH ()

要检查丢失的包含文件,请执行make chkdeps

为了只编译,我使用add_custom_target。自定义目标名称为chkdeps(检查依赖关系)。这是所有头文件依赖检查的目标。

我使用file(GLOB HDR_ROOT "*.hpp") 获得*.hpp 列表。对于每个获取的文件,我添加了自定义目标,仅使用add_custom_target 进行编译。

我添加了扩展名.chk 以避免冲突。例如,如果文件名为a.hpp,则目标名称为a.chk

我使用-c 选项执行命令${CMAKE_CXX_COMPILER}-c 选项仅用于编译。我只在 Linux 上测试了 cmake。我知道直接设置编译选项不利于跨平台开发。 cmake 可能提供仅编译跨平台机制。但目前我还没有找到。

然后我使用add_dependencies 将依赖项添加到chkdeps。由于这种依赖性,当我执行make chkdeps 时,所有自定义目标(a.chkb.chk)都会运行。

当我运行make chkdeps 时,我得到了预期的错误“'func_a' is not declared in this scope”,如下所示。

make chkdeps                                                                                                                                                    
Built target a.chk
/home/kondo/work/tmp/fly_check/b.hpp: In function 'void func_b()':
/home/kondo/work/tmp/fly_check/b.hpp:3:5: error: 'func_a' was not declared in this scope; did you mean 'func_b'?
    3 |     func_a();
      |     ^~~~~~
      |     func_b
make[3]: *** [CMakeFiles/b.chk.dir/build.make:57: CMakeFiles/b.chk] Error 1
make[2]: *** [CMakeFiles/Makefile2:78: CMakeFiles/b.chk.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:113: CMakeFiles/chkdeps.dir/rule] Error 2
make: *** [Makefile:131: chkdeps] Error 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-27
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2011-03-05
    相关资源
    最近更新 更多