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
to tutorial::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?
The variable you need to pass to target_link_libraries
is Protobuf_LIBRARIES
. See documentation.
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.