Unable to link protobuf library using CMake. My CMakeLists is
cmake_minimum_required(VERSION 3.6)
project(addressbook)
set(CMAKE_CXX_STANDARD 11)
set(PROJECT_NAME addressbook)
ADD_SUBDIRECTORY(proto)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})
and in proto subdirectory there is another CMakeLists.txt (that way it is done in github repo https://github.com/shaochuan/cmake-protobuf-example)
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER message.proto)
ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC})
But my IDE still outputs buch of lines like
CMakeFiles/main.dir/main.cpp.o: In function
main': /home/camille/ClionProjects/protobuf/main.cpp:42: undefined reference togoogle::protobuf::internal::VerifyVersion(int, int, char const*)' /home/camille/ClionProjects/protobuf/main.cpp:49: undefined reference totutorial::AddressBook::AddressBook()' /home/camille/ClionProjects/protobuf/main.cpp:54: undefined reference togoogle::protobuf::Message::ParseFromIstream(std::istream*)'
Where is my mistake? How do I make it work?
Your program fails to link because ${PROTOBUF_LIBRARY} is empty in the scope of your top-level CMakeLists.txt. This happens because calling add_subdirectory creates a child scope, and the Protobuf_XXX variables set by find_package(Protobuf REQUIRED) are only in that child scope.
A good way to fix this is to add the following to proto/CMakeLists.txt:
target_link_libraries(proto INTERFACE ${Protobuf_LIBRARIES})
This instructs targets that link to proto to also link to ${Protobuf_LIBRARIES}. Now you can simplify target_link_libraries in your top-level CMakeLists.txt:
target_link_libraries(addressbook proto)
On a side note, you could also use e.g.
target_link_libraries(${PROJECT_NAME} INTERFACE ... )
${PROJECT_NAME} resolves to whatever you have set in the project(...) statement in that CMakeLists.txt file.
Finally, note that this links to Protobuf_LIBRARIES instead of PROTOBUF_LIBRARY. Protobuf_LIBRARIES includes both the Protocol Buffers libraries and the dependent Pthreads library.
Watch out for variable name case: With CMake 3.6 and later, the FindProtobuf module input and output variables were all renamed from PROTOBUF_ to Protobuf_ (see release notes), so using Protobuf_ works with CMake 3.6, but fails with undefined reference with an earlier version.
To be on the safe side, either use the old style
target_link_libraries(${PROJECT_NAME} INTERFACE ${PROTOBUF_LIBRARIES}))
or force everyone to use at least CMake 3.6
cmake_minimum_required(VERSION 3.6)
Also, there is a resolved bug report in the Kitware cmake issue tracker with more information on how to diagnose such issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With