Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,13 @@ proto_lang_toolchain(
command_line = "--cpp_out=$(OUT)",
plugin = "//src/google/protobuf/compiler/cpp:protoc-gen-cpp",
plugin_format_flag = "--plugin=protoc-gen-cpp=%s",
protoc_minimal_do_not_use = "//src/google/protobuf/compiler:protoc_minimal",
protoc_minimal_do_not_use = select({
# Set minimal protoc if prefer_prebuilt_protoc.flag_set is true since a prebuilt for protoc_minimal is not available
# TODO: Add a flag to switch between minimal and full protoc with proto_lang_toolchain once we have a minimal protoc binary.
# Setting this attribute to None will make the toolchain to pick the full protoc binary.
"//bazel/toolchains:prefer_prebuilt_protoc.flag_set": None,
"//conditions:default": "//src/google/protobuf/compiler:protoc_minimal",
}),
runtime = "//src/google/protobuf",
visibility = ["//visibility:public"],
)
Expand Down
3 changes: 3 additions & 0 deletions bazel/tests/BUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
load("//bazel:proto_descriptor_set.bzl", "proto_descriptor_set")
load("//bazel:proto_library.bzl", "proto_library")
load(":bazel_proto_library_tests.bzl", "bazel_proto_library_test_suite")
load(":cc_toolchain_tests.bzl", "cc_toolchain_test_suite")
load(":java_proto_library_tests.bzl", "java_proto_library_test_suite")
load(":proto_common_check_collocated_tests.bzl", "proto_common_check_collocated_test_suite")
load(":proto_common_compile_tests.bzl", "proto_common_compile_test_suite")
Expand All @@ -19,6 +20,8 @@ proto_common_check_collocated_test_suite(name = "proto_common_check_collocated_t

bazel_proto_library_test_suite(name = "bazel_proto_library_test_suite")

cc_toolchain_test_suite(name = "cc_toolchain_test_suite")

java_proto_library_test_suite(name = "java_proto_library_test_suite")

proto_library(
Expand Down
79 changes: 79 additions & 0 deletions bazel/tests/cc_toolchain_tests.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2025 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
"""Tests for cc_toolchain prebuilt protoc configuration."""

load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
load("@rules_testing//lib:truth.bzl", "matching")
load("@rules_testing//lib:util.bzl", "util")
load("//bazel:proto_library.bzl", "proto_library")
load("//bazel/tests/testdata:compile_rule.bzl", "compile_rule")

_PREFER_PREBUILT_PROTOC = str(Label("//bazel/toolchains:prefer_prebuilt_protoc"))

def cc_toolchain_test_suite(name):
test_suite(
name = name,
tests = [
_test_cc_toolchain_uses_full_protoc_when_prefer_prebuilt_flag_set,
_test_cc_toolchain_uses_protoc_minimal_by_default,
],
)

def _test_cc_toolchain_uses_full_protoc_when_prefer_prebuilt_flag_set(name):
util.helper_target(
proto_library,
name = name + "_proto",
srcs = ["A.proto"],
)
util.helper_target(
compile_rule,
name = name + "_compile",
proto_dep = ":" + name + "_proto",
toolchain = "//:cc_toolchain",
)

analysis_test(
name = name,
target = name + "_compile",
impl = _test_cc_toolchain_uses_full_protoc_when_prefer_prebuilt_flag_set_impl,
config_settings = {_PREFER_PREBUILT_PROTOC: True},
)

def _test_cc_toolchain_uses_full_protoc_when_prefer_prebuilt_flag_set_impl(env, target):
# Find the compile action
action = env.expect.that_target(target).action_named("GenProto")
# When prefer_prebuilt_protoc is True, protoc_minimal_do_not_use is None,
# so the cc_toolchain should use the full protoc (not protoc_minimal).
# The protoc path should end with "/protoc" not contain "protoc_minimal"
action.argv().contains_predicate(matching.str_matches("*/protoc"))
action.argv().not_contains_predicate(matching.str_matches("*protoc_minimal*"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we actually do a positive check that this uses the prebuilt? Negative regex checks are kindof brittle (a typo trivially passes) and this might start failing if we switch to a prebuilt protoc_minimal


def _test_cc_toolchain_uses_protoc_minimal_by_default(name):
util.helper_target(
proto_library,
name = name + "_proto",
srcs = ["A.proto"],
)
util.helper_target(
compile_rule,
name = name + "_compile",
proto_dep = ":" + name + "_proto",
toolchain = "//:cc_toolchain",
)

analysis_test(
name = name,
target = name + "_compile",
impl = _test_cc_toolchain_uses_protoc_minimal_by_default_impl,
)

def _test_cc_toolchain_uses_protoc_minimal_by_default_impl(env, target):
# Find the compile action
action = env.expect.that_target(target).action_named("GenProto")
# By default (prefer_prebuilt_protoc is False), protoc_minimal_do_not_use is set,
# so the cc_toolchain should use protoc_minimal.
action.argv().contains_predicate(matching.str_matches("*protoc_minimal*"))
6 changes: 5 additions & 1 deletion bazel/toolchains/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ bool_flag(
config_setting(
name = "prefer_prebuilt_protoc.flag_set",
flag_values = {":prefer_prebuilt_protoc": "true"},
visibility = ["//bazel/private/toolchains/prebuilt:__pkg__"],
visibility = [
"//bazel/private/toolchains/prebuilt:__pkg__",
# Needed by cc_toolchain to switch between minimal and full protoc
"//:__pkg__",
],
)

# The public API users set to disable the validation action failing.
Expand Down
6 changes: 3 additions & 3 deletions examples/example_without_cc_toolchain/.bazelrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Simulate a non-functional CC toolchain
common --per_file_copt=external/.*protobuf.*@--THIS_CC_TOOLCHAIN_IS_BROKEN
common --host_per_file_copt=external/.*protobuf.*@--THIS_CC_TOOLCHAIN_IS_BROKEN
common --per_file_copt=external/.*protobuf.*/src/google/protobuf/compiler/main.cc@--THIS_CC_TOOLCHAIN_IS_BROKEN
common --host_per_file_copt=external/.*protobuf.*/src/google/protobuf/compiler/main.cc@--THIS_CC_TOOLCHAIN_IS_BROKEN
# But, users should be able to use pre-built protoc toolchains instead.
common --incompatible_enable_proto_toolchain_resolution
common --@com_google_protobuf//bazel/toolchains:prefer_prebuilt_protoc
common --@com_google_protobuf//bazel/toolchains:prefer_prebuilt_protoc
11 changes: 11 additions & 0 deletions examples/example_without_cc_toolchain/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")

proto_library(
name = "empty_proto",
srcs = ["empty.proto"],
)

cc_proto_library(
name = "cc_empty_proto",
deps = [":empty_proto"],
# We already have a anaylsis test that asserts that the cc_proto_library

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: analysis

# uses the correct prebuilt toolchain, this cc_proto_library will never
# compile since the prebuilt toolchain is always behind the HEAD therefore
# will end up in version skew compilation errors.
Comment thread
mkruskal-google marked this conversation as resolved.
tags = ["manual"],
Comment thread
mkruskal-google marked this conversation as resolved.
)
Loading