I cannot add protobuf using CPM.
M46f988b814 opened this issue · comments
I have a small example.
Here is my protobuf file
syntax = "proto3";
message Example{
double version=13;
double d = 1;
}
Here is my cpp file
#include "example.pb.h"
#include <iostream>
#include "example.pb.h"
int main()
{
Example e;
std::cout << "Testing" << std::endl;
}
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(protobuf_example)
# Include CPM.cmake
include(cmake/CPM.cmake)
# Use CPM to fetch and configure Protobuf
CPMAddPackage(
NAME protobuf
GITHUB_REPOSITORY protocolbuffers/protobuf
VERSION 3.21.12
OPTIONS("-Dprotobuf_BUILD_TESTS=OFF")
)
# Protobuf-generated files
set(PROTO_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.cc)
set(PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.h)
add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS}
COMMAND ${CMAKE_BINARY_DIR}/_deps/protobuf-build/protoc
--cpp_out=${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/example.proto
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example.proto
)
# Compile executable using generated protobuf files
add_executable(${PROJECT_NAME}
${PROTO_SRCS}
main.cpp
)
# Include directories for the generated protobuf files
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
# Link against protobuf
target_link_libraries(${PROJECT_NAME} PRIVATE protobuf::libprotobuf)
If I run this with -G "Ninja" (ninja 1.10.1) then it fails at building protobuf at ~51%
[build] FAILED: ../example.pb.cc ../example.pb.h <path>/software/scratch/example.pb.cc <path>/software/scratch/example.pb.h
[build] cd <path>/build/_deps/protobuf-build/protoc --cpp_out= <path>/example.proto
...
[build] [209/407 51% :: 12.310] Building CXX object _deps/protobuf-build/CMakeFiles/gmock.dir/third_party/googletest/googletest/src/gtest-all.cc.o
[build] ninja: build stopped: subcommand failed.
If I run this with -G "Unix Makefiles" (make version 4.3) then it will not try building, but if I go into build/_deps/protobuf-build and run make -j. Everything completes as expected. The problem here is that without building I can't link against protobuf. Any ideas with why CPM isn't working here?
More system info.
g++ 11.4.0
cmake 3.22.1
Ubuntu 22.04 LTS
Hmm It seems like the issue was some async behavior because protoc is needed before target link libraries perhaps. However I couldn't fix it with a sleep like follows. I think the build is run before the target link libraries perhaps?
# Use CPM to fetch and configure Protobuf
CPMAddPackage(
NAME protobuf
GITHUB_REPOSITORY protocolbuffers/protobuf
VERSION 3.21.12
OPTIONS("-Dprotobuf_BUILD_TESTS=OFF")
)
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 180)
#Protobuf-generated files
set(PROTO_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.cc)
set(PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.h)
add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS}
COMMAND ${CMAKE_BINARY_DIR}/_deps/protobuf-build/protoc
--cpp_out=${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/example.proto
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example.proto
)
Solved. I was able to wait by adding protoc to the DEPENDS
cmake_minimum_required(VERSION 3.17)
project(protobuf_example)
# Include CPM.cmake
include(cmake/CPM.cmake)
set(CPM_SOURCE_CACHE ${CMAKE_CURRENT_SOURCE_DIR}/cache)
# Use CPM to fetch and configure Protobuf
CPMAddPackage(
NAME protobuf
GITHUB_REPOSITORY protocolbuffers/protobuf
VERSION 3.21.12
OPTIONS("-Dprotobuf_BUILD_TESTS=OFF")
)
#Protobuf-generated files
set(PROTO_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.cc)
set(PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/example.pb.h)
add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS}
COMMAND ${CMAKE_BINARY_DIR}/_deps/protobuf-build/protoc
--cpp_out=${CMAKE_CURRENT_SOURCE_DIR}
--proto_path=${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/example.proto
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example.proto ${CMAKE_BINARY_DIR}/_deps/protobuf-build/protoc
)
# Compile library using generated protobuf files
add_executable(${PROJECT_NAME}
${PROTO_SRCS}
main.cpp
)
# Include directories for the generated protobuf files
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
# Link against protobuf
target_link_libraries(${PROJECT_NAME} PRIVATE protobuf::libprotobuf)
Won't using generator expression be a cleaner way to solve your issue?
ie $<TARGET_FILE:protoc>
so you don't have specify full path to protoc that will most likely break?
add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS}
COMMAND $<TARGET_FILE:protoc>
--cpp_out=${CMAKE_CURRENT_SOURCE_DIR}
--proto_path=${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/example.proto
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example.proto protoc
)
I haven't tested but depending on CMAKE_BINARY_DIR
is quite a bad practice for cases like that, since the binary could easily be relocated, or this will break when using multi config generator (msvc, ...)
Note that in DEPENDS
I used the target protoc
.