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-levelCMakeLists.txt
. This happens because callingadd_subdirectory
creates a child scope, and theProtobuf_XXX
variables set byfind_package(Protobuf REQUIRED)
are only in that child scope.A good way to fix this is to add the following to
proto/CMakeLists.txt
:This instructs targets that link to
proto
to also link to${Protobuf_LIBRARIES}
. Now you can simplifytarget_link_libraries
in your top-levelCMakeLists.txt
:On a side note, you could also use e.g.
${PROJECT_NAME}
resolves to whatever you have set in theproject(...)
statement in thatCMakeLists.txt
file.Finally, note that this links to
Protobuf_LIBRARIES
instead ofPROTOBUF_LIBRARY
.Protobuf_LIBRARIES
includes both the Protocol Buffers libraries and the dependent Pthreads library.The variable you need to pass to
target_link_libraries
isProtobuf_LIBRARIES
. See documentation.Watch out for variable name case: With CMake 3.6 and later, the
FindProtobuf
module input and output variables were all renamed fromPROTOBUF_
toProtobuf_
(see release notes), so usingProtobuf_
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
or force everyone to use at least CMake 3.6
Also, there is a resolved bug report in the Kitware cmake issue tracker with more information on how to diagnose such issues.