1"""Internal rules for building upb.""" 2 3load(":upb_proto_library.bzl", "GeneratedSrcsInfo") 4 5def _librule(name): 6 return name + "_lib" 7 8runfiles_init = """\ 9# --- begin runfiles.bash initialization v2 --- 10# Copy-pasted from the Bazel Bash runfiles library v2. 11set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash 12source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ 13 source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ 14 source "$0.runfiles/$f" 2>/dev/null || \ 15 source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ 16 source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ 17 { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e 18# --- end runfiles.bash initialization v2 --- 19""" 20 21def _get_real_short_path(file): 22 # For some reason, files from other archives have short paths that look like: 23 # ../com_google_protobuf/google/protobuf/descriptor.proto 24 short_path = file.short_path 25 if short_path.startswith("../"): 26 second_slash = short_path.index("/", 3) 27 short_path = short_path[second_slash + 1:] 28 return short_path 29 30def _get_real_root(file): 31 real_short_path = _get_real_short_path(file) 32 return file.path[:-len(real_short_path) - 1] 33 34def _get_real_roots(files): 35 roots = {} 36 for file in files: 37 real_root = _get_real_root(file) 38 if real_root: 39 roots[real_root] = True 40 return roots.keys() 41 42def _remove_prefix(str, prefix): 43 if not str.startswith(prefix): 44 fail("%s doesn't start with %s" % (str, prefix)) 45 return str[len(prefix):] 46 47def _remove_suffix(str, suffix): 48 if not str.endswith(suffix): 49 fail("%s doesn't end with %s" % (str, suffix)) 50 return str[:-len(suffix)] 51 52def make_shell_script(name, contents, out): 53 contents = runfiles_init + contents # copybara:strip_for_google3 54 contents = contents.replace("$", "$$") 55 native.genrule( 56 name = "gen_" + name, 57 outs = [out], 58 cmd = "(cat <<'HEREDOC'\n%s\nHEREDOC\n) > $@" % contents, 59 ) 60 61def generated_file_staleness_test(name, outs, generated_pattern): 62 """Tests that checked-in file(s) match the contents of generated file(s). 63 64 The resulting test will verify that all output files exist and have the 65 correct contents. If the test fails, it can be invoked with --fix to 66 bring the checked-in files up to date. 67 68 Args: 69 name: Name of the rule. 70 outs: the checked-in files that are copied from generated files. 71 generated_pattern: the pattern for transforming each "out" file into a 72 generated file. For example, if generated_pattern="generated/%s" then 73 a file foo.txt will look for generated file generated/foo.txt. 74 """ 75 76 script_name = name + ".py" 77 script_src = "//:tools/staleness_test.py" 78 79 # Filter out non-existing rules so Blaze doesn't error out before we even 80 # run the test. 81 existing_outs = native.glob(include = outs) 82 83 # The file list contains a few extra bits of information at the end. 84 # These get unpacked by the Config class in staleness_test_lib.py. 85 file_list = outs + [generated_pattern, native.package_name() or ".", name] 86 87 native.genrule( 88 name = name + "_makescript", 89 outs = [script_name], 90 srcs = [script_src], 91 testonly = 1, 92 cmd = "cat $(location " + script_src + ") > $@; " + 93 "sed -i.bak -e 's|INSERT_FILE_LIST_HERE|" + "\\\n ".join(file_list) + "|' $@", 94 ) 95 96 native.py_test( 97 name = name, 98 srcs = [script_name], 99 data = existing_outs + [generated_pattern % file for file in outs], 100 deps = [ 101 "//:staleness_test_lib", 102 ], 103 ) 104 105# upb_amalgamation() rule, with file_list aspect. 106 107SrcList = provider( 108 fields = { 109 "srcs": "list of srcs", 110 }, 111) 112 113def _file_list_aspect_impl(target, ctx): 114 if GeneratedSrcsInfo in target: 115 srcs = target[GeneratedSrcsInfo] 116 return [SrcList(srcs = srcs.srcs + srcs.hdrs)] 117 118 srcs = [] 119 for src in ctx.rule.attr.srcs: 120 srcs += src.files.to_list() 121 for hdr in ctx.rule.attr.hdrs: 122 srcs += hdr.files.to_list() 123 for hdr in ctx.rule.attr.textual_hdrs: 124 srcs += hdr.files.to_list() 125 return [SrcList(srcs = srcs)] 126 127_file_list_aspect = aspect( 128 implementation = _file_list_aspect_impl, 129) 130 131def _upb_amalgamation(ctx): 132 inputs = [] 133 for lib in ctx.attr.libs: 134 inputs += lib[SrcList].srcs 135 srcs = [src for src in inputs if src.path.endswith("c")] 136 ctx.actions.run( 137 inputs = inputs, 138 outputs = ctx.outputs.outs, 139 arguments = [ctx.bin_dir.path + "/", ctx.attr.prefix] + [f.path for f in srcs] + ["-I" + root for root in _get_real_roots(inputs)], 140 progress_message = "Making amalgamation", 141 executable = ctx.executable.amalgamator, 142 ) 143 return [] 144 145upb_amalgamation = rule( 146 attrs = { 147 "amalgamator": attr.label( 148 executable = True, 149 cfg = "host", 150 ), 151 "prefix": attr.string( 152 default = "", 153 ), 154 "libs": attr.label_list(aspects = [_file_list_aspect]), 155 "outs": attr.output_list(), 156 }, 157 implementation = _upb_amalgamation, 158) 159 160def licenses(*args): 161 # No-op (for Google-internal usage). 162 pass 163