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 to
google::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 to
google::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