protoc-c: add options for function generation

Add options controller helper function generation. Preserve existing
behavior of not generating pack/unpack functions for sub-messages if
option is not explicitly set.

Fixes #240
Fixes #442
This commit is contained in:
Ilya Lipnitskiy 2021-03-20 16:57:34 -07:00
parent 883b1acc1b
commit baa860ff97
No known key found for this signature in database
GPG Key ID: 435C02AAE7CF2014
6 changed files with 132 additions and 18 deletions

View File

@ -37,6 +37,14 @@ option (pb_c_file).no_generate = true;
message ProtobufCFileOptions {
// Suppresses pb-c.{c,h} file output completely.
optional bool no_generate = 1 [default = false];
// Generate helper pack/unpack functions?
// For backwards compatibility, if this field is not explicitly set,
// only top-level message pack/unpack functions will be generated
optional bool gen_pack_helpers = 2 [default = true];
// Generate helper init message functions?
optional bool gen_init_helpers = 3 [default = true];
}
extend google.protobuf.FileOptions {
@ -44,6 +52,11 @@ extend google.protobuf.FileOptions {
}
message ProtobufCMessageOptions {
// Overrides the parent setting only if present
optional bool gen_pack_helpers = 1 [default = false];
// Overrides the parent setting only if present
optional bool gen_init_helpers = 2 [default = true];
}
extend google.protobuf.MessageOptions {

View File

@ -191,7 +191,13 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
}
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateHelperFunctionDeclarations(printer, false);
const ProtobufCFileOptions opt = file_->options().GetExtension(pb_c_file);
message_generators_[i]->GenerateHelperFunctionDeclarations(
printer,
opt.has_gen_pack_helpers(),
opt.gen_pack_helpers(),
opt.gen_init_helpers());
}
printer->Print("/* --- per-message closures --- */\n\n");
@ -265,11 +271,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
}
#endif
const ProtobufCFileOptions opt = file_->options().GetExtension(pb_c_file);
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateHelperFunctionDefinitions(printer, false);
message_generators_[i]->GenerateHelperFunctionDefinitions(
printer,
opt.has_gen_pack_helpers(),
opt.gen_pack_helpers(),
opt.gen_init_helpers());
}
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateMessageDescriptor(printer);
message_generators_[i]->GenerateMessageDescriptor(printer,
opt.gen_init_helpers());
}
for (int i = 0; i < file_->enum_type_count(); i++) {
enum_generators_[i]->GenerateEnumDescriptor(printer);

View File

@ -252,21 +252,38 @@ GenerateStructDefinition(io::Printer* printer) {
}
void MessageGenerator::
GenerateHelperFunctionDeclarations(io::Printer* printer, bool is_submessage)
GenerateHelperFunctionDeclarations(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init)
{
const ProtobufCMessageOptions opt =
descriptor_->options().GetExtension(pb_c_msg);
// Override parent settings, if needed
if (opt.has_gen_pack_helpers())
gen_pack = opt.gen_pack_helpers();
if (opt.has_gen_init_helpers())
gen_init = opt.gen_init_helpers();
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateHelperFunctionDeclarations(printer, true);
bool nested_pack = !is_pack_deep ? opt.gen_pack_helpers() : gen_pack;
nested_generators_[i]->GenerateHelperFunctionDeclarations(printer, true,
nested_pack,
gen_init);
}
std::map<std::string, std::string> vars;
vars["classname"] = FullNameToC(descriptor_->full_name());
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
printer->Print(vars,
if (gen_init) {
printer->Print(vars,
"/* $classname$ methods */\n"
"void $lcclassname$__init\n"
" ($classname$ *message);\n"
);
if (!is_submessage) {
}
if (gen_pack) {
printer->Print(vars,
"size_t $lcclassname$__get_packed_size\n"
" (const $classname$ *message);\n"
@ -325,24 +342,41 @@ compare_pfields_by_number (const void *a, const void *b)
}
void MessageGenerator::
GenerateHelperFunctionDefinitions(io::Printer* printer, bool is_submessage)
GenerateHelperFunctionDefinitions(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init)
{
const ProtobufCMessageOptions opt =
descriptor_->options().GetExtension(pb_c_msg);
// Override parent settings, if needed
if (opt.has_gen_pack_helpers())
gen_pack = opt.gen_pack_helpers();
if (opt.has_gen_init_helpers())
gen_init = opt.gen_init_helpers();
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateHelperFunctionDefinitions(printer, true);
bool nested_pack = !is_pack_deep ? opt.gen_pack_helpers() : gen_pack;
nested_generators_[i]->GenerateHelperFunctionDefinitions(printer, true,
nested_pack,
gen_init);
}
std::map<std::string, std::string> vars;
vars["classname"] = FullNameToC(descriptor_->full_name());
vars["lcclassname"] = FullNameToLower(descriptor_->full_name());
vars["ucclassname"] = FullNameToUpper(descriptor_->full_name());
printer->Print(vars,
if (gen_init) {
printer->Print(vars,
"void $lcclassname$__init\n"
" ($classname$ *message)\n"
"{\n"
" static const $classname$ init_value = $ucclassname$__INIT;\n"
" *message = init_value;\n"
"}\n");
if (!is_submessage) {
}
if (gen_pack) {
printer->Print(vars,
"size_t $lcclassname$__get_packed_size\n"
" (const $classname$ *message)\n"
@ -388,7 +422,7 @@ GenerateHelperFunctionDefinitions(io::Printer* printer, bool is_submessage)
}
void MessageGenerator::
GenerateMessageDescriptor(io::Printer* printer) {
GenerateMessageDescriptor(io::Printer* printer, bool gen_init) {
std::map<std::string, std::string> vars;
vars["fullname"] = descriptor_->full_name();
vars["classname"] = FullNameToC(descriptor_->full_name());
@ -401,8 +435,14 @@ GenerateMessageDescriptor(io::Printer* printer) {
descriptor_->file()->options().optimize_for() ==
FileOptions_OptimizeMode_CODE_SIZE;
const ProtobufCMessageOptions opt =
descriptor_->options().GetExtension(pb_c_msg);
// Override parent settings, if needed
if (opt.has_gen_init_helpers())
gen_init = opt.gen_init_helpers();
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateMessageDescriptor(printer);
nested_generators_[i]->GenerateMessageDescriptor(printer, gen_init);
}
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@ -568,8 +608,15 @@ GenerateMessageDescriptor(io::Printer* printer) {
}
printer->Print(vars,
" $n_ranges$,"
" $lcclassname$__number_ranges,\n"
" (ProtobufCMessageInit) $lcclassname$__init,\n"
" $lcclassname$__number_ranges,\n");
if (gen_init) {
printer->Print(vars,
" (ProtobufCMessageInit) $lcclassname$__init,\n");
} else {
printer->Print(vars,
" NULL, /* gen_init_helpers = false */\n");
}
printer->Print(vars,
" NULL,NULL,NULL /* reserved[123] */\n"
"};\n");
}

View File

@ -111,14 +111,20 @@ class MessageGenerator {
void GenerateStructStaticInitMacro(io::Printer* printer);
// Generate standard helper functions declarations for this message.
void GenerateHelperFunctionDeclarations(io::Printer* printer, bool is_submessage);
void GenerateHelperFunctionDeclarations(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init);
// Source file stuff.
// Generate code that initializes the global variable storing the message's
// descriptor.
void GenerateMessageDescriptor(io::Printer* printer);
void GenerateHelperFunctionDefinitions(io::Printer* printer, bool is_submessage);
void GenerateMessageDescriptor(io::Printer* printer, bool gen_init);
void GenerateHelperFunctionDefinitions(io::Printer* printer,
bool is_pack_deep,
bool gen_pack,
bool gen_init);
private:

View File

@ -432,6 +432,39 @@ static void test_required_SubMess (void)
#undef DO_TEST
}
static size_t foo__test_mess_optional__get_packed_size
(const Foo__TestMessOptional *message)
{
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
static size_t foo__test_mess_optional__pack
(const Foo__TestMessOptional *message,
uint8_t *out)
{
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
static Foo__TestMessOptional *
foo__test_mess_optional__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Foo__TestMessOptional *)
protobuf_c_message_unpack (&foo__test_mess_optional__descriptor,
allocator, len, data);
}
static void foo__test_mess_optional__free_unpacked
(Foo__TestMessOptional *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &foo__test_mess_optional__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
/* === Optional type fields === */
static void test_empty_optional (void)
{

View File

@ -117,6 +117,8 @@ message TestMessPacked {
}
message TestMessOptional {
option (pb_c_msg).gen_pack_helpers = false;
option (pb_c_msg).gen_init_helpers = false;
optional int32 test_int32 = 1;
optional sint32 test_sint32 = 2;
optional sfixed32 test_sfixed32 = 3;