Skip to content

Commit

Permalink
[ObjC] Improve handing of the WKT ObjC Category additions.
Browse files Browse the repository at this point in the history
Include a comment in the generated header about there being helpers
in GPBWellKnowTypes.h

Generate some extra code for the WKTs that have categories to help
ensure the categories get linked so developers don't have to use
-ObjC in some cases.

PiperOrigin-RevId: 589179237
  • Loading branch information
thomasvl authored and Copybara-Service committed Dec 8, 2023
1 parent cca8a7c commit b146d14
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 0 deletions.
3 changes: 3 additions & 0 deletions objectivec/GPBAny.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions objectivec/GPBAny.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions objectivec/GPBDuration.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions objectivec/GPBDuration.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions objectivec/GPBTimestamp.pbobjc.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions objectivec/GPBTimestamp.pbobjc.m

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions src/google/protobuf/compiler/objectivec/file.cc
Expand Up @@ -22,6 +22,8 @@
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/objectivec/enum.h"
#include "google/protobuf/compiler/objectivec/extension.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
Expand Down Expand Up @@ -139,6 +141,27 @@ void MakeDescriptors(
}
}

void EmitLinkWKTs(absl::string_view name, io::Printer* p) {
absl::string_view::size_type last_slash = name.rfind('/');
std::string basename;
if (last_slash == absl::string_view::npos) {
basename = std::string(name);
} else {
basename = std::string(name.substr(last_slash + 1));
}

p->Emit({{"basename", StripProto(basename)}},
R"objc(
// This is to help make sure that the GPBWellKnownTypes.* categories get linked and
// developers do not have to use the `-ObjC` linker flag. More information
// here: https://medium.com/ios-os-x-development/categories-in-static-libraries-78e41f8ddb96
__attribute__((used)) static NSString* $basename$_importCategories () {
return GPBWellKnownTypesErrorDomain;
}
)objc");
p->Emit("\n");
}

void EmitSourceFwdDecls(const absl::btree_set<std::string>& fwd_decls,
io::Printer* p) {
if (fwd_decls.empty()) {
Expand Down Expand Up @@ -385,6 +408,10 @@ void FileGenerator::GenerateSource(io::Printer* p) const {
EmitRootImplementation(p, deps_with_extensions);
EmitFileDescription(p);

if (is_bundled_proto_ && HasWKTWithObjCCategory(file_)) {
EmitLinkWKTs(file_->name(), p);
}

for (const auto& generator : enum_generators_) {
generator->GenerateSource(p);
}
Expand All @@ -395,6 +422,8 @@ void FileGenerator::GenerateSource(io::Printer* p) const {
}

void FileGenerator::GenerateGlobalSource(io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
std::vector<const FileDescriptor*> deps_with_extensions =
common_state_->CollectMinimalFileDepsContainingExtensions(file_);
GeneratedFileOptions file_options;
Expand All @@ -416,6 +445,8 @@ void FileGenerator::GenerateGlobalSource(io::Printer* p) const {
}

void FileGenerator::GenerateSourceForEnums(io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
// Enum implementation uses atomic in the generated code.
GeneratedFileOptions file_options;
file_options.extra_system_headers.push_back("stdatomic.h");
Expand All @@ -428,6 +459,8 @@ void FileGenerator::GenerateSourceForEnums(io::Printer* p) const {
}

void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) const {
ABSL_CHECK(!is_bundled_proto_)
<< "Bundled protos aren't expected to use multi source generation.";
const auto& generator = message_generators_[idx];

absl::btree_set<std::string> fwd_decls;
Expand Down Expand Up @@ -485,6 +518,9 @@ void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type,
break;
case GeneratedFileType::kSource:
import_writer.AddRuntimeImport("GPBProtocolBuffers_RuntimeSupport.h");
if (is_bundled_proto_ && HasWKTWithObjCCategory(file_)) {
import_writer.AddRuntimeImport("GPBWellKnownTypes.h");
}
import_writer.AddFile(file_, header_extension);
if (HeadersUseForwardDeclarations()) {
if (generation_options_.generate_minimal_imports) {
Expand Down
28 changes: 28 additions & 0 deletions src/google/protobuf/compiler/objectivec/helpers.cc
Expand Up @@ -13,6 +13,7 @@
#include <string>
#include <vector>

#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
Expand Down Expand Up @@ -393,6 +394,33 @@ void EmitCommentsString(io::Printer* printer, const SourceLocation& location,
)");
}

bool HasWKTWithObjCCategory(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 std::string name = file->name();
if (name == "google/protobuf/any.proto" ||
name == "google/protobuf/duration.proto" ||
name == "google/protobuf/timestamp.proto") {
ABSL_DCHECK(IsProtobufLibraryBundledProtoFile(file));
return true;
}
return false;
}

bool IsWKTWithObjCCategory(const Descriptor* descriptor) {
if (!HasWKTWithObjCCategory(descriptor->file())) {
return false;
}
const std::string full_name = descriptor->full_name();
if (full_name == "google.protobuf.Any" ||
full_name == "google.protobuf.Duration" ||
full_name == "google.protobuf.Timestamp") {
return true;
}
return false;
}

} // namespace objectivec
} // namespace compiler
} // namespace protobuf
Expand Down
5 changes: 5 additions & 0 deletions src/google/protobuf/compiler/objectivec/helpers.h
Expand Up @@ -148,6 +148,11 @@ std::string GetOptionalDeprecatedAttribute(
}
}

// Helpers to identify the WellKnownType files/messages that get an Objective-C
// category within the runtime to add helpers.
bool HasWKTWithObjCCategory(const FileDescriptor* file);
bool IsWKTWithObjCCategory(const Descriptor* descriptor);

} // namespace objectivec
} // namespace compiler
} // namespace protobuf
Expand Down
12 changes: 12 additions & 0 deletions src/google/protobuf/compiler/objectivec/message.cc
Expand Up @@ -336,6 +336,17 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const {
}
field_generators_.get(field).GeneratePropertyDeclaration(printer);
}
}},
{"wkt_extra",
[&] {
if (!IsWKTWithObjCCategory(descriptor_)) {
return;
}
printer->Emit(R"objc(
// NOTE: There are some Objective-C specific methods/properties in
// GPBWellKnownTypes.h that will likey be useful.
)objc");
printer->Emit("\n");
}}},
R"objc(
#pragma mark - $classname$
Expand All @@ -347,6 +358,7 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const {
GPB_FINAL @interface $classname$ : GPBMessage
$message_properties$
$wkt_extra$
@end
)objc");
printer->Emit("\n");
Expand Down

0 comments on commit b146d14

Please sign in to comment.