Well, I'm having some problems trying to understand how to compile libraries that include the code generated by Google's protobuf. Here's my CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
set (CMAKE_CXX_STANDARD 11)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/sandbox
/usr
)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/libraries)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/executables)
SET(COMPILE_FLAGS "-I/usr/local/include -pthread ")
SET(LINK_FLAGS "-L/usr/local/lib -lprotobuf -pthread -lpthread")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}" )
add_library(
protoAddress
SHARED
${CMAKE_CURRENT_SOURCE_DIR}/sandbox/addressbook.pb.cc
)
add_executable(prueba sandbox/testProto.cpp)
target_link_libraries(prueba protoAddress)
addressbook.pb.cc is the source code generated when you use protoc command with --cpp_out on Google's example:
syntax = "proto2";
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
The test I'm trying to make executable is the same of the example that uses google to explain how does it work with c++:
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_people());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
After trying to make this CMakeLists, I get a lot of errors, mostly from undefined reference:
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jverdeguer/Documents/workspace/protobuf/build
[ 25%] Building CXX object CMakeFiles/protoAddress.dir/sandbox/addressbook.pb.cc.o
[ 50%] Linking CXX shared library ../libraries/libprotoAddress.so
[ 50%] Built target protoAddress
[ 75%] Building CXX object CMakeFiles/prueba.dir/sandbox/testProto.cpp.o
[100%] Linking CXX executable ../executables/prueba
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `main':
testProto.cpp:(.text+0x2f6): undefined reference to `google::protobuf::internal::VerifyVersion(int, int, char const*)'
testProto.cpp:(.text+0x3f0): undefined reference to `google::protobuf::Message::ParseFromIstream(std::istream*)'
testProto.cpp:(.text+0x4b1): undefined reference to `google::protobuf::Message::SerializeToOstream(std::ostream*) const'
testProto.cpp:(.text+0x502): undefined reference to `google::protobuf::ShutdownProtobufLibrary()'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::Arena::AllocHook(std::type_info const*, unsigned long) const':
testProto.cpp:(.text._ZNK6google8protobuf5Arena9AllocHookEPKSt9type_infom[_ZNK6google8protobuf5Arena9AllocHookEPKSt9type_infom]+0x3d): undefined reference to `google::protobuf::Arena::OnArenaAllocation(std::type_info const*, unsigned long)const'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::internal::ArenaStringPtr::CreateInstanceNoArena(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const*)':
testProto.cpp:(.text._ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x4b): undefined reference to `google::protobuf::internal::LogMessage::LogMessage(google::protobuf::LogLevel, char const*, int)'
testProto.cpp:(.text._ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x61): undefined reference to `google::protobuf::internal::LogMessage::operator<<(char const*)'
testProto.cpp:(.text._ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x79): undefined reference to `google::protobuf::internal::LogFinisher::operator=(google::protobuf::internal::LogMessage&)'
testProto.cpp:(.text._ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x8d): undefined reference to `google::protobuf::internal::LogMessage::~LogMessage()'
testProto.cpp:(.text._ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN6google8protobuf8internal14ArenaStringPtr21CreateInstanceNoArenaEPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0xdc): undefined reference to `google::protobuf::internal::LogMessage::~LogMessage()'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::internal::GetEmptyStringAlreadyInited[abi:cxx11]()':
testProto.cpp:(.text._ZN6google8protobuf8internal27GetEmptyStringAlreadyInitedB5cxx11Ev[_ZN6google8protobuf8internal27GetEmptyStringAlreadyInitedB5cxx11Ev]+0x5): undefined reference to `google::protobuf::internal::fixed_address_empty_string[abi:cxx11]'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::RepeatedPtrField<tutorial::Person_PhoneNumber>::TypeHandler::Type* google::protobuf::internal::RepeatedPtrFieldBase::Add<google::protobuf::RepeatedPtrField<tutorial::Person_PhoneNumber>::TypeHandler>(google::protobuf::RepeatedPtrField<tutorial::Person_PhoneNumber>::TypeHandler::Type*)':
testProto.cpp:(.text._ZN6google8protobuf8internal20RepeatedPtrFieldBase3AddINS0_16RepeatedPtrFieldIN8tutorial18Person_PhoneNumberEE11TypeHandlerEEEPNT_4TypeESB_[_ZN6google8protobuf8internal20RepeatedPtrFieldBase3AddINS0_16RepeatedPtrFieldIN8tutorial18Person_PhoneNumberEE11TypeHandlerEEEPNT_4TypeESB_]+0x95): undefined reference to `google::protobuf::internal::RepeatedPtrFieldBase::Reserve(int)'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::RepeatedPtrField<tutorial::Person>::TypeHandler::Type* google::protobuf::internal::RepeatedPtrFieldBase::Add<google::protobuf::RepeatedPtrField<tutorial::Person>::TypeHandler>(google::protobuf::RepeatedPtrField<tutorial::Person>::TypeHandler::Type*)':
testProto.cpp:(.text._ZN6google8protobuf8internal20RepeatedPtrFieldBase3AddINS0_16RepeatedPtrFieldIN8tutorial6PersonEE11TypeHandlerEEEPNT_4TypeESB_[_ZN6google8protobuf8internal20RepeatedPtrFieldBase3AddINS0_16RepeatedPtrFieldIN8tutorial6PersonEE11TypeHandlerEEEPNT_4TypeESB_]+0x95): undefined reference to `google::protobuf::internal::RepeatedPtrFieldBase::Reserve(int)'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::internal::GenericTypeHandler<tutorial::Person_PhoneNumber>::New(google::protobuf::Arena*)':
testProto.cpp:(.text._ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial18Person_PhoneNumberEE3NewEPNS0_5ArenaE[_ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial18Person_PhoneNumberEE3NewEPNS0_5ArenaE]+0xb6): undefined reference to `google::protobuf::internal::ArenaImpl::AllocateAligned(unsigned long)'
testProto.cpp:(.text._ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial18Person_PhoneNumberEE3NewEPNS0_5ArenaE[_ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial18Person_PhoneNumberEE3NewEPNS0_5ArenaE]+0xd3): undefined reference to `google::protobuf::internal::ArenaImpl::AllocateAlignedAndAddCleanup(unsigned long, void (*)(void*))'
CMakeFiles/prueba.dir/sandbox/testProto.cpp.o: In function `google::protobuf::internal::GenericTypeHandler<tutorial::Person>::New(google::protobuf::Arena*)':
testProto.cpp:(.text._ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial6PersonEE3NewEPNS0_5ArenaE[_ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial6PersonEE3NewEPNS0_5ArenaE]+0xb6): undefined reference to `google::protobuf::internal::ArenaImpl::AllocateAligned(unsigned long)'
testProto.cpp:(.text._ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial6PersonEE3NewEPNS0_5ArenaE[_ZN6google8protobuf8internal18GenericTypeHandlerIN8tutorial6PersonEE3NewEPNS0_5ArenaE]+0xd3): undefined reference to `google::protobuf::internal::ArenaImpl::AllocateAlignedAndAddCleanup(unsigned long, void (*)(void*))'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::RegisterAllTypes(google::protobuf::Metadata const*, int)'
../libraries/libprotoAddress.so: undefined reference to `vtable for google::protobuf::Closure'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedOutputStream::WriteStringWithSizeToArray(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned char*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::WriteEnum(int, int, google::protobuf::io::CodedOutputStream*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::io::CodedOutputStream*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedInputStream::ReadVarintSizeAsIntFallback()'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::InitProtobufDefaults()'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::WriteInt32(int, int, google::protobuf::io::CodedOutputStream*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::Message::CheckTypeAndMergeFrom(google::protobuf::MessageLite const&)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::GoogleOnceInitImpl(long*, google::protobuf::Closure*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedInputStream::ReadTagFallback(unsigned int)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::ReadBytes(google::protobuf::io::CodedInputStream*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::Message::GetTypeName[abi:cxx11]() const'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::Message::InitializationErrorString[abi:cxx11]() const'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormat::SerializeUnknownFields(google::protobuf::UnknownFieldSet const&, google::protobuf::io::CodedOutputStream*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::Message::DiscardUnknownFields()'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::UnknownFieldSet::AddVarint(int, unsigned long)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::MessageLite::SerializeWithCachedSizesToArray(unsigned char*) const'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(int, google::protobuf::MessageLite const&, google::protobuf::io::CodedOutputStream*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormatLite::VerifyUtf8String(char const*, int, google::protobuf::internal::WireFormatLite::Operation, char const*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::OnShutdownDestroyMessage(void const*)'
../libraries/libprotoAddress.so: undefined reference to `vtable for google::protobuf::internal::FunctionClosure0'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::DescriptorPool::InternalAddGeneratedFile(void const*, int)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::ReflectionOps::Merge(google::protobuf::Message const&, google::protobuf::Message*)'
../libraries/libprotoAddress.so: undefined reference to `vtable for google::protobuf::MessageLite'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::FunctionClosure0::~FunctionClosure0()'
../libraries/libprotoAddress.so: undefined reference to `typeinfo for google::protobuf::Message'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::UnknownFieldSet::default_instance()'
../libraries/libprotoAddress.so: undefined reference to `vtable for google::protobuf::Message'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::UnknownFieldSet::MergeFrom(google::protobuf::UnknownFieldSet const&)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::UnknownFieldSet::ClearFallback()'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedInputStream::IncrementRecursionDepthAndPushLimit(int)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(google::protobuf::UnknownFieldSet const&, unsigned char*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(google::protobuf::UnknownFieldSet const&)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::Message::SpaceUsedLong() const'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedInputStream::ReadVarint32Fallback(unsigned int)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::RepeatedPtrFieldBase::InternalExtend(int)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::WireFormat::SkipField(google::protobuf::io::CodedInputStream*, unsigned int, google::protobuf::UnknownFieldSet*)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::MessageFactory::InternalRegisterGeneratedFile(char const*, void (*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&))'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::internal::AssignDescriptors(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::internal::MigrationSchema const*, google::protobuf::Message const* const*, unsigned int const*, google::protobuf::MessageFactory*, google::protobuf::Metadata*, google::protobuf::EnumDescriptor const**, google::protobuf::ServiceDescriptor const**)'
../libraries/libprotoAddress.so: undefined reference to `google::protobuf::io::CodedInputStream::DecrementRecursionDepthAndPopLimit(int)'
collect2: error: ld returned 1 exit status
CMakeFiles/prueba.dir/build.make:95: recipe for target '../executables/prueba' failed
make[2]: *** [../executables/prueba] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/prueba.dir/all' failed
make[1]: *** [CMakeFiles/prueba.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
It seems pretty clear that something is wrong when linking with the google library, but I can't see what is wrong or how to solve it
FYI: I run this is Linux Mint 18 'Sonya' and installed the protoc package from the github with the default options.
Can anyone help me solve this errors and explain what is happening? If you feel like you need more information feel free to ask. Thanks in advance.
EDIT: I updated my cmakelists and now it works, but I dont understand why. I list next the new CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
set (CMAKE_CXX_STANDARD 11)
include(FindProtobuf)
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIR})
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/sandbox
/usr
)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/libraries)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/executables)
SET(COMPILE_FLAGS "-I/usr/local/include -pthread ")
SET(LINK_FLAGS "-L/usr/local/lib -lprotobuf -pthread -lpthread")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}" )
add_library(
protoAddress
SHARED
${CMAKE_CURRENT_SOURCE_DIR}/sandbox/addressbook.pb.cc
)
add_executable(prueba sandbox/testProto.cpp)
target_link_libraries(prueba protoAddress ${PROTOBUF_LIBRARY})
I understand the fact of why I need the library, but not how Cmake does locate that and give me a link for linking both libraries.