Skip to content

Commit

Permalink
Use a objc class prefix mappings path generator option instead.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnkoutso committed Feb 12, 2022
1 parent 250fafa commit 0e1ab8f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 28 deletions.
12 changes: 7 additions & 5 deletions objectivec/README.md
Expand Up @@ -133,7 +133,7 @@ This options allow you to provide a custom prefix for all the symbols generated
from a proto file (classes (from message), enums, the Root for extension
support).

If not set, the generation options `default_objc_class_prefix` and `use_package_as_prefix`
If not set, the generation options `objc_class_prefix_mappings_path` and `use_package_as_prefix`
(documented below) control what is used instead. Since Objective C uses a global namespace for all
of its classes, there can be collisions. `use_package_as_prefix=yes` should
avoid collisions since proto package are used to scope/name things in other
Expand Down Expand Up @@ -182,10 +182,12 @@ supported keys are:
having to add the runtime directory to the header search path since the
generate `#import` will be more complete.

* `default_objc_class_prefix`: The default ObjC prefix value to use when
generating sources. The generator will use this if the `objc_class_prefix`
file option is not set. This option can be useful if multiple iOS apps
consume the same proto file but wish to use a different prefix for their
* `objc_class_prefix_mappings_path`: The `value` used for this key
is a path to a file containing a list of prefixes and proto files.
The generator will use this to locate a ObjC class prefix to use when
generating sources. The generator will first honor the `objc_class_prefix`
file option if it is set. This option can be useful if multiple iOS apps
consume a common set of proto files but wish to use a different prefix for
generated sources.

* `use_package_as_prefix` and `proto_package_prefix_exceptions_path`: The
Expand Down
22 changes: 12 additions & 10 deletions src/google/protobuf/compiler/objectivec/objectivec_generator.cc
Expand Up @@ -190,19 +190,21 @@ bool ObjectiveCGenerator::GenerateAll(
// header search path since the generate #import will be more complete.
generation_options.runtime_import_prefix =
StripSuffixString(options[i].second, "/");
} else if (options[i].first == "default_objc_class_prefix") {
// The default objc class prefix to use if specified by the command line
// invocation. The file option is always honored first if one is present.
std::string value = options[i].second;
if (value.empty()) {
*error = "error: default_objc_class_prefix cannot be empty.";
return false;
}
SetDefaultObjcClassPrefix(value);
} else if (options[i].first == "objc_class_prefix_mappings_path") {
// Path to use for when loading the objc class prefix mappings to use.
// The `objc_class_prefix` option is always honored first if one is present.
//
// The format of the file is:
// - An entry is a line of "objc_class_prefix: file.proto, dir/file2.proto".
// - Comments start with "#".
// - A comment can go on a line after a expected package/prefix pair.
// (i.e. - "GPB: descriptor.proto # comment")
//
SetObjCClassPrefixMappingsPath(options[i].second);
} else if (options[i].first == "use_package_as_prefix") {
// Controls how the symbols should be prefixed to avoid symbols
// collisions. The objc_class_prefix file option is always honored first
// followed by the default_objc_class_prefix generator option. This is is just
// followed by the objc_class_prefix_mappings_path generator option. This is is just
// what to do if either of these options are not set. The available options are:
// "no": Not prefixed (the existing mode).
// "yes": Make a prefix out of the proto package.
Expand Down
59 changes: 51 additions & 8 deletions src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
Expand Up @@ -99,8 +99,13 @@ class PrefixModeStorage {
public:
PrefixModeStorage();

const std::string default_objc_class_prefix() const { return default_objc_class_prefix_; }
void set_default_objc_class_prefix(const std::string& default_objc_class_prefix) { default_objc_class_prefix_ = default_objc_class_prefix; }
const std::string objc_class_prefix_mappings_path() const { return objc_class_prefix_mappings_path_; }
void set_objc_class_prefix_mappings_path(const std::string& path) {
objc_class_prefix_mappings_path_ = path;
objc_class_prefix_map_.clear();
}

std::string objc_class_prefix(const FileDescriptor* file);

bool use_package_name() const { return use_package_name_; }
void set_use_package_name(bool on_or_off) { use_package_name_ = on_or_off; }
Expand All @@ -119,7 +124,8 @@ class PrefixModeStorage {

private:
bool use_package_name_;
std::string default_objc_class_prefix_;
std::map<std::string, std::string> objc_class_prefix_map_;
std::string objc_class_prefix_mappings_path_;
std::string exception_path_;
std::string forced_prefix_;
std::unordered_set<std::string> exceptions_;
Expand All @@ -144,6 +150,38 @@ PrefixModeStorage::PrefixModeStorage() {
}
}

std::string PrefixModeStorage::objc_class_prefix(const FileDescriptor* file) {
if (!file) {
return "";
}

if (objc_class_prefix_map_.empty() && !objc_class_prefix_mappings_path_.empty()) {
std::string error_str;
// Re use the same collector as we use for the named framework paths as the file
// is expected to be in the same format.
ImportWriter::ProtoFrameworkCollector collector(&objc_class_prefix_map_);
if (!ParseSimpleFile(objc_class_prefix_mappings_path_, &collector, &error_str)) {
if (error_str.empty()) {
error_str = std::string("protoc:0: warning: Failed to parse")
+ std::string(" objc class prefix mappings file: ")
+ objc_class_prefix_mappings_path_;
}
std::cerr << error_str << std::endl;
std::cerr.flush();
objc_class_prefix_map_.clear();
}
}

std::map<std::string, std::string>::iterator objc_class_prefix_lookup =
objc_class_prefix_map_.find(file->name());

if (objc_class_prefix_lookup != objc_class_prefix_map_.end()) {
return objc_class_prefix_lookup->second;
}

return "";
}

bool PrefixModeStorage::is_package_exempted(const std::string& package) {
if (exceptions_.empty() && !exception_path_.empty()) {
std::string error_str;
Expand Down Expand Up @@ -173,8 +211,12 @@ PrefixModeStorage g_prefix_mode;

} // namespace

void SetDefaultObjcClassPrefix(const std::string& default_objc_class_prefix) {
g_prefix_mode.set_default_objc_class_prefix(default_objc_class_prefix);
std::string GetObjCClassPrefixMappingsPath() {
return g_prefix_mode.objc_class_prefix_mappings_path();
}

void SetObjCClassPrefixMappingsPath(const std::string& file_path) {
g_prefix_mode.set_objc_class_prefix_mappings_path(file_path);
}

bool UseProtoPackageAsDefaultPrefix() {
Expand Down Expand Up @@ -539,9 +581,10 @@ std::string FileClassPrefix(const FileDescriptor* file) {
return file->options().objc_class_prefix();
}

// If a default prefix is passed through objc_opt then accept it.
if (!g_prefix_mode.default_objc_class_prefix().empty()) {
return g_prefix_mode.default_objc_class_prefix();
// If package prefix is specified in an objc class prefix mapping file then use that.
std::string objc_class_prefix = g_prefix_mode.objc_class_prefix(file);
if (!objc_class_prefix.empty()) {
return objc_class_prefix;
}

// If package prefix isn't enabled, done.
Expand Down
10 changes: 5 additions & 5 deletions src/google/protobuf/compiler/objectivec/objectivec_helpers.h
Expand Up @@ -47,9 +47,10 @@ namespace protobuf {
namespace compiler {
namespace objectivec {

// Set the default objc class prefix that should be used. This method is used only
// when default_objc_class_prefix is passed through objc_opt.
void PROTOC_EXPORT SetDefaultObjcClassPrefix(const std::string& objc_class_prefix);
// TODO
std::string PROTOC_EXPORT GetObjCClassPrefixMappingsPath();
void PROTOC_EXPORT SetObjCClassPrefixMappingsPath(
const std::string& file_path);
// Get/Set if the proto package should be used to make the default prefix for
// symbols. This will then impact most of the type naming apis below. It is done
// as a global to not break any other generator reusing the methods since they
Expand All @@ -71,7 +72,7 @@ struct Options {
std::string generate_for_named_framework;
std::string named_framework_to_proto_path_mappings_path;
std::string runtime_import_prefix;
std::string default_objc_class_prefix;
std::string objc_class_prefix_mappings_path;
bool prefixes_must_be_registered;
bool require_prefixes;
};
Expand Down Expand Up @@ -315,7 +316,6 @@ class PROTOC_EXPORT ImportWriter {
const std::string& runtime_import_prefix,
bool default_cpp_symbol = false);

private:
class ProtoFrameworkCollector : public LineConsumer {
public:
ProtoFrameworkCollector(std::map<std::string, std::string>* inout_proto_file_to_framework_name)
Expand Down

0 comments on commit 0e1ab8f

Please sign in to comment.