|  | """Macros that implement bootstrapping for the upb code generator.""" | 
|  |  | 
|  | load("@rules_cc//cc:cc_binary.bzl", "cc_binary") | 
|  | load("@rules_cc//cc:cc_library.bzl", "cc_library") | 
|  | load( | 
|  | "//bazel:upb_minitable_proto_library.bzl", | 
|  | "upb_minitable_proto_library", | 
|  | ) | 
|  | load( | 
|  | "//bazel:upb_proto_library.bzl", | 
|  | "upb_proto_library", | 
|  | ) | 
|  | load( | 
|  | "//upb/cmake:build_defs.bzl", | 
|  | "staleness_test", | 
|  | ) | 
|  |  | 
|  | _stages = ["_stage0", "_stage1", ""] | 
|  | _protoc = "//src/google/protobuf/compiler/release:protoc_minimal" | 
|  |  | 
|  | _extra_proto_path = "-I$$(dirname $(location //:descriptor_proto_srcs))/../.. " | 
|  |  | 
|  | # This visibility is used automatically for anything used by the bootstrapping process. | 
|  | _bootstrap_visibility = [ | 
|  | # TODO: b/396430482 - Remove protoc from bootstrap visibility. | 
|  | "//src/google/protobuf/compiler:__pkg__", | 
|  | "//src/google/protobuf/compiler/rust:__pkg__", | 
|  | "//third_party/upb/github:__pkg__", | 
|  | "//upb_generator:__subpackages__", | 
|  | "//upb/reflection:__pkg__", | 
|  | "//upb:__pkg__",  # For the amalgamations. | 
|  | "//python/dist:__pkg__",  # For the Python source package. | 
|  | "//:__pkg__",  # For protoc | 
|  | ] | 
|  |  | 
|  | def _stage_visibility(stage, visibility): | 
|  | return visibility if stage == "" else _bootstrap_visibility | 
|  |  | 
|  | def _upbc(generator, stage): | 
|  | if generator == "upb": | 
|  | return "//upb_generator/c:protoc-gen-upb" + _stages[stage] | 
|  | else: | 
|  | return "//upb_generator/minitable:protoc-gen-upb_minitable" + _stages[stage] | 
|  |  | 
|  | def bootstrap_cc_library(name, visibility = [], deps = [], bootstrap_deps = [], **kwargs): | 
|  | """A version of cc_library() that is augmented to allow for bootstrapping the compiler. | 
|  |  | 
|  | In addition to the normal cc_library() target, this rule will also generate _stage0 and _stage1 | 
|  | targets that are used internally for bootstrapping, and will automatically have bootstrap | 
|  | visibility. However the final target will use the normal visibility, and will behave like a | 
|  | normal cc_library() target. | 
|  |  | 
|  | Args: | 
|  | name: Name of this rule.  This name will resolve to a upb_proto_library(). | 
|  | deps: Normal cc_library() deps. | 
|  | bootstrap_deps: Special bootstrap_upb_proto_library() or bootstrap_cc_library() deps. | 
|  | visibility: Visibility of the final target. | 
|  | **kwargs: Other arguments that will be passed through to cc_library(). | 
|  | upb_proto_library(). | 
|  | """ | 
|  | for stage in _stages: | 
|  | cc_library( | 
|  | name = name + stage, | 
|  | deps = deps + [dep + stage for dep in bootstrap_deps], | 
|  | visibility = _stage_visibility(stage, visibility), | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | def bootstrap_cc_binary(name, visibility = [], deps = [], bootstrap_deps = [], **kwargs): | 
|  | """A version of cc_binary() that is augmented to allow for bootstrapping the compiler. | 
|  |  | 
|  | In addition to the normal cc_binary() target, this rule will also generate _stage0 and _stage1 | 
|  | targets that are used internally for bootstrapping, and will automatically have bootstrap | 
|  | visibility. However the final target will use the normal visibility, and will behave like a | 
|  | normal cc_binary() target. | 
|  |  | 
|  | Args: | 
|  | name: Name of this rule.  This name will resolve to a upb_proto_library(). | 
|  | deps: Normal cc_library() deps. | 
|  | bootstrap_deps: Special bootstrap_upb_proto_library() or bootstrap_cc_library() deps. | 
|  | visibility: Visibility of the final target. | 
|  | **kwargs: Other arguments that will be passed through to cc_binary(). | 
|  | upb_proto_library(). | 
|  | """ | 
|  | for stage in _stages: | 
|  | cc_binary( | 
|  | name = name + stage, | 
|  | malloc = "@bazel_tools//tools/cpp:malloc", | 
|  | deps = deps + [dep + stage for dep in bootstrap_deps], | 
|  | visibility = _stage_visibility(stage, visibility), | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | def _generated_file(proto, stage, generator, suffix): | 
|  | stripped = proto[:-len(".proto")] | 
|  | return "{}/{}.{}.{}".format(stage, stripped, generator, suffix) | 
|  |  | 
|  | def _generated_files(protos, stage, generator, suffix): | 
|  | return [_generated_file(proto, stage, generator, suffix) for proto in protos] | 
|  |  | 
|  | def _generated_hdrs_and_srcs(protos, stage, generator): | 
|  | ret = _generated_files(protos, stage, generator, "h") | 
|  | if generator != "upb" or stage == "stage0": | 
|  | ret += _generated_files(protos, stage, generator, "c") | 
|  | return ret | 
|  |  | 
|  | def _stage0_proto_staleness_test(name, src_files, src_rules, strip_prefix): | 
|  | native.genrule( | 
|  | name = name + "_generate_bootstrap", | 
|  | srcs = src_rules, | 
|  | outs = ["bootstrap_generated_sources/" + f.replace("third_party", "3rd_party") for f in _generated_hdrs_and_srcs(src_files, "stage0", "upb")], | 
|  | tools = [_protoc, _upbc("upb", 0)], | 
|  | cmd = | 
|  | "$(location " + _protoc + ") " + | 
|  | "-I. -I$(GENDIR)/" + strip_prefix + " " + _extra_proto_path + | 
|  | "--plugin=protoc-gen-upb=$(location " + _upbc("upb", 0) + ") " + | 
|  | "--upb_out=bootstrap_stage=0:$(@D)/bootstrap_generated_sources/stage0 " + | 
|  | " ".join(src_files) + | 
|  | "; rm -rf $(@D)/bootstrap_generated_sources/stage0/3rd_party" + | 
|  | "; if [ -e $(@D)/bootstrap_generated_sources/stage0/third_party ]; then mv $(@D)/bootstrap_generated_sources/stage0/third_party $(@D)/bootstrap_generated_sources/stage0/3rd_party; fi", | 
|  | ) | 
|  |  | 
|  | staleness_test( | 
|  | name = name + "_stage0_staleness_test", | 
|  | outs = [f.replace("third_party", "3rd_party") for f in _generated_hdrs_and_srcs(src_files, "stage0", "upb")], | 
|  | generated_pattern = "bootstrap_generated_sources/%s", | 
|  | target_files = native.glob(["stage0/**"]), | 
|  | # To avoid skew problems for descriptor.proto/plugin.proto between | 
|  | # GitHub repos.  It's not critical that the checked-in protos are up to | 
|  | # date for every change, they just needs to be complete enough to have | 
|  | # everything needed by the code generator itself. | 
|  | tags = ["manual"], | 
|  | ) | 
|  |  | 
|  | def _generate_stage1_proto(name, src_files, src_rules, generator, kwargs): | 
|  | native.genrule( | 
|  | name = "gen_{}_{}_stage1".format(name, generator), | 
|  | srcs = src_rules, | 
|  | outs = _generated_hdrs_and_srcs(src_files, "stage1", generator), | 
|  | cmd = "$(location " + _protoc + ") " + | 
|  | "--plugin=protoc-gen-" + generator + | 
|  | "=$(location " + _upbc(generator, 0) + ") " + _extra_proto_path + | 
|  | "--" + generator + "_out=bootstrap_stage=1:$(RULEDIR)/stage1 " + | 
|  | " ".join(src_files), | 
|  | visibility = _bootstrap_visibility, | 
|  | tools = [ | 
|  | _protoc, | 
|  | _upbc(generator, 0), | 
|  | ], | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | def _cmake_staleness_test(name, src_files, proto_lib_deps, **kwargs): | 
|  | upb_minitable_proto_library( | 
|  | name = name + "_minitable", | 
|  | deps = proto_lib_deps, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | # Copy the final gencode for staleness comparison | 
|  | files = _generated_hdrs_and_srcs(src_files, "cmake", "upb") + \ | 
|  | _generated_hdrs_and_srcs(src_files, "cmake", "upb_minitable") | 
|  | genrule = 0 | 
|  | for src in files: | 
|  | genrule += 1 | 
|  | native.genrule( | 
|  | name = name + "_copy_gencode_%d" % genrule, | 
|  | outs = ["generated_sources/" + src], | 
|  | srcs = [name + "_upb_proto", name + "_minitable"], | 
|  | cmd = """ | 
|  | mkdir -p $(@D) | 
|  | for src in $(SRCS); do | 
|  | if [[ $$src == *%s ]]; then | 
|  | cp -f $$src $(@D) || echo 'copy failed!' | 
|  | fi | 
|  | done | 
|  | """ % src[src.rfind("/"):], | 
|  | ) | 
|  |  | 
|  | # Keep bazel gencode in sync with our checked-in sources needed for cmake builds. | 
|  | staleness_test( | 
|  | name = name + "_staleness_test", | 
|  | outs = files, | 
|  | generated_pattern = "generated_sources/%s", | 
|  | tags = ["manual"], | 
|  | ) | 
|  |  | 
|  | def bootstrap_upb_proto_library( | 
|  | name, | 
|  | bootstrap_hdr, | 
|  | src_files, | 
|  | src_rules, | 
|  | proto_lib_deps, | 
|  | deps = [], | 
|  | strip_prefix = "", | 
|  | **kwargs): | 
|  | """A version of upb_proto_library() that is augmented to allow for bootstrapping the compiler. | 
|  |  | 
|  | Note that this rule is only intended to be used by bootstrap_cc_library() targets. End users | 
|  | should use the normal upb_proto_library() targets. As a result, we don't have a visibility | 
|  | parameter: all targets will automatically have bootstrap visibility. | 
|  |  | 
|  | Args: | 
|  | name: Name of this rule.  This name will resolve to a upb_proto_library(). | 
|  | bootstrap_hdr: The forwarding header that exposes the generated code, taking into account | 
|  | the current stage. | 
|  | src_files: Filenames of .proto files that should be built by this rule. | 
|  | src_rules: Target names of the Blaze/Bazel rules that will provide these filenames. | 
|  | proto_lib_deps: proto_library() rules that we will use to build the protos when we are | 
|  | not bootstrapping. | 
|  | deps: other bootstrap_upb_proto_library() rules that this one depends on. | 
|  | strip_prefix: Prefix that should be stripped from file names. | 
|  | **kwargs: Other arguments that will be passed through to cc_library(), genrule(), and | 
|  | upb_proto_library(). | 
|  | """ | 
|  | _stage0_proto_staleness_test(name, src_files, src_rules, strip_prefix) | 
|  |  | 
|  | # stage0 uses checked-in protos, and has no MiniTable. | 
|  | cc_library( | 
|  | name = name + "_stage0", | 
|  | srcs = _generated_hdrs_and_srcs(src_files, "stage0", "upb"), | 
|  | hdrs = [bootstrap_hdr], | 
|  | visibility = _bootstrap_visibility, | 
|  | defines = ["UPB_BOOTSTRAP_STAGE=0"], | 
|  | deps = [ | 
|  | "//upb:generated_code_support", | 
|  | "//upb/mini_table", | 
|  | ] + [dep + "_stage0" for dep in deps], | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | # Generate stage1 protos (C API and MiniTables) using stage0 compiler. | 
|  | _generate_stage1_proto(name, src_files, src_rules, "upb", kwargs) | 
|  | _generate_stage1_proto(name, src_files, src_rules, "upb_minitable", kwargs) | 
|  | cc_library( | 
|  | name = name + "_minitable_stage1", | 
|  | srcs = _generated_files(src_files, "stage1", "upb_minitable", "c"), | 
|  | hdrs = _generated_files(src_files, "stage1", "upb_minitable", "h"), | 
|  | visibility = _bootstrap_visibility, | 
|  | defines = ["UPB_BOOTSTRAP_STAGE=1"], | 
|  | deps = [ | 
|  | "//upb:generated_code_support", | 
|  | ] + [dep + "_minitable_stage1" for dep in deps], | 
|  | **kwargs | 
|  | ) | 
|  | cc_library( | 
|  | name = name + "_stage1", | 
|  | srcs = _generated_files(src_files, "stage1", "upb", "h"), | 
|  | hdrs = [bootstrap_hdr], | 
|  | visibility = _bootstrap_visibility, | 
|  | defines = ["UPB_BOOTSTRAP_STAGE=1"], | 
|  | deps = [ | 
|  | "//upb:generated_code_support", | 
|  | ":" + name + "_minitable_stage1", | 
|  | ] + [dep + "_minitable_stage1" for dep in deps], | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | # The final protos are generated via normal upb_proto_library(). | 
|  | upb_proto_library( | 
|  | name = name + "_upb_proto", | 
|  | deps = proto_lib_deps, | 
|  | **kwargs | 
|  | ) | 
|  | cc_library( | 
|  | name = name, | 
|  | hdrs = [bootstrap_hdr], | 
|  | deps = [name + "_upb_proto"], | 
|  | visibility = _bootstrap_visibility, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | _cmake_staleness_test(name, src_files, proto_lib_deps, **kwargs) |