First, let’s clear up a confusion.
The phrases “static linking”, “linking statically”, “dynamic linking”, “linking dynamically” give the impression that you have a library and you can choose whether to link it
statically or dynamically. This is NOT true. The more accurate description is that when you build a library, you either build a static (.a in Unix, .lib on Windows) or dynamic (.so on Unix, .dll on Windows) version of the library. Then, when you link against it, you have no choice. Depending on what you built, the linker will do the next steps.
For a static library (.a file; also known appropriately as an archive), its contents will be essentially copied and pasted into the target.
For a dynamic library (.so or .dll), a function call to the DLL will be inserted into the target and the DLL will be dynamically loaded at runtime.
The last two sentences really capture what is meant by static vs. dynamic linking.
- A static library is built on Windows via the
lib.execommand and on Unix via thearcommand. - A dynamic library is built on Windows via the
link.execommand and on Unix via theldcommand.
If you run dumpbin /exports on a static library, you should not see any exports. Opening a static library in Dependency Walker should give you an error.
Running dumpbin /exports on a dynamic library will show the symbols exported from it and you will be able to open and inspect it in Dependency Walker.
To inspect a static library, run lib /list which will list the object files packaged into the static library.
A file with .lib extension can mean two things on Windows:
- It could be a static library
- It could be the import library that is needed by the linker to link against a DLL.
Running lib /list will disambiguate between the two.
Next confusion: The link.exe command is always run when building a DLL or .exe. Again, it is NOT run when building a static library. Running link.exe produces a DLL or .exe.
The act of copying-pasting the object files vs. inserting function calls to external DLLs is done by link.exe.
This means:
- If the definition of linking means running
link.exe, then you do not link a static library against another library. It does not make any sense. - You do have to specify the dependencies a static library may have on other libraries for source code to compile – this is done via the header files and the headers act as stubs.
- When you run the linker to build the final executable or DLL, then the heavy lifting of either copy-pasting object files or inserting function calls to a DLL will happen.
- The linker takes input
.libfiles. As mentioned earlier, the.libfile is different for a static vs. dynamic library. - For a static library
lib /listwill always list only its own object files. It will never list object files of the dependencies.
Now we come to the runtime. The flags MD, MDd, MT, MTd control whether you link against the dynamic vs. static version of the VC++ Runtime (CRT).
These flags control only how your project links against the CRT. They don’t control how your project links against its dependencies.
And again, there is no flag to be passed to link.exe to tell it whether to link statically or dynamically against your dependencies – it does not make any sense.
Given the .lib file, the linker infers whether this is a static vs. import library and performs the next steps (copy-paste vs. dynamic function call) automatically.
Next, consider following table to aid you in deciding how to build dependencies of your project:
| Type | Flag | Advantages | Disadvantages |
|---|---|---|---|
| Static | MD |
Solid option. In final stage all static dependencies will be copied into the target and all of them will use the same CRT that is loaded dynamically at runtime. Resulting binary is small and compact. | The CRT is loaded dynamically at runtime which means it needs to be available on the system as a pre-requisite (i.e., needs to be installed if not already available). Further, you need to ensure you are installing (and loading) the correct version of CRT. |
| Static | MT |
Acceptable. In final stage all static dependencies will be copied into the target and all of them will use the same CRT that is also packaged into the final binary. Resulting binary is standalone. Installation is simple. | Binary will not be small and compact as it will have a copy of CRT packaged into it. |
| Dynamic | MD |
OK. The dependencies exist as DLLs and separate from main application and loaded dynamically at runtime. This is ok when the same DLL has to be reused by many applications that you might be distributing. | Dynamic loading means there are DLL boundaries and in C++ there are some things you need to be careful about when crossing DLL boundaries. |
| Dynamic | MT |
– | Do not do this. Each DLL will have a separate copy of CRT in it. This is a huge wastage and will create technical problems as well. |
Translation for Java developers:
- In the first two rows, you are essentially building the equivalent of a fat jar in C++.
- In the first row, the JRE is installed separately on the target machine whereas in the second row you are also packing the JRE into your binary itself.
Tips
>Your code may have errors when you pass C Runtime (CRT) objects such as file handles, locales, and environment variables into or out of a DLL. Function calls across the DLL boundary can cause unexpected behavior if the DLL and any files that call into the DLL use different copies of the CRT libraries.
3 Power Tools You Must Know on Linux to debug DLL (.so) not loading
stracelddobjdumpLD_DEBUG