【问题标题】:why do I need to link a lib file to my project?为什么我需要将 lib 文件链接到我的项目?
【发布时间】:2011-10-20 21:16:59
【问题描述】:

我正在创建一个使用 DLL 的项目。要构建我的项目,我需要包含一个头文件和一个 lib 文件。为什么我需要包含相应的 lib 文件?头文件不应该声明所有需要的信息,然后在运行时加载任何需要的库/dll吗?

谢谢

【问题讨论】:

  • 但是如果您不指定,运行时链接器如何知道您要链接的库/库版本?
  • 因为 Windows 链接器相对过时。在 Unix/Linux 上,您只需要一个标头和 .so。
  • @Maxim 我不知道。另一方面,Linux 上的所有功能不都只有一个巨大的公共命名空间吗?
  • 不,Linux 非常先进,它会将 .lib 和 .dll 压缩到一个 .so 文件中。使其性能是 Windows 的两倍。 :-)
  • 有。它由具有外部链接的所有程序符号组成。因此,不需要愚蠢的 __declspec(dllimport)。

标签: c++ c dll


【解决方案1】:

在许多其他语言中,您只需要等效的头文件即可。但是 Windows 上常见的 C 链接器一直使用导入库,C++ 链接器紧随其后,想改变可能已经来不及了。

作为一个思想实验,可以想象这样的语法:

__declspec(dllimport, "kernel32") void __stdcall  Sleep(DWORD dwMilliseconds);

有了这些信息,编译器/链接器工具链就可以完成剩下的工作了。

再举一个例子,在 Delphi 中,可以使用隐式链接导入此函数,如下所示:

procedure Sleep(dwMilliseconds: DWORD); stdcall; external 'kernel32';

这只是表明导入库对于链接到 DLL 不是先验的。

【讨论】:

  • 您说“C 一直使用导入库”是错误的。事实上,C 与库无关,因为它们超出了 C 标准的范围。这是关于链接器的,并且是特定于平台的。
  • C 或 C++ 编译器与任何库无关。它仅将源代码转换为目标文件。请参阅上面的更新评论。
  • @David:看起来更好。虽然只有 C 链接器,但无需为每种新语言重新发明链接器。
  • @Maxim 为什么你如此专注于术语的本质,而不是提出的问题和我给出的答案?这不是更有趣吗?
  • 大卫,我不确定导入库的作用。你能进一步深入研究吗?另外,为什么 C 链接器总是使用导入库?谢谢
【解决方案2】:

这是一个所谓的“导入库”,其中包含最少的接线,稍后(在加载时)会要求操作系统加载 DLL。

【讨论】:

  • 我认为 OP 知道它是什么,但更想知道为什么需要它。
  • 感谢您的回答。您能否进一步解释稍后将要求操作系统加载 DLL 的最小接线?我不确定那个过程。
【解决方案3】:

DLL 是 Windows (MS/Intel) 的东西。 (生成的)库包含调用 DLL 所需的代码,并将“正常”函数公开给应用程序的其余部分。

【讨论】:

  • 感谢您的回答。 .Lib 也是只有 Windows 的东西吗?哪些终端是跨平台库?
  • 不,.lib 更笼统。但他们的内容通常是非常特定于平台的。
【解决方案4】:

不,头文件还不够。头文件可以只包含函数和类的声明以及您需要的其他内容,而不是它们的实现。

这段代码有天壤之别:

void Multiply(int x, int y);

还有这段代码:

void Multiply(int x, int y)
{
   return x * y;
}

第一个是声明,第二个是定义或实现。通常第一个示例放在头文件中,第二个示例放在 .CPP 文件中(如果您正在创建库)。如果您在第一个标题中包含一个标题并且没有链接任何内容,那么您的应用程序应该如何知道如何实现乘法?

现在,如果您使用的头文件包含全部内联的代码,那么您不需要链接任何内容。但是,即使一个方法没有被内联,而是在编译成 .lib 文件的 .CPP 文件中实现,那么您需要在 .lib 文件中进行链接。

[编辑] 通过使用导入库,您告诉链接器不要将导入代码的实现细节包含到您的二进制文件中。相反,操作系统将在运行时将导入 DLL 加载到您的进程中。这将使您的应用程序更小,但您必须随它一起提供另一个 DLL。如果库的实现发生变化,您只需将另一个 DLL 重新发送给您的客户,而不必重新发送整个应用程序。

还有另一种选择,您可以只在库中进行链接,而无需发送另一个 DLL。该选项是链接器将实现包含到您的应用程序中的地方,使其尺寸更大。如果您必须更改导入库中的实现细节,那么您必须重新编译和重新链接您的整个应用程序,并将整个内容重新发送给您的客户。

【讨论】:

  • 这都是真的,但并不能证明导入库的必要性。
  • 哦,是的,我忘记了他的那部分问题...必须,编辑...到达...为... ...编辑...按钮。 :) 我会修改它。
  • @C, @David:我对导入库有点困惑。如果您告诉链接器不包括导入代码的实现细节,那么为什么要关心实现呢。稍后在运行时关心。我想原因是能够运行调试器或类似的东西。
  • @Peretz 没有理由需要使用 .lib 文件来链接到具有隐式链接的 DLL。这只是 Windows 上 C 链接器的约定,但没有必要这样做。可以使用#pragma 或一些此类实现特定的语法轻松完成。
  • 这并不能回答为什么需要.lib.dll 似乎就足够了。
【解决方案5】:

这里的构建过程有两个相关阶段:

  • 编译:从源代码到目标文件。在编译期间,编译器需要知道有哪些外部事物可用,因为需要声明。设计用于多个编译单元的声明被分组在标题中。所以你需要图书馆的标题。

  • 链接:对于静态库,您需要库的编译版本。对于动态库,在 Unix 中您需要该库,在 Windows 中,您需要“导入库”。

您可能认为库也可以嵌入声明,或者标头可以包含需要链接的库。第一个通常是用其他语言完成的。第二种方法有时可以通过 C 和 C++ 中的编译指示获得,但没有标准的方法来做到这一点,并且会与常见用法相冲突(例如从几个为相同声明提供代码变体的库中选择一个库,例如 debug/释放单线程/多线程)。而且这两种选择都与起源于 60 年代的 C 和 C++ 的简单编译模型很好地对应。

【讨论】:

  • 当我链接我的 .lib 库时,我可以将它静态包含在我的项目中,这样我以后就不需要包含 DLL 了吗?我怎么做?。另外,到目前为止,我使用 .lib 文件为项目提供了所需的细节,我可以使用 DLL 文件而不是 lib 文件来提供实现细节吗?谢谢
  • 从源代码中,您可以构建一个可以静态链接的 .LIB(在运行时不需要)或一个带有伴随 .LIB 的 .DLL(.LIB 将链接,并且在运行时将需要 .DLL)。
  • 知道了,所以.lib文件总是在开发代码的时候明确实现细节,然后我就可以判断是静态库还是动态库了。 linux 中的 .lib 和 .dll 文件等价于什么? .so 文件等价于两者?
  • .a 等价于 .lib,.so 等价于 .dll。但是不需要导入库,您将 .so 提供给链接器,然后它会完成其余的工作。
  • 要在 Linux 中静态链接(以便在运行时不需要任何内容​​),您需要 .a,在 Windows 中,您需要 .lib。要动态链接(以便在运行时需要该库,但可以更轻松地更改),您需要 linux 中的 .so 和 windows 中的一对 .lib/.dll (.lib 不是静态所需的)链接)。然后你可以在运行时打开一个库(想想插件),你只需要 linux 中的 .so 和 windows 中的 .dll 。
【解决方案6】:

头文件被编译器使用。它包含将要使用的函数、类和全局变量的所有前向声明。它还可能包含一些内联函数定义。

编译器使用这些信息为它提供编译代码所需的最少信息。它不会包含实现细节。

但是,您仍然需要链接您告诉编译器的所有函数和变量定义。否则将导致链接器错误。这通常包含在其他目标文件中,这些目标文件可能会合并到一个静态库中。

对于 DLL(或 .so 文件),我们仍然需要告诉链接器缺少的符号在 DLL 或共享对象中的什么位置。在 Windows 上,此信息包含在 .lib 文件中。这将生成代码以在运行时加载和链接代码。

在 unix 上,dll 和 lib 文件被合并到一个 .so 文件中,您必须链接到关于链接器错误的链接。

您仍然可以使用没有 .lib 文件的 dll,但您必须使用操作系统 API 手动加载和链接所有符号。

【讨论】:

    【解决方案7】:

    从 1000 英尺开始,lib 包含 dll 导出的函数列表和调用所需的地址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 2017-01-18
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      相关资源
      最近更新 更多