4

我对使用库很陌生,并且正在尝试了解有关静态库和目标文件的一些细节。

概括

我注意到的行为是我可以链接多个对象以毫无问题地生成可执行文件,但如果我采取将这些对象组合到静态库中的中间步骤,我无法在不额外指定的情况下链接这些静态库以生成可执行文件链接命令中需要 C 运行时库。

另外,或者记录,我正在从命令行使用 Visual Studio 2010 进行编译/链接。我正在遵循的过程的更多详细信息如下。



首先,假设我在一个项目中有四个源文件:main.cutil1.cutil2.cutil3.c.

什么有效

  1. 我可以使用以下命令编译这些源

    cl -c main.c util1.c util2.c util3.c

    文件: 结果,我现在有四个目标文件:main.objutil1.objutil2.objutil3.obj. 这些目标文件中的每一个都包含一个 DEFAULTLIB 语句,旨在通知链接器在链接这些目标文件时,它应该另外检查静态 C 运行时库 libcmt.lib 中是否存在任何未解决的外部依赖项。

  2. 我可以通过使用以下命令链接这些对象来创建一个名为“app_objs.exe”的可执行文件:

    link -out:app_objs.exe main.obj util1.obj util2.obj util3.obj

    如步骤 1 中所述,由于编译器向对象添加默认库语句的步骤,链接器使用了运行时库。

我困惑的地方

  1. 假设我想要一个将这些对象组合到静态库中的中间步骤,然后链接这些生成的 LIB 文件以创建我的可执行文件。首先,我可以使用以下命令创建这些库:

    link -lib -out:main.lib main.obj
    link -lib -out:util.lib util1.obj util2.obj util3.obj

  2. 现在,我最初的想法是,我可以简单地链接这些库并拥有我在“什么有效”的第 2 步中创建的相同可执行文件。我尝试了以下命令并收到链接器错误 LNK1561,它指出需要指定入口点:

    link -out:app_libs.exe main.lib util.lib

  3. 从 Microsoft 的文档中,很明显,链接没有任何目标文件的库可能需要指定入口点,因此我修改了命令以将子系统设置为“控制台”以指定可执行文件旨在成为控制台应用程序(这似乎暗示某些入口点,从而解决该错误):

    link -out:app_libs.exe -subsystem:console main.lib util.lib

    不幸的是,现在我收到一个链接器错误,指出 mainCRTStartup 是一个未解析的外部符号。我知道这是在 C 运行时库中定义的,因此我可以通过手动指定要链接到 libcmt.lib 来解决此问题,这为我提供了一个正常运行的可执行文件:

    link -out:app_libs.exe -subsystem:console main.lib util.lib libcmt.lib

我不明白的是为什么编译器放置在每个目标文件中的默认库信息不能用于解决对 libcmt.lib 的依赖关系。如果我可以在不明确声明我想要 libcmt.lib 的情况下链接目标文件,并且我创建了作为目标文件容器的静态库,为什么我不能在不明确声明我想要 libcmt.lib 的情况下链接这些静态库?事情就是这样,还是有什么方法可以创建静态库,以便链接器知道在运行时库中检查未解析的符号?



谢谢你的帮助。如果我在这里有一些根本不正确的想法,我会喜欢关于好的参考的建议,以正确学习所有这些。

4

1 回答 1

1

好吧,您的误解的答案是 .lib 文件本身通常是一种产品,编译器无法安全地做出这些假设。这就是“外部”的用途。

如果我为某人的平台生成二进制文件,因为它的用户完全无助,并且他们想要/需要静态链接,我必须给他们 foo.h 和 libfoo.lib 而不将它们绑定到特定的运行时入口点。他们很可能已经为他们的最终产品定义了自己的入口点,无论是 DLL 还是 EXE。

您要么想要运行时,要么想要包含入口点的自己的 .obj。请注意,自行声明和定义 mainCRTStartup 可能意味着您没有为目标平台执行重要指令。

于 2013-05-09T13:46:14.773 回答