dep-protobuf/bazel/private/oss/proto_bazel_features.bzl
Joshua Haberman f1c23cb216 Prepare Protobuf for a future version of Bazel which will lack the proto fragment
The ultimate effect of this change will be that both the native flags and Starlark flags will continue to work with future versions of Bazel that lack the proto fragment, until such time as we deprecate or remove the flags in a Protobuf release.  This decouples Bazel releases from Protobuf behavior changes.

1. Builds on the Bazel 8-compatible abstraction layer we submitted in cl/955468205 by setting `HAS_NATIVE_PROTO_FLAGS` properly in Bazel.  We do this by adding a `rules.has_proto_fragment` setting to the `proto_bazel_features.bzl` mechanism: we know that the fragment no longer needs to be read in Bazel 9+, because we can use `flag_alias()` instead.
2. Adds `flag_alias()` declarations in MODULE.bazel for all compat layer flags.  This will work in Bazel 9, but is ignored in Bazel 8.

This leads to a slight inconsistency.  Consider the following set of flags set by a user:

```
--@protobuf//bazel/flags:protocopt=foo --protocopt=bar
```

In Bazel 9+, where the flag alias is respected, the final value of the flag will be `bar`.  In Bazel 8, where we emulate `flag_alias()` by reconciling the two different values at analysis time, we always prefer the Starlark version (and cannot tell the relative order), so the final value of the flag will be `foo`.

To avoid this, prefer setting the Starlark version of the flag whenever possible.

PiperOrigin-RevId: 970834999
2026-08-25 15:30:42 -07:00

70 lines
2.9 KiB
Python

# Protocol Buffers - Google's data interchange format
# Copyright 2024 Google Inc. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
#
"""Vendored version of bazel_features for protobuf, to keep a one-step setup"""
_PROTO_BAZEL_FEATURES = """bazel_features = struct(
cc = struct(
protobuf_on_allowlist = {protobuf_on_allowlist},
),
proto = struct(
starlark_proto_info = {starlark_proto_info},
),
rules = struct(
analysis_tests_can_transition_on_experimental_incompatible_flags = {analysis_tests_can_transition_on_experimental_incompatible_flags},
has_proto_fragment = {has_proto_fragment},
),
globals = struct(
PackageSpecificationInfo = {PackageSpecificationInfo},
ProtoInfo = getattr(getattr(native, 'legacy_globals', None), 'ProtoInfo', {ProtoInfo}),
cc_proto_aspect = getattr(getattr(native, 'legacy_globals', None), 'cc_proto_aspect', {cc_proto_aspect}),
),
)
"""
def _proto_bazel_features_impl(rctx):
# An empty string is treated as a "dev version", which is greater than anything.
bazel_version = native.bazel_version or "999999.999999.999999"
version_parts = bazel_version.split("-")[0].split(".")
if len(version_parts) != 3:
fail("invalid Bazel version '{}': got {} dot-separated segments, want 3".format(bazel_version, len(version_parts)))
major_version_int = int(version_parts[0])
minor_version_int = int(version_parts[1])
starlark_proto_info = major_version_int >= 7
PackageSpecificationInfo = major_version_int > 6 or (major_version_int == 6 and minor_version_int >= 4)
protobuf_on_allowlist = major_version_int > 7
ProtoInfo = "ProtoInfo" if major_version_int < 8 else "None"
cc_proto_aspect = "cc_proto_aspect" if major_version_int < 8 else "None"
has_proto_fragment = major_version_int < 9
rctx.file("BUILD.bazel", """
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
bzl_library(
name = "features",
srcs = ["features.bzl"],
visibility = ["//visibility:public"],
)
exports_files(["features.bzl"])
""")
rctx.file("features.bzl", _PROTO_BAZEL_FEATURES.format(
starlark_proto_info = repr(starlark_proto_info),
PackageSpecificationInfo = "PackageSpecificationInfo" if PackageSpecificationInfo else "None",
protobuf_on_allowlist = repr(protobuf_on_allowlist),
ProtoInfo = ProtoInfo,
cc_proto_aspect = cc_proto_aspect,
analysis_tests_can_transition_on_experimental_incompatible_flags =
"True" if major_version_int > 8 or (major_version_int == 8 and minor_version_int >= 2) else "False",
has_proto_fragment = repr(has_proto_fragment),
))
proto_bazel_features = repository_rule(
implementation = _proto_bazel_features_impl,
# Force reruns on server restarts to keep native.bazel_version up-to-date.
local = True,
)