1"""Internal rules for building upb."""
2
3load(":upb_proto_library.bzl", "GeneratedSrcsInfo")
4
5UPB_DEFAULT_CPPOPTS = select({
6    "//:windows": [],
7    "//conditions:default": [
8        # copybara:strip_for_google3_begin
9        "-Wextra",
10        # "-Wshorten-64-to-32",  # not in GCC (and my Kokoro images doesn't have Clang)
11        "-Werror",
12        "-Wno-long-long",
13        # copybara:strip_end
14    ],
15})
16
17UPB_DEFAULT_COPTS = select({
18    "//:windows": [],
19    "//:fasttable_enabled_setting": ["-std=gnu99", "-DUPB_ENABLE_FASTTABLE"],
20    "//conditions:default": [
21        # copybara:strip_for_google3_begin
22        "-std=c99",
23        "-pedantic",
24        "-Werror=pedantic",
25        "-Wall",
26        "-Wstrict-prototypes",
27        # GCC (at least) emits spurious warnings for this that cannot be fixed
28        # without introducing redundant initialization (with runtime cost):
29        #   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
30        #"-Wno-maybe-uninitialized",
31        # copybara:strip_end
32    ],
33})
34
35def _librule(name):
36    return name + "_lib"
37
38runfiles_init = """\
39# --- begin runfiles.bash initialization v2 ---
40# Copy-pasted from the Bazel Bash runfiles library v2.
41set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
42source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
43  source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
44  source "$0.runfiles/$f" 2>/dev/null || \
45  source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
46  source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
47  { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
48# --- end runfiles.bash initialization v2 ---
49"""
50
51def _get_real_short_path(file):
52    # For some reason, files from other archives have short paths that look like:
53    #   ../com_google_protobuf/google/protobuf/descriptor.proto
54    short_path = file.short_path
55    if short_path.startswith("../"):
56        second_slash = short_path.index("/", 3)
57        short_path = short_path[second_slash + 1:]
58    return short_path
59
60def _get_real_root(file):
61    real_short_path = _get_real_short_path(file)
62    return file.path[:-len(real_short_path) - 1]
63
64def _get_real_roots(files):
65    roots = {}
66    for file in files:
67        real_root = _get_real_root(file)
68        if real_root:
69            roots[real_root] = True
70    return roots.keys()
71
72def _remove_prefix(str, prefix):
73    if not str.startswith(prefix):
74        fail("%s doesn't start with %s" % (str, prefix))
75    return str[len(prefix):]
76
77def _remove_suffix(str, suffix):
78    if not str.endswith(suffix):
79        fail("%s doesn't end with %s" % (str, suffix))
80    return str[:-len(suffix)]
81
82def make_shell_script(name, contents, out):
83    contents = runfiles_init + contents  # copybara:strip_for_google3
84    contents = contents.replace("$", "$$")
85    native.genrule(
86        name = "gen_" + name,
87        outs = [out],
88        cmd = "(cat <<'HEREDOC'\n%s\nHEREDOC\n) > $@" % contents,
89    )
90
91# upb_amalgamation() rule, with file_list aspect.
92
93SrcList = provider(
94    fields = {
95        "srcs": "list of srcs",
96    },
97)
98
99def _file_list_aspect_impl(target, ctx):
100    if GeneratedSrcsInfo in target:
101        srcs = target[GeneratedSrcsInfo]
102        return [SrcList(srcs = srcs.srcs + srcs.hdrs)]
103
104    srcs = []
105    for src in ctx.rule.attr.srcs:
106        srcs += src.files.to_list()
107    for hdr in ctx.rule.attr.hdrs:
108        srcs += hdr.files.to_list()
109    for hdr in ctx.rule.attr.textual_hdrs:
110        srcs += hdr.files.to_list()
111    return [SrcList(srcs = srcs)]
112
113_file_list_aspect = aspect(
114    implementation = _file_list_aspect_impl,
115)
116
117def _upb_amalgamation(ctx):
118    inputs = []
119    for lib in ctx.attr.libs:
120        inputs += lib[SrcList].srcs
121    srcs = [src for src in inputs if src.path.endswith("c")]
122    ctx.actions.run(
123        inputs = inputs,
124        outputs = ctx.outputs.outs,
125        arguments = [ctx.bin_dir.path + "/", ctx.attr.prefix] + [f.path for f in srcs] + ["-I" + root for root in _get_real_roots(inputs)],
126        progress_message = "Making amalgamation",
127        executable = ctx.executable.amalgamator,
128    )
129    return []
130
131upb_amalgamation = rule(
132    attrs = {
133        "amalgamator": attr.label(
134            executable = True,
135            cfg = "host",
136        ),
137        "prefix": attr.string(
138            default = "",
139        ),
140        "libs": attr.label_list(aspects = [_file_list_aspect]),
141        "outs": attr.output_list(),
142    },
143    implementation = _upb_amalgamation,
144)
145