为什么我需要在不使用任何对象文件的情况下从静态库创建EXE时手动链接C运行时库?

时间:2021-08-25 13:16:31

I'm pretty new to working with libraries and I'm in the process of trying to understand some specifics regarding static libraries and object files.

我对使用库非常陌生,我正在尝试理解关于静态库和对象文件的一些细节。

Summary

The behavior I'm noticing is that I can link several objects to make an executable with no problem, but if I take an intermediate step of combining those objects into static libraries, I cannot link those static libraries to make an executable without additionally specifying the needed C Run-time library in the link command.

我注意到我的行为可以链接多个对象可执行没有问题,但如果我取一个中间步骤将这些对象组合成静态库,我不能链接这些静态库没有另外指定一个可执行命令所需的C运行时库的链接。

Also, or the record, I'm doing the compiling/linking with Visual Studio 2010 from the command line. More details of the process I'm following are below.

另外,或者记录,我正在从命令行编译/链接Visual Studio 2010。下面是我所遵循的过程的更多细节。



First, let's say I have four source files in a project: main.c, util1.c, util2.c, and util3.c.

首先,假设我在一个项目中有四个源文件:main。c,util1。c,util2。c,util3.c。

What works

  1. I can compile these sources with the following command:

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

    As a result, I now have four object files: main.obj, util1.obj, util2.obj, and util3.obj. These object files each contain a DEFAULTLIB statement intended to inform the linker that it should additionally check the static C Run-time library libcmt.lib for any unresolved external dependencies in these object files when linking them.

    我可以使用以下命令来编译这些源代码:cl -c main。c util1。c util2。c util3。因此,我现在有四个对象文件:main。util1 obj。util2 obj。obj,util3.obj。这些对象文件每个都包含一个DEFAULTLIB语句,目的是通知链接器它应该另外检查静态C运行时库libcmt。在链接对象文件时,为这些对象文件中的任何未解决的外部依赖项释放库。

  2. I can create an executable named "app_objs.exe" by linking these objects with the following command:

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

    As mentioned in step 1, the linker used the runtime library due to the compiler's step of adding a default library statement to the objects.

    我可以创建一个名为“app_objs”的可执行文件。通过以下命令链接这些对象:link out:app_objs。exe主要。obj util1。obj util2。obj util3。正如第1步中提到的,由于编译器向对象添加默认库语句,链接器使用了运行时库。

Where I'm confused

  1. Let's say I want to have an intermediate step of combining these objects into static libraries, and then linking those resulting LIB files to create my executable. First, I can create these libraries with the following commands:

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

    假设我想要有一个中间步骤,将这些对象合并到静态库中,然后将这些产生的LIB文件链接起来,创建我的可执行文件。首先,我可以使用以下命令创建这些库:link -lib out:main。*主要。obj链接*治疗:实效。*util1。obj util2。obj util3.obj

  2. Now, my original thought was that I could simply link these libraries and have the same executable that I created in step 2 of "What works". I tried the following command and received linker error LNK1561, which states that an entry point needs to be specified:

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

    现在,我最初的想法是,我可以简单地链接这些库,并拥有我在“什么工作”的第2步中创建的相同的可执行文件。我尝试了以下命令,并收到了linker error LNK1561,它指出需要指定一个入口点:链接:app_libs。exe主要。*util.lib

  3. From Microsoft's documentation, it is evident that linking libraries without any object files may require entry points to be specified, so I modified the command to set the subsystem as "console" to specify that the executable in intended to be a console application (which seems to imply certain entry points, thereby resolving that error):

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

    Unfortunately, now I get a linker error stating that mainCRTStartup is an unresolved external symbol. I understand that this is defined in the C runtime library, so I can resolve this issue by manually specifying that I want to link against libcmt.lib, and this gives me a functioning executable:

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

    从微软的文档,很明显,没有任何目标文件链接库可能需要指定入口点,所以我修改了命令来设置子系统“控制台”指定的可执行旨在成为一个控制台应用程序(这似乎暗示特定的入口点,因此,解决错误):链接两级:app_libs。exe子系统:主要控制台。*跑龙套。不幸的是,现在我得到了一个链接器错误,说明mainCRTStartup是一个未解决的外部符号。我理解这是在C运行时库中定义的,因此我可以通过手动指定要链接到libcmt来解决这个问题。lib提供了一个可执行文件:link out:app_libs。exe子系统:主要控制台。*跑龙套。*libcmt.lib

What I'm not understanding is why the default library info that the compiler placed in each object file couldn't be used to resolve the dependency on libcmt.lib. If I can link object files without explicitly stating I want libcmt.lib, and I created static libraries that are containers for the object files, why can't I link those static libraries without having to explicitly state that I want libcmt.lib? Is this just the way things are, or is there some way I could create the static libraries so that the linker will know to check for unresolved symbols in the runtime library?

我不理解的是,为什么不能使用编译器放在每个对象文件中的默认库信息来解决libcmt.lib的依赖关系。如果我可以链接对象文件而不显式地声明我想要libcmt。我创建了静态库,它们是对象文件的容器,为什么我不能链接这些静态库而不需要显式地声明我想要libcmt.lib?这只是事情的方式,还是我有什么方法可以创建静态库,以便链接器知道在运行时库中检查未解析的符号?



Thanks for your help. If I have some fundamentally incorrect ideas here, I'd love suggestions on good references to learn all of this correctly.

谢谢你的帮助。如果我在这里有一些根本不正确的想法,我希望能有好的参考建议来正确地学习所有这些。

1 个解决方案

#1


1  

Well the answer to your misunderstanding is that .lib files are often a product in themselves, and the compiler can't make those assumptions safely. That's what "external" is for.

你误解的答案是。lib文件本身就是一个产品,编译器不能安全地做这些假设。这就是“外部”的作用。

If I produce binaries for someone's platform because its users are totally helpless, and they want/need static linkage, I have to give them foo.h and libfoo.lib without tying them to a specific runtime entry point. They may very well have defined their own entry point already for their final product, whether DLL or EXE.

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

You either want the runtime, or you want your own .obj that contains your entry point. Be warned that declaring and defining mainCRTStartup on your own may mean you're not executing important instructions for the target platform.

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

#1


1  

Well the answer to your misunderstanding is that .lib files are often a product in themselves, and the compiler can't make those assumptions safely. That's what "external" is for.

你误解的答案是。lib文件本身就是一个产品,编译器不能安全地做这些假设。这就是“外部”的作用。

If I produce binaries for someone's platform because its users are totally helpless, and they want/need static linkage, I have to give them foo.h and libfoo.lib without tying them to a specific runtime entry point. They may very well have defined their own entry point already for their final product, whether DLL or EXE.

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

You either want the runtime, or you want your own .obj that contains your entry point. Be warned that declaring and defining mainCRTStartup on your own may mean you're not executing important instructions for the target platform.

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