From a2a3399a6f84e29ab2dfc8c55739bbd495c314ce Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 14 Jun 2016 13:23:37 -0400 Subject: [PATCH] Add support for generation sources into a framework. - Add a protoc objc option (generate_for_named_framework) to set the name of the framework all generated sources will be in. - Tweak some comments/naming to make it clear what is the Protobuf framework vs. the framework for generated code. - Update the objc README to document the new generation option to protoc. This is working towards https://github.com/google/protobuf/issues/1457. --- objectivec/README.md | 17 +++++++- .../compiler/objectivec/objectivec_file.cc | 42 +++++++++++++++---- .../compiler/objectivec/objectivec_file.h | 2 +- .../objectivec/objectivec_generator.cc | 2 + .../compiler/objectivec/objectivec_helpers.h | 1 + 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/objectivec/README.md b/objectivec/README.md index c7313e4fe9..beda2cb6bb 100644 --- a/objectivec/README.md +++ b/objectivec/README.md @@ -123,8 +123,8 @@ never included when the message is encoded. The Objective C classes/enums can be used from Swift code. -Objective C Generator Options ------------------------------ +Objective C Generator Proto File Options +---------------------------------------- **objc_class_prefix=\** (no default) @@ -133,6 +133,19 @@ be collisions. This option provides a prefix that will be added to the Enums and Objects (for messages) generated from the proto. Convention is to base the prefix on the package the proto is in. +Objective C Generator `protoc` Options +-------------------------------------- + +When generating Objective C code, `protoc` supports a `--objc_opt` argument; the +argument is comma-delimited name/value pairs (_key=value,key2=value2_). The +_keys_ are used to change the behavior during generation. The currently +supported keys are: + + * `generate_for_framework_named`: The `value` used for this key will be used + when generating the `#import` statements in the generated code. Instead + of being plain `#import "some/path/file.pbobjc.h"` lines, they will be + framework based, i.e. - `#import `. + Contributing ------------ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 7774058eca..73e6d8d73e 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -54,14 +54,16 @@ namespace { class ImportWriter { public: - ImportWriter() {} + ImportWriter(const Options& options) : options_(options) {} void AddFile(const FileGenerator* file); void Print(io::Printer *printer) const; private: + const Options options_; vector protobuf_framework_imports_; vector protobuf_non_framework_imports_; + vector other_framework_imports_; vector other_imports_; }; @@ -72,6 +74,10 @@ void ImportWriter::AddFile(const FileGenerator* file) { protobuf_framework_imports_.push_back( FilePathBasename(file_descriptor) + extension); protobuf_non_framework_imports_.push_back(file->Path() + extension); + } else if (!options_.generate_for_named_framework.empty()) { + other_framework_imports_.push_back( + options_.generate_for_named_framework + "/" + + FilePathBasename(file_descriptor) + extension); } else { other_imports_.push_back(file->Path() + extension); } @@ -81,6 +87,8 @@ void ImportWriter::Print(io::Printer *printer) const { assert(protobuf_non_framework_imports_.size() == protobuf_framework_imports_.size()); + bool add_blank_line = false; + if (protobuf_framework_imports_.size() > 0) { const string framework_name(ProtobufLibraryFrameworkName); const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name)); @@ -106,12 +114,29 @@ void ImportWriter::Print(io::Printer *printer) const { printer->Print( "#endif\n"); - if (other_imports_.size() > 0) { + add_blank_line = true; + } + + if (other_framework_imports_.size() > 0) { + if (add_blank_line) { printer->Print("\n"); } + + for (vector::const_iterator iter = other_framework_imports_.begin(); + iter != other_framework_imports_.end(); ++iter) { + printer->Print( + " #import <$header$>\n", + "header", *iter); + } + + add_blank_line = true; } if (other_imports_.size() > 0) { + if (add_blank_line) { + printer->Print("\n"); + } + for (vector::const_iterator iter = other_imports_.begin(); iter != other_imports_.end(); ++iter) { printer->Print( @@ -156,7 +181,7 @@ FileGenerator::~FileGenerator() { } void FileGenerator::GenerateHeader(io::Printer *printer) { - PrintFilePreamble(printer, "GPBProtocolBuffers.h"); + PrintFileRuntimePreamble(printer, "GPBProtocolBuffers.h"); // Add some verification that the generated code matches the source the // code is being compiled with. @@ -170,7 +195,7 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { // #import any headers for "public imports" in the proto file. { - ImportWriter import_writer; + ImportWriter import_writer(options_); const vector &dependency_generators = DependencyGenerators(); for (vector::const_iterator iter = dependency_generators.begin(); @@ -273,10 +298,10 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { void FileGenerator::GenerateSource(io::Printer *printer) { // #import the runtime support. - PrintFilePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h"); + PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h"); { - ImportWriter import_writer; + ImportWriter import_writer(options_); // #import the header for this proto file. import_writer.AddFile(this); @@ -471,7 +496,10 @@ const vector &FileGenerator::DependencyGenerators() { return dependency_generators_; } -void FileGenerator::PrintFilePreamble( +// Helper to print the import of the runtime support at the top of generated +// files. This currently only supports the runtime coming from a framework +// as defined by the official CocoaPod. +void FileGenerator::PrintFileRuntimePreamble( io::Printer* printer, const string& header_to_import) const { printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index 7326c901c1..8e4388d8d2 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -88,7 +88,7 @@ class FileGenerator { const Options options_; const vector& DependencyGenerators(); - void PrintFilePreamble( + void PrintFileRuntimePreamble( io::Printer* printer, const string& header_to_import) const; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index 72e295de49..ed3ece7fa1 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -59,6 +59,8 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, for (int i = 0; i < options.size(); i++) { if (options[i].first == "expected_prefixes_path") { generation_options.expected_prefixes_path = options[i].second; + } else if (options[i].first == "generate_for_named_framework") { + generation_options.generate_for_named_framework = options[i].second; } else { *error = "error: Unknown generator option: " + options[i].first; return false; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 5898d69209..60536c8cbd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -46,6 +46,7 @@ namespace objectivec { struct Options { Options(); string expected_prefixes_path; + string generate_for_named_framework; }; // Escape C++ trigraphs by escaping question marks to "\?".