7

我在工作的地方遇到了几个“未定义的引用”(链接期间)和“未解析的符号”(dlopen 之后的运行时)问题。这是一个相当大的makefile系统。

是否有链接库和使用编译器标志/选项来规避这些类型的错误的一般规则和指南?

4

2 回答 2

6

如果您使用的是 MSVC:

您不能通过设置标志来规避此类错误:这意味着某些单元 (.cpp) 没有声明标识符的定义。这肯定是由于某处缺少包含或缺少对象定义(通常是静态对象)引起的。

在开发过程中,您可以遵循这些指南(来自那些文章),以确保您的所有 cpp 都包含他们需要的所有标题,但仅此而已:

  • 每个 cpp 文件首先包含自己的头文件。这是最重要的准则;其他一切都从这里开始。此规则的唯一例外是 Visual Studio 中包含的预编译头文件;那些总是必须是文件中的第一个包含。本文第二部分中有关预编译头文件的更多信息。
  • 头文件必须包含解析它所需的所有头文件。这与第一条准则密切相关。我知道有些人试图从不将头文件包含在声称效率或类似内容的头文件中。但是,如果在解析头文件之前必须包含文件,则必须将其包含在某处。将它直接包含在头文件中的好处是我们总是可以决定拉入我们感兴趣的头文件,并且我们保证它会按原样工作。我们不必玩“猜猜你还需要什么其他标题”的游戏。
  • 头文件应该具有解析它所需的最少数量的头文件。前面的规则说你应该在头文件中包含你需要的所有内容。这条规则说你不应该比你必须拥有的更多。显然,首先删除(或首先不添加)无用的包含语句。然后,尽可能多地使用前向声明而不是包含。如果你只有一个类的引用或指针,你不需要包含那个类的头文件;前向参考会做得更好,效率更高。

但正如评论者所建议的那样,您似乎正在使用 g++ ...

于 2009-01-29T15:05:44.233 回答
5

建立一个 X 依赖于 Y 的构建系统,而 Y 依赖于 Z 会有所帮助。当你进入圈子(Z 取决于 X)时,事情就会变得丑陋。

通常是链接库的顺序(“-lZ -lY -lX”与“-lX -lY -lZ”)导致悲伤。更罕见的是,您在搜索路径的多个位置具有相同的库名称,或者链接到尚未重新编译的过时版本。

“nm --demangle”可以让您查看定义/使用事物的位置。

“ldd”可以用来查看你依赖的动态库。

gcc/g++ 标志-print-file-name=LIBRARY可以帮助准确跟踪正在使用的库。


事后思考:(因为您询问规则/指南。)

可以设置一个 makefile 系统,这样:

  • 如果 module=D 取决于模块 A、B 和 C。
  • 然后尝试制作 module=D 将首先制作模块 A、B 和 C。
  • 而且,更重要的是,module=D 将自动从模块 A、B 和 C 的生成文件中确定其库(-lA 等)、库路径(-LA)和包含路径(-IA)。

设置起来可能有点麻烦。上次我这样做时,我倾向于只缓存信息而不是分叉过多的 make 子进程。再加上 makefile-importing 和一个小的 perl 脚本来删除重复项。克鲁奇,我知道。(那些不想花时间在基础设施上的权力。)但这是可以做到的。

再说一次,我使用的是 GNU-make,它有一些扩展。

于 2009-01-29T15:05:17.853 回答