0

In my project I'm using protobuf 3.5. I need at least the debug and the RelWithDebugInfo configurations. To be able to build the project with protobuf debug libraries led to some problems alone:

I needed to build the protobuf libraries from source using both the release and the debug target since the _ITERATOR_DEBUG_LEVEL of my libraries (= 2) didn't match the level of the protobuf libraries (= 0). After building the debug libraries as well as the release libraries, compiling in debug configuration was possible.

Now, after changing back to RelWithDebugInfo I get the same error again, but now just the opposite: The _ITERATOR_DEBUG_LEVEL of my libraries is 0 and the level of the used protobuf libraries is 2.

When checking the linker configuration, I can see that my libraries are linked against the libprotobufd.lib. This makes sense since I've read somewhere that everything which is not Release will use the debug libraries, if available. And this leads to my problem:

I won't build my libraries in Release during development. It's most of the time RelWithDebugInfo. But the _ITERATOR_DEBUG_LEVEL for this configuration is obviously set to 0 (because it is a release configuration with additional information). But CMake then links against protobuf's debug libraries which are not compatible with the rest.

I'm now looking for a possibility to tell CMake to not use the debug version of the libraries but the release version instead without changing the CMake scripts of protobuf itself.

Normally my way to go would be to link different libraries depending on the actual build configuration. But unfortunately, the protobuf CMake configuration tries to handle this by itself.

# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/protobuf-targets-*.cmake")
foreach(f ${CONFIG_FILES})
  include(${f})
endforeach()

whilst the imported target is overwritten selected depending on the actual configuration:

protobuf-targets-release.cmake:

# Import target "protobuf::libprotobuf-lite" for configuration "Release"
set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
  IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libprotobuf-lite.lib"
  )

protobuf-targets-debug.cmake:

# Import target "protobuf::libprotobuf-lite" for configuration "Debug"
set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
  IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/libprotobuf-lited.lib"
  )

whereas the linking in my CMakeLists.txt looks like this:

target_link_libraries(${PROJECT_NAME} PRIVATE
    protobuf::libprotobuf
    protobuf::libprotoc
)

I don't see any possibility here to specify the desired library. Normally I'd say I would specify it somehow like this:

target_link_libraries(MyEXE
    debug protobuf::libprotobufd optimized protobuf::libprotobuf
    debug protobuf::libprotocd optimized protobuf::libprotoc)

or wrap some fancy if-condition for the different build configurations around it. But due to protobuf effectively overwriting the target, I don't know how to extract the correct library for each build.

Any ideas?

Niklas
  • 102
  • 10
  • 1
    "But due to protobuf effectively overwriting the target" - No, the target is not overwritten. It is their properties which are assigned, but all of them are different (different suffix). The only same property is *IMPORTED_CONFIGURATIONS*, but it is *APPEND*'ed, not overwitten. What you are looking for is [CMAKE_MAP_IMPORTED_CONFIG_](https://cmake.org/cmake/help/v3.7/variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG.html) variables, which "map" configurations of your project to the imported configurations. – Tsyvarev Mar 20 '19 at 16:01
  • Sorry, yes! You are absolutely correct! This means I can put the mapping command into a if condition and do something like this: `if (build == RelWithDebugInfo) then CMAKE_MAP_IMPORTED_CONFIG_RELEASE`? – Niklas Mar 20 '19 at 16:52

1 Answers1

1

I'm now looking for a possibility to tell CMake to not use the debug version of the libraries but the release version instead

Variables CMAKE_MAP_IMPORTED_CONFIG_ are intended for resolve exactly that problem:

# When build your project in RelWithDebugInfo configuration,
# try to use Release configuration of the *IMPORTED* libraries.
# If some IMPORTED library has no Release configuration, fallback to Debug one.
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBUGINFO Release Debug)

# Imported targets set with given call will be aware of the variable's set above
find_package(Protobuf REQUIRED)

# Simply link with an IMPORTED library. 
target_link_libraries(MyExe protobuf::libprotobuf)

If you want to use Release configuration only from the specific IMPORTED libraries, but not all, you may set corresponded properties for these specific libraries:

# Firstly, create needed IMPORTED target.
find_package(Protobuf REQUIRED)

# Then adjust its properties.
# While the target is created by others, given property is specifically
# designed to be set in *your project*.
set_property(TARGET protobuf::libprotobuf PROPERTY MAP_IMPORTED_CONFIG_RELWITHDEBUGINFO Release Debug)

# Simply link with an IMPORTED library. 
target_link_libraries(MyExe protobuf::libprotobuf)
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • Thanks for your answer! This works fine now. It only took me another hour to find out that the build configuration is named `RelWithDebInfo` and *not* `RelWithDebugInfo` as I thought at first. Man, it would be lovely if CMake would be *a little bit* more verbose when variables are not set... – Niklas Mar 21 '19 at 18:48