"""Wrappers for common build rules. These wrappers apply common BUILD configurations (e.g., proto_library automagically creating cc_ and go_ proto targets) and act as a single point of change for Google-internal and bazel-compatible rules. """ load("//tools/go_stateify:defs.bzl", "go_stateify") load("//tools/go_marshal:defs.bzl", "go_marshal", "marshal_deps", "marshal_test_deps") load("//tools/nogo:defs.bzl", "nogo_test") load("//tools/bazeldefs:defs.bzl", _arch_genrule = "arch_genrule", _build_test = "build_test", _bzl_library = "bzl_library", _coreutil = "coreutil", _default_installer = "default_installer", _default_net_util = "default_net_util", _more_shards = "more_shards", _most_shards = "most_shards", _proto_library = "proto_library", _select_arch = "select_arch", _select_system = "select_system", _short_path = "short_path", _version = "version") load("//tools/bazeldefs:cc.bzl", _cc_binary = "cc_binary", _cc_flags_supplier = "cc_flags_supplier", _cc_grpc_library = "cc_grpc_library", _cc_library = "cc_library", _cc_proto_library = "cc_proto_library", _cc_test = "cc_test", _cc_toolchain = "cc_toolchain", _gbenchmark = "gbenchmark", _grpcpp = "grpcpp", _gtest = "gtest", _vdso_linker_option = "vdso_linker_option") load("//tools/bazeldefs:go.bzl", _gazelle = "gazelle", _go_binary = "go_binary", _go_embed_data = "go_embed_data", _go_grpc_and_proto_libraries = "go_grpc_and_proto_libraries", _go_library = "go_library", _go_path = "go_path", _go_proto_library = "go_proto_library", _go_test = "go_test", _select_goarch = "select_goarch", _select_goos = "select_goos") load("//tools/bazeldefs:pkg.bzl", _pkg_deb = "pkg_deb", _pkg_tar = "pkg_tar") load("//tools/bazeldefs:platforms.bzl", _default_platform = "default_platform", _platforms = "platforms") load("//tools/bazeldefs:tags.bzl", "go_suffixes") # Core rules. arch_genrule = _arch_genrule build_test = _build_test bzl_library = _bzl_library default_installer = _default_installer default_net_util = _default_net_util select_arch = _select_arch select_system = _select_system short_path = _short_path coreutil = _coreutil more_shards = _more_shards most_shards = _most_shards version = _version # C++ rules. cc_binary = _cc_binary cc_flags_supplier = _cc_flags_supplier cc_grpc_library = _cc_grpc_library cc_library = _cc_library cc_test = _cc_test cc_toolchain = _cc_toolchain gbenchmark = _gbenchmark gtest = _gtest grpcpp = _grpcpp vdso_linker_option = _vdso_linker_option # Go rules. gazelle = _gazelle go_embed_data = _go_embed_data go_path = _go_path select_goos = _select_goos select_goarch = _select_goarch # Packaging rules. pkg_deb = _pkg_deb pkg_tar = _pkg_tar # Platform options. default_platform = _default_platform platforms = _platforms def go_binary(name, nogo = True, pure = False, static = False, x_defs = None, **kwargs): """Wraps the standard go_binary. Args: name: the rule name. nogo: enable nogo analysis. pure: build a pure Go (no CGo) binary. static: build a static binary. x_defs: additional linker definitions. **kwargs: standard go_binary arguments. """ _go_binary( name = name, pure = pure, static = static, x_defs = x_defs, **kwargs ) if nogo: # Note that the nogo rule applies only for go_library and go_test # targets, therefore we construct a library from the binary sources. # This is done because the binary may not be in a form that objdump # supports (i.e. a pure Go binary). _go_library( name = name + "_nogo_library", srcs = kwargs.get("srcs", []), deps = kwargs.get("deps", []), testonly = 1, ) nogo_test( name = name + "_nogo", config = "//:nogo_config", srcs = kwargs.get("srcs", []), deps = [":" + name + "_nogo_library"], tags = ["nogo"], ) def calculate_sets(srcs): """Calculates special Go sets for templates. Args: srcs: the full set of Go sources. Returns: A dictionary of the form: "": [src1.go, src2.go] "suffix": [src3suffix.go, src4suffix.go] Note that suffix will typically start with '_'. """ result = dict() for file in srcs: if not file.endswith(".go"): continue target = "" for suffix in go_suffixes: if file.endswith(suffix + ".go"): target = suffix if not target in result: result[target] = [file] else: result[target].append(file) return result def go_imports(name, src, out): """Simplify a single Go source file by eliminating unused imports.""" native.genrule( name = name, srcs = [src], outs = [out], tools = ["@org_golang_x_tools//cmd/goimports:goimports"], cmd = ("$(location @org_golang_x_tools//cmd/goimports:goimports) $(SRCS) > $@"), ) def go_library(name, srcs, deps = [], imports = [], stateify = True, marshal = False, marshal_debug = False, nogo = True, **kwargs): """Wraps the standard go_library and does stateification and marshalling. The recommended way is to use this rule with mostly identical configuration as the native go_library rule. These definitions provide additional flags (stateify, marshal) that can be used with the generators to automatically supplement the library code. load("//tools:defs.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], ) Args: name: the rule name. srcs: the library sources. deps: the library dependencies. imports: imports required for stateify. stateify: whether statify is enabled (default: true). marshal: whether marshal is enabled (default: false). marshal_debug: whether the gomarshal tools emits debugging output (default: false). nogo: enable nogo analysis. **kwargs: standard go_library arguments. """ all_srcs = srcs all_deps = deps dirname, _, _ = native.package_name().rpartition("/") full_pkg = dirname + "/" + name if stateify: # Only do stateification for non-state packages without manual autogen. # First, we need to segregate the input files via the special suffixes, # and calculate the final output set. state_sets = calculate_sets(srcs) for (suffix, src_subset) in state_sets.items(): go_stateify( name = name + suffix + "_state_autogen_with_imports", srcs = src_subset, imports = imports, package = full_pkg, out = name + suffix + "_state_autogen_with_imports.go", ) go_imports( name = name + suffix + "_state_autogen", src = name + suffix + "_state_autogen_with_imports.go", out = name + suffix + "_state_autogen.go", ) all_srcs = all_srcs + [ name + suffix + "_state_autogen.go" for suffix in state_sets.keys() ] if "//pkg/state" not in all_deps: all_deps = all_deps + ["//pkg/state"] if marshal: # See above. marshal_sets = calculate_sets(srcs) for (suffix, src_subset) in marshal_sets.items(): go_marshal( name = name + suffix + "_abi_autogen", srcs = src_subset, debug = select({ "//tools/go_marshal:marshal_config_verbose": True, "//conditions:default": marshal_debug, }), imports = imports, package = name, ) extra_deps = [ dep for dep in marshal_deps if not dep in all_deps ] all_deps = all_deps + extra_deps all_srcs = all_srcs + [ name + suffix + "_abi_autogen_unsafe.go" for suffix in marshal_sets.keys() ] _go_library( name = name, srcs = all_srcs, deps = all_deps, **kwargs ) if nogo: nogo_test( name = name + "_nogo", config = "//:nogo_config", srcs = all_srcs, deps = [":" + name], tags = ["nogo"], ) if marshal: # Ignore importpath for go_test. kwargs.pop("importpath", None) # See above. marshal_sets = calculate_sets(srcs) for (suffix, _) in marshal_sets.items(): _go_test( name = name + suffix + "_abi_autogen_test", srcs = [ name + suffix + "_abi_autogen_test.go", name + suffix + "_abi_autogen_unconditional_test.go", ], library = ":" + name, deps = marshal_test_deps, **kwargs ) def go_test(name, nogo = True, **kwargs): """Wraps the standard go_test. Args: name: the rule name. nogo: enable nogo analysis. **kwargs: standard go_test arguments. """ _go_test( name = name, **kwargs ) if nogo: nogo_test( name = name + "_nogo", config = "//:nogo_config", srcs = kwargs.get("srcs", []), deps = [":" + name], tags = ["nogo"], ) def proto_library(name, srcs, deps = None, has_services = 0, **kwargs): """Wraps the standard proto_library. Given a proto_library named "foo", this produces up to five different targets: - foo_proto: proto_library rule. - foo_go_proto: go_proto_library rule. - foo_cc_proto: cc_proto_library rule. - foo_go_grpc_proto: go_grpc_library rule. - foo_cc_grpc_proto: cc_grpc_library rule. Args: name: the name to which _proto, _go_proto, etc, will be appended. srcs: the proto sources. deps: for the proto library and the go_proto_library. has_services: 1 to build gRPC code, otherwise 0. **kwargs: standard proto_library arguments. """ _proto_library( name = name + "_proto", srcs = srcs, deps = deps, has_services = has_services, **kwargs ) if has_services: _go_grpc_and_proto_libraries( name = name, deps = deps, **kwargs ) else: _go_proto_library( name = name, deps = deps, **kwargs ) _cc_proto_library( name = name + "_cc_proto", deps = [":" + name + "_proto"], **kwargs ) if has_services: _cc_grpc_library( name = name + "_cc_grpc_proto", srcs = [":" + name + "_proto"], deps = [":" + name + "_cc_proto"], **kwargs )