1"""Macros that implement bootstrapping for the upb code generator."""
2
3load(
4    "//bazel:upb_proto_library.bzl",
5    "upb_proto_library",
6)
7load(
8    "//cmake:build_defs.bzl",
9    "staleness_test",
10)
11
12_stages = ["_stage0", "_stage1", ""]
13_protoc = "@com_google_protobuf//:protoc"
14_upbc_base = "//upbc:protoc-gen-upb"
15
16# begin:google_only
17# _is_google3 = True
18# _extra_proto_path = ""
19# end:google_only
20
21# begin:github_only
22_is_google3 = False
23_extra_proto_path = "-Iexternal/com_google_protobuf/src "
24# end:github_only
25
26def _upbc(stage):
27    return _upbc_base + _stages[stage]
28
29def bootstrap_cc_library(name, visibility, deps, bootstrap_deps, **kwargs):
30    for stage in _stages:
31        stage_visibility = visibility if stage == "" else ["//upbc:__pkg__"]
32        native.cc_library(
33            name = name + stage,
34            deps = deps + [dep + stage for dep in bootstrap_deps],
35            visibility = stage_visibility,
36            **kwargs
37        )
38
39def bootstrap_cc_binary(name, deps, bootstrap_deps, **kwargs):
40    for stage in _stages:
41        native.cc_binary(
42            name = name + stage,
43            deps = deps + [dep + stage for dep in bootstrap_deps],
44            **kwargs
45        )
46
47def _generated_srcs_for_suffix(prefix, srcs, suffix):
48    return [prefix + "/" + src[:-len(".proto")] + suffix for src in srcs]
49
50def _generated_srcs(prefix, srcs):
51    return _generated_srcs_for_suffix(prefix, srcs, ".upb.h") + _generated_srcs_for_suffix(prefix, srcs, ".upb.c")
52
53def _stage0_proto_staleness_test(name, base_dir, src_files, src_rules, strip_prefix):
54    native.genrule(
55        name = name + "_generate_bootstrap",
56        srcs = src_rules,
57        outs = _generated_srcs("bootstrap_generated_sources/" + base_dir + "stage0", src_files),
58        tools = [_protoc, _upbc(0)],
59        cmd =
60            "$(location " + _protoc + ") " +
61            "-I$(GENDIR)/" + strip_prefix + " " + _extra_proto_path +
62            "--plugin=protoc-gen-upb=$(location " + _upbc(0) + ") " +
63            "--upb_out=bootstrap_upb:$(@D)/bootstrap_generated_sources/" + base_dir + "stage0 " +
64            " ".join(src_files),
65    )
66
67    staleness_test(
68        name = name + "_staleness_test",
69        outs = _generated_srcs(base_dir + "stage0", src_files),
70        generated_pattern = "bootstrap_generated_sources/%s",
71        target_files = native.glob([base_dir + "stage0/**"]),
72        # To avoid skew problems for descriptor.proto/pluging.proto between
73        # GitHub repos.  It's not critical that the checked-in protos are up to
74        # date for every change, they just needs to be complete enough to have
75        # everything needed by the code generator itself.
76        tags = ["manual"],
77    )
78
79def bootstrap_upb_proto_library(
80        name,
81        base_dir,
82        google3_src_files,
83        google3_src_rules,
84        oss_src_files,
85        oss_src_rules,
86        oss_strip_prefix,
87        proto_lib_deps,
88        visibility,
89        deps = [],
90        **kwargs):
91    """A version of upb_proto_library() that is augmented to allow for bootstrapping the compiler.
92
93    Args:
94        name: Name of this rule.  This name will resolve to a upb_proto_library().
95        base_dir: The directory that all generated files should be placed under.
96        google3_src_files: Google3 filenames of .proto files that should be built by this rule.
97          The names should be relative to the depot base.
98        google3_src_rules: Target names of the Blaze rules that will provide these filenames.
99        oss_src_files: OSS filenames of .proto files that should be built by this rule.
100        oss_src_rules: Target names of the Bazel rules that will provide these filenames.
101        oss_strip_prefix: Prefix that should be stripped from OSS file names.
102        proto_lib_deps: proto_library() rules that we will use to build the protos when we are
103          not bootstrapping.
104        visibility: Visibility list for the final upb_proto_library() rule.  Bootstrapping rules
105          will always be hidden, and will not honor the visibility parameter passed here.
106        deps: other bootstrap_upb_proto_library() rules that this one depends on.
107        **kwargs: Other arguments that will be passed through to cc_library(), genrule(), and
108          upb_proto_library().
109    """
110    _stage0_proto_staleness_test(name, base_dir, oss_src_files, oss_src_rules, oss_strip_prefix)
111
112    # stage0 uses checked-in protos.
113    native.cc_library(
114        name = name + "_stage0",
115        srcs = _generated_srcs_for_suffix(base_dir + "stage0", oss_src_files, ".upb.c"),
116        hdrs = _generated_srcs_for_suffix(base_dir + "stage0", oss_src_files, ".upb.h"),
117        includes = [base_dir + "stage0"],
118        visibility = ["//upbc:__pkg__"],
119        # This macro signals to the runtime that it must use OSS APIs for descriptor.proto/plugin.proto.
120        defines = ["UPB_BOOTSTRAP_STAGE0"],
121        deps = [
122            "//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
123            "//:mini_table",
124        ] + [dep + "_stage0" for dep in deps],
125        **kwargs
126    )
127
128    src_files = google3_src_files if _is_google3 else oss_src_files
129    src_rules = google3_src_rules if _is_google3 else oss_src_rules
130
131    # Generate stage1 protos using stage0 compiler.
132    native.genrule(
133        name = "gen_" + name + "_stage1",
134        srcs = src_rules,
135        outs = _generated_srcs(base_dir + "stage1", src_files),
136        cmd = "$(location " + _protoc + ") " +
137              "--plugin=protoc-gen-upb=$(location " + _upbc(0) + ") " + _extra_proto_path +
138              "--upb_out=$(@D)/" + base_dir + "stage1 " +
139              " ".join(src_files),
140        visibility = ["//upbc:__pkg__"],
141        tools = [
142            _protoc,
143            _upbc(0),
144        ],
145        **kwargs
146    )
147
148    native.cc_library(
149        name = name + "_stage1",
150        srcs = _generated_srcs_for_suffix(base_dir + "stage1", src_files, ".upb.c"),
151        hdrs = _generated_srcs_for_suffix(base_dir + "stage1", src_files, ".upb.h"),
152        includes = [base_dir + "stage1"],
153        visibility = ["//upbc:__pkg__"],
154        deps = [
155            "//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
156        ] + [dep + "_stage1" for dep in deps],
157        **kwargs
158    )
159
160    # The final protos are generated via normal upb_proto_library().
161    upb_proto_library(
162        name = name,
163        deps = proto_lib_deps,
164        visibility = visibility,
165        **kwargs
166    )
167