Errors when linking to protobuf 3 on MS Visual C

It’s a mismatch of how the VStudio C (and C++) RunTime Library (VCRTLib or UCRT – check [SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati’s answer)) is used by your project and by LibProtoBuf project. Let me detail:

Let’s say there’s some C (C++) code. The purpose of that code is to be run. Than can be achieved:

  • Directly: including that code in an VC Application type project – which will generate an .exe

  • Indirectly: including the code in an VC Library type project – which will generate a library which will only be able to run when called from another .exe (that calls that library). The library can be:

    • static: all the C (C++) code will be compiled and stored in a .lib file. You will need that file when using the library in another project (whether it’s an application or a library) – at link time. Note that all the needed code from your .lib will be “copied” into the other project

    • dynamic: you will have 2 files now: a .dll file which will contain the compiled (and linked) code, and a .lib file(1) which will contain “pointers” (if you will) to the code in the .dll file. When using the library in another project, you will also need the .lib file at link time, but now it won’t contain the code so it won’t be copied in the other library (the other library will be smaller), but at run time the other library will need the .dll file

You can check [SO]: LNK2005 Error in CLR Windows Form (@CristiFati’s answer) for details of how C (C++) code gets to be transformed in executable format. Also Google is full of articles about differences between static and dynamic libraries, when to use one or the other, an example can be found on [SO]: When to use dynamic vs. static libraries.

As you guessed, the CRT or C RunTime library (that contains the underlying system that makes C code able to run – one example are memory management functions: malloc, free) makes no exception – it’s the equivalent of Nix‘s libc.a (static or archive) vs. libc.so (dynamic or shared object) – but in VStudio it’s a little bit more complicated:

  • Static CRT resides in libcmt.lib

  • Dynamic CRT resides in msvcrt.lib which “points” to msvcr###.dll(2) (msvcr120.dll for VStudio 2013)

Notes:

  • A “d” at the end of the library name (msvcrd.lib), means that it’s built with debug symbols (also bigger and slower)

  • C++ runtime library is under the exact situation; the names have an extra p: libcpmt.lib, msvcprt.lib, msvcp120.dll

  • For more details, check [MS.Docs]: CRT Library Features

Now, UCRT parts, are not included in the project like any other lib (Project Properties -> Linker -> Input -> Additional Dependencies), but because their nature (static or dynamic) is required at compile time they are configured from: [MS.Docs]: /MD, /MT, /LD (Use Run-Time Library), where there are 4 available choices:

  1. Multi-threaded (/MT)

  2. Multi-threaded Debug (/MTd)

  3. Multi-threaded DLL (/MD)

  4. Multi-threaded Debug DLL (/MDd)

Obviously, the ones that contain “Debug” are when building for Debug configuration while the other ones for Release; the key point is that the ones that have DLL are using the dynamic runtime version, while the other ones the static version.

Back to your error: the linker complains that main.obj (part of your project) has MDd_DynamicDebug (linking against the dynamic debug version), while common.obj (part of LibProtoBuf project) has MTd_StaticDebug (linking against the static debug version), so you link against 2 runtimes in the same executable (or .dll) – which is not possible.

In order to fix it, you should make sure that both LibProtoBuf and your main project have the same value for UCRT.
Of course it’s simpler to change your main project setting to match LibProtoBuf‘s one, but it’s recommended to use the dynamic runtime version (things can get messy in larger projects that have .dlls involved) even if this requires to recompile LibProtoBuf (well, if changing that option generates errors that make LibProtoBuf very hard to build, and your project is going to stay this simple, you can use the static UCRT).

Note: Not to mistake UCRT type (static / dynamic) with the way LibProtoBuf is being built (static at this point, but I’m sure that it can be built as dynamic too).


Update #0

Adding some additional info on the above note, as some comments requested it, and it might be useful to other users.

There are 2 aspects about a library (including LibProtoBuf), that are totally unrelated:

  1. Library type (the way it is being built): dynamic / static

  2. UCRT type (the way it uses UCRT): again, dynamic / static

So, there are 4 perfectly valid combinations:

  1. Dynamic library using dynamic UCRT

  2. Dynamic library using static UCRT

  3. Static library using dynamic UCRT

  4. Static library using static UCRT

For LibProtoBuf, each of the aspects is controlled by a boolean CMake option:

  1. Library type: protobuf_BUILD_SHARED_LIBS
  2. UCRT type: protobuf_MSVC_STATIC_RUNTIME

The 2 flags can be set by either:

  • CMake-GUI

  • CMake CmdLine (passing them as arguments – e.g.: -Dprotobuf_BUILD_SHARED_LIBS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF)

The above 4 combinations are thus possible (at least in v3.5), but #2. is disabled by default (specifying -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_MSVC_STATIC_RUNTIME=ON will build a .dll which will link to the dynamic UCRT), in order to avoid possible runtime problems, and enabling it requires manual intervention.

For more details regarding build instructions (via cmake), check: [GitHub]: protocolbuffers/protobuf – (master) protobuf/cmake/README.md.


Footnotes

  • #1: The .lib file will only be created if the library exports symbols, as it wouldn’t make sense otherwise (nothing needed at link time, and the .dll will be created, but pretty much unusable)

  • #2: For newer VStudio versions (starting with v2015), the msvcr(t) part has been replaced by vcruntime (or at least this is the entrypoint, as it was split in smaller logical pieces (check the URL at the beginning))

Leave a Comment