Why do I need to manually link the C runtime library when creating an EXE out of static libraries without any object files?

StackOverflow https://stackoverflow.com/questions/14743404

Question

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.

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.



First, let's say I have four source files in a project: main.c, util1.c, util2.c, and 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.

  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.

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

  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

  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

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?



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.

Was it helpful?

Solution

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top