What Are Default Libraries
When we build a Visual C++ or MFC project, we don’t need to explicitly instruct Visual Studio to link with CRT or MFC libraries, and it still builds our project just fine. Obviously, it knows how to find the necessary libraries. These libraries are so-called default libraries.
As we know, at the linking stage, all the externals must be resolved, either from .obj files, or from libraries. If an external is not found in our .obj files, it must come from a library, and the linker must know a list of libraries to search for the external.
So what are these libraries? These libraries are search by the linker in the following order:
- Explicit libraries we specify on linker command line (i.e., Linker | Input | Additional Dependencies);
- Default libraries we specify on linker command line /DEFAULTLIB option;
- Default libraries prescribed in the .obj files.
Nowadays, the .obj files can contain various information for the linker to use as options. One type of this information is the default library search records, which are given as #pragma directive in the source code:
#pragma comment(lib, "mylib.lib")
When a translation unit is compiled, such a directive would embed the library name into the .obj file. When the .obj file is being linked, these libraries would be added to the end of the list of libraries-to-search. If we use dumpbin.exe /all to check such a .obj file, we can actually find this:
RAW DATA #1 … /DEFAULTLIB:”MYLIB.LIB” …
Linker Directives
—————–
/DEFAULTLIB:"MYLIB"
…
It just reveals that #pragma comment lib just literally puts /DEFAULTLIB linker option into the .obj file.
Nevertheless, I rarely see /DEFAULTLIB command line option used directly; most of the default libraries I have seen are from #pragma comment lib in the header files or the .cpp files.
Project using MFC
Let us see what default libraries an MFC project uses. Create a new project in Visual C++ | MFC | MFC application. Without we specifying any explicit library, the linker finds the default libraries from inside our .obj file, because the .obj file is compiled with (indirect) inclusion of afx.h through pre-compilation header file stdafx.h, which has this fragment:
#ifndef _AFX_NOFORCE_LIBS / // Win32 libraries #ifndef _AFXDLL #ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, "nafxcwd.lib") #else #pragma comment(lib, "nafxcw.lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "uafxcwd.lib") #else #pragma comment(lib, "uafxcw.lib") #endif #endif #else #ifndef _UNICODE #ifdef _DEBUG #pragma comment(lib, "mfc" _MFC_FILENAME_VER "d.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "d.lib") #else #pragma comment(lib, "mfc" _MFC_FILENAME_VER ".lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER ".lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "mfc" _MFC_FILENAME_VER "ud.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "ud.lib") #else #pragma comment(lib, "mfc" _MFC_FILENAME_VER "u.lib") #pragma comment(lib, "mfcs" _MFC_FILENAME_VER "u.lib") #endif #endif #endif #ifdef _DLL #if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG) #pragma comment(lib, "msvcrtd.lib") #else #pragma comment(lib, "msvcrt.lib") #endif #else #if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG) #pragma comment(lib, "libcmtd.lib") #else #pragma comment(lib, "libcmt.lib") #endif #endif #pragma comment(lib, "kernel32.lib") #pragma comment(lib, "user32.lib") #pragma comment(lib, "gdi32.lib") #pragma comment(lib, "msimg32.lib") #pragma comment(lib, "comdlg32.lib") #pragma comment(lib, "winspool.lib") #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "shell32.lib") #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "windowscodecs.lib") // force inclusion of NOLIB.OBJ for /disallowlib directives #pragma comment(linker, "/include:__afxForceEXCLUDE") // force inclusion of DLLMODUL.OBJ for _USRDLL #ifdef _USRDLL #pragma comment(linker, "/include:__afxForceUSRDLL") #endif // force inclusion of STDAFX.OBJ for precompiled types #ifdef _AFXDLL #pragma comment(linker, "/include:__afxForceSTDAFX") #endif #endif //!_AFX_NOFORCE_LIBS
As we can see in the code fragment above, an MFC project would add the default libraries in this order:
- MFC libraries
- CRT libraries
- Win32 libraries
Those are all the libraries that a fresh MFC application needs, and it builds just fine without user providing libraries.
Vanilla Console Project
If we try with a fresh Windows console application (Visual C++ | Win32 | Win32 Console Application) without using MFC, we can quickly find out that there is no #pragma comment lib code, but our application still links and builds fine.
To illustrate this more clearly, add an empty dumb.cpp file (no #include at all) to the project, then compile the file to get dumb.obj. Now use dumpbin.exe /all, we can see this:
Linker Directives
—————–
/DEFAULTLIB:"MSVCRTD"
/DEFAULTLIB:”OLDNAMES”
(If it is Release build, make sure General | Whole Program Optimization is set to No, otherwise dumpbin will not show anything for the obj file.)
Obviously, Visual Studio automatically add these default libraries to any C/C++ translation unit in a Visual C/C++ project. OLDNAMES.LIB is a library mapping old names to new names for backward compatibility. MSVCRTD.LIB is one of the possible libraries for CRT, and the actual library can change if you change the settings under C/C++ | Code Generation | Runtime Library.
In fact, if we dig all the .obj files found in this project, we only find these two default libraries. However, as we all know, our console executable would at least need to link with Kernel32.dll, which must be statically linked with our exe, therefore its import library, kernel32.lib must be a default library!
The secret is in the default CRT library, here, MSVCRTD.LIB. It further has a default library record in it. Due to the amount of information in this big library, we only want to check the RAWDATA of the library: dumpbin.exe /rawdata msvcrtd.lib, and this reveals:
/merge:.CRT=.rdata
/defaultlib:kernel32.lib
/disallowlib:libcmt.lib
/disallowlib:libcmtd.lib
/disallowlib:msvcrt.lib
This shows that the code in CRT further depends on Kernel32. Most likely our application code does not directly depend on Kernel32, so this library does not have to be a direct default library.
Vanilla Win32 GUI Project
Now let us create a Visual C++ | Win32 | Win32 Project. Visual Studio 2010 spits quite some code to register window class, create window, and handle some messages. It evens has an About dialog box. However, when we build the project, we get a lot of link errors:
1>------ Build started: Project: win32, Configuration: Release Win32 ------ 1>win32.obj : error LNK2001: unresolved external symbol __imp__LoadStringW@16 1>win32.obj : error LNK2001: unresolved external symbol __imp__LoadAcceleratorsW@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__GetMessageW@16 1>win32.obj : error LNK2001: unresolved external symbol __imp__TranslateAcceleratorW@12 1>win32.obj : error LNK2001: unresolved external symbol __imp__TranslateMessage@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__DispatchMessageW@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__LoadIconW@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__LoadCursorW@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__RegisterClassExW@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__CreateWindowExW@48 1>win32.obj : error LNK2001: unresolved external symbol __imp__ShowWindow@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__UpdateWindow@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__DialogBoxParamW@20 1>win32.obj : error LNK2001: unresolved external symbol __imp__DestroyWindow@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__DefWindowProcW@16 1>win32.obj : error LNK2001: unresolved external symbol __imp__BeginPaint@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__EndPaint@8 1>win32.obj : error LNK2001: unresolved external symbol __imp__PostQuitMessage@4 1>win32.obj : error LNK2001: unresolved external symbol __imp__EndDialog@8 1>D:\temp\testcrt\lib\Win32\Release\win32.exe : fatal error LNK1120: 19 unresolved externals ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Obviously, the project wizard in Visual Studio has some problems.
Since the project does not have any explicit library, it means the default libraries are not sufficient. We can check all .obj files in the project, and only our old friends MSVCRTD.LIB and OLDNAMES.LIB are prescribed. As we know all the unresolved functions above are from User32.lib, adding User32.lib to Linker | Input | Additional Dependencies as explicit library solves the problem.
Tweak around Default Libraries
- /Zl This compiler option (Omit Default Library Name) causes the .obj file to have no default library entry (disregard #pragma comment lib).
- /NODEFAULTLIB This linker option allows us to remove one, several, or all default libraries that were introduced by either /DEFAULTLIB or #pragma comment lib.
- /DEFAULTLIB This linker option adds a default library (less often used than #pragma).
- /FORCE:MULTIPLE This linker option forces linking even multiple definitions are found for a symbol among the libraries (often highly discouraged). The linker searches all libraries for a symbol, and normally refuses to link if multiple definitions are found. There is an exception: If a function is a library has weak external linkage (#pragma weak in other compilers), it can be replaced at link time by a “strong” external linkage version from another module without any error, given the “strong” library appears first in the library list. For example, new, delete and DllMain in CRT can be eclipsed by those in MFC if the MFC library is seen first than CRT by the linker (see A LNK2005 error occurs when the CRT library and MFC libraries are linked in the wrong order in Visual C++).
copied from: http://binglongx.wordpress.com/tag/pragma-comment-lib/