FindProtobuf: add flag to allow descriptor files to be generated

- The .desc files will be in the same folder as the generated .cc and .h files.
- Paths to generate .desc files are stored in a variable passed in
- This is only implemented for C++
- Remove legacy ARGS
- Add test that generates and uses C++ protobuf message
- Add test that checks that the generated .desc file can be instantiated
  with DynamicMessageFactory
- Add Help rst for new feature
This commit is contained in:
Peter Mitrano 2017-09-21 09:23:30 -04:00 committed by Brad King
parent 4e91be9532
commit 1299f4cc5e
7 changed files with 129 additions and 4 deletions

View File

@ -0,0 +1,5 @@
protobuf-desc
-------------
* The :module:`FindProtobuf` module :command:`protobuf_generate_cpp` command
gained a ``DESCRIPTORS`` option to generate descriptor files.

View File

@ -79,6 +79,7 @@
# include_directories(${CMAKE_CURRENT_BINARY_DIR})
# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
# protobuf_generate_python(PROTO_PY foo.proto)
# add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
# target_link_libraries(bar ${Protobuf_LIBRARIES})
@ -92,12 +93,15 @@
#
# Add custom commands to process ``.proto`` files to C++::
#
# protobuf_generate_cpp (<SRCS> <HDRS> [EXPORT_MACRO <MACRO>] [<ARGN>...])
# protobuf_generate_cpp (<SRCS> <HDRS>
# [DESCRIPTORS <DESC>] [EXPORT_MACRO <MACRO>] [<ARGN>...])
#
# ``SRCS``
# Variable to define with autogenerated source files
# ``HDRS``
# Variable to define with autogenerated header files
# ``DESCRIPTORS``
# Variable to define with auotgenerated descriptor files, if requested.
# ``EXPORT_MACRO``
# is a macro which should expand to ``__declspec(dllexport)`` or
# ``__declspec(dllimport)`` depending on what is being compiled.
@ -116,7 +120,7 @@
# ``.proto`` filess
function(PROTOBUF_GENERATE_CPP SRCS HDRS)
cmake_parse_arguments(protobuf "" "EXPORT_MACRO" "" ${ARGN})
cmake_parse_arguments(protobuf "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN})
set(PROTO_FILES "${protobuf_UNPARSED_ARGUMENTS}")
if(NOT PROTO_FILES)
@ -158,6 +162,10 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
set(${SRCS})
set(${HDRS})
if (protobuf_DESCRIPTORS)
set(${protobuf_DESCRIPTORS})
endif()
foreach(FIL ${PROTO_FILES})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
@ -173,11 +181,23 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
list(APPEND ${SRCS} "${_protobuf_protoc_src}")
list(APPEND ${HDRS} "${_protobuf_protoc_hdr}")
if(protobuf_DESCRIPTORS)
set(_protobuf_protoc_desc "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.desc")
set(_protobuf_protoc_flags "--descriptor_set_out=${_protobuf_protoc_desc}")
list(APPEND ${protobuf_DESCRIPTORS} "${_protobuf_protoc_desc}")
else()
set(_protobuf_protoc_desc "")
set(_protobuf_protoc_flags "")
endif()
add_custom_command(
OUTPUT "${_protobuf_protoc_src}"
"${_protobuf_protoc_hdr}"
${_protobuf_protoc_desc}
COMMAND protobuf::protoc
ARGS "--cpp_out=${DLL_EXPORT_DECL}${CMAKE_CURRENT_BINARY_DIR}" ${_protobuf_include_path} ${ABS_FIL}
"--cpp_out=${DLL_EXPORT_DECL}${CMAKE_CURRENT_BINARY_DIR}"
${_protobuf_protoc_flags}
${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL} protobuf::protoc
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
VERBATIM )
@ -185,6 +205,9 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS)
set(${SRCS} "${${SRCS}}" PARENT_SCOPE)
set(${HDRS} "${${HDRS}}" PARENT_SCOPE)
if(protobuf_DESCRIPTORS)
set(${protobuf_DESCRIPTORS} "${${protobuf_DESCRIPTORS}}" PARENT_SCOPE)
endif()
endfunction()
function(PROTOBUF_GENERATE_PYTHON SRCS)

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.4)
cmake_minimum_required(VERSION 3.8)
project(TestFindProtobuf CXX)
include(CTest)
@ -32,3 +32,19 @@ target_link_libraries(test_var_protoc PRIVATE ${Protobuf_PROTOC_LIBRARIES})
add_test(NAME test_var_protoc COMMAND test_var_protoc)
add_test(NAME test_tgt_protoc_version COMMAND protobuf::protoc --version)
set(Protobuf_IMPORT_DIRS ${Protobuf_INCLUDE_DIRS})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER msgs/example.proto)
PROTOBUF_GENERATE_CPP(DESC_PROTO_SRC DESC_PROTO_HEADER DESCRIPTORS DESC_PROTO_DESC msgs/example_desc.proto)
add_library(msgs ${PROTO_SRC} ${PROTO_HEADER})
add_executable(test_generate main-generate.cxx ${PROTO_SRC})
target_include_directories(test_generate PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(test_generate msgs ${Protobuf_LIBRARIES})
add_test(NAME test_generate COMMAND test_generate)
add_executable(test_desc main-desc.cxx ${DESC_PROTO_SRC})
target_compile_features(test_desc PRIVATE cxx_std_11)
target_include_directories(test_desc PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(test_desc msgs ${Protobuf_LIBRARIES})
add_test(NAME test_desc COMMAND test_desc ${DESC_PROTO_DESC})

View File

@ -0,0 +1,57 @@
#include <fstream>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/text_format.h>
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
std::ifstream fs;
fs.open(argv[1], std::ifstream::in);
google::protobuf::FileDescriptorSet file_descriptor_set;
file_descriptor_set.ParseFromIstream(&fs);
const google::protobuf::DescriptorPool* compiled_pool =
google::protobuf::DescriptorPool::generated_pool();
if (compiled_pool == NULL) {
std::cerr << "compiled pool is NULL." << std::endl;
return 1;
}
google::protobuf::DescriptorPool pool(compiled_pool);
google::protobuf::DynamicMessageFactory dynamic_message_factory(&pool);
for (const google::protobuf::FileDescriptorProto& file_descriptor_proto :
file_descriptor_set.file()) {
const google::protobuf::FileDescriptor* file_descriptor =
pool.BuildFile(file_descriptor_proto);
if (file_descriptor == NULL) {
continue;
}
const google::protobuf::Descriptor* descriptor =
pool.FindMessageTypeByName("example.msgs.ExampleDesc");
if (descriptor == NULL) {
continue;
}
google::protobuf::Message* msg =
dynamic_message_factory.GetPrototype(descriptor)->New();
std::string data = "data: 1";
bool success = google::protobuf::TextFormat::ParseFromString(data, msg);
if (success) {
return 0;
} else {
std::cerr << "Failed to parse message." << std::endl;
return 2;
}
}
std::cerr << "No matching message found." << std::endl;
return 3;
}

View File

@ -0,0 +1,8 @@
#include <example.pb.h>
int main()
{
example::msgs::Example msg;
return 0;
}

View File

@ -0,0 +1,6 @@
syntax = "proto2";
package example.msgs;
message Example {
required int32 data = 1;
}

View File

@ -0,0 +1,10 @@
syntax = "proto2";
package example.msgs;
import "google/protobuf/descriptor.proto";
message ExampleDesc {
required int32 data = 1;
optional google.protobuf.FileDescriptorSet desc = 2;
}