Search code examples
c++visual-studio-2013cmakeprotocol-buffers

Using google protobuf with libraries in cmake on Windows, Visual Studio 2013


I have a CMake project with several sub-directories and library modules that eventually get built into client and server libraries, and those libraries are used from executable to test them. I am trying to use Google's protobuf library inside one of those libraries. I am creating my sub-library as follows:

include_directories(
    .
    ../rendering_backend
    ../shared
    ${MY_THIRDPARTY_DIR}/protobuf/include
)

add_library(Client STATIC
    client.cpp
    client.hpp
    ../common.hpp
    ../shared/protobufs/my_bufs.pb.cc
    ../shared/protobufs/my_bufs.pb.h
)

target_link_libraries(Client
    RenderingBackend
    ${MY_THIRDPARTY_DIR}/protobuf/lib/libprotobufd.lib
)

The executable is declared as follows:

add_executable(TEST_Client
    client_tester.cpp
    ../src/rendering_backend/rendering_backend.hpp)

target_link_libraries(TEST_Client Client)

All these files seem to be generating properly, but when I build, I get the following error (and many just like it):

libprotobufd.lib(zero_copy_stream_impl.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug' in client_tester.obj

I have gone back to the protobuf solution and verified that all projects are set to use /MDd in their Runtime Library setting. It was generated following the guide at https://github.com/google/protobuf/tree/master/cmake.

I have seen many questions and answers about protobufs, but none seem to address this problem. I don't know what could be trying to build /MTd when everything is set to /MDd inside Visual Studio.

Assuming that this process would work if I were doing it correctly, I can only assume I'm doing something wrong. What is the intended way to do something like this?

[EDIT] I was trying to use protobuf 3.0.0 here.


Solution

  • In order for find_package to identify the correct paths, you must edit the CMAKE_PREFIX_PATH variable to search for libraries. This code allows it to find the path correctly, assuming that you have correctly set up THIRDPARTY_DIR and you downloaded the release version of protobuf (2.6.1 as of this writing):

    set(CMAKE_PREFIX_PATH
        ${CMAKE_PREFIX_PATH}
        ${THIRDPARTY_DIR}/protobuf-2.6.1
    )
    

    Protobuf3 can also be used but in addition to setting the install path in CMAKE_PREFIX_PATH, you must also supply the CONFIG argument to find_package as follows:

    find_package(Protobuf CONFIG REQUIRED)
    

    ...assuming Protobuf is required.

    In my case, I configured Protobuf 3.0.0 beta 2 to install to a folder "install" within its own directory:

    set(CMAKE_PREFIX_PATH
        ${CMAKE_PREFIX_PATH}
        ${THIRDPARTY_DIR}/protobuf-3.0.0-beta-2/install
    )
    
    find_package(Protobuf CONFIG REQUIRED)
    

    (Thanks to tamas.kenez for correcting me on this.)

    Note that I had to build the release library before find_package(Protobuf) would return without errors. I originally only build the debug libraries.

    I also had to be cautious of which MSVC runtime I build with. Dynamic seems to be the default for most projects, but Protobuf3 builds with the static runtime unless you configure it to do otherwise (there's a checkbox if you're using the GUI). Linking static runtime libraries to dynamic runtime executables causes all kinds of linker problems and redefinitions, so be careful of that.

    Lastly, CMake GUI seems to retain some information about directory structures until you reload the project (or possibly restart the program entirely); so I hit a snag in trying to change which version of protobuf I used when CMake kept finding a directory structure I had already deleted, even after clearing the whole build directory. (Solved by clearing the build directory and relaunching CMake GUI and reloading the base project.)