"""Marshal is a tool for generating marshalling interfaces for Go types. The recommended way is to use the go_library rule defined below with mostly identical configuration as the native go_library rule. load("//tools/go_marshal:defs.bzl", "go_library") go_library( name = "foo", srcs = ["foo.go"], ) Under the hood, the go_marshal rule is used to generate a file that will appear in a Go target; the output file should appear explicitly in a srcs list. For example (the above is still the preferred way): load("//tools/go_marshal:defs.bzl", "go_marshal") go_marshal( name = "foo_abi", srcs = ["foo.go"], out = "foo_abi.go", package = "foo", ) go_library( name = "foo", srcs = [ "foo.go", "foo_abi.go", ], deps = [ "//tools/go_marshal:marshal", "//pkg/sentry/platform/safecopy", "//pkg/sentry/usermem", ], ) """ load("@io_bazel_rules_go//go:def.bzl", _go_library = "go_library", _go_test = "go_test") def _go_marshal_impl(ctx): """Execute the go_marshal tool.""" output = ctx.outputs.lib output_test = ctx.outputs.test (build_dir, _, _) = ctx.build_file_path.rpartition("/BUILD") decl = "/".join(["gvisor.dev/gvisor", build_dir]) # Run the marshal command. args = ["-output=%s" % output.path] args += ["-pkg=%s" % ctx.attr.package] args += ["-output_test=%s" % output_test.path] args += ["-declarationPkg=%s" % decl] if ctx.attr.debug: args += ["-debug"] args += ["--"] for src in ctx.attr.srcs: args += [f.path for f in src.files.to_list()] ctx.actions.run( inputs = ctx.files.srcs, outputs = [output, output_test], mnemonic = "GoMarshal", progress_message = "go_marshal: %s" % ctx.label, arguments = args, executable = ctx.executable._tool, ) # Generates save and restore logic from a set of Go files. # # Args: # name: the name of the rule. # srcs: the input source files. These files should include all structs in the # package that need to be saved. # imports: an optional list of extra, non-aliased, Go-style absolute import # paths. # out: the name of the generated file output. This must not conflict with any # other files and must be added to the srcs of the relevant go_library. # package: the package name for the input sources. go_marshal = rule( implementation = _go_marshal_impl, attrs = { "srcs": attr.label_list(mandatory = True, allow_files = True), "libname": attr.string(mandatory = True), "imports": attr.string_list(mandatory = False), "package": attr.string(mandatory = True), "debug": attr.bool(doc = "enable debugging output from the go_marshal tool"), "_tool": attr.label(executable = True, cfg = "host", default = Label("//tools/go_marshal:go_marshal")), }, outputs = { "lib": "%{name}_unsafe.go", "test": "%{name}_test.go", }, ) def go_library(name, srcs, deps = [], imports = [], debug = False, **kwargs): """wraps the standard go_library and does mashalling interface generation. Args: name: Same as native go_library. srcs: Same as native go_library. deps: Same as native go_library. imports: Extra import paths to pass to the go_marshal tool. debug: Enables debugging output from the go_marshal tool. **kwargs: Remaining args to pass to the native go_library rule unmodified. """ go_marshal( name = name + "_abi_autogen", libname = name, srcs = [src for src in srcs if src.endswith(".go")], debug = debug, imports = imports, package = name, ) extra_deps = [ "//tools/go_marshal/marshal", "//pkg/sentry/platform/safecopy", "//pkg/sentry/usermem", ] all_srcs = srcs + [name + "_abi_autogen_unsafe.go"] all_deps = deps + [] # + extra_deps for extra in extra_deps: if extra not in deps: all_deps.append(extra) _go_library( name = name, srcs = all_srcs, deps = all_deps, **kwargs ) # Don't pass importpath arg to go_test. kwargs.pop("importpath", "") _go_test( name = name + "_abi_autogen_test", srcs = [name + "_abi_autogen_test.go"], # Generated test has a fixed set of dependencies since we generate these # tests. They should only depend on the library generated above, and the # Marshallable interface. deps = [ ":" + name, "//tools/go_marshal/analysis", ], **kwargs ) def go_test(**kwargs): """Wraps the standard go_test.""" _go_test( **kwargs )