diff options
author | Thomas Van Lenten <thomasvl@google.com> | 2016-05-09 13:53:20 -0400 |
---|---|---|
committer | Thomas Van Lenten <thomasvl@google.com> | 2016-05-24 09:25:02 -0400 |
commit | 7da023b892ccd7135b6c9762d7618ccf414a4cd7 (patch) | |
tree | 04eb21f4a5a59ce61be4dc974d2e7cd6857f296a /src | |
parent | 2131b2d544bf6eeb789c128ef3e9e04fc299237a (diff) | |
download | protobuf-7da023b892ccd7135b6c9762d7618ccf414a4cd7.tar.gz protobuf-7da023b892ccd7135b6c9762d7618ccf414a4cd7.tar.bz2 protobuf-7da023b892ccd7135b6c9762d7618ccf414a4cd7.zip |
Better support for using the proto library from a framework.
- Add generator constant for the default framework name.
- Add generator api for making the CPP symbol from the name.
- Add generator api to see if it is a bundled proto file.
- Output a CPP conditional and two imports for the core library headers.
- Add helper for generating the #import for file headers to deal with the
framework imports.
- Add a reference from the unittests to a WKT to use that to inspect how
imports generate.
- Update the podspec to define the CPP symbol and require pods 1.0 (or later).
Fixes https://github.com/google/protobuf/issues/1457
Diffstat (limited to 'src')
4 files changed, 199 insertions, 48 deletions
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index ed4fc6a3..ccf5fbb4 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -50,6 +50,80 @@ const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001; namespace compiler { namespace objectivec { +namespace { + +class ImportWriter { + public: + ImportWriter() {} + + void AddFile(const FileGenerator* file); + void Print(io::Printer *printer) const; + + private: + vector<string> protobuf_framework_imports_; + vector<string> protobuf_non_framework_imports_; + vector<string> other_imports_; +}; + +void ImportWriter::AddFile(const FileGenerator* file) { + const FileDescriptor* file_descriptor = file->Descriptor(); + const string extension(".pbobjc.h"); + if (IsProtobufLibraryBundledProtoFile(file_descriptor)) { + protobuf_framework_imports_.push_back( + FilePathBasename(file_descriptor) + extension); + protobuf_non_framework_imports_.push_back(file->Path() + extension); + } else { + other_imports_.push_back(file->Path() + extension); + } +} + +void ImportWriter::Print(io::Printer *printer) const { + assert(protobuf_non_framework_imports_.size() == + protobuf_framework_imports_.size()); + + if (protobuf_framework_imports_.size() > 0) { + const string framework_name(ProtobufLibraryFrameworkName); + const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); + + printer->Print( + "#if $cpp_symbol$\n", + "cpp_symbol", cpp_symbol); + for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin(); + iter != protobuf_framework_imports_.end(); ++iter) { + printer->Print( + " #import <$framework_name$/$header$>\n", + "framework_name", framework_name, + "header", *iter); + } + printer->Print( + "#else\n"); + for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.begin(); + iter != protobuf_non_framework_imports_.end(); ++iter) { + printer->Print( + " #import \"$header$\"\n", + "header", *iter); + } + printer->Print( + "#endif\n"); + + if (other_imports_.size() > 0) { + printer->Print("\n"); + } + } + + if (other_imports_.size() > 0) { + for (vector<string>::const_iterator iter = other_imports_.begin(); + iter != other_imports_.end(); ++iter) { + printer->Print( + " #import \"$header$\"\n", + "header", *iter); + } + } +} + +} // namespace + + FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options) : file_(file), root_class_name_(FileClassName(file)), @@ -82,15 +156,7 @@ FileGenerator::~FileGenerator() { } void FileGenerator::GenerateHeader(io::Printer *printer) { - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n", - "filename", file_->name()); - - printer->Print( - "#import \"GPBProtocolBuffers.h\"\n" - "\n"); + PrintFilePreamble(printer, "GPBProtocolBuffers.h"); // Add some verification that the generated code matches the source the // code is being compiled with. @@ -102,14 +168,18 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { "protoc_gen_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION)); - const vector<FileGenerator *> &dependency_generators = DependencyGenerators(); - for (vector<FileGenerator *>::const_iterator iter = - dependency_generators.begin(); - iter != dependency_generators.end(); ++iter) { - if ((*iter)->IsPublicDependency()) { - printer->Print("#import \"$header$.pbobjc.h\"\n", - "header", (*iter)->Path()); + // #import any headers for "public imports" in the proto file. + { + ImportWriter import_writer; + const vector<FileGenerator *> &dependency_generators = DependencyGenerators(); + for (vector<FileGenerator *>::const_iterator iter = + dependency_generators.begin(); + iter != dependency_generators.end(); ++iter) { + if ((*iter)->IsPublicDependency()) { + import_writer.AddFile(*iter); + } } + import_writer.Print(printer); } printer->Print( @@ -198,27 +268,30 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { } void FileGenerator::GenerateSource(io::Printer *printer) { - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n", - "filename", file_->name()); + // #import the runtime support. + PrintFilePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h"); - string header_file = Path() + ".pbobjc.h"; - printer->Print( - "#import \"GPBProtocolBuffers_RuntimeSupport.h\"\n" - "#import \"$header_file$\"\n", - "header_file", header_file); - const vector<FileGenerator *> &dependency_generators = - DependencyGenerators(); - for (vector<FileGenerator *>::const_iterator iter = - dependency_generators.begin(); - iter != dependency_generators.end(); ++iter) { - if (!(*iter)->IsPublicDependency()) { - printer->Print("#import \"$header$.pbobjc.h\"\n", - "header", (*iter)->Path()); + { + ImportWriter import_writer; + + // #import the header for this proto file. + import_writer.AddFile(this); + + // #import the headers for anything that a plain dependency of this proto + // file (that means they were just an include, not a "public" include). + const vector<FileGenerator *> &dependency_generators = + DependencyGenerators(); + for (vector<FileGenerator *>::const_iterator iter = + dependency_generators.begin(); + iter != dependency_generators.end(); ++iter) { + if (!(*iter)->IsPublicDependency()) { + import_writer.AddFile(*iter); + } } + + import_writer.Print(printer); } + printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" @@ -356,8 +429,6 @@ void FileGenerator::GenerateSource(io::Printer *printer) { "// @@protoc_insertion_point(global_scope)\n"); } -const string FileGenerator::Path() const { return FilePath(file_); } - const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { if (file_->dependency_count() != dependency_generators_.size()) { set<string> public_import_names; @@ -376,6 +447,34 @@ const vector<FileGenerator *> &FileGenerator::DependencyGenerators() { return dependency_generators_; } +void FileGenerator::PrintFilePreamble( + io::Printer* printer, const string& header_to_import) const { + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n", + "filename", file_->name()); + + const string framework_name(ProtobufLibraryFrameworkName); + const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); + printer->Print( + "// This CPP symbol can be defined to use imports that match up to the framework\n" + "// imports needed when using CocoaPods.\n" + "#if !defined($cpp_symbol$)\n" + " #define $cpp_symbol$ 0\n" + "#endif\n" + "\n" + "#if $cpp_symbol$\n" + " #import <$framework_name$/$header$>\n" + "#else\n" + " #import \"$header$\"\n" + "#endif\n" + "\n", + "cpp_symbol", cpp_symbol, + "header", header_to_import, + "framework_name", framework_name); +} + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index 4c0fcd3f..7326c901 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -62,7 +62,8 @@ class FileGenerator { void GenerateHeader(io::Printer* printer); const string& RootClassName() const { return root_class_name_; } - const string Path() const; + const string Path() const { return FilePath(file_); } + const FileDescriptor* Descriptor() const { return file_; } bool IsPublicDependency() const { return is_public_dep_; } @@ -87,6 +88,8 @@ class FileGenerator { const Options options_; const vector<FileGenerator*>& DependencyGenerators(); + void PrintFilePreamble( + io::Printer* printer, const string& header_to_import) const; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 196b39dd..65bf8348 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -293,13 +293,6 @@ string BaseFileName(const FileDescriptor* file) { return basename; } -string FileName(const FileDescriptor* file) { - string path = FilePath(file); - string basename; - PathSplit(path, NULL, &basename); - return basename; -} - string FilePath(const FileDescriptor* file) { string output; string basename; @@ -317,6 +310,19 @@ string FilePath(const FileDescriptor* file) { return output; } +string FilePathBasename(const FileDescriptor* file) { + string output; + string basename; + string directory; + PathSplit(file->name(), &directory, &basename); + basename = StripProto(basename); + + // CamelCase to be more ObjC friendly. + output = UnderscoresToCamelCase(basename, true); + + return output; +} + string FileClassPrefix(const FileDescriptor* file) { // Default is empty string, no need to check has_objc_class_prefix. string result = file->options().objc_class_prefix(); @@ -831,6 +837,40 @@ string BuildCommentsString(const SourceLocation& location) { return final_comments; } +// Making these a generator option for folks that don't use CocoaPods, but do +// want to put the library in a framework is an interesting question. The +// problem is it means changing sources shipped with the library to actually +// use a different value; so it isn't as simple as a option. +const char* const ProtobufLibraryFrameworkName = "Protobuf"; + +string ProtobufFrameworkImportSymbol(const string& framework_name) { + // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS + string result = string("GPB_USE_"); + result += ToUpper(framework_name); + result += "_FRAMEWORK_IMPORTS"; + return result; +} + +bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { + // We don't check the name prefix or proto package because some files + // (descriptor.proto), aren't shipped generated by the library, so this + // seems to be the safest way to only catch the ones shipped. + const string name = file->name(); + if (name == "google/protobuf/any.proto" || + name == "google/protobuf/api.proto" || + name == "google/protobuf/duration.proto" || + name == "google/protobuf/empty.proto" || + name == "google/protobuf/field_mask.proto" || + name == "google/protobuf/source_context.proto" || + name == "google/protobuf/struct.proto" || + name == "google/protobuf/timestamp.proto" || + name == "google/protobuf/type.proto" || + name == "google/protobuf/wrappers.proto") { + return true; + } + return false; +} + namespace { // Internal helper class that parses the expected package to prefix mappings diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 3f56d94b..5898d692 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -62,15 +62,14 @@ bool IsRetainedName(const string& name); // handling under ARC. bool IsInitName(const string& name); -// Gets the name of the file we're going to generate (sans the .pb.h -// extension). This does not include the path to that file. -string FileName(const FileDescriptor* file); - // Gets the path of the file we're going to generate (sans the .pb.h // extension). The path will be dependent on the objectivec package // declared in the proto package. string FilePath(const FileDescriptor* file); +// Just like FilePath(), but without the directory part. +string FilePathBasename(const FileDescriptor* file); + // Gets the name of the root class we'll generate in the file. This class // is not meant for external consumption, but instead contains helpers that // the rest of the classes need @@ -169,6 +168,16 @@ string BuildFlagsString(const vector<string>& strings); // Builds a HeaderDoc style comment out of the comments in the .proto file. string BuildCommentsString(const SourceLocation& location); +// The name the commonly used by the library when built as a framework. +// This lines up to the name used in the CocoaPod. +extern const char* const ProtobufLibraryFrameworkName; +// Returns the CPP symbol name to use as the gate for framework style imports +// for the given framework name to use. +string ProtobufFrameworkImportSymbol(const string& framework_name); + +// Checks if the file is one of the proto's bundled with the library. +bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file); + // Checks the prefix for a given file and outputs any warnings needed, if // there are flat out errors, then out_error is filled in and the result is // false. |