【问题标题】:C++ : Difference between linking library and adding include directoriesC++:链接库和添加包含目录之间的区别
【发布时间】:2011-10-29 02:19:43
【问题描述】:

很多标题都概括了。

如果我想使用库,我不确定两者之间的区别。

谢谢!

【问题讨论】:

  • 请举例说明你的问题。
  • 这是一个“苹果和橘子”的比较。它们是完全不相关的东西。请在此处添加一些上下文。
  • 我对此也有类似的困惑,所以我认为这是相关的。对于完全的新手来说,这是一个很好的信息,尤其是当@Matteo Italia 如此彻底地回答时。

标签: c++ compiler-construction linker


【解决方案1】:

一般来说,两者都需要。

包含文件包含类型的声明、函数的原型、inline 函数、#defines、...,通常是关于库的所有信息编译器 编译文件时需要注意。

相反,静态库包含库函数的实际目标代码。如果标头包含原型,则静态库包含(编译的)函数的定义,即链接器将与您的链接器链接的对象模块。

如果你只包含头文件而不链接静态库,链接器会抱怨缺少定义,因为你会在头文件中使用 declared 函数,而不是 defined 任何地方(即没有实现)。另一方面,如果你只链接静态库而不提供头文件,编译器会抱怨未知标识符,因为它不知道你正在使用的库符号。

这个概念与编译多文件项目时非常相似:要访问在其他 .cpp 中编写的定义,您只需在其声明中包含一个标头,最后的链接器将各种对象链接在一起模块。

就dll而言,通常会提供一个导入库;导入库类似于静态库,但它们不包含库的所有代码,而是包含将函数调用到 dll 中的小存根。每次在您的一个对象模块中遇到对库函数的调用时,链接器都会将其定向到存根,而存根又将其重定向到 dll1 中的代码。总而言之,在 Windows 上处理 dll 时,您通常有一个 .h(原型/...)、一个 .lib(您链接的导入库,包含存根)和一个 .dll(动态链接库包含库的实际代码)。

顺便说一句,有些库是“仅头文件”(你可以在 boost 中找到很多),这意味着它们的所有代码都放在头文件中,因此不需要静态库。此类库通常仅由内联代码(函数/类/...)和模板组成,无需单独定义。

通常这样做是因为静态库是丑陋的野兽,原因如下:

  • 您必须明确链接到它们;
  • 由于它们直接链接到您的代码,它们必须使用完全相同的 C/C++ 运行时库,这意味着,至少在 Windows 上,分发静态库(不同的编译器、不同的编译器版本、不同的配置)是不切实际的同一个编译器使用不同的标准库,至少为这些方面的每个组合分发一个静态库是不切实际的);
  • 因此,通常您必须首先在您自己的静态库版本上编译,然后才链接它。

将所有这些与仅包含一个头文件进行比较... :)


  1. 实际上,现代工具链可以识别这些存根并避免额外的间接步骤。详情请参阅 Raymond Chen 的 this series

【讨论】:

  • 精彩,详解。令人印象深刻:)
  • 静态库和“仅标头”库有什么关系?一个是另一个的子集吗?
  • @giannisgonidelis a header-only library 是一个整个实现都在头文件中的库(通常使用inline 函数完成),可能只有一个;因此,不需要 .cpp 或相应的目标文件。事实上,它们经常受到赞赏,因为它们不会增加任何构建复杂性 - 只要您可以让编译器看到您设置的相关包含。
【解决方案2】:

编译器需要知道包含目录,因为它需要包含您要使用的库的头文件(interface)。

链接器需要知道库目录,因为它需要将您的可执行文件链接到库的(预编译)实现

另见What are the differences between a compiler and a linker?

【讨论】:

  • 这就是他们所说的抽象。
  • 有时我会混淆这两者,所以我有一个说法“链接器喜欢库”如果有人有编译器的助记符,我想听听。
【解决方案3】:

包含目录仅用于头文件,通常仅提供函数/方法签名。您需要链接到一个库才能访问其实际的目标代码。

this question

【讨论】:

  • 所以 DLL 总是以 .dll 和头文件的形式给出?
猜你喜欢
  • 2011-10-16
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-06
  • 2018-10-13
  • 1970-01-01
相关资源
最近更新 更多