1"""Internal rules for building upb.""" 2 3load(":upb_proto_library.bzl", "GeneratedSrcsInfo") 4 5def _librule(name): 6 return name + "_lib" 7 8def _get_real_short_path(file): 9 # For some reason, files from other archives have short paths that look like: 10 # ../com_google_protobuf/google/protobuf/descriptor.proto 11 short_path = file.short_path 12 if short_path.startswith("../"): 13 second_slash = short_path.index("/", 3) 14 short_path = short_path[second_slash + 1:] 15 return short_path 16 17def _get_real_root(file): 18 real_short_path = _get_real_short_path(file) 19 return file.path[:-len(real_short_path) - 1] 20 21def _get_real_roots(files): 22 roots = {} 23 for file in files: 24 real_root = _get_real_root(file) 25 if real_root: 26 roots[real_root] = True 27 return roots.keys() 28 29def lua_cclibrary(name, srcs, hdrs = [], deps = [], luadeps = []): 30 lib_rule = name + "_lib" 31 so_rule = "lib" + name + ".so" 32 so_file = _remove_prefix(name, "lua/") + ".so" 33 34 native.cc_library( 35 name = _librule(name), 36 hdrs = hdrs, 37 srcs = srcs, 38 deps = deps + [_librule(dep) for dep in luadeps] + ["@lua//:liblua_headers"], 39 ) 40 41 native.cc_binary( 42 name = so_rule, 43 linkshared = True, 44 deps = [_librule(name)], 45 linkopts = select({ 46 ":darwin": [ 47 "-undefined dynamic_lookup", 48 ], 49 "//conditions:default": [], 50 }), 51 ) 52 53 native.genrule( 54 name = name + "_copy", 55 srcs = [":" + so_rule], 56 outs = [so_file], 57 cmd = "cp $< $@", 58 ) 59 60 native.filegroup( 61 name = name, 62 data = [so_file], 63 ) 64 65def _remove_prefix(str, prefix): 66 if not str.startswith(prefix): 67 fail("%s doesn't start with %s" % (str, prefix)) 68 return str[len(prefix):] 69 70def _remove_suffix(str, suffix): 71 if not str.endswith(suffix): 72 fail("%s doesn't end with %s" % (str, suffix)) 73 return str[:-len(suffix)] 74 75def lua_library(name, srcs, strip_prefix, luadeps = []): 76 outs = [_remove_prefix(src, strip_prefix + "/") for src in srcs] 77 native.genrule( 78 name = name + "_copy", 79 srcs = srcs, 80 outs = outs, 81 cmd = "cp $(SRCS) $(@D)", 82 ) 83 84 native.filegroup( 85 name = name, 86 data = outs + luadeps, 87 ) 88 89def make_shell_script(name, contents, out): 90 contents = contents.replace("$", "$$") 91 native.genrule( 92 name = "gen_" + name, 93 outs = [out], 94 cmd = "(cat <<'HEREDOC'\n%s\nHEREDOC\n) > $@" % contents, 95 ) 96 97def _lua_binary_or_test(name, luamain, luadeps, rule): 98 script = name + ".sh" 99 100 make_shell_script( 101 name = "gen_" + name, 102 out = script, 103 contents = """ 104BASE=$(dirname $(rlocation upb/upb_c.so)) 105export LUA_CPATH="$BASE/?.so" 106export LUA_PATH="$BASE/?.lua" 107$(rlocation lua/lua) $(rlocation upb/tools/upbc.lua) "$@" 108""", 109 ) 110 111 rule( 112 name = name, 113 srcs = [script], 114 data = ["@lua//:lua", luamain] + luadeps, 115 ) 116 117def lua_binary(name, luamain, luadeps = []): 118 _lua_binary_or_test(name, luamain, luadeps, native.sh_binary) 119 120def lua_test(name, luamain, luadeps = []): 121 _lua_binary_or_test(name, luamain, luadeps, native.sh_test) 122 123def generated_file_staleness_test(name, outs, generated_pattern): 124 """Tests that checked-in file(s) match the contents of generated file(s). 125 126 The resulting test will verify that all output files exist and have the 127 correct contents. If the test fails, it can be invoked with --fix to 128 bring the checked-in files up to date. 129 130 Args: 131 name: Name of the rule. 132 outs: the checked-in files that are copied from generated files. 133 generated_pattern: the pattern for transforming each "out" file into a 134 generated file. For example, if generated_pattern="generated/%s" then 135 a file foo.txt will look for generated file generated/foo.txt. 136 """ 137 138 script_name = name + ".py" 139 script_src = "//:tools/staleness_test.py" 140 141 # Filter out non-existing rules so Blaze doesn't error out before we even 142 # run the test. 143 existing_outs = native.glob(include = outs) 144 145 # The file list contains a few extra bits of information at the end. 146 # These get unpacked by the Config class in staleness_test_lib.py. 147 file_list = outs + [generated_pattern, native.package_name() or ".", name] 148 149 native.genrule( 150 name = name + "_makescript", 151 outs = [script_name], 152 srcs = [script_src], 153 testonly = 1, 154 cmd = "cat $(location " + script_src + ") > $@; " + 155 "sed -i.bak -e 's|INSERT_FILE_LIST_HERE|" + "\\\n ".join(file_list) + "|' $@", 156 ) 157 158 native.py_test( 159 name = name, 160 srcs = [script_name], 161 data = existing_outs + [generated_pattern % file for file in outs], 162 deps = [ 163 "//:staleness_test_lib", 164 ], 165 ) 166 167# upb_amalgamation() rule, with file_list aspect. 168 169SrcList = provider( 170 fields = { 171 "srcs": "list of srcs", 172 }, 173) 174 175def _file_list_aspect_impl(target, ctx): 176 if GeneratedSrcsInfo in target: 177 srcs = target[GeneratedSrcsInfo] 178 return [SrcList(srcs = srcs.srcs + srcs.hdrs)] 179 180 srcs = [] 181 for src in ctx.rule.attr.srcs: 182 srcs += src.files.to_list() 183 for hdr in ctx.rule.attr.hdrs: 184 srcs += hdr.files.to_list() 185 for hdr in ctx.rule.attr.textual_hdrs: 186 srcs += hdr.files.to_list() 187 return [SrcList(srcs = srcs)] 188 189_file_list_aspect = aspect( 190 implementation = _file_list_aspect_impl, 191) 192 193def _upb_amalgamation(ctx): 194 inputs = [] 195 for lib in ctx.attr.libs: 196 inputs += lib[SrcList].srcs 197 srcs = [src for src in inputs if src.path.endswith("c")] 198 ctx.actions.run( 199 inputs = inputs, 200 outputs = ctx.outputs.outs, 201 arguments = [ctx.bin_dir.path + "/"] + [f.path for f in srcs] + ["-I" + root for root in _get_real_roots(inputs)], 202 progress_message = "Making amalgamation", 203 executable = ctx.executable.amalgamator, 204 ) 205 return [] 206 207upb_amalgamation = rule( 208 attrs = { 209 "amalgamator": attr.label( 210 executable = True, 211 cfg = "host", 212 ), 213 "libs": attr.label_list(aspects = [_file_list_aspect]), 214 "outs": attr.output_list(), 215 }, 216 implementation = _upb_amalgamation, 217) 218 219def licenses(*args): 220 # No-op (for Google-internal usage). 221 pass 222