aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp/cpp_file.cc
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
commitd37d46dfbcedadeb439ad0367f8afcf8867dca43 (patch)
treeb896df229f7c671637924c156d5a759ba50a3190 /src/google/protobuf/compiler/cpp/cpp_file.cc
parent709ea28f3264aa5632e5577a4080671173fc6166 (diff)
Integrate recent changes from Google-internal code tree. See CHANGES.txt
for details.
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_file.cc')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc152
1 files changed, 115 insertions, 37 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 6487979f..dcc48552 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -143,17 +143,20 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// Open namespace.
GenerateNamespaceOpeners(printer);
- // Forward-declare the AssignGlobalDescriptors function, so that we can
- // declare it to be a friend of each class.
+ // Forward-declare the AddDescriptors and AssignDescriptors functions, so
+ // that we can declare them to be friends of each class.
printer->Print(
"\n"
"// Internal implementation detail -- do not call these.\n"
- "void $dllexport_decl$ $builddescriptorsname$();\n"
- "void $builddescriptorsname$_AssignGlobalDescriptors(\n"
- " ::google::protobuf::FileDescriptor* file);\n"
- "\n",
- "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()),
+ "void $dllexport_decl$ $adddescriptorsname$();\n",
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
"dllexport_decl", dllexport_decl_);
+ printer->Print(
+ // Note that we don't put dllexport_decl on this because it is only called
+ // by the .pb.cc file in which it is defined.
+ "void $assigndescriptorsname$();\n"
+ "\n",
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
// Generate forward declarations of classes.
for (int i = 0; i < file_->message_type_count(); i++) {
@@ -232,6 +235,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"\n"
"#include \"$basename$.pb.h\"\n"
+ "#include <google/protobuf/stubs/once.h>\n"
"#include <google/protobuf/descriptor.h>\n"
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/reflection_ops.h>\n"
@@ -296,23 +300,46 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
}
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
- // BuildDescriptors() is a file-level procedure which initializes all of
- // the Descriptor objects for this file. It runs the first time one of the
- // descriptors is accessed. This will always be at static initialization
- // time, because every message has a statically-initialized default instance,
- // and the constructor for a message class accesses its descriptor. See the
- // constructor and the descriptor() method of message classes.
+ // AddDescriptors() is a file-level procedure which adds the encoded
+ // FileDescriptorProto for this .proto file to the global DescriptorPool
+ // for generated files (DescriptorPool::generated_pool()). It always runs
+ // at static initialization time, so all files will be registered before
+ // main() starts. This procedure also constructs default instances and
+ // registers extensions.
//
- // We also construct the reflection object for each class inside
- // BuildDescriptors().
+ // Its sibling, AssignDescriptors(), actually pulls the compiled
+ // FileDescriptor from the DescriptorPool and uses it to populate all of
+ // the global variables which store pointers to the descriptor objects.
+ // It also constructs the reflection objects. It is called the first time
+ // anyone calls descriptor() or GetReflection() on one of the types defined
+ // in the file.
- // First we generate a method to assign the global descriptors.
printer->Print(
"\n"
- "void $builddescriptorsname$_AssignGlobalDescriptors("
- "const ::google::protobuf::FileDescriptor* file) {\n",
- "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()));
+ "void $assigndescriptorsname$() {\n",
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
printer->Indent();
+
+ // Make sure the file has found its way into the pool. If a descriptor
+ // is requested *during* static init then AddDescriptors() may not have
+ // been called yet, so we call it manually. Note that it's fine if
+ // AddDescriptors() is called multiple times.
+ printer->Print(
+ "$adddescriptorsname$();\n",
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
+
+ // Get the file's descriptor from the pool.
+ printer->Print(
+ "const ::google::protobuf::FileDescriptor* file =\n"
+ " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
+ " \"$filename$\");\n"
+ // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
+ // being unused when compiling an empty .proto file.
+ "GOOGLE_CHECK(file != NULL);\n",
+ "filename", file_->name());
+
+ // Go through all the stuff defined in this file and generated code to
+ // assign the global descriptor pointers based on the file descriptor.
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
@@ -322,29 +349,63 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
for (int i = 0; i < file_->service_count(); i++) {
service_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+
+ // -----------------------------------------------------------------
+
+ // protobuf_AssignDescriptorsOnce(): The first time it is called, calls
+ // AssignDescriptors(). All later times, waits for the first call to
+ // complete and then returns.
+ printer->Print(
+ "namespace {\n"
+ "\n"
+ "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
+ "inline void protobuf_AssignDescriptorsOnce() {\n"
+ " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
+ " &$assigndescriptorsname$);\n"
+ "}\n"
+ "\n",
+ "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
+
+ // protobuf_RegisterTypes(): Calls
+ // MessageFactory::InternalRegisterGeneratedType() for each message type.
+ printer->Print(
+ "void protobuf_RegisterTypes() {\n"
+ " protobuf_AssignDescriptorsOnce();\n");
+ printer->Indent();
+
for (int i = 0; i < file_->message_type_count(); i++) {
- message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
+ message_generators_[i]->GenerateTypeRegistrations(printer);
}
printer->Outdent();
printer->Print(
- "}\n");
+ "}\n"
+ "\n"
+ "} // namespace\n");
+ // -----------------------------------------------------------------
+
+ // Now generate the AddDescriptors() function.
printer->Print(
"\n"
- "void $builddescriptorsname$() {\n"
+ "void $adddescriptorsname$() {\n"
+ // We don't need any special synchronization here because this code is
+ // called at static init time before any threads exist.
" static bool already_here = false;\n"
" if (already_here) return;\n"
" already_here = true;\n"
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
- " ::google::protobuf::DescriptorPool* pool =\n"
- " ::google::protobuf::DescriptorPool::internal_generated_pool();\n"
"\n",
- "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()));
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
printer->Indent();
- // Call the BuildDescriptors() methods for all of our dependencies, to make
- // sure they get initialized first.
+ // Call the AddDescriptors() methods for all of our dependencies, to make
+ // sure they get added first.
for (int i = 0; i < file_->dependency_count(); i++) {
const FileDescriptor* dependency = file_->dependency(i);
// Print the namespace prefix for the dependency.
@@ -355,10 +416,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
printer->Print("$name$::",
"name", dependency_package_parts[i]);
}
- // Call its BuildDescriptors function.
+ // Call its AddDescriptors function.
printer->Print(
"$name$();\n",
- "name", GlobalBuildDescriptorsName(dependency->name()));
+ "name", GlobalAddDescriptorsName(dependency->name()));
}
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
@@ -370,7 +431,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
file_proto.SerializeToString(&file_data);
printer->Print(
- "pool->InternalBuildGeneratedFile(");
+ "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
// Only write 40 bytes per line.
static const int kBytesPerLine = 40;
@@ -379,24 +440,41 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"data", CEscape(file_data.substr(i, kBytesPerLine)));
}
printer->Print(
- ", $size$,\n"
- "&$builddescriptorsname$_AssignGlobalDescriptors);\n",
- "size", SimpleItoa(file_data.size()),
- "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()));
+ ", $size$);\n",
+ "size", SimpleItoa(file_data.size()));
+
+ // Call MessageFactory::InternalRegisterGeneratedFile().
+ printer->Print(
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
+ " \"$filename$\", &protobuf_RegisterTypes);\n",
+ "filename", file_->name());
+
+ // Allocate and initialize default instances. This can't be done lazily
+ // since default instances are returned by simple accessors and are used with
+ // extensions. Speaking of which, we also register extensions at this time.
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateDefaultInstanceAllocator(printer);
+ }
+ for (int i = 0; i < file_->extension_count(); i++) {
+ extension_generators_[i]->GenerateRegistration(printer);
+ }
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
+ }
printer->Outdent();
printer->Print(
"}\n"
"\n"
- "// Force BuildDescriptors() to be called at static initialization time.\n"
+ "// Force AddDescriptors() to be called at static initialization time.\n"
"struct StaticDescriptorInitializer_$filename$ {\n"
" StaticDescriptorInitializer_$filename$() {\n"
- " $builddescriptorsname$();\n"
+ " $adddescriptorsname$();\n"
" }\n"
"} static_descriptor_initializer_$filename$_;\n"
"\n",
- "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()),
+ "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
"filename", FilenameIdentifier(file_->name()));
}