【问题标题】:Fast way to identify necessary includes for C++ [duplicate]识别 C++ 必要包含的快速方法 [重复]
【发布时间】:2013-09-21 09:05:09
【问题描述】:

在 Linux 上,有什么方法可以快速确定 C++ 项目所需的 #include 语句是什么?

我的意思是,假设有人从网络上为您提供了一个 sn-p,但未能提供必要的 #include 语句。有没有一种方法可以让您运行 Linux 命令或编译器命令选项并确定缺少哪些函数或类,并且作为奖励,确定我可能在头文件中包含这些内容的硬盘驱动器上的位置。

【问题讨论】:

  • 阅读手册。我不是轻率,我认为没有更好的方法。
  • 请定义你所说的“快”是什么意思。
  • @john 我只是想也许您键入了一个命令,它会尝试在现有的头文件中识别它需要哪些函数或类。如果没有,请告诉我,我会立即关闭此请求。
  • @Volomike 如果有,那么它将是您的编译器的一个选项,因为它具有解析 C++ 源代码的必要知识。不要关闭这个问题,这是一个非常好的问题。
  • 哦,在这种情况下,不要尝试将来自全球四个角落的 sn-ps 组合在一起,了解它的作用,如果它是一个库,请学习如何为编译器指定库。

标签: c++ include


【解决方案1】:

基本上,您需要一些分析器来解析您的源代码和标头并构建一个完整的依赖关系图,它最终会吐出供您进一步阅读和处理。

为此,我会听从 john 关于 g++ 和 Clang 的建议,但我非常怀疑他们是否能做到。

至少使用 g++,您实际上可以做的是为现有的包含打印一个图表。使用 -H 选项打印树或使用 -M 获取列表。

我也建议您参考这个相关主题:Tool to track #include dependencies

不完全是您想要的,但那里提到的工具可能会有所帮助。

【讨论】:

  • 很好,不加解释地投反对票……喜欢它。
【解决方案2】:

我认为Clang's "include-what-you-use" tool 是你想要的。

【讨论】:

    【解决方案3】:

    如果,必要时您的意思是最小(即如果 A 包含 B,B 包含 C,则 A 不需要包含 C)我不知道快速的方法。

    然而,一个好的方法是让每个 cpp 文件首先包含它自己的头文件(在任何预编译的头文件之后)。这样可以确保每个头文件(直接或间接地)包含定义符号所需的所有头文件在标题中使用。

    同样,一个合理规模的项目应该被设计在层中,这样层 A 知道/依赖于层 B,而层 B 依赖于层 C 等,但较低的层从不包含较高的层(即 C 从不包含来自 A 层的任何东西)

    在这种情况下,每个 cpp 或 hpp 中的包含应按层顺序(A、B、C)。如果您这样做,则很容易检查是否可以消除任何 C 层标头(暂时将它们注释掉),因为它们之前的包含之一已经包含它们。这种情况经常发生,并且可以显着减少每个文件中的#include 数量。

    说了这么多,这是一个比以前更不重要的问题,因为编译器更聪明了。 #pragma once 和预编译头文件的组合可以减少构建时间,而无需您花费大量时间优化包含。

    【讨论】:

    • 回到它确实很重要的时候,我曾经在 Alec Teal 用 #pragma message("Unnecessary include of " FILE) 提到的标头保护上使用 #else 子句同样不是解决问题的快速方法,但它可以让您进行一些包含优化。
    • 我认为现在更重要的是安抚使用的 IDE,我也认为这已经很久没有问题了,代码文件很少显着大于 1mb,pre -处理器在解析(甚至标记化 - 超出行数)开始之前启动,并且他正在使用具有文件系统缓存的 Linux。如果这是一个问题,您认为我应该在链接答案中看到的 -MM 上附加一些解释吗?我有我的 makefile 为我解决依赖关系,这使得 GCC 吐出包含的文件,一个可以(Python FTW)编译包含图。不过我不会。
    【解决方案4】:

    我所知道的在程序中找到未定义标识符的最好方法就是尝试编译它。根据您使用的具体编译器,您可以简单地将 GCC 或 Clang 的输出通过管道传输到 grep 中,查找诸如“未声明的标识符”之类的短语。

    至于确定符号的定义位置,我建议以查看Ctags 为起点来解析您的系统标头(最好使用 Makefile 进行管理)并使用生成的标签表查找 grep 从 GCC 捕获的任何内容.

    【讨论】:

      【解决方案5】:

      最快的方式……你不应该这么想。

      https://stackoverflow.com/a/18544093/2112028

      我在那里写了一个可爱的(我很自豪:P)答案,谈论链接如何工作(使用模板)并证明它有效等等,理解这一点。

      #include 指令的目标是创建一个“翻译单元”,其中声明了每个符号(即使未定义)我的答案中有一个示例,我只需将原型复制并粘贴到代码文件中,而不是使用包括。

      如果你使用一种叫做“Header guards”的东西,你不应该担心“最快”的方式(这些在底部简要提到,但这还不够详细)它们是这样的:

      #ifndef __WHATEVER_H
      #define __WHATEVER_H
      
      /*Your code here*/
      
      #endif
      

      所以现在您可以随意添加“whatever.h”。第一次在翻译单元中,将定义 __WHATEVER_H,因此包含它的下一个文件(无论正在编译的文件中有多少包含深度)将为空。因为#ifndef 和#endif 之间的所有内容都将消失。

      希望这会有所帮助。

      此外,如果您有不必要的输入,请使用 -Wextra 和 -Wall,GCC 会告诉您未使用的函数、类型定义等。你可以使用编译错误推送和弹出的东西来控制它。例如 wxWidget 的头文件可能包含很多未使用的东西,因此您将警告压入堆栈,删除未使用的警告标志,包含文件,弹出警告堆栈(重新打开它们),少了数千行警告。

      【讨论】:

      • 这并没有真正的帮助。其中没有任何部分提供了一种方法来告诉您要包​​含哪些文件以满足给定源代码的依赖关系,或者您已经包含哪些文件是不必要的。您不能只包含 everything 并希望这就足够了,并且包含文件可能会以不良方式相互交互。此外,包含不必要的头文件会使依赖管理变得很痛苦。
      • @user2357112 当时两个人(另一个回答者和我)认为这个问题不是他所问的。我们都假设新手包括我们都经历过的强迫症。另外你会注意到我建议 -Wextra 和 -Wall 并讨论消除未使用的错误。我认为他的实际问题不值得回答;所以我尊重你的反对意见。
      猜你喜欢
      • 1970-01-01
      • 2011-03-10
      • 2013-11-26
      • 2012-08-08
      • 2010-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多