summaryrefslogtreecommitdiffhomepage
path: root/tools/nogo/defs.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/nogo/defs.bzl')
-rw-r--r--tools/nogo/defs.bzl176
1 files changed, 0 insertions, 176 deletions
diff --git a/tools/nogo/defs.bzl b/tools/nogo/defs.bzl
deleted file mode 100644
index d399079c5..000000000
--- a/tools/nogo/defs.bzl
+++ /dev/null
@@ -1,176 +0,0 @@
-"""Nogo rules."""
-
-load("//tools/bazeldefs:defs.bzl", "go_context", "go_importpath", "go_rule")
-
-# NogoInfo is the serialized set of package facts for a nogo analysis.
-#
-# Each go_library rule will generate a corresponding nogo rule, which will run
-# with the source files as input. Note however, that the individual nogo rules
-# are simply stubs that enter into the shadow dependency tree (the "aspect").
-NogoInfo = provider(
- fields = {
- "facts": "serialized package facts",
- "importpath": "package import path",
- "binaries": "package binary files",
- },
-)
-
-def _nogo_aspect_impl(target, ctx):
- # If this is a nogo rule itself (and not the shadow of a go_library or
- # go_binary rule created by such a rule), then we simply return nothing.
- # All work is done in the shadow properties for go rules. For a proto
- # library, we simply skip the analysis portion but still need to return a
- # valid NogoInfo to reference the generated binary.
- if ctx.rule.kind == "go_library":
- srcs = ctx.rule.files.srcs
- elif ctx.rule.kind == "go_proto_library" or ctx.rule.kind == "go_wrap_cc":
- srcs = []
- else:
- return [NogoInfo()]
-
- go_ctx = go_context(ctx)
-
- # Construct the Go environment from the go_ctx.env dictionary.
- env_prefix = " ".join(["%s=%s" % (key, value) for (key, value) in go_ctx.env.items()])
-
- # Start with all target files and srcs as input.
- inputs = target.files.to_list() + srcs
-
- # Generate a shell script that dumps the binary. Annoyingly, this seems
- # necessary as the context in which a run_shell command runs does not seem
- # to cleanly allow us redirect stdout to the actual output file. Perhaps
- # I'm missing something here, but the intermediate script does work.
- binaries = target.files.to_list()
- disasm_file = ctx.actions.declare_file(target.label.name + ".out")
- dumper = ctx.actions.declare_file("%s-dumper" % ctx.label.name)
- ctx.actions.write(dumper, "\n".join([
- "#!/bin/bash",
- "%s %s tool objdump %s > %s\n" % (
- env_prefix,
- go_ctx.go.path,
- [f.path for f in binaries if f.path.endswith(".a")][0],
- disasm_file.path,
- ),
- ]), is_executable = True)
- ctx.actions.run(
- inputs = binaries,
- outputs = [disasm_file],
- tools = go_ctx.runfiles,
- mnemonic = "GoObjdump",
- progress_message = "Objdump %s" % target.label,
- executable = dumper,
- )
- inputs.append(disasm_file)
-
- # Extract the importpath for this package.
- importpath = go_importpath(target)
-
- # The nogo tool requires a configfile serialized in JSON format to do its
- # work. This must line up with the nogo.Config fields.
- facts = ctx.actions.declare_file(target.label.name + ".facts")
- config = struct(
- ImportPath = importpath,
- GoFiles = [src.path for src in srcs if src.path.endswith(".go")],
- NonGoFiles = [src.path for src in srcs if not src.path.endswith(".go")],
- # Google's internal build system needs a bit more help to find std.
- StdZip = go_ctx.std_zip.short_path if hasattr(go_ctx, "std_zip") else "",
- GOOS = go_ctx.goos,
- GOARCH = go_ctx.goarch,
- Tags = go_ctx.tags,
- FactMap = {}, # Constructed below.
- ImportMap = {}, # Constructed below.
- FactOutput = facts.path,
- Objdump = disasm_file.path,
- )
-
- # Collect all info from shadow dependencies.
- for dep in ctx.rule.attr.deps:
- # There will be no file attribute set for all transitive dependencies
- # that are not go_library or go_binary rules, such as a proto rules.
- # This is handled by the ctx.rule.kind check above.
- info = dep[NogoInfo]
- if not hasattr(info, "facts"):
- continue
-
- # Configure where to find the binary & fact files. Note that this will
- # use .x and .a regardless of whether this is a go_binary rule, since
- # these dependencies must be go_library rules.
- x_files = [f.path for f in info.binaries if f.path.endswith(".x")]
- if not len(x_files):
- x_files = [f.path for f in info.binaries if f.path.endswith(".a")]
- config.ImportMap[info.importpath] = x_files[0]
- config.FactMap[info.importpath] = info.facts.path
-
- # Ensure the above are available as inputs.
- inputs.append(info.facts)
- inputs += info.binaries
-
- # Write the configuration and run the tool.
- config_file = ctx.actions.declare_file(target.label.name + ".cfg")
- ctx.actions.write(config_file, config.to_json())
- inputs.append(config_file)
-
- # Run the nogo tool itself.
- ctx.actions.run(
- inputs = inputs,
- outputs = [facts],
- tools = go_ctx.runfiles,
- executable = ctx.files._nogo[0],
- mnemonic = "GoStaticAnalysis",
- progress_message = "Analyzing %s" % target.label,
- arguments = ["-config=%s" % config_file.path],
- )
-
- # Return the package facts as output.
- return [NogoInfo(
- facts = facts,
- importpath = importpath,
- binaries = binaries,
- )]
-
-nogo_aspect = go_rule(
- aspect,
- implementation = _nogo_aspect_impl,
- attr_aspects = ["deps"],
- attrs = {
- "_nogo": attr.label(
- default = "//tools/nogo/check:check",
- allow_single_file = True,
- ),
- },
-)
-
-def _nogo_test_impl(ctx):
- """Check nogo findings."""
-
- # Build a runner that checks for the existence of the facts file. Note that
- # the actual build will fail in the case of a broken analysis. We things
- # this way so that any test applied is effectively pushed down to all
- # upstream dependencies through the aspect.
- inputs = []
- runner = ctx.actions.declare_file("%s-executer" % ctx.label.name)
- runner_content = ["#!/bin/bash"]
- for dep in ctx.attr.deps:
- info = dep[NogoInfo]
- inputs.append(info.facts)
-
- # Draw a sweet unicode checkmark with the package name (in green).
- runner_content.append("echo -e \"\\033[0;32m\\xE2\\x9C\\x94\\033[0;31m\\033[0m %s\"" % info.importpath)
- runner_content.append("exit 0\n")
- ctx.actions.write(runner, "\n".join(runner_content), is_executable = True)
- return [DefaultInfo(
- runfiles = ctx.runfiles(files = inputs),
- executable = runner,
- )]
-
-_nogo_test = rule(
- implementation = _nogo_test_impl,
- attrs = {
- "deps": attr.label_list(aspects = [nogo_aspect]),
- },
- test = True,
-)
-
-def nogo_test(**kwargs):
- tags = kwargs.pop("tags", []) + ["nogo"]
- _nogo_test(tags = tags, **kwargs)