diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_file.cc')
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_file.cc | 279 |
1 files changed, 123 insertions, 156 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index a922ee97..42525687 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -35,20 +35,17 @@ #include <google/protobuf/compiler/cpp/cpp_file.h> #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <set> #include <vector> #include <google/protobuf/compiler/cpp/cpp_enum.h> -#include <google/protobuf/compiler/cpp/cpp_service.h> #include <google/protobuf/compiler/cpp/cpp_extension.h> +#include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_message.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/io/printer.h> +#include <google/protobuf/compiler/cpp/cpp_service.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -61,11 +58,11 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) options_(options), scc_analyzer_(options), enum_generators_owner_( - new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]), + new std::unique_ptr<EnumGenerator>[file->enum_type_count()]), service_generators_owner_( - new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]), + new std::unique_ptr<ServiceGenerator>[file->service_count()]), extension_generators_owner_( - new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) { + new std::unique_ptr<ExtensionGenerator>[file->extension_count()]) { std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); for (int i = 0; i < msgs.size(); i++) { // Deleted in destructor @@ -141,6 +138,9 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "// @@protoc_insertion_point(includes)\n"); + printer->Print("#define PROTOBUF_INTERNAL_EXPORT_$filename$ $export$\n", + "filename", FileLevelNamespace(file_), + "export", options_.dllexport_decl); GenerateMacroUndefs(printer); GenerateGlobalStateFunctionDeclarations(printer); @@ -223,8 +223,9 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, GenerateTopHeaderGuard(printer, filename_identifier); if (options_.proto_h) { + string target_basename = StripProto(file_->name()); printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", - "basename", StripProto(file_->name())); + "basename", target_basename); } else { GenerateLibraryIncludes(printer); } @@ -256,9 +257,10 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, } void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { + string target_basename = StripProto(file_->name()); const bool use_system_include = IsWellKnownMessage(file_); - string header = - StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); + + string header = target_basename + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" @@ -269,7 +271,6 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { "\n" "#include <google/protobuf/stubs/common.h>\n" "#include <google/protobuf/stubs/port.h>\n" - "#include <google/protobuf/stubs/once.h>\n" "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), @@ -296,7 +297,8 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dep = file_->dependency(i); const char* extension = ".proto.h"; - string dependency = StripProto(dep->name()) + extension; + string basename = StripProto(dep->name()); + string dependency = basename + extension; printer->Print( "#include \"$dependency$\"\n", "dependency", dependency); @@ -338,33 +340,34 @@ namespace { // Generates weak symbol declarations for types that are to be considered weakly // referenced. -void GenerateWeakDeclarations( - const FileDescriptor* file, const Options& options, - SCCAnalyzer* scc_analyzer, - io::Printer* printer) { - std::vector<const FieldDescriptor*> fields; - ListAllFields(file, &fields); - +void GenerateInternalForwardDeclarations( + const std::vector<const FieldDescriptor*>& fields, const Options& options, + SCCAnalyzer* scc_analyzer, io::Printer* printer) { // To ensure determinism and minimize the number of namespace statements, // we output the forward declarations sorted on namespace and type / function // name. std::set<std::pair<string, string> > messages; + std::set<std::pair<string, string> > sccs; std::set<std::pair<string, string> > inits; for (int i = 0; i < fields.size(); ++i) { const FieldDescriptor* field = fields[i]; - bool is_weak = IsImplicitWeakField(field, options); + const Descriptor* msg = field->message_type(); + if (msg == nullptr) continue; + bool is_weak = IsImplicitWeakField(field, options, scc_analyzer); + string flns = FileLevelNamespace(msg); + auto scc = scc_analyzer->GetSCC(msg); + string repr = ClassName(scc->GetRepresentative()); + string weak_attr; if (is_weak) { - const Descriptor* msg = field->message_type(); - string flns = FileLevelNamespace(msg); - string repr = ClassName(scc_analyzer->GetSCC(msg)->GetRepresentative()); - inits.insert(std::make_pair(flns, "InitDefaults" + repr)); inits.insert(std::make_pair(flns, "AddDescriptors")); messages.insert(std::make_pair(Namespace(msg), ClassName(msg))); + weak_attr = " __attribute__((weak))"; } - } - - if (messages.empty()) { - return; + string dllexport = "PROTOBUF_INTERNAL_EXPORT_" + FileLevelNamespace(msg); + sccs.insert(std::make_pair(flns, "extern " + dllexport + weak_attr + + " ::google::protobuf::internal::SCCInfo<" + + SimpleItoa(scc->children.size()) + + "> scc_info_" + repr + ";\n")); } printer->Print("\n"); @@ -384,13 +387,33 @@ void GenerateWeakDeclarations( printer->Print("void $name$() __attribute__((weak));\n", "name", it->second); } + for (const auto& p : sccs) { + ns.ChangeTo(p.first); + printer->Print(p.second.c_str()); + } } } // namespace void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + + // Generate weak declarations. We do this for the whole strongly-connected + // component (SCC), because we have a single InitDefaults* function for the + // SCC. + std::vector<const FieldDescriptor*> fields; + for (const Descriptor* message : + scc_analyzer_.GetSCC(message_generators_[idx]->descriptor_) + ->descriptors) { + ListAllFields(message, &fields); + } + GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, + printer); + + if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { + NamespaceOpener ns(FileLevelNamespace(file_), printer); + GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); + } { // package namespace NamespaceOpener ns(Namespace(file_), printer); @@ -411,12 +434,6 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { "// @@protoc_insertion_point(namespace_scope)\n"); } // end package namespace - if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { - NamespaceOpener ns(FileLevelNamespace(file_), printer); - GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); - } - - printer->Print( "namespace google {\nnamespace protobuf {\n"); message_generators_[idx]->GenerateSourceInProto2Namespace(printer); @@ -430,15 +447,16 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { void FileGenerator::GenerateGlobalSource(io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); - // TODO(gerbens) Generate tables here - - // Define the code to initialize reflection. This code uses a global - // constructor to register reflection data with the runtime pre-main. - if (HasDescriptorMethods(file_, options_)) { + { NamespaceOpener ns(FileLevelNamespace(file_), printer); - GenerateReflectionInitializationCode(printer); + GenerateTables(printer); + + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. + if (HasDescriptorMethods(file_, options_)) { + GenerateReflectionInitializationCode(printer); + } } NamespaceOpener ns(Namespace(file_), printer); @@ -466,7 +484,10 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) { GenerateSourceIncludes(printer); - GenerateWeakDeclarations(file_, options_, &scc_analyzer_, printer); + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + GenerateInternalForwardDeclarations(fields, options_, &scc_analyzer_, + printer); { NamespaceOpener ns(Namespace(file_), printer); @@ -483,9 +504,25 @@ void FileGenerator::GenerateSource(io::Printer* printer) { { NamespaceOpener ns(FileLevelNamespace(file_), printer); - // Define the initialization code to initialize the default instances. - // This code doesn't use a global constructor. - GenerateInitializationCode(printer); + GenerateTables(printer); + + // Now generate the InitDefaults for each SCC. + for (int i = 0; i < message_generators_.size(); i++) { + if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { + GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), + printer); + } + } + + printer->Print("void InitDefaults() {\n"); + for (int i = 0; i < message_generators_.size(); i++) { + if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; + string scc_name = ClassName(message_generators_[i]->descriptor_); + printer->Print( + " ::google::protobuf::internal::InitSCC(&scc_info_$scc_name$.base);\n", + "scc_name", scc_name); + } + printer->Print("}\n\n"); // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. @@ -560,7 +597,7 @@ class FileGenerator::ForwardDeclarations { ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { ForwardDeclarations*& ns = namespaces_[ns_name]; - if (ns == NULL) { + if (ns == nullptr) { ns = new ForwardDeclarations; } return ns; @@ -648,17 +685,12 @@ class FileGenerator::ForwardDeclarations { end = classes_.end(); it != end; ++it) { const Descriptor* d = it->second; - string extra_class_qualifier; - // "class" is to disambiguate in case there is also a function with this - // name. There is code out there that does this! printer->Print( "template<> " "$dllexport_decl$" - "$class$$classname$* Arena::$func$< $class$$classname$>(Arena*);\n", - "classname", QualifiedClassName(d), - "func", MessageCreateFunction(d), - "class", extra_class_qualifier, - "dllexport_decl", + "$classname$* Arena::CreateMaybeMessage<$classname$>" + "(Arena*);\n", + "classname", QualifiedClassName(d), "dllexport_decl", options.dllexport_decl.empty() ? "" : options.dllexport_decl + " "); } printer->Print( @@ -758,7 +790,6 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // protobuf_AssignDescriptorsOnce(): The first time it is called, calls // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. - string message_factory = "NULL"; printer->Print( "void protobuf_AssignDescriptors() {\n" // Make sure the file has found its way into the pool. If a descriptor @@ -766,10 +797,9 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // been called yet, so we call it manually. Note that it's fine if // AddDescriptors() is called multiple times. " AddDescriptors();\n" - " ::google::protobuf::MessageFactory* factory = $factory$;\n" " AssignDescriptors(\n" " \"$filename$\", schemas, file_default_instances, " - "TableStruct::offsets, factory,\n" + "TableStruct::offsets,\n" " $metadata$, $enum_descriptors$, $service_descriptors$);\n", "filename", file_->name(), "metadata", !message_generators_.empty() ? "file_level_metadata" : "NULL", @@ -778,14 +808,13 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" - : "NULL", - "factory", message_factory); + : "NULL"); printer->Print( "}\n" "\n" "void protobuf_AssignDescriptorsOnce() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);\n" + " static ::google::protobuf::internal::once_flag once;\n" + " ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);\n" "}\n" "\n", "filename", file_->name(), "metadata", @@ -795,8 +824,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "service_descriptors", HasGenericServices(file_, options_) && file_->service_count() > 0 ? "file_level_service_descriptors" - : "NULL", - "factory", message_factory); + : "NULL"); // Only here because of useless string reference that we don't want in // protobuf_AssignDescriptorsOnce, because that is called from all the @@ -891,8 +919,8 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { "}\n" "\n" "void AddDescriptors() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n" + " static ::google::protobuf::internal::once_flag once;\n" + " ::google::protobuf::internal::call_once(once, AddDescriptorsImpl);\n" "}\n"); printer->Print( @@ -907,47 +935,16 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { const string scc_name = ClassName(scc->GetRepresentative()); + // We use static and not anonymous namespace because symbol names are + // substantially shorter. printer->Print( - "void InitDefaults$scc_name$Impl() {\n" + "static void InitDefaults$scc_name$() {\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" - "#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n" - " ::google::protobuf::internal::InitProtobufDefaultsForceUnique();\n" - "#else\n" - " ::google::protobuf::internal::InitProtobufDefaults();\n" - "#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n", - // Force initialization of primitive values we depend on. + , // awkward comma due to macro "scc_name", scc_name); printer->Indent(); - // Call the InitDefaults() methods for all of our dependencies, to make - // sure they get added first. - for (int i = 0; i < scc->children.size(); i++) { - const SCC* child_scc = scc->children[i]; - const FileDescriptor* dependency = child_scc->GetRepresentative()->file(); - // Print the namespace prefix for the dependency. - string file_namespace = FileLevelNamespace(dependency); - std::map<string, string> variables; - variables["file_namespace"] = file_namespace; - variables["scc_name"] = ClassName(child_scc->GetRepresentative(), false); - bool using_weak_fields = UsingImplicitWeakFields(file_, options_); - if (using_weak_fields) { - // We're building for lite with implicit weak fields, so we need to handle - // the possibility that this InitDefaults function is not linked into the - // binary. Some of these might actually be guaranteed to be non-null since - // we might have a strong reference to the dependency (via a required - // field, for example), but it's simplest to just assume that any of them - // could be null. - printer->Print( - variables, - "if (&$file_namespace$::InitDefaults$scc_name$ != NULL) {\n" - " $file_namespace$::InitDefaults$scc_name$();\n" - "}\n"); - } else { - printer->Print(variables, - "$file_namespace$::InitDefaults$scc_name$();\n"); - } - } // First construct all the necessary default instances. for (int i = 0; i < message_generators_.size(); i++) { @@ -982,23 +979,24 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { } printer->Outdent(); printer->Print("}\n\n"); + printer->Print( - "void InitDefaults$scc_name$() {\n" - " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" - " ::google::protobuf::GoogleOnceInit(&once, " - "&InitDefaults$scc_name$Impl);\n" - "}\n\n", - "scc_name", scc_name); + "$dllexport_decl$::google::protobuf::internal::SCCInfo<$size$> " + "scc_info_$scc_name$ =\n" + " {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), " + "$size$, InitDefaults$scc_name$}, {", + "size", SimpleItoa(scc->children.size()), "scc_name", + ClassName(scc->GetRepresentative()), "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + for (const SCC* child : scc->children) { + auto repr = child->GetRepresentative(); + printer->Print("\n &$ns$::scc_info_$child$.base,", "ns", + FileLevelNamespace(repr), "child", ClassName(repr)); + } + printer->Print("}};\n\n"); } -void FileGenerator::GenerateInitializationCode(io::Printer* printer) { - // Messages depend on the existence of a default instance, which has to - // initialized properly. The default instances are allocated in the data - // segment, but we can't quite allocate the type directly. The destructors - // cannot run at program exit as this could lead to segfaults in a threaded - // environment. Hence these instances must be inplace constructed at first - // use. - +void FileGenerator::GenerateTables(io::Printer* printer) { if (options_.table_driven_parsing) { // TODO(ckennelly): Gate this with the same options flag to enable // table-driven parsing. @@ -1105,16 +1103,6 @@ void FileGenerator::GenerateInitializationCode(io::Printer* printer) { "};\n" "\n"); } - - // ----------------------------------------------------------------- - // All functionality that need private access. - - // Now generate the InitDefaults for each SCC. - for (int i = 0; i < message_generators_.size(); i++) { - if (IsSCCRepresentative(message_generators_[i]->descriptor_)) { - GenerateInitForSCC(GetSCC(message_generators_[i]->descriptor_), printer); - } - } } void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { @@ -1145,8 +1133,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" - "#ifndef PROTOBUF_$filename_identifier$_INCLUDED\n" - "#define PROTOBUF_$filename_identifier$_INCLUDED\n" + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$\n" "\n" "#include <string>\n", "filename", file_->name(), "filename_identifier", filename_identifier); @@ -1156,7 +1144,7 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, void FileGenerator::GenerateBottomHeaderGuard( io::Printer* printer, const string& filename_identifier) { printer->Print( - "#endif // PROTOBUF_$filename_identifier$_INCLUDED\n", + "#endif // PROTOBUF_INCLUDED_$filename_identifier$\n", "filename_identifier", filename_identifier); } @@ -1193,7 +1181,9 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include <google/protobuf/arena.h>\n" "#include <google/protobuf/arenastring.h>\n" "#include <google/protobuf/generated_message_table_driven.h>\n" - "#include <google/protobuf/generated_message_util.h>\n"); + "#include <google/protobuf/generated_message_util.h>\n" + "#include <google/protobuf/inlined_string_field.h>\n"); + if (HasDescriptorMethods(file_, options_)) { printer->Print( @@ -1280,11 +1270,12 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); + string basename = StripProto(name); printer->Print( "#include $left$$dependency$.pb.h$right$$iwyu$\n", - "dependency", StripProto(name), + "dependency", basename, "iwyu", (public_import) ? " // IWYU pragma: export" : "", "left", use_system_include ? "<" : "\"", "right", use_system_include ? ">" : "\""); @@ -1318,28 +1309,6 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); } - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; - string scc_name = ClassName(message_generators_[i]->descriptor_); - // TODO(gerbens) Remove the Impl from header. This is solely because - // it currently still needs to be a friend of the protos. - printer->Print( - "void $dllexport_decl$InitDefaults$scc_name$Impl();\n" - "void $dllexport_decl$InitDefaults$scc_name$();\n", - "scc_name", scc_name, "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - } - // TODO(gerbens) This is for proto1 interoperability. Remove when proto1 - // is gone. - printer->Print( - "inline void $dllexport_decl$InitDefaults() {\n", "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; - string scc_name = ClassName(message_generators_[i]->descriptor_); - printer->Print(" InitDefaults$scc_name$();\n", "scc_name", scc_name); - } - printer->Print("}\n"); printer->Print( "} // namespace $file_namespace$\n", "file_namespace", FileLevelNamespace(file_)); @@ -1416,8 +1385,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { printer->Print(kThinSeparator); printer->Print("\n"); } - // Methods of the dependent base class must always be inline in the header. - message_generators_[i]->GenerateDependentInlineMethods(printer); } } |