Synopsis:
Managed (/clr
) C++ project (.dll
) statically links native C++ library (which is compiled with /MD
). Static library is big and references a lot of other libraries, but functionality used by managed C++ code is trivial and shouldn't pull in any additional dependencies.
Problems:
LNK2001
and LNK2019
mentioning symbols that code definitely does not depend onVS2017
to VS2019
) causes errors to come back (this time mentioning other dependencies)What happens:
Apparently, /clr
switch causes compiler to treat inlined functions differently -- they are no longer get embedded into .obj
files (as "weak symbols"), instead they get referenced in the table of imports. This means linker has to find things like:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
... which it does and (since CRT libraries are DEFAULTLIB
and therefore are used last) typically it finds it in other library (namely, in aforementioned static native lib). So, it finds first .obj
file in static lib that contains std::exception::what()
and pulls it in -- meaning we now depend on everything said .obj
depends. This explains problem #1 (bogus linker errors).
Now, if you compile your static lib with another toolset -- obj
files can be stored in different order, causing problem #2.
To reproduce the issue you can use this code (make sure managed project links static lib):
//--------------------
// statlib.cpp
//
#include <exception>
void this_is_a_trap() { throw std::exception(); }
extern int bar();
int foo() { return bar(); }
//--------------------
// clrdll.cpp (managed code)
//
#include <exception>
__declspec(dllexport) void oops()
{
throw std::exception();
}
If you link with /VERBOSE
flag you'll see smth like:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\oleaut32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\uuid.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbc32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbccp32.lib:
1> Searching C:\tst\x64\Release\statlib.lib:
1> Found "public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
1> Referenced in clrdll.obj
1> Loaded statlib.lib(statlib.obj) <-- Now we depend on `bar()`
Question
What is the best way to deal with this?
Notes:
adding msvcrt.lib
to linker inputs (before other static libs) helps, but not always -- certain symbols (such as std::bad_weak_ptr::what()
aren't present in msvcrt.lib
)
this problem is the root cause for this SO post
In mixed (/clr
and native) code std::exception::what()
(and other similar symbols) do get inlined, but these definitions are managed (not native). Which normally is not an issue, but native code refers to native definition via std::exception
's vtable. Normally, such reference (once it fails to resolve) gets redirected to managed definition (which is generated, as stated above), but in this case -- native definition is found in another object (random object from native static library) before "redirection" kicks in, causing that object to be referenced.
See details here. MS is figuring out a best way to deal with this.