diff --git a/objectivec/BUILD.bazel b/objectivec/BUILD.bazel index 3a63685b2f..fae65c298f 100644 --- a/objectivec/BUILD.bazel +++ b/objectivec/BUILD.bazel @@ -1,6 +1,60 @@ load("@rules_cc//cc:defs.bzl", "objc_library") load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix") +load("@upb//cmake:build_defs.bzl", "staleness_test") load("//conformance:defs.bzl", "conformance_test") +load(":defs.bzl", "objc_proto_camel_case_name") + +# The WKTs have to be checked in to support the CocoaPods and Xcode builds. This +# generule and test ensure the source are current. +# +# TODO: Improve the bazel build so it uses these generated headers so it is +# always current, and only the builds that can't easily build protoc and +# generate the files rely on the checked in ones. + +_WELL_KNOWN_TYPES = [ + "any", + "api", + "duration", + "empty", + "field_mask", + "source_context", + "struct", + "timestamp", + "type", + "wrappers", +] + +_OBJC_WKT_NAMES = [objc_proto_camel_case_name(x) for x in _WELL_KNOWN_TYPES] + +_OBJC_EXTS = [ + ".pbobjc.h", + ".pbobjc.m", +] + +genrule( + name = "gen_wkt_sources", + srcs = ["//src/google/protobuf:well_known_type_protos"], + outs = ["wkt/GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS], + cmd = " && ".join([ + "$(execpath //:protoc) --objc_out=$(RULEDIR)/wkt --proto_path=src $(SRCS)", + ] + [ + "mv $(RULEDIR)/wkt/google/protobuf/" + wkt + ext + " $(RULEDIR)/wkt/GPB" + wkt + ext + for wkt in _OBJC_WKT_NAMES + for ext in _OBJC_EXTS + ]), + exec_tools = ["//:protoc"], +) + +staleness_test( + name = "well_known_types_staleness_test", + outs = ["GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS], + generated_pattern = "wkt/%s", + tags = ["manual"], +) + +################################################################################ +# Objective-C Runtime Library +################################################################################ objc_library( name = "objectivec", diff --git a/objectivec/defs.bzl b/objectivec/defs.bzl new file mode 100644 index 0000000000..5535868bd7 --- /dev/null +++ b/objectivec/defs.bzl @@ -0,0 +1,68 @@ +"""Starlark helpers for Objective-C protos.""" + +# State constants for objc_proto_camel_case_name. +_last_was_other = 0 +_last_was_lowercase = 1 +_last_was_uppercase = 2 +_last_was_number = 3 + +def objc_proto_camel_case_name(name): + """A Starlark version of the ObjC generator's CamelCase name transform. + + This needs to track + src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase() + + NOTE: This code is written to model the C++ in protoc's ObjC generator so it + is easier to confirm that the algorithms between the implementations match. + The customizations for starlark performance are: + - The cascade within the loop is reordered and special cases "_" to + optimize for google3 inputs. + - The "last was" state is handled via integers instead of three booleans. + + The `first_capitalized` argument in the C++ code is left off this code and + it acts as if the value were `True`. + + Args: + name: The proto file name to convert to camel case. The extension should + already be removed. + + Returns: + The converted proto name to camel case. + """ + segments = [] + current = "" + last_was = _last_was_other + for c in name.elems(): + if c.islower(): + # lowercase letter can follow a lowercase or uppercase letter. + if last_was != _last_was_lowercase and last_was != _last_was_uppercase: + segments.append(current) + current = c.upper() + else: + current += c + last_was = _last_was_lowercase + elif c == "_": # more common than rest, special case it. + last_was = _last_was_other + elif c.isdigit(): + if last_was != _last_was_number: + segments.append(current) + current = "" + current += c + last_was = _last_was_number + elif c.isupper(): + if last_was != _last_was_uppercase: + segments.append(current) + current = c + else: + current += c.lower() + last_was = _last_was_uppercase + else: + last_was = _last_was_other + segments.append(current) + result = "" + for x in segments: + if x in ("Url", "Http", "Https"): + result += x.upper() + else: + result += x + return result diff --git a/regenerate_stale_files.sh b/regenerate_stale_files.sh index 1c38104135..58c640b38b 100755 --- a/regenerate_stale_files.sh +++ b/regenerate_stale_files.sh @@ -15,6 +15,7 @@ readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS}" # Run and fix all staleness tests. ${BazelBin} test src:cmake_lists_staleness_test "$@" || ./bazel-bin/src/cmake_lists_staleness_test --fix ${BazelBin} test src/google/protobuf:well_known_types_staleness_test "$@" || ./bazel-bin/src/google/protobuf/well_known_types_staleness_test --fix +${BazelBin} test objectivec:well_known_types_staleness_test "$@" || ./bazel-bin/objectivec/well_known_types_staleness_test --fix # Generate C# code. # This doesn't currently have Bazel staleness tests, but there's an existing