c++cmakeprotocol-buffers

How to build an example C++ project which uses CMake, protobuf and vcpkg


I'm trying to build a C++ project with a later version of the protobuf libraries than my OS package manager provides.

To do this, I have chosen to use vcpkg to configure the project dependencies. (In this case, just protobuf and nothing else.)

I have followed the Microsoft tutorial for vcpkg + cmake, but I am encountering linker errors.

It may just be that I have missed something.

I am familiar with most of these tools, with the exception of vcpkg which I have not used before.

The following files are all contained within a single directory.

Here is my main.cpp.

#include "message.pb.h"

int main() {

    std::cout << "hello world" << std::endl;

    PersonMessage person_message;

    person_message.set_name("henry");

    std::cout << person_message.name() << std::endl;
    std::cout << person_message.DebugString() << std::endl;

    return 0;
}

Here is the message.proto definition.

syntax = "proto3";

message PersonMessage {
  string name = 1;
}

CMakeLists.txt. I think this is sensible, but although I have used cmake a bit, I'm not really an expert. I know how to do some things with the build system, but this CMakeLists.txt might not be optimal.

cmake_minimum_required(VERSION 3.5)

project(vcpkg-project-test CXX)

find_package(Protobuf REQUIRED)

set(CMAKE_CXX_STANDARD 23)

set(PROTO_FILES message.proto)
set(PROTO_GENERATE_DIR ${CMAKE_BINARY_DIR}/generated)
file(MAKE_DIRECTORY ${PROTO_GENERATE_DIR})

protobuf_generate_cpp(
    PROTO_SRCS PROTO_HDRS ${PROTO_FILES}
)

add_library(
    lib_proto
    STATIC
    ${PROTO_SRCS}
)

target_include_directories(
    lib_proto
    PUBLIC
    ${Protobuf_INCLUDE_DIRS}
    ${CMAKE_CURRENT_BINARY_DIR}
)

target_link_libraries(
    lib_proto
    PUBLIC
    ${Protobuf_LIBRARIES}
)

add_executable(
    a.out
    main.cpp
)

target_link_libraries(
    a.out
    PRIVATE
    lib_proto
    ${Protobuf_LIBRARIES}
)

I have configured vcpkg.json to define the dependencies. This file contains the following contents.

{
    "dependencies": [
        "protobuf"
    ]
}

Finally, these are the commands I am running to attempt to build this project.

cmake -B build -S . -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build build

I am using the g++ compiler, version g++ (Ubuntu 14.2.0-4ubuntu2) 14.2.0.

When I try to build this project I encounter a very large list of linker errors. This is the first such error.

[build] /usr/bin/ld: liblib_proto.a(message.pb.cc.o): warning: relocation against `_ZN4absl12lts_2025012712log_internal9kCharNullE' in read-only section `.text._ZN4absl12lts_2025012712log_internal9NullGuardIPKcE5GuardES4_[_ZN4absl12lts_2025012712log_internal9NullGuardIPKcE5GuardES4_]'
[build] /usr/bin/ld: vcpkg_installed/x64-linux/lib/libprotobuf.a(arena.cc.o): in function `google::protobuf::internal::(anonymous namespace)::AllocateBlock(google::protobuf::internal::AllocationPolicy const*, unsigned long, unsigned long)':

Solution

  • The problem is that ${Protobuf_LIBRARIES} contains only the local libraries built by protoc.

    It contains the following string:

    /home/username/vcpkg-project-test/build/vcpkg_installed/x64-linux/lib/libprotobuf.a
    

    What it does not contain are the general libraries which are also required.

    We need to add them:

    target_link_libraries(
        a.out
        PRIVATE
        lib_proto
        protobuf::libprotoc protobuf::libprotobuf protobuf::libprotobuf-lite
    )
    

    Also note that ${Protobuf_LIBRARIES} is not required here, as the dependency is brought in via lib_proto.

    There is actually a helpful message printed by vcpkg about this.

    protobuf provides CMake targets:
    
      # this is heuristically generated, and may not be correct
      find_package(protobuf CONFIG REQUIRED)
      target_link_libraries(main PRIVATE protobuf::libprotoc protobuf::libprotobuf protobuf::libprotobuf-lite)
    

    It now works.