问题
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?
回答1:
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.
回答2:
The variable you need to pass to target_link_libraries
is Protobuf_LIBRARIES
. See documentation.
回答3:
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.
回答4:
cmakeList.txt:
cmake_minimum_required(VERSION 3.12) project(protobuf)
SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")
set(CMAKE_CXX_STANDARD 11)
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER addressbook.proto) ADD_LIBRARY(proto2 ${PROTO_HEADER} ${PROTO_SRC}) TARGET_LINK_LIBRARIES(proto2)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
add_executable(protobuf main.cpp)
TARGET_LINK_LIBRARIES(protobuf proto2 ${PROTOBUF_LIBRARY})
来源:https://stackoverflow.com/questions/41043184/cmake-doesnt-work-with-google-protobuf