0

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.

Seraphid
  • 11
  • 1
  • 1
  • 4
  • 2
    do you link `libprotobuf` ? I dont see it – 463035818_is_not_a_number Feb 21 '18 at 16:51
  • At first make sure that you are linking with `libprotobuf`. – Naseef Chowdhury Feb 21 '18 at 16:56
  • 1
    Doesn't the `-lprotobuf` flag in the Linker_Flags do that? – Seraphid Feb 21 '18 at 17:00
  • After making a bit of searching with what I learned from your comments, I found what I need in this answer https://stackoverflow.com/questions/10010398/how-to-link-google-protobuf-libraries-via-cmake-on-linux Thanks! Anyway, I'm still not understanding how does it exactly work, so I will update the question(Sorry, I'm not really proficient with cmake) – Seraphid Feb 21 '18 at 17:06
  • 2
    **Never** place `-l` flags into *CMAKE_EXE_LINKER_FLAGS*, use `target_link_libraries` instead. In the command line for link, *linker flags* are located *before* your object files. This is why compiler [cannot find them](https://stackoverflow.com/a/24675715/3440745). Flags created from `target_link_libraries` invocation are placed *after* your object files. – Tsyvarev Feb 21 '18 at 17:24

0 Answers0