Add GoContext (#1140)

* Add GoContext

This collects up all dependancies that were on the toolchain, but shoudld be in
target configuration (rather than host) and migrates them to a common
go_context_data dependancy.
It then adds a GoContext object, that holds the toolchain, build mode, standard
library and all mode specific attributes. go_context(ctx) will build one of
these and prepare to use it.
This simplifies a lot of the logic in the rules, and helps enforce the isolation
of action methods from ctx attributes.

* Review feedback plus documentation
diff --git a/BUILD.bazel b/BUILD.bazel
index fc061a4..7ed2446 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -2,6 +2,17 @@
 load("@io_bazel_rules_go//go/private:tools/lines_sorted_test.bzl", "lines_sorted_test")
 load("@io_bazel_rules_go//go/private:rules/info.bzl", "go_info")
 load("@io_bazel_rules_go//proto:go_proto_library.bzl", "go_google_protobuf")
+load("@io_bazel_rules_go//go/private:context.bzl", "go_context_data")
+
+go_context_data(
+    name = "go_context_data",
+    strip = select({
+        "@io_bazel_rules_go//go/private:strip-always": "always",
+        "@io_bazel_rules_go//go/private:strip-sometimes": "sometimes",
+        "@io_bazel_rules_go//go/private:strip-never": "never",
+    }),
+    visibility = ["//visibility:public"],
+)
 
 # gazelle:prefix github.com/bazelbuild/rules_go
 
diff --git a/examples/bindata/BUILD.bazel b/examples/bindata/BUILD.bazel
index f80df5a..eab89b2 100644
--- a/examples/bindata/BUILD.bazel
+++ b/examples/bindata/BUILD.bazel
@@ -1,5 +1,5 @@
 load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-load("@io_bazel_rules_go//examples/bindata:bindata.bzl", "bindata")
+load("@io_bazel_rules_go//extras:bindata.bzl", "bindata")
 
 bindata(
     name = "data",
diff --git a/extras/BUILD.bazel b/extras/BUILD.bazel
new file mode 100644
index 0000000..6f3d971
--- /dev/null
+++ b/extras/BUILD.bazel
@@ -0,0 +1,5 @@
+filegroup(
+    name = "all_rules",
+    srcs = glob(["*.bzl"]) + ["//go/private:all_rules"],
+    visibility = ["//visibility:public"],
+)
diff --git a/examples/bindata/bindata.bzl b/extras/bindata.bzl
similarity index 78%
rename from examples/bindata/bindata.bzl
rename to extras/bindata.bzl
index b937525..e2116ba 100644
--- a/examples/bindata/bindata.bzl
+++ b/extras/bindata.bzl
@@ -1,8 +1,8 @@
-load("@io_bazel_rules_go//go/private:go_repository.bzl", "go_repository")
-load("@io_bazel_rules_go//go/private:common.bzl", "declare_file")
+load("@io_bazel_rules_go//go:def.bzl", "go_context")
 
 def _bindata_impl(ctx):
-  out = declare_file(ctx, ext=".go")
+  go = go_context(ctx)
+  out = go.declare_file(go, ext=".go")
   arguments = ctx.actions.args()
   arguments.add([
       "-o", out.path,
@@ -35,5 +35,7 @@
         "compress": attr.bool(default=True),
         "metadata": attr.bool(default=False),
         "_bindata":  attr.label(allow_files=True, single_file=True, default=Label("@com_github_jteeuwen_go_bindata//go-bindata:go-bindata")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
+    toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/tools/embed_data.bzl b/extras/embed_data.bzl
similarity index 81%
rename from go/private/tools/embed_data.bzl
rename to extras/embed_data.bzl
index e1a542b..da2c3ff 100644
--- a/go/private/tools/embed_data.bzl
+++ b/extras/embed_data.bzl
@@ -12,18 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
-)
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
+load("@io_bazel_rules_go//go/private:context.bzl", #TODO: This ought to be def
+    "go_context",
 )
 
 def _go_embed_data_impl(ctx):
+  go = go_context(ctx)
   if ctx.attr.src and ctx.attr.srcs:
     fail("%s: src and srcs attributes cannot both be specified" % ctx.label)
   if ctx.attr.src and ctx.attr.flatten:
@@ -43,7 +37,7 @@
     if package == "":
       fail("%s: must provide package attribute for go_embed_data rules in the repository root directory" % ctx.label)
 
-  out = declare_file(ctx, ext=".go")
+  out = go.declare_file(go, ext=".go")
   args.add([
     "-workspace", ctx.workspace_name,
     "-label", str(ctx.label),
@@ -57,9 +51,8 @@
     args.add("-string")
   args.add(srcs)
 
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  library = new_go_library(ctx, srcs=srcs)
-  source = library_to_source(ctx, ctx.attr, library, mode)
+  library = go.new_library(go, srcs=srcs)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
 
   ctx.actions.run(
       outputs = [out],
@@ -87,7 +80,7 @@
             executable = True,
             cfg = "host",
         ),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/core.rst b/go/core.rst
index a756f0c..52d3462 100644
--- a/go/core.rst
+++ b/go/core.rst
@@ -6,7 +6,7 @@
 .. _gazelle: tools/gazelle/README.rst
 .. _build constraints: http://golang.org/pkg/go/build/
 .. _GoLibrary: providers.rst#GoLibrary
-.. _GoSourceList: providers.rst#GoSourceList
+.. _GoSource: providers.rst#GoSource
 .. _GoArchive: providers.rst#GoArchive
 .. _cgo: http://golang.org/cmd/cgo/
 .. _"Make variable": https://docs.bazel.build/versions/master/be/make-variables.html
@@ -15,6 +15,8 @@
 .. _cc library deps: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library.deps
 .. _pure: modes.rst#pure
 .. _static: modes.rst#static
+.. _goos: modes.rst#goos
+.. _goarch: modes.rst#goarch
 .. _mode attributes: modes.rst#mode-attributes
 
 .. role:: param(kbd)
@@ -58,7 +60,7 @@
 ^^^^^^^^^
 
 * GoLibrary_
-* GoSourceList_
+* GoSource_
 * GoArchive_
 
 Attributes
@@ -94,7 +96,7 @@
 | :param:`embed`             | :type:`label_list`          | :value:`None`                         |
 +----------------------------+-----------------------------+---------------------------------------+
 | List of Go libraries this test library directly.                                                 |
-| These may be go_library rules or compatible rules with the GoSourceList_ provider.               |
+| These may be go_library rules or compatible rules with the GoLibrary_ provider.                  |
 | These can provide both :param:`srcs` and :param:`deps` to this library.                          |
 | See Embedding_ for more information about how and when to use this.                              |
 +----------------------------+-----------------------------+---------------------------------------+
@@ -167,7 +169,8 @@
 ^^^^^^^^^
 
 * GoLibrary_
-* GoSourceList_
+* GoSource_
+* GoArchive_
 
 Attributes
 ^^^^^^^^^^
@@ -202,7 +205,7 @@
 | :param:`embed`             | :type:`label_list`          | :value:`None`                         |
 +----------------------------+-----------------------------+---------------------------------------+
 | List of Go libraries this binary embeds directly.                                                |
-| These may be go_library rules or compatible rules with the GoSourceList_ provider.               |
+| These may be go_library rules or compatible rules with the GoLibrary_ provider.                  |
 | These can provide both :param:`srcs` and :param:`deps` to this binary.                           |
 | See Embedding_ for more information about how and when to use this.                              |
 +----------------------------+-----------------------------+---------------------------------------+
@@ -223,6 +226,26 @@
 | This is one of the `mode attributes`_ that controls whether to link in static_ mode.             |
 | It should be one of :value:`on`, :value:`off` or :value:`auto`.                                  |
 +----------------------------+-----------------------------+---------------------------------------+
+| :param:`goos`              | :type:`string`              | :value:`auto`                         |
++----------------------------+-----------------------------+---------------------------------------+
+| This is one of the `mode attributes`_ that controls which goos_ to compile and link for.         |
+|                                                                                                  |
+| If set to anything other than :value:`auto` this overrideds the default as set by the current    |
+| target platform, and allows for single builds to make binaries for multiple architectures.       |
+|                                                                                                  |
+| Because this has no control over the cc toolchain, it does not work for cgo, so if this          |
+| attribute is set then :param:`pure` must be set to :value:`on`.                                  |
++----------------------------+-----------------------------+---------------------------------------+
+| :param:`goarch`            | :type:`string`              | :value:`auto`                         |
++----------------------------+-----------------------------+---------------------------------------+
+| This is one of the `mode attributes`_ that controls which goarch_ to compile and link for.       |
+|                                                                                                  |
+| If set to anything other than :value:`auto` this overrideds the default as set by the current    |
+| target platform, and allows for single builds to make binaries for multiple architectures.       |
+|                                                                                                  |
+| Because this has no control over the cc toolchain, it does not work for cgo, so if this          |
+| attribute is set then :param:`pure` must be set to :value:`on`.                                  |
++----------------------------+-----------------------------+---------------------------------------+
 | :param:`gc_goopts`         | :type:`string_list`         | :value:`[]`                           |
 +----------------------------+-----------------------------+---------------------------------------+
 | List of flags to add to the Go compilation command when using the gc compiler.                   |
@@ -314,7 +337,7 @@
 | :param:`embed`             | :type:`label_list`          | :value:`None`                         |
 +----------------------------+-----------------------------+---------------------------------------+
 | List of Go libraries this test embeds directly.                                                  |
-| These may be go_library rules or compatible rules with the GoSourceList_ provider.               |
+| These may be go_library rules or compatible rules with the GoLibrary_ provider.                  |
 | These can provide both :param:`srcs` and :param:`deps` to this test.                             |
 | See Embedding_ for more information about how and when to use this.                              |
 +----------------------------+-----------------------------+---------------------------------------+
@@ -438,7 +461,8 @@
 Providers
 ^^^^^^^^^
 
-* GoSourceList_
+* GoLibrary_
+* GoSource_
 
 Attributes
 ^^^^^^^^^^
@@ -464,7 +488,7 @@
 | :param:`embed`             | :type:`label_list`          | :value:`None`                         |
 +----------------------------+-----------------------------+---------------------------------------+
 | List of sources to directly embed in this list.                                                  |
-| These may be go_library rules or compatible rules with the GoSourceList_ provider.               |
+| These may be go_library rules or compatible rules with the GoSource_ provider.                   |
 | These can provide both :param:`srcs` and :param:`deps` to this library.                          |
 | See Embedding_ for more information about how and when to use this.                              |
 +----------------------------+-----------------------------+---------------------------------------+
diff --git a/go/def.bzl b/go/def.bzl
index 1ea70f1..8e3b628 100644
--- a/go/def.bzl
+++ b/go/def.bzl
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    go_context = "go_context",
+)
 load("@io_bazel_rules_go//go/private:go_repository.bzl",
     "go_repository",
 )
@@ -22,7 +25,7 @@
     "go_rules_dependencies",
     "go_register_toolchains",
 )
-load("@io_bazel_rules_go//go/private:toolchain.bzl",
+load("@io_bazel_rules_go//go/private:sdk.bzl",
     go_host_sdk = "go_host_sdk",
     go_download_sdk = "go_download_sdk",
     go_local_sdk = "go_local_sdk",
@@ -42,7 +45,7 @@
 load("@io_bazel_rules_go//go/private:rules/source.bzl",
     _go_source = "go_source",
 )
-load("@io_bazel_rules_go//go/private:tools/embed_data.bzl",
+load("@io_bazel_rules_go//extras:embed_data.bzl",
     "go_embed_data",
 )
 load("@io_bazel_rules_go//go/private:tools/gazelle.bzl",
diff --git a/go/modes.rst b/go/modes.rst
index e7f31ae..93ae810 100644
--- a/go/modes.rst
+++ b/go/modes.rst
@@ -63,7 +63,7 @@
 the binary rule. The compiled libraries are distinct and multiple modes can be built in a single pass,
 but are shared between leaves building in the same mode.
 
-Currently only static_ and pure_ can be specified as attributes.
+Currently only static_, pure_, goos_ and goarch_ can be specified as attributes.
 Both of these can take one of the values "on", "off" or "auto", and "auto" is the default.
 
 +--------------+-------------------------------------------------------------------------+
@@ -88,6 +88,8 @@
 * link_
 * debug_
 * strip_
+* goos_
+* goarch_
 
 Build modes
 -----------
@@ -148,6 +150,16 @@
 
 Causes debugging information to be stripped from the binaries.
 
+goos
+~~~~
+
+This controls which operating system to target.
+
+goarch
+~~~~~~
+
+This controls which architecture to target.
+
 Using build modes
 -----------------
 
@@ -204,3 +216,15 @@
 .. code::
 
     bazel test --features=race //...
+
+but in general it is strongly recommended instead to turn it on for specific tests.
+
+.. code::
+
+    go_test(
+        name = "go_default_test",
+        srcs = ["lib_test.go"],
+        embed = [":go_default_library"],
+        race = "on",
+  )
+
diff --git a/go/private/BUILD.bazel b/go/private/BUILD.bazel
index 044bfa5..123e6da 100644
--- a/go/private/BUILD.bazel
+++ b/go/private/BUILD.bazel
@@ -1,5 +1,3 @@
-load("@io_bazel_rules_go//go/private:go_toolchain.bzl", "go_toolchain_flags")
-
 filegroup(
     name = "all_rules",
     srcs = glob(["**/*.bzl"]),
@@ -21,12 +19,3 @@
     values = {"strip": "never"},
 )
 
-go_toolchain_flags(
-    name = "go_toolchain_flags",
-    strip = select({
-        "@io_bazel_rules_go//go/private:strip-always": "always",
-        "@io_bazel_rules_go//go/private:strip-sometimes": "sometimes",
-        "@io_bazel_rules_go//go/private:strip-never": "never",
-    }),
-    visibility = ["//visibility:public"],
-)
diff --git a/go/private/actions/action.bzl b/go/private/actions/action.bzl
deleted file mode 100644
index 846d4c3..0000000
--- a/go/private/actions/action.bzl
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2014 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-def add_go_env(args, stdlib, mode):
-  args.add([
-      "-go", stdlib.go,
-      "-root_file", stdlib.root_file,
-      "-goos", stdlib.goos,
-      "-goarch", stdlib.goarch,
-      "-cgo=" + ("0" if mode.pure else "1"),
-  ])
-
-def bootstrap_action(ctx, go_toolchain, mode, inputs, outputs, mnemonic, arguments):
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  ctx.actions.run_shell(
-    inputs = inputs + stdlib.files,
-    outputs = outputs,
-    mnemonic = mnemonic,
-    command = "export GOROOT=$(pwd)/{} && {} {}".format(stdlib.root_file.dirname, stdlib.go.path, " ".join(arguments)),
-  )
diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl
index 47db97d..560fc49 100644
--- a/go/private/actions/archive.bzl
+++ b/go/private/actions/archive.bzl
@@ -13,71 +13,60 @@
 # limitations under the License.
 
 load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
     "split_srcs",
     "sets",
 )
 load("@io_bazel_rules_go//go/private:mode.bzl",
     "mode_string",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "get_archive",
-)
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoArchive",
     "GoArchiveData",
+    "get_archive",
 )
 
-def emit_archive(ctx, go_toolchain, source=None):
+def emit_archive(go, source=None):
   """See go/toolchains.rst#archive for full documentation."""
 
   if source == None: fail("source is a required parameter")
 
   cover_vars = []
-  if ctx.configuration.coverage_enabled:
-    source, cover_vars = go_toolchain.actions.cover(ctx, go_toolchain, source)
+  if go.cover:
+    source, cover_vars = go.cover(go, source)
   split = split_srcs(source.srcs)
   compilepath = source.library.importpath if source.library.importpath else source.library.name
   lib_name = compilepath + ".a"
-  out_lib = declare_file(ctx, path=lib_name, mode=source.mode)
+  out_lib = go.declare_file(go, path=lib_name)
   searchpath = out_lib.path[:-len(lib_name)]
 
   extra_objects = []
   for src in split.asm:
-    obj = declare_file(ctx, path=src.basename[:-2], ext=".o", mode=source.mode)
-    go_toolchain.actions.asm(ctx, go_toolchain, mode=source.mode, source=src, hdrs=split.headers, out_obj=obj)
-    extra_objects.append(obj)
+    extra_objects.append(go.asm(go, source=src, hdrs=split.headers))
 
   direct = [get_archive(dep) for dep in source.deps]
   runfiles = source.runfiles
   for a in direct:
     runfiles = runfiles.merge(a.runfiles)
-    if a.source.mode != source.mode: fail("Archive mode does not match {} is {} expected {}".format(a.data.source.library.label, mode_string(a.source.mode), mode_string(source.mode)))
+    if a.source.mode != go.mode: fail("Archive mode does not match {} is {} expected {}".format(a.data.source.library.label, mode_string(a.source.mode), mode_string(go.mode)))
 
   if len(extra_objects) == 0 and source.cgo_archive == None:
-    go_toolchain.actions.compile(ctx,
-        go_toolchain = go_toolchain,
+    go.compile(go,
         sources = split.go,
         importpath = compilepath,
         archives = direct,
-        mode = source.mode,
         out_lib = out_lib,
         gc_goopts = source.gc_goopts,
     )
   else:
-    partial_lib = declare_file(ctx, path="partial", ext=".a", mode=source.mode)
-    go_toolchain.actions.compile(ctx,
-        go_toolchain = go_toolchain,
+    partial_lib = go.declare_file(go, path="partial", ext=".a")
+    go.compile(go,
         sources = split.go,
         importpath = compilepath,
         archives = direct,
-        mode = source.mode,
         out_lib = partial_lib,
         gc_goopts = source.gc_goopts,
     )
-    go_toolchain.actions.pack(ctx,
-        go_toolchain = go_toolchain,
-        mode = source.mode,
+    go.pack(go,
         in_lib = partial_lib,
         out_lib = out_lib,
         objects = extra_objects,
diff --git a/go/private/actions/asm.bzl b/go/private/actions/asm.bzl
index 51083d1..1984874 100644
--- a/go/private/actions/asm.bzl
+++ b/go/private/actions/asm.bzl
@@ -12,39 +12,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-)
 load("@io_bazel_rules_go//go/private:common.bzl",
     "to_set",
     "sets",
 )
 
-def emit_asm(ctx, go_toolchain,
+def emit_asm(go,
     source = None,
-    hdrs = [],
-    out_obj = None,
-    mode = None):
+    hdrs = []):
   """See go/toolchains.rst#asm for full documentation."""
 
   if source == None: fail("source is a required parameter")
-  if out_obj == None: fail("out_obj is a required parameter")
-  if mode == None: fail("mode is a required parameter")
 
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  includes = to_set([stdlib.root_file.dirname + "/pkg/include"])
+  out_obj = go.declare_file(go, path=source.basename[:-2], ext=".o")
+  includes = to_set([go.stdlib.root_file.dirname + "/pkg/include"])
   includes = sets.union(includes, [f.dirname for f in hdrs])
-  inputs = hdrs + stdlib.files + [source]
+  inputs = hdrs + go.stdlib.files + [source]
 
-  asm_args = ctx.actions.args()
-  add_go_env(asm_args, stdlib, mode)
+  asm_args = go.args(go)
   asm_args.add(["-o", out_obj, "-trimpath", "."])
   asm_args.add(includes, before_each="-I")
   asm_args.add(source.path)
-  ctx.actions.run(
+  go.actions.run(
       inputs = inputs,
       outputs = [out_obj],
       mnemonic = "GoAsmCompile",
-      executable = go_toolchain.tools.asm,
+      executable = go.toolchain.tools.asm,
       arguments = [asm_args],
   )
+  return out_obj
diff --git a/go/private/actions/binary.bzl b/go/private/actions/binary.bzl
index 86e6eea..f6dd1da 100644
--- a/go/private/actions/binary.bzl
+++ b/go/private/actions/binary.bzl
@@ -12,28 +12,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
-)
-
-def emit_binary(ctx, go_toolchain,
+def emit_binary(go,
     name="",
     source = None,
     gc_linkopts = [],
     x_defs = {},
-    wrap = None):
+    linkstamp=None,
+    version_file=None,
+    info_file=None):
   """See go/toolchains.rst#binary for full documentation."""
 
   if name == "": fail("name is a required parameter")
 
-  archive = go_toolchain.actions.archive(ctx, go_toolchain, source)
-  executable = declare_file(ctx, name=name, ext=go_toolchain.data.extension, mode=source.mode)
-  go_toolchain.actions.link(ctx,
-      go_toolchain = go_toolchain,
+  archive = go.archive(go, source)
+  executable = go.declare_file(go, name=name, ext=go.exe_extension)
+  go.link(go,
       archive=archive,
       executable=executable,
       gc_linkopts=gc_linkopts,
       x_defs=x_defs,
+      linkstamp=linkstamp,
+      version_file=version_file,
+      info_file=info_file,
   )
 
   return archive, executable
diff --git a/go/private/actions/compile.bzl b/go/private/actions/compile.bzl
index b1a07f8..c20d3b4 100644
--- a/go/private/actions/compile.bzl
+++ b/go/private/actions/compile.bzl
@@ -15,10 +15,6 @@
 load("@io_bazel_rules_go//go/private:common.bzl",
     "sets",
 )
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-    "bootstrap_action",
-)
 
 def _importpath(l):
   return [v.data.importpath for v in l]
@@ -26,37 +22,35 @@
 def _searchpath(l):
   return [v.data.searchpath for v in l]
 
-def emit_compile(ctx, go_toolchain,
+def emit_compile(go,
     sources = None,
     importpath = "",
     archives = [],
-    mode = None,
     out_lib = None,
     gc_goopts = []):
   """See go/toolchains.rst#compile for full documentation."""
 
   if sources == None: fail("sources is a required parameter")
   if out_lib == None: fail("out_lib is a required parameter")
-  if mode == None: fail("mode is a required parameter")
 
   # Add in any mode specific behaviours
-  if mode.race:
+  if go.mode.race:
     gc_goopts = gc_goopts + ["-race"]
-  if mode.msan:
+  if go.mode.msan:
     gc_goopts = gc_goopts + ["-msan"]
 
-  gc_goopts = [ctx.expand_make_variables("gc_goopts", f, {}) for f in gc_goopts]
-  inputs = sets.union(sources, [go_toolchain.data.package_list])
+  #TODO: Check if we really need this expand make variables in here
+  #TODO: If we really do then it needs to be moved all the way back out to the rule
+  gc_goopts = [go._ctx.expand_make_variables("gc_goopts", f, {}) for f in gc_goopts]
+  inputs = sets.union(sources, [go.package_list])
   go_sources = [s.path for s in sources if not s.basename.startswith("_cgo")]
   cgo_sources = [s.path for s in sources if s.basename.startswith("_cgo")]
 
   inputs = sets.union(inputs, [archive.data.file for archive in archives])
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  inputs = sets.union(inputs, stdlib.files)
+  inputs = sets.union(inputs, go.stdlib.files)
 
-  args = ctx.actions.args()
-  add_go_env(args, stdlib, mode)
-  args.add(["-package_list", go_toolchain.data.package_list])
+  args = go.args(go)
+  args.add(["-package_list", go.package_list])
   args.add(go_sources, before_each="-src")
   args.add(archives, before_each="-dep", map_fn=_importpath)
   args.add(archives, before_each="-I", map_fn=_searchpath)
@@ -65,23 +59,22 @@
   if importpath:
     args.add(["-p", importpath])
   args.add(gc_goopts)
-  args.add(go_toolchain.flags.compile)
-  if mode.debug:
+  args.add(go.toolchain.flags.compile)
+  if go.mode.debug:
     args.add(["-N", "-l"])
   args.add(cgo_sources)
-  ctx.actions.run(
+  go.actions.run(
       inputs = inputs,
       outputs = [out_lib],
       mnemonic = "GoCompile",
-      executable = go_toolchain.tools.compile,
+      executable = go.toolchain.tools.compile,
       arguments = [args],
   )
 
-def bootstrap_compile(ctx, go_toolchain,
+def bootstrap_compile(go,
     sources = None,
     importpath = "",
     archives = [],
-    mode = None,
     out_lib = None,
     gc_goopts = []):
   """See go/toolchains.rst#compile for full documentation."""
@@ -89,14 +82,13 @@
   if sources == None: fail("sources is a required parameter")
   if out_lib == None: fail("out_lib is a required parameter")
   if archives:  fail("compile does not accept deps in bootstrap mode")
-  if mode == None: fail("mode is a required parameter")
 
   args = ["tool", "compile", "-o", out_lib.path]
   args.extend(gc_goopts)
   args.extend([s.path for s in sources])
-  bootstrap_action(ctx, go_toolchain, mode,
-      inputs = sources,
+  go.actions.run_shell(
+      inputs = sources + go.stdlib.files,
       outputs = [out_lib],
       mnemonic = "GoCompile",
-      arguments = args,
+      command = "export GOROOT=$(pwd)/{} && {} {}".format(go.stdlib.root_file.dirname, go.stdlib.go.path, " ".join(args)),
   )
diff --git a/go/private/actions/cover.bzl b/go/private/actions/cover.bzl
index 380f4a7..2129e11 100644
--- a/go/private/actions/cover.bzl
+++ b/go/private/actions/cover.bzl
@@ -12,26 +12,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-)
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoSource",
 )
 load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
     "structs",
 )
 
-def emit_cover(ctx, go_toolchain, source):
+def emit_cover(go, source):
   """See go/toolchains.rst#cover for full documentation."""
 
   if source == None: fail("source is a required parameter")
   if not source.cover:
     return source, []
 
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, source.mode)
-
   covered = []
   cover_vars = []
   for src in source.srcs:
@@ -40,16 +34,15 @@
       continue
     cover_var = "Cover_" + src.basename[:-3].replace("-", "_").replace(".", "_")
     cover_vars.append("{}={}={}".format(cover_var, src.short_path, source.library.importpath))
-    out = declare_file(ctx, path=cover_var, ext='.cover.go')
+    out = go.declare_file(go, path=cover_var, ext='.cover.go')
     covered.append(out)
-    args = ctx.actions.args()
-    add_go_env(args, stdlib, source.mode)
+    args = go.args(go)
     args.add(["--", "--mode=set", "-var=%s" % cover_var, "-o", out, src])
-    ctx.actions.run(
-        inputs = [src] + stdlib.files,
+    go.actions.run(
+        inputs = [src] + go.stdlib.files,
         outputs = [out],
         mnemonic = "GoCover",
-        executable = go_toolchain.tools.cover,
+        executable = go.toolchain.tools.cover,
         arguments = [args],
     )
   members = structs.to_dict(source)
diff --git a/go/private/actions/link.bzl b/go/private/actions/link.bzl
index da7af06..90caa51 100644
--- a/go/private/actions/link.bzl
+++ b/go/private/actions/link.bzl
@@ -19,31 +19,29 @@
 load("@io_bazel_rules_go//go/private:mode.bzl",
     "LINKMODE_NORMAL",
 )
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-    "bootstrap_action",
-)
 
-def emit_link(ctx, go_toolchain,
+def emit_link(go,
     archive = None,
     executable = None,
     gc_linkopts = [],
-    x_defs = {}):
+    x_defs = {},
+    linkstamp=None,
+    version_file=None,
+    info_file=None):
   """See go/toolchains.rst#link for full documentation."""
 
   if archive == None: fail("archive is a required parameter")
   if executable == None: fail("executable is a required parameter")
 
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, archive.source.mode)
-
-  config_strip = len(ctx.configuration.bin_dir.path) + 1
+  #TODO: There has to be a better way to work out the rpath
+  config_strip = len(go._ctx.configuration.bin_dir.path) + 1
   pkg_depth = executable.dirname[config_strip:].count('/') + 1
 
   ld = None
   extldflags = []
-  if stdlib.cgo_tools:
-    ld = stdlib.cgo_tools.compiler_executable
-    extldflags.extend(stdlib.cgo_tools.options)
+  if go.stdlib.cgo_tools:
+    ld = go.stdlib.cgo_tools.compiler_executable
+    extldflags.extend(go.stdlib.cgo_tools.options)
   extldflags.extend(["-Wl,-rpath,$ORIGIN/" + ("../" * pkg_depth)])
 
   gc_linkopts, extldflags = _extract_extldflags(gc_linkopts, extldflags)
@@ -81,7 +79,7 @@
     else:
       link_opts.extend(["-X", "%s=%s" % (k, v)])
 
-  link_opts.extend(go_toolchain.flags.link)
+  link_opts.extend(go.toolchain.flags.link)
   if archive.source.mode.strip:
     link_opts.extend(["-w"])
 
@@ -91,38 +89,40 @@
         "-extldflags", " ".join(extldflags),
     ])
   link_opts.append(archive.data.file.path)
-  link_args = ctx.actions.args()
-  add_go_env(link_args, stdlib, archive.source.mode)
+  link_args = go.args(go)
   # Stamping support
   stamp_inputs = []
-  if stamp_x_defs or ctx.attr.linkstamp:
-    stamp_inputs = [ctx.info_file, ctx.version_file]
+  if stamp_x_defs or linkstamp:
+    stamp_inputs = [info_file, version_file]
     link_args.add(stamp_inputs, before_each="-stamp")
     for k,v in stamp_x_defs.items():
       link_args.add(["-X", "%s=%s" % (k, v)])
     # linkstamp option support: read workspace status files,
     # converting "KEY value" lines to "-X $linkstamp.KEY=value" arguments
     # to the go linker.
-    if ctx.attr.linkstamp:
-      link_args.add(["-linkstamp", ctx.attr.linkstamp])
+    if linkstamp:
+      link_args.add(["-linkstamp", linkstamp])
 
   link_args.add("--")
   link_args.add(link_opts)
 
-  ctx.actions.run(
+  go.actions.run(
       inputs = sets.union(archive.libs, archive.cgo_deps,
-                go_toolchain.data.crosstool, stamp_inputs, stdlib.files),
+                go.crosstool, stamp_inputs, go.stdlib.files),
       outputs = [executable],
       mnemonic = "GoLink",
-      executable = go_toolchain.tools.link,
+      executable = go.toolchain.tools.link,
       arguments = [link_args],
   )
 
-def bootstrap_link(ctx, go_toolchain,
+def bootstrap_link(go,
     archive = None,
     executable = None,
     gc_linkopts = [],
-    x_defs = {}):
+    x_defs = {},
+    linkstamp=None,
+    version_file=None,
+    info_file=None):
   """See go/toolchains.rst#link for full documentation."""
 
   if archive == None: fail("archive is a required parameter")
@@ -134,11 +134,11 @@
   args = ["tool", "link", "-o", executable.path]
   args.extend(gc_linkopts)
   args.append(archive.data.file.path)
-  bootstrap_action(ctx, go_toolchain, archive.source.mode,
-      inputs = inputs,
+  go.actions.run_shell(
+      inputs = inputs + go.stdlib.files,
       outputs = [executable],
-      mnemonic = "GoCompile",
-      arguments = args,
+      mnemonic = "GoLink",
+      command = "export GOROOT=$(pwd)/{} && {} {}".format(go.stdlib.root_file.dirname, go.stdlib.go.path, " ".join(args)),
   )
 
 def _extract_extldflags(gc_linkopts, extldflags):
diff --git a/go/private/actions/pack.bzl b/go/private/actions/pack.bzl
index a4f1340..1c9d904 100644
--- a/go/private/actions/pack.bzl
+++ b/go/private/actions/pack.bzl
@@ -12,27 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-)
-
-def emit_pack(ctx, go_toolchain,
+def emit_pack(go,
     in_lib = None,
     out_lib = None,
     objects = [],
-    archive = None,
-    mode = None):
+    archive = None):
   """See go/toolchains.rst#pack for full documentation."""
 
   if in_lib == None: fail("in_lib is a required parameter")
   if out_lib == None: fail("out_lib is a required parameter")
-  if mode == None: fail("mode is a required parameter")
 
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  inputs = [in_lib] + stdlib.files
+  inputs = [in_lib] + go.stdlib.files
 
-  arguments = ctx.actions.args()
-  add_go_env(arguments, stdlib, mode)
+  arguments = go.args(go)
   arguments.add([
       "-in", in_lib,
       "-out", out_lib,
@@ -44,10 +36,10 @@
     inputs.append(archive)
     arguments.add(["-arc", archive])
 
-  ctx.actions.run(
+  go.actions.run(
       inputs = inputs,
       outputs = [out_lib],
       mnemonic = "GoPack",
-      executable = go_toolchain.tools.pack,
+      executable = go.toolchain.tools.pack,
       arguments = [arguments],
   )
diff --git a/go/private/common.bzl b/go/private/common.bzl
index 25babb8..0b21c05 100644
--- a/go/private/common.bzl
+++ b/go/private/common.bzl
@@ -20,9 +20,6 @@
 load("//go/private:skylib/lib/structs.bzl", "structs")
 load("@io_bazel_rules_go//go/private:mode.bzl", "mode_string")
 
-DEFAULT_LIB = "go_default_library"
-VENDOR_PREFIX = "/vendor/"
-
 go_exts = [
     ".go",
 ]
@@ -98,32 +95,6 @@
   return source.go + source.headers + source.asm + source.c
 
 
-def go_importpath(ctx):
-  """Returns the expected importpath of the go_library being built.
-
-  Args:
-    ctx: The skylark Context
-
-  Returns:
-    Go importpath of the library
-  """
-  path = getattr(ctx.attr, "importpath", None)
-  if path != "":
-    return path
-  prefix = getattr(ctx.attr, "_go_prefix", None)
-  path = prefix.go_prefix if prefix else ""
-  if path.endswith("/"):
-    path = path[:-1]
-  if ctx.label.package:
-    path += "/" + ctx.label.package
-  if ctx.label.name != DEFAULT_LIB and not path.endswith(ctx.label.name):
-    path += "/" + ctx.label.name
-  if path.rfind(VENDOR_PREFIX) != -1:
-    path = path[len(VENDOR_PREFIX) + path.rfind(VENDOR_PREFIX):]
-  if path[0] == "/":
-    path = path[1:]
-  return path
-
 def env_execute(ctx, arguments, environment = {}, **kwargs):
   """env_executes a command in a repository context. It prepends "env -i"
   to "arguments" before calling "ctx.execute".
@@ -146,13 +117,3 @@
     fail("Do not pass a depset to to_set")
   return depset(v)
 
-def declare_file(ctx, path="", ext="", mode=None, name = ""):
-  filename = ""
-  if mode:
-    filename += mode_string(mode) + "/"
-  filename += name if name else ctx.label.name
-  if path:
-    filename += "~/" + path
-  if ext:
-    filename += ext
-  return ctx.actions.declare_file(filename)
\ No newline at end of file
diff --git a/go/private/context.bzl b/go/private/context.bzl
new file mode 100644
index 0000000..e9acbe9
--- /dev/null
+++ b/go/private/context.bzl
@@ -0,0 +1,218 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("@io_bazel_rules_go//go/private:providers.bzl",
+    "GoLibrary",
+    "GoSource",
+    "GoAspectProviders",
+    "GoStdLib",
+    "get_source",
+)
+load("@io_bazel_rules_go//go/platform:list.bzl",
+    "GOOS_GOARCH",
+)
+load("@io_bazel_rules_go//go/private:mode.bzl",
+    "get_mode",
+    "mode_string",
+)
+load("@io_bazel_rules_go//go/private:common.bzl",
+    "structs",
+)
+
+GoContext = provider()
+
+def executable_extension(ctx):
+  extension = ""
+  if ctx.os.name.startswith('windows'):
+    extension = ".exe"
+  return extension
+
+def _goos_to_extension(goos):
+  if goos == "windows":
+    return ".exe"
+  return ""
+
+def _declare_file(go, path="", ext="", name = ""):
+  filename = mode_string(go.mode) + "/"
+  filename += name if name else go._ctx.label.name
+  if path:
+    filename += "~/" + path
+  if ext:
+    filename += ext
+  return go.actions.declare_file(filename)
+
+def _new_args(go):
+  args = go.actions.args()
+  args.add([
+      "-go", go.stdlib.go,
+      "-root_file", go.stdlib.root_file,
+      "-goos", go.mode.goos,
+      "-goarch", go.mode.goarch,
+      "-cgo=" + ("0" if go.mode.pure else "1"),
+  ])
+  return args
+
+def _new_library(go, resolver=None, importable=True, **kwargs):
+  return GoLibrary(
+      name = go._ctx.label.name,
+      label = go._ctx.label,
+      importpath = go._inferredpath if importable else None, # The canonical import path for this library
+      exportpath = go._inferredpath, # The export source path for this library
+      resolve = resolver,
+      **kwargs
+  )
+
+def _merge_embed(source, embed):
+  s = get_source(embed)
+  source["srcs"] = s.srcs + source["srcs"]
+  source["cover"] = source["cover"] + s.cover
+  source["deps"] = source["deps"] + s.deps
+  source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts
+  source["runfiles"] = source["runfiles"].merge(s.runfiles)
+  source["cgo_deps"] = source["cgo_deps"] + s.cgo_deps
+  source["cgo_exports"] = source["cgo_exports"] + s.cgo_exports
+  if s.cgo_archive:
+    if source["cgo_archive"]:
+      fail("multiple libraries with cgo_archive embedded")
+    source["cgo_archive"] = s.cgo_archive
+
+def _library_to_source(go, attr, library, coverage_instrumented):
+  attr_srcs = [f for t in getattr(attr, "srcs", []) for f in t.files]
+  generated_srcs = getattr(library, "srcs", [])
+  source = {
+      "library" : library,
+      "mode" : go.mode,
+      "srcs" : generated_srcs + attr_srcs,
+      "cover" : [],
+      "deps" : getattr(attr, "deps", []),
+      "gc_goopts" : getattr(attr, "gc_goopts", []),
+      "runfiles" : go._ctx.runfiles(collect_data = True),
+      "cgo_archive" : None,
+      "cgo_deps" : [],
+      "cgo_exports" : [],
+  }
+  if coverage_instrumented and not attr.testonly:
+    source["cover"] = attr_srcs
+  for e in getattr(attr, "embed", []):
+    _merge_embed(source, e)
+  if library.resolve:
+    library.resolve(go, attr, source, _merge_embed)
+  return GoSource(**source)
+
+
+def _infer_importpath(ctx):
+  DEFAULT_LIB = "go_default_library"
+  VENDOR_PREFIX = "/vendor/"
+  path = getattr(ctx.attr, "importpath", None)
+  if path != "":
+    return path
+  prefix = getattr(ctx.attr, "_go_prefix", None)
+  path = prefix.go_prefix if prefix else ""
+  if path.endswith("/"):
+    path = path[:-1]
+  if ctx.label.package:
+    path += "/" + ctx.label.package
+  if ctx.label.name != DEFAULT_LIB and not path.endswith(ctx.label.name):
+    path += "/" + ctx.label.name
+  if path.rfind(VENDOR_PREFIX) != -1:
+    path = path[len(VENDOR_PREFIX) + path.rfind(VENDOR_PREFIX):]
+  if path[0] == "/":
+    path = path[1:]
+  return path
+
+
+def go_context(ctx, attr=None):
+  if "@io_bazel_rules_go//go:toolchain" in ctx.toolchains:
+    toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
+  elif "@io_bazel_rules_go//go:bootstrap_toolchain" in ctx.toolchains:
+    toolchain = ctx.toolchains["@io_bazel_rules_go//go:bootstrap_toolchain"]
+  else:
+    fail('Rule {} does not have the go toolchain available\nAdd toolchains = ["@io_bazel_rules_go//go:toolchain"] to the rule definition.'.format(ctx.label))
+
+  if not attr:
+    attr = ctx.attr
+
+  context_data = attr._go_context_data
+  mode = get_mode(ctx, toolchain, context_data)
+
+  stdlib = None
+  for check in [s[GoStdLib] for s in context_data.stdlib_all]:
+    if (check.goos == mode.goos and
+        check.goarch == mode.goarch and
+        check.race == mode.race and
+        check.pure == mode.pure):
+      if stdlib:
+        fail("Multiple matching standard library for "+mode_string(mode))
+      stdlib = check
+  if not stdlib:
+    fail("No matching standard library for "+mode_string(mode))
+
+  return GoContext(
+      # Fields
+      toolchain = toolchain,
+      mode = mode,
+      stdlib = stdlib,
+      actions = ctx.actions,
+      exe_extension = _goos_to_extension(mode.goos),
+      crosstool = context_data.crosstool,
+      package_list = context_data.package_list,
+      # Action generators
+      archive = toolchain.actions.archive,
+      asm = toolchain.actions.asm,
+      binary = toolchain.actions.binary,
+      compile = toolchain.actions.compile,
+      cover = toolchain.actions.cover if ctx.configuration.coverage_enabled else None,
+      link = toolchain.actions.link,
+      pack = toolchain.actions.pack,
+
+      # Helpers
+      args = _new_args,
+      new_library = _new_library,
+      library_to_source = _library_to_source,
+      declare_file = _declare_file,
+
+      # Private
+      _ctx = ctx, # TODO: All uses of this should be removed
+      _inferredpath = _infer_importpath(ctx), # TODO: remove when go_prefix goes away
+  )
+
+def _stdlib_all():
+  stdlibs = []
+  for goos, goarch in GOOS_GOARCH:
+    stdlibs.extend([
+      Label("@go_stdlib_{}_{}_cgo".format(goos, goarch)),
+      Label("@go_stdlib_{}_{}_pure".format(goos, goarch)),
+      Label("@go_stdlib_{}_{}_cgo_race".format(goos, goarch)),
+      Label("@go_stdlib_{}_{}_pure_race".format(goos, goarch)),
+    ])
+  return stdlibs
+
+def _go_context_data(ctx):
+    return struct(
+        strip = ctx.attr.strip,
+        stdlib_all = ctx.attr._stdlib_all,
+        crosstool = ctx.files._crosstool,
+        package_list = ctx.file._package_list,
+    )
+
+go_context_data = rule(
+    _go_context_data,
+    attrs = {
+        "strip": attr.string(mandatory=True),
+        # Hidden internal attributes
+        "_stdlib_all": attr.label_list(default = _stdlib_all()),
+        "_crosstool": attr.label(default=Label("//tools/defaults:crosstool")),
+        "_package_list": attr.label(allow_files = True, single_file = True, default="@go_sdk//:packages.txt"),
+    },
+)
diff --git a/go/private/go_repository.bzl b/go/private/go_repository.bzl
index 80daba0..53dd8b7 100644
--- a/go/private/go_repository.bzl
+++ b/go/private/go_repository.bzl
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 load("@io_bazel_rules_go//go/private:common.bzl", "env_execute")
-load("@io_bazel_rules_go//go/private:toolchain.bzl", "executable_extension")
+load("@io_bazel_rules_go//go/private:context.bzl", "executable_extension")
 
 def _go_repository_impl(ctx):
   if ctx.attr.urls:
diff --git a/go/private/go_toolchain.bzl b/go/private/go_toolchain.bzl
index 0dfb55a..722f02f 100644
--- a/go/private/go_toolchain.bzl
+++ b/go/private/go_toolchain.bzl
@@ -21,24 +21,7 @@
 load("@io_bazel_rules_go//go/private:actions/cover.bzl", "emit_cover")
 load("@io_bazel_rules_go//go/private:actions/link.bzl", "emit_link", "bootstrap_link")
 load("@io_bazel_rules_go//go/private:actions/pack.bzl", "emit_pack")
-load("@io_bazel_rules_go//go/private:providers.bzl", "GoStdLib")
-load("@io_bazel_rules_go//go/platform:list.bzl", "GOOS_GOARCH")
-load("@io_bazel_rules_go//go/private:mode.bzl", "mode_string")
 
-def _get_stdlib(ctx, go_toolchain, mode):
-  for stdlib in go_toolchain.stdlib.all:
-    stdlib = stdlib[GoStdLib]
-    if (stdlib.goos == mode.goos and
-        stdlib.goarch == mode.goarch and
-        stdlib.race == mode.race and
-        stdlib.pure == mode.pure):
-      return stdlib
-  fail("No matching standard library for "+mode_string(mode))
-
-def _goos_to_extension(goos):
-  if goos == "windows":
-    return ".exe"
-  return ""
 
 def _go_toolchain_impl(ctx):
   return [platform_common.ToolchainInfo(
@@ -47,10 +30,6 @@
       bootstrap = ctx.attr.bootstrap,
       default_goos = ctx.attr.goos,
       default_goarch = ctx.attr.goarch,
-      stdlib = struct(
-          all = ctx.attr._stdlib_all,
-          get = _get_stdlib,
-      ),
       actions = struct(
           archive = emit_archive,
           asm = emit_asm,
@@ -74,24 +53,8 @@
           link = ctx.attr.link_flags,
           link_cgo = ctx.attr.cgo_link_flags,
       ),
-      data = struct(
-          crosstool = ctx.files._crosstool,
-          package_list = ctx.file._package_list,
-          extension = _goos_to_extension(ctx.attr.goos),
-      ),
   )]
 
-def _stdlib_all():
-  stdlibs = []
-  for goos, goarch in GOOS_GOARCH:
-    stdlibs.extend([
-      Label("@go_stdlib_{}_{}_cgo".format(goos, goarch)),
-      Label("@go_stdlib_{}_{}_pure".format(goos, goarch)),
-      Label("@go_stdlib_{}_{}_cgo_race".format(goos, goarch)),
-      Label("@go_stdlib_{}_{}_pure_race".format(goos, goarch)),
-    ])
-  return stdlibs
-
 def _asm(bootstrap):
   if bootstrap:
     return None
@@ -146,10 +109,6 @@
         "_cgo": attr.label(allow_files = True, single_file = True, executable = True, cfg = "host", default = _cgo),
         "_test_generator": attr.label(allow_files = True, single_file = True, executable = True, cfg = "host", default = _test_generator),
         "_cover": attr.label(allow_files = True, single_file = True, executable = True, cfg = "host", default = _cover),
-        # Hidden internal attributes
-        "_stdlib_all": attr.label_list(default = _stdlib_all()),
-        "_crosstool": attr.label(default=Label("//tools/defaults:crosstool")),
-        "_package_list": attr.label(allow_files = True, single_file = True, default="@go_sdk//:packages.txt"),
     },
 )
 
@@ -208,15 +167,3 @@
         target_compatible_with = target_constraints,
         toolchain = ":"+impl_name,
     )
-
-def _go_toolchain_flags(ctx):
-    return struct(
-        strip = ctx.attr.strip,
-    )
-
-go_toolchain_flags = rule(
-    _go_toolchain_flags,
-    attrs = {
-        "strip": attr.string(mandatory=True),
-    },
-)
diff --git a/go/private/mode.bzl b/go/private/mode.bzl
index 17a9c2b..b883fd9 100644
--- a/go/private/mode.bzl
+++ b/go/private/mode.bzl
@@ -49,13 +49,8 @@
     fail("Invalid value {}".format(v))
   fail("_ternary failed to produce a final result from {}".format(values))
 
-def get_mode(ctx, toolchain_flags):
-  if "@io_bazel_rules_go//go:toolchain" in ctx.toolchains:
-    go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  else:
-    go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:bootstrap_toolchain"]
-
-  # We always have to use the pure stdlib in cross compilation mode
+def get_mode(ctx, go_toolchain, go_context_data):
+  # We always have to  use the pure stdlib in cross compilation mode
   force_pure = "on" if go_toolchain.cross_compile else "auto"
   force_race = "off" if go_toolchain.bootstrap else "auto"
 
@@ -83,8 +78,8 @@
     race = False
   debug = ctx.var["COMPILATION_MODE"] == "debug"
   strip_mode = "sometimes"
-  if toolchain_flags:
-    strip_mode = toolchain_flags.strip
+  if go_context_data:
+    strip_mode = go_context_data.strip
   strip = True
   if strip_mode == "always":
     strip = True
diff --git a/go/private/providers.bzl b/go/private/providers.bzl
index 15811ce..dca4836 100644
--- a/go/private/providers.bzl
+++ b/go/private/providers.bzl
@@ -47,3 +47,20 @@
 GoAspectProviders = provider()
 GoPath = provider()
 GoStdLib = provider()
+
+def new_aspect_provider(source = None, archive = None):
+  return GoAspectProviders(
+      source = source,
+      archive = archive,
+  )
+
+def get_source(dep):
+  if GoAspectProviders in dep:
+    return dep[GoAspectProviders].source
+  return dep[GoSource]
+
+def get_archive(dep):
+  if GoAspectProviders in dep:
+    return dep[GoAspectProviders].archive
+  return dep[GoArchive]
+
diff --git a/go/private/repository_tools.bzl b/go/private/repository_tools.bzl
index b01fa23..47ceee0 100644
--- a/go/private/repository_tools.bzl
+++ b/go/private/repository_tools.bzl
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 load("@io_bazel_rules_go//go/private:go_repository.bzl", "go_repository", "env_execute")
-load("@io_bazel_rules_go//go/private:toolchain.bzl", "executable_extension")
+load("@io_bazel_rules_go//go/private:context.bzl", "executable_extension")
 
 _GO_REPOSITORY_TOOLS_BUILD_FILE = """
 package(default_visibility = ["//visibility:public"])
diff --git a/go/private/rules/aspect.bzl b/go/private/rules/aspect.bzl
index 21dfbd4..ab277aa 100644
--- a/go/private/rules/aspect.bzl
+++ b/go/private/rules/aspect.bzl
@@ -12,15 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:common.bzl",
     "split_srcs",
     "to_set",
     "sets",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "library_to_source",
-    "new_aspect_provider",
-)
 load("@io_bazel_rules_go//go/private:mode.bzl",
     "mode_string",
 )
@@ -29,21 +28,19 @@
     "GoArchive",
     "GoArchiveData",
     "GoSource",
+    "new_aspect_provider",
 )
 load("@io_bazel_rules_go//go/platform:list.bzl",
     "GOOS",
     "GOARCH",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
 
 def _go_archive_aspect_impl(target, ctx):
-  mode = get_mode(ctx, ctx.rule.attr._go_toolchain_flags)
+  go = go_context(ctx, ctx.rule.attr)
   source = target[GoSource] if GoSource in target else None
   archive = target[GoArchive] if GoArchive in target else None
-  if source and source.mode == mode:
+  if source and source.mode == go.mode:
     # The base layer already built the right mode for us
     return [new_aspect_provider(
       source = source,
@@ -54,12 +51,9 @@
     return []
   # We have a library and we need to compile it in a new mode
   library = target[GoLibrary]
-  source = library_to_source(ctx, ctx.rule.attr, library, mode)
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  archive = go_toolchain.actions.archive(ctx,
-      go_toolchain = go_toolchain,
-      source = source,
-  )
+  source = go.library_to_source(go, ctx.rule.attr, library, ctx.coverage_instrumented())
+  if archive:
+    archive = go.archive(go, source = source)
   return [new_aspect_provider(
     source = source,
     archive = archive,
diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl
index d17f538..8aae244 100644
--- a/go/private/rules/binary.bzl
+++ b/go/private/rules/binary.bzl
@@ -12,6 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:common.bzl",
     "go_filetype",
 )
@@ -24,35 +27,27 @@
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
 load("@io_bazel_rules_go//go/platform:list.bzl",
     "GOOS",
     "GOARCH",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
 def _go_binary_impl(ctx):
   """go_binary_impl emits actions for compiling and linking a go executable."""
-  if "@io_bazel_rules_go//go:toolchain" in ctx.toolchains:
-    go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  else:
-    go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:bootstrap_toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  library = new_go_library(ctx, importable=False)
-  source = library_to_source(ctx, ctx.attr, library, mode)
+  go = go_context(ctx)
+  library = go.new_library(go, importable=False)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
   name = ctx.attr.basename
   if not name:
     name = ctx.label.name
-  archive, executable = go_toolchain.actions.binary(ctx, go_toolchain,
+  archive, executable = go.binary(go,
       name = name,
       source = source,
       gc_linkopts = gc_linkopts(ctx),
       x_defs = ctx.attr.x_defs,
+      linkstamp=ctx.attr.linkstamp,
+      version_file=ctx.version_file,
+      info_file=ctx.info_file,
   )
   return [
       library, source, archive,
@@ -86,7 +81,7 @@
         "linkstamp": attr.string(),
         "x_defs": attr.string_dict(),
         "_go_prefix": attr.label(default = go_prefix_default),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     executable = True,
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
@@ -110,7 +105,7 @@
         "linkstamp": attr.string(),
         "x_defs": attr.string_dict(),
         "_go_prefix": attr.label(default = go_prefix_default),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     executable = True,
     toolchains = ["@io_bazel_rules_go//go:bootstrap_toolchain"],
diff --git a/go/private/rules/cgo.bzl b/go/private/rules/cgo.bzl
index b81213e..5e95713 100644
--- a/go/private/rules/cgo.bzl
+++ b/go/private/rules/cgo.bzl
@@ -12,27 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
     "split_srcs",
     "join_srcs",
     "pkg_dir",
     "sets",
     "to_set",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-)
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
 
 _CgoCodegen = provider()
 
@@ -61,23 +53,20 @@
   fail("cc_library did not produce any files")
 
 def _cgo_codegen_impl(ctx):
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  if not stdlib.cgo_tools:
+  go = go_context(ctx)
+  if not go.stdlib.cgo_tools:
     fail("Go toolchain does not support cgo")
   linkopts = ctx.attr.linkopts[:]
-  copts = stdlib.cgo_tools.c_options + ctx.attr.copts
+  copts = go.stdlib.cgo_tools.c_options + ctx.attr.copts
   deps = depset([], order="topological")
-  cgo_export_h = declare_file(ctx, path="_cgo_export.h")
-  cgo_export_c = declare_file(ctx, path="_cgo_export.c")
-  cgo_main = declare_file(ctx, path="_cgo_main.c")
-  cgo_types = declare_file(ctx, path="_cgo_gotypes.go")
+  cgo_export_h = go.declare_file(go, path="_cgo_export.h")
+  cgo_export_c = go.declare_file(go, path="_cgo_export.c")
+  cgo_main = go.declare_file(go, path="_cgo_main.c")
+  cgo_types = go.declare_file(go, path="_cgo_gotypes.go")
   out_dir = cgo_main.dirname
 
-  cc = stdlib.cgo_tools.compiler_executable
-  args = ctx.actions.args()
-  add_go_env(args, stdlib, mode)
+  cc = go.stdlib.cgo_tools.compiler_executable
+  args = go.args(go)
   args.add(["-cc", str(cc), "-objdir", out_dir])
 
   c_outs = [cgo_export_h, cgo_export_c]
@@ -88,23 +77,23 @@
       copts.extend(['-iquote', src.dirname])
   for src in source.go:
     mangled_stem, src_ext = _mangle(src)
-    gen_file = declare_file(ctx, path=mangled_stem + ".cgo1."+src_ext)
-    gen_c_file = declare_file(ctx, path=mangled_stem + ".cgo2.c")
+    gen_file = go.declare_file(go, path=mangled_stem + ".cgo1."+src_ext)
+    gen_c_file = go.declare_file(go, path=mangled_stem + ".cgo2.c")
     go_outs.append(gen_file)
     c_outs.append(gen_c_file)
     args.add(["-src", gen_file.path + "=" + src.path])
   for src in source.asm:
     mangled_stem, src_ext = _mangle(src)
-    gen_file = declare_file(ctx, path=mangled_stem + ".cgo1."+src_ext)
+    gen_file = go.declare_file(go, path=mangled_stem + ".cgo1."+src_ext)
     go_outs.append(gen_file)
     args.add(["-src", gen_file.path + "=" + src.path])
   for src in source.c:
     mangled_stem, src_ext = _mangle(src)
-    gen_file = declare_file(ctx, path=mangled_stem + ".cgo1."+src_ext)
+    gen_file = go.declare_file(go, path=mangled_stem + ".cgo1."+src_ext)
     c_outs.append(gen_file)
     args.add(["-src", gen_file.path + "=" + src.path])
 
-  inputs = sets.union(ctx.files.srcs, go_toolchain.data.crosstool, stdlib.files,
+  inputs = sets.union(ctx.files.srcs, go.crosstool, go.stdlib.files,
                       *[d.cc.transitive_headers for d in ctx.attr.deps])
   deps = sets.union(deps, *[d.cc.libs for d in ctx.attr.deps])
   runfiles = ctx.runfiles(collect_data = True)
@@ -133,7 +122,7 @@
       outputs = c_outs + go_outs + [cgo_main],
       mnemonic = "CGoCodeGen",
       progress_message = "CGoCodeGen %s" % ctx.label,
-      executable = go_toolchain.tools.cgo,
+      executable = go.toolchain.tools.cgo,
       arguments = [args],
       env = {
           "CGO_LDFLAGS": " ".join(linkopts),
@@ -169,18 +158,15 @@
         ),
         "copts": attr.string_list(),
         "linkopts": attr.string_list(),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
 
 def _cgo_import_impl(ctx):
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  out = declare_file(ctx, ext=".go")
-  args = ctx.actions.args()
-  add_go_env(args, stdlib, mode)
+  go = go_context(ctx)
+  out = go.declare_file(go, ext=".go")
+  args = go.args(go)
   args.add([
       "-dynout", out,
       "-dynimport", ctx.file.cgo_o,
@@ -190,9 +176,9 @@
       inputs = [
           ctx.file.cgo_o,
           ctx.files.sample_go_srcs[0],
-      ] + stdlib.files,
+      ] + go.stdlib.files,
       outputs = [out],
-      executable = go_toolchain.tools.cgo,
+      executable = go.toolchain.tools.cgo,
       arguments = [args],
       mnemonic = "CGoImportGen",
   )
@@ -208,7 +194,7 @@
             single_file = True,
         ),
         "sample_go_srcs": attr.label_list(allow_files = True),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
@@ -227,7 +213,7 @@
 def _not_pure(ctx, mode):
     return not mode.pure
 
-def _cgo_library_to_source(ctx, attr, source):
+def _cgo_library_to_source(go, attr, source, merge):
   library = source["library"]
   if source["mode"].pure:
     source["srcs"] = library.input_go_srcs + source["srcs"]
@@ -240,11 +226,12 @@
 
 
 def _cgo_collect_info_impl(ctx):
+  go = go_context(ctx)
   codegen = ctx.attr.codegen[_CgoCodegen]
   runfiles = ctx.runfiles(collect_data = True)
   runfiles = runfiles.merge(ctx.attr.codegen.data_runfiles)
 
-  library = new_go_library(ctx,
+  library = go.new_library(go,
       resolver=_cgo_library_to_source,
       input_go_srcs = ctx.files.input_go_srcs,
       gen_go_srcs = ctx.files.gen_go_srcs,
@@ -252,8 +239,7 @@
       cgo_exports = ctx.attr.codegen[_CgoCodegen].exports,
       cgo_archive = _select_archive(ctx.files.lib),
   )
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  source = library_to_source(ctx, ctx.attr, library, mode)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
 
   return [
       source, library,
@@ -267,7 +253,7 @@
         "input_go_srcs": attr.label_list(mandatory = True, allow_files = [".go"]),
         "gen_go_srcs": attr.label_list(mandatory = True, allow_files = [".go"]),
         "lib": attr.label(mandatory = True, providers = ["cc"]),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/rules/helpers.bzl b/go/private/rules/helpers.bzl
deleted file mode 100644
index 7ac54d9..0000000
--- a/go/private/rules/helpers.bzl
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "go_importpath",
-    "sets",
-)
-load("@io_bazel_rules_go//go/private:providers.bzl",
-    "GoLibrary",
-    "GoSource",
-    "GoArchive",
-    "GoAspectProviders",
-)
-
-def new_go_library(ctx, resolver=None, importable=True, **kwargs):
-  inferredpath = go_importpath(ctx)
-  return GoLibrary(
-      name = ctx.label.name,
-      label = ctx.label,
-      importpath = inferredpath if importable else None, # The canonical import path for this library
-      exportpath = inferredpath, # The export source path for this library
-      resolve = resolver,
-      **kwargs
-  )
-
-def new_aspect_provider(source = None, archive = None):
-  return GoAspectProviders(
-      source = source,
-      archive = archive,
-  )
-
-def get_source(dep):
-  if GoAspectProviders in dep:
-    return dep[GoAspectProviders].source
-  return dep[GoSource]
-
-def get_archive(dep):
-  if GoAspectProviders in dep:
-    return dep[GoAspectProviders].archive
-  return dep[GoArchive]
-
-def merge_embed(source, embed):
-  s = get_source(embed)
-  source["srcs"] = s.srcs + source["srcs"]
-  source["cover"] = source["cover"] + s.cover
-  source["deps"] = source["deps"] + s.deps
-  source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts
-  source["runfiles"] = source["runfiles"].merge(s.runfiles)
-  source["cgo_deps"] = source["cgo_deps"] + s.cgo_deps
-  source["cgo_exports"] = source["cgo_exports"] + s.cgo_exports
-  if s.cgo_archive:
-    if source["cgo_archive"]:
-      fail("multiple libraries with cgo_archive embedded")
-    source["cgo_archive"] = s.cgo_archive
-
-def library_to_source(ctx, attr, library, mode):
-  attr_srcs = [f for t in getattr(attr, "srcs", []) for f in t.files]
-  generated_srcs = getattr(library, "srcs", [])
-  source = {
-      "library" : library,
-      "mode" : mode,
-      "srcs" : generated_srcs + attr_srcs,
-      "cover" : [],
-      "deps" : getattr(attr, "deps", []),
-      "gc_goopts" : getattr(attr, "gc_goopts", []),
-      "runfiles" : ctx.runfiles(collect_data = True),
-      "cgo_archive" : None,
-      "cgo_deps" : [],
-      "cgo_exports" : [],
-  }
-  if ctx.coverage_instrumented() and not attr.testonly:
-    source["cover"] = attr_srcs
-  for e in getattr(attr, "embed", []):
-    merge_embed(source, e)
-  if library.resolve:
-    library.resolve(ctx, attr, source)
-  return GoSource(**source)
-
diff --git a/go/private/rules/info.bzl b/go/private/rules/info.bzl
index 7a3da0b..78f8b40 100644
--- a/go/private/rules/info.bzl
+++ b/go/private/rules/info.bzl
@@ -12,23 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
-)
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
 )
 
 def _go_info_script_impl(ctx):
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  out = declare_file(ctx, ext=".bash")
-  args = ctx.actions.args()
-  add_go_env(args, stdlib, mode)
+  go = go_context(ctx)
+  out = go.declare_file(go, ext=".bash")
+  args = go.args(go)
   args.add(["-script", "-out", out])
   ctx.actions.run(
       inputs = [],
@@ -52,7 +43,7 @@
             executable = True,
             cfg = "host",
             default="@io_bazel_rules_go//go/tools/builders:info"),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/rules/library.bzl b/go/private/rules/library.bzl
index e9656b9..520e0b2 100644
--- a/go/private/rules/library.bzl
+++ b/go/private/rules/library.bzl
@@ -12,27 +12,22 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
 load("@io_bazel_rules_go//go/private:rules/prefix.bzl",
     "go_prefix_default",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
 def _go_library_impl(ctx):
   """Implements the go_library() rule."""
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  library = new_go_library(ctx)
-  source = library_to_source(ctx, ctx.attr, library, mode)
-  archive = go_toolchain.actions.archive(ctx, go_toolchain, source)
+  go = go_context(ctx)
+  library = go.new_library(go)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
+  archive = go.archive(go, source)
 
   return [
       library, source, archive,
@@ -54,7 +49,7 @@
         "embed": attr.label_list(providers = [GoLibrary]),
         "gc_goopts": attr.string_list(),
         "_go_prefix": attr.label(default = go_prefix_default),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/rules/source.bzl b/go/private/rules/source.bzl
index 443560b..50b3ab8 100644
--- a/go/private/rules/source.bzl
+++ b/go/private/rules/source.bzl
@@ -20,22 +20,18 @@
 # depend on a globally unique target that has a "go_prefix" transitive
 # info provider.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
 def _go_source_impl(ctx):
   """Implements the go_source() rule."""
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  library = new_go_library(ctx)
-  source = library_to_source(ctx, ctx.attr, library, mode)
+  go = go_context(ctx)
+  library = go.new_library(go)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
   return [library, source]
 
 go_source = rule(
@@ -46,7 +42,7 @@
         "deps": attr.label_list(providers = [GoLibrary]),
         "embed": attr.label_list(providers = [GoLibrary]),
         "gc_goopts": attr.string_list(),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl
index 1a41825..5f01964 100644
--- a/go/private/rules/test.bzl
+++ b/go/private/rules/test.bzl
@@ -12,11 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:common.bzl",
     "go_filetype",
     "split_srcs",
     "pkg_dir",
-    "declare_file",
 )
 load("@io_bazel_rules_go//go/private:rules/prefix.bzl",
     "go_prefix_default",
@@ -24,23 +26,13 @@
 load("@io_bazel_rules_go//go/private:rules/binary.bzl", "gc_linkopts")
 load("@io_bazel_rules_go//go/private:providers.bzl",
     "GoLibrary",
-)
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
     "get_archive",
-    "new_go_library",
-    "library_to_source",
-)
-load("@io_bazel_rules_go//go/private:actions/action.bzl",
-    "add_go_env",
 )
 load("@io_bazel_rules_go//go/private:rules/aspect.bzl",
     "go_archive_aspect",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
-def _testmain_library_to_source(ctx, attr, source):
+def _testmain_library_to_source(go, attr, source, merge):
   source["deps"] = source["deps"] + [attr.library]
 
 def _go_test_impl(ctx):
@@ -49,10 +41,8 @@
   It emits an action to run the test generator, and then compiles the
   test into a binary."""
 
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
+  go = go_context(ctx)
   archive = get_archive(ctx.attr.library)
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, archive.source.mode)
 
   # now generate the main function
   if ctx.attr.rundir:
@@ -63,9 +53,8 @@
   else:
     run_dir = pkg_dir(ctx.label.workspace_root, ctx.label.package)
 
-  main_go = declare_file(ctx, "testmain.go")
-  arguments = ctx.actions.args()
-  add_go_env(arguments, stdlib, archive.source.mode)
+  main_go = go.declare_file(go, "testmain.go")
+  arguments = go.args(go)
   arguments.add([
       '--package',
       archive.source.library.importpath,
@@ -82,7 +71,7 @@
       inputs = go_srcs,
       outputs = [main_go],
       mnemonic = "GoTestGenTest",
-      executable = go_toolchain.tools.test_generator,
+      executable = go.toolchain.tools.test_generator,
       arguments = [arguments],
       env = {
           "RUNDIR" : ctx.label.package,
@@ -90,17 +79,20 @@
   )
 
   # Now compile the test binary itself
-  test_library = new_go_library(ctx,
+  test_library = go.new_library(go,
       resolver=_testmain_library_to_source,
       srcs=[main_go],
       importable=False,
   )
-  test_source = library_to_source(ctx, ctx.attr, test_library, mode)
-  test_archive, executable = go_toolchain.actions.binary(ctx, go_toolchain,
+  test_source = go.library_to_source(go, ctx.attr, test_library, False)
+  test_archive, executable = go.binary(go,
       name = ctx.label.name,
       source = test_source,
       gc_linkopts = gc_linkopts(ctx),
       x_defs=ctx.attr.x_defs,
+      linkstamp=ctx.attr.linkstamp,
+      version_file=ctx.version_file,
+      info_file=ctx.info_file,
   )
 
   runfiles = ctx.runfiles(files = [executable])
@@ -135,7 +127,7 @@
         "rundir": attr.string(),
         "x_defs": attr.string_dict(),
         "_go_prefix": attr.label(default = go_prefix_default),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     executable = True,
     test = True,
diff --git a/go/private/toolchain.bzl b/go/private/sdk.bzl
similarity index 96%
rename from go/private/toolchain.bzl
rename to go/private/sdk.bzl
index 2e74f02..62cee75 100644
--- a/go/private/toolchain.bzl
+++ b/go/private/sdk.bzl
@@ -13,12 +13,7 @@
 # limitations under the License.
 
 load("@io_bazel_rules_go//go/private:common.bzl", "env_execute")
-
-def executable_extension(ctx):
-  extension = ""
-  if ctx.os.name.startswith('windows'):
-    extension = ".exe"
-  return extension
+load("@io_bazel_rules_go//go/private:context.bzl", "executable_extension")
 
 def _go_host_sdk_impl(ctx):
   path = _detect_host_sdk(ctx)
diff --git a/go/private/tools/gazelle.bzl b/go/private/tools/gazelle.bzl
index c20edb3..b6c39a4 100644
--- a/go/private/tools/gazelle.bzl
+++ b/go/private/tools/gazelle.bzl
@@ -12,8 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
 )
 
 _script_content = """
@@ -26,6 +26,7 @@
 def _gazelle_script_impl(ctx):
   # TODO(jayconrod): add a fix to Gazelle to replace invocations of this rule
   # with the new one in @bazel_gazelle. Once in place, fail here.
+  go = go_context(ctx)
   prefix = ctx.attr.prefix if ctx.attr.prefix else ctx.attr._go_prefix.go_prefix
   args = [ctx.attr.command]
   args += [
@@ -38,7 +39,7 @@
     args += ["-build_tags", ",".join(ctx.attr.build_tags)]
   args += ctx.attr.args
   script_content = _script_content.format(gazelle=ctx.file._gazelle.short_path, args=" ".join(args))
-  script_file = declare_file(ctx, ext=".bash")
+  script_file = go.declare_file(go, ext=".bash")
   ctx.actions.write(output=script_file, is_executable=True, content=script_content)
   return struct(
     files = depset([script_file]),
diff --git a/go/private/tools/path.bzl b/go/private/tools/path.bzl
index 646e7b1..311ce23 100644
--- a/go/private/tools/path.bzl
+++ b/go/private/tools/path.bzl
@@ -12,16 +12,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", "GoPath")
-load("@io_bazel_rules_go//go/private:common.bzl", "declare_file")
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl", "get_archive")
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
+load("@io_bazel_rules_go//go/private:providers.bzl",
+    "GoLibrary",
+    "GoPath",
+    "get_archive",
+)
 
-
-def _tag(ctx, path, outputs):
+def _tag(go, path, outputs):
   """this generates a existance tag file for dependencies, and returns the path to the tag file"""
-  tag = declare_file(ctx, path=path+".tag")
+  tag = go.declare_file(go, path=path+".tag")
   path, _, _ = tag.short_path.rpartition("/")
-  ctx.actions.write(tag, content="")
+  go.actions.write(tag, content="")
   outputs.append(tag)
   return path
 
@@ -30,7 +34,7 @@
 EXPERIMENTAL: the go_path rule is still very experimental
 Please do not rely on it for production use, but feel free to use it and file issues
 """)
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
+  go = go_context(ctx)
   #TODO: non specific mode?
   # First gather all the library rules
   golibs = depset()
@@ -64,7 +68,7 @@
         # If we see the same path twice, it's a fatal error
         fail("Duplicate path {}".format(outpath))
       seen_paths[outpath] = True
-      out = declare_file(ctx, path=outpath)
+      out = go.declare_file(go, path=outpath)
       package_files += [out]
       outputs += [out]
       if ctx.attr.mode == "copy":
@@ -81,10 +85,10 @@
         fail("Invalid go path mode '{}'".format(ctx.attr.mode))
     packages += [struct(
       golib = golib,
-      dir = _tag(ctx, prefix, outputs),
+      dir = _tag(go, prefix, outputs),
       files = package_files,
     )]
-  gopath = _tag(ctx, "", outputs)
+  gopath = _tag(go, "", outputs)
   return [
       DefaultInfo(
           files = depset(outputs),
@@ -101,6 +105,7 @@
     attrs = {
         "deps": attr.label_list(providers=[GoLibrary]),
         "mode": attr.string(default="copy", values=["link", "copy"]),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/private/tools/vet.bzl b/go/private/tools/vet.bzl
index 7170c68..783fb78 100644
--- a/go/private/tools/vet.bzl
+++ b/go/private/tools/vet.bzl
@@ -12,26 +12,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
 load("@io_bazel_rules_go//go/private:providers.bzl", "GoPath")
 
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
-)
-
 def _go_vet_generate_impl(ctx):
   print("""
 EXPERIMENTAL: the go_vet_test rule is still very experimental
 Please do not rely on it for production use, but feel free to use it and file issues
 """)
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode)
-  script_file = declare_file(ctx, ext=".bash")
+  go = go_context(ctx)
+  script_file = go.declare_file(go, ext=".bash")
   gopath = []
-  files = ctx.files.data + stdlib.files
+  files = ctx.files.data + go.stdlib.files
   gopath = []
   packages = []
   for data in ctx.attr.data:
@@ -42,7 +36,7 @@
 export GOPATH="{gopath}"
 {go} tool vet {packages}
 """.format(
-      go=stdlib.go.short_path,
+      go=go.stdlib.go.short_path,
       gopath=":".join(['$(pwd)/{})'.format(entry) for entry in gopath]),
       packages=" ".join(packages),
   ))
@@ -55,7 +49,7 @@
     _go_vet_generate_impl,
     attrs = {
         "data": attr.label_list(providers=[GoPath], cfg = "data"),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
diff --git a/go/toolchain/toolchains.bzl b/go/toolchain/toolchains.bzl
index 6e6f9d6..3530792 100644
--- a/go/toolchain/toolchains.bzl
+++ b/go/toolchain/toolchains.bzl
@@ -1,7 +1,7 @@
 load("//go/private:go_toolchain.bzl",
     "go_toolchain",
 )
-load("//go/private:toolchain.bzl",
+load("//go/private:sdk.bzl",
     "go_download_sdk",
     "go_host_sdk",
 )
diff --git a/go/toolchains.rst b/go/toolchains.rst
index 8c11f9f..fe7a2ad 100644
--- a/go/toolchains.rst
+++ b/go/toolchains.rst
@@ -12,6 +12,9 @@
 .. _register_toolchains: https://docs.bazel.build/versions/master/skylark/lib/globals.html#register_toolchains
 .. _compilation modes: modes.rst#compilation-modes
 .. _go assembly: https://golang.org/doc/asm
+.. _GoLibrary: providers.rst#GoLibrary
+.. _GoSource: providers.rst#GoSource
+.. _GoArchive: providers.rst#GoArchive
 
 .. role:: param(kbd)
 .. role:: type(emphasis)
@@ -28,7 +31,7 @@
 Design
 ------
 
-The Go toolchain consists of two main layers, `the sdk`_ and `the toolchain`_.
+The Go toolchain consists of three main layers, `the sdk`_ and `the toolchain`_ and `the context`_.
 
 The SDK
 ~~~~~~~
@@ -56,6 +59,9 @@
 The toolchain
 ~~~~~~~~~~~~~
 
+This a wrapper over the sdk that provides enough extras to match, target and work on a specific
+platforms. It should be considered an opaqute type, you only ever use it through `the context`_.
+
 Declaration
 ^^^^^^^^^^^
 
@@ -97,6 +103,13 @@
 It is important to note that you **must** also register the boostrap toolchain for any other
 toolchain that you register, otherwise the tools for that toolchain cannot be built.
 
+
+
+The context
+~~~~~~~~~~~
+
+This is the type you use if you are writing custom rules that need
+
 Use
 ^^^
 
@@ -109,6 +122,7 @@
       _my_rule_impl,
       attrs = {
           ...
+          "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
       },
       toolchains = ["@io_bazel_rules_go//go:toolchain"],
   )
@@ -227,6 +241,7 @@
         "@io_bazel_rules_go//go/toolchain:1.8.3_darwin_amd64-bootstrap",
     )
 
+
 API
 ---
 
@@ -386,54 +401,139 @@
 | should apply when using this toolchain.                                                          |
 +--------------------------------+-----------------------------+-----------------------------------+
 
-The toolchain object
-~~~~~~~~~~~~~~~~~~~~
+go_context
+~~~~~~~~~~
 
-When you get a Go toolchain from a context (see use_) it exposes a number of fields, of those
-the stable public interface is
+This collects the information needed to form and return a :type:`GoContext` from a rule ctx.
+It uses the attrbutes and the toolchains.
+It can only be used in the implementation of a rule that has the go toolchain attached and
+the go context data as an attribute.
 
-* go_toolchain
+.. code:: bzl
 
-  * actions
+  my_rule = rule(
+      _my_rule_impl,
+      attrs = {
+          ...
+          "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
+      },
+      toolchains = ["@io_bazel_rules_go//go:toolchain"],
+  )
 
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`ctx`                   | :type:`ctx`                 | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| The Bazel ctx object for the current rule.                                                       |
++--------------------------------+-----------------------------+-----------------------------------+
+
+The context object
+~~~~~~~~~~~~~~~~~~
+
+GoContext is never returned by a rule, instead you build one using go_context(ctx) in the top of
+any custom skylark rule that wants to interact with the go rules.
+It provides all the information needed to create go actions, and create or interact with the other
+go providers.
+
+When you get a GoContext from a context (see use_) it exposes a number of fields and methods.
+
+All methods take the GoContext as the only positional argument, all other arguments even if
+mandatory must be specified by name, to allow us to re-order and deprecate individual parameters
+over time.
+
+
+Methods
+*******
+
+  * Action generators
+    * archive_
     * asm_
     * binary_
     * compile_
     * cover_
-    * library_
     * link_
     * pack_
+  * Helpers
+    * args_
+    * declare_file_
+    * library_to_source_
+    * new_library_
 
 
-The only stable public interface is the actions member.
-This holds a collection of functions for generating the standard actions the toolchain knows
-about, compiling and linking for instance.
-All the other members are there to provide information to those action functions, and the api of
-any other part is subject to arbritary breaking changes at any time.
+Fields
+******
 
-All action functions take the ctx and the go_toolchain as the only positional arguments, all
-other arguments even if mandator must be specified by name, to allow us to re-order and
-deprecate individual parameters over time.
++--------------------------------+-----------------------------------------------------------------+
+| **Name**                       | **Type**                                                        |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`toolchain`             | :type:`GoToolchain`                                             |
++--------------------------------+-----------------------------------------------------------------+
+| The underlying toolchain. This should be considered an opaque type subject to change.            |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`mode`                  | :type:`Mode`                                                    |
++--------------------------------+-----------------------------------------------------------------+
+| Controls the compilation setup affecting things like enabling profilers and sanitizers.          |
+| See `compilation modes`_ for more information about the allowed values.                          |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`stdlib`                | :type:`GoStdlib`                                                |
++--------------------------------+-----------------------------------------------------------------+
+| The standard library and tools to use in this build mode.                                        |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`actions`               | :type:`ctx.actions`                                             |
++--------------------------------+-----------------------------------------------------------------+
+| The actions structure from the Bazel context, which has all the methods for building new         |
+| bazel actions.                                                                                   |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`exe_extension`         | :type:`String`                                                  |
++--------------------------------+-----------------------------------------------------------------+
+| The suffix to use for all executables in this build mode. Mostly used when generating the output |
+| filenames of binary rules.                                                                       |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`crosstool`             | :type:`list of File`                                            |
++--------------------------------+-----------------------------------------------------------------+
+| The files you need to add to the inputs of an action in order to use the cc toolchain.           |
++--------------------------------+-----------------------------------------------------------------+
+| :param:`package_list`          | :type:`File`                                                    |
++--------------------------------+-----------------------------------------------------------------+
+| A file that contains the package list of the standard library.                                   |
++--------------------------------+-----------------------------------------------------------------+
+
+
+archive
+~~~~~~~
+
+This emits actions to compile Go code into an archive.
+It supports embedding, cgo dependencies, coverage, and assembling and packing .s files.
+
+It returns a GoArchive_.
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This must be the same GoContext object you got this function from.                               |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`source`                | :type:`GoSource`            | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| The GoSource_ that should be compiled into an archive.                                           |
++--------------------------------+-----------------------------+-----------------------------------+
 
 
 asm
 ~~~
 
 The asm function adds an action that runs ``go tool asm`` on a source file
-to produce an object.
-
-It does not return anything.
+to produce an object, and returns the File of that object.
 
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
 | :param:`source`                | :type:`File`                | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
@@ -444,10 +544,6 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | The list of .h files that may be included by the source.                                         |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`out_obj`               | :type:`File`                | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The output object file that should be built by the generated action.                             |
-+--------------------------------+-----------------------------+-----------------------------------+
 
 
 binary
@@ -461,44 +557,17 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
 | :param:`name`                  | :type:`string`              | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
 | The base name of the generated binaries.                                                         |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`executable`            | :type:`File`                | |mandatory|                       |
+| :param:`source`                | :type:`GoSource`            | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The binary to produce.                                                                           |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`srcs`                  | :type:`File iterable`       | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| An iterable of Go source Files to be compiled.                                                   |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`deps`                  | :type:`GoLibrary iterable`  | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The list of direct dependencies of this package.                                                 |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`cgo_info`              | :type:`CgoInfo`             | :value:`None`                     |
-+--------------------------------+-----------------------------+-----------------------------------+
-| An optional CgoInfo provider for this library.                                                   |
-| There may be at most one of these among the library and its embeds.                              |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`embed`                 | :type:`GoSourceList list`   | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| Sources, dependencies, and other information from these are combined with the package            |
-| being compiled.                                                                                  |
-| Used to build internal test packages.                                                            |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`importpath`            | :type:`string`              | :value:`""`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The import path this package represents.                                                         |
+| The GoSource_ that should be compiled and linked.                                                |
 +--------------------------------+-----------------------------+-----------------------------------+
 | :param:`gc_linkopts`           | :type:`string_list`         | :value:`[]`                       |
 +--------------------------------+-----------------------------+-----------------------------------+
@@ -521,13 +590,9 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
 | :param:`sources`               | :type:`File iterable`       | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
@@ -538,18 +603,13 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | The import path this package represents. This is passed to the -p flag.                          |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`golibs`                | :type:`GoLibrary iterable`  | :value:`[]`                       |
+| :param:`archives`              | :type:`GoArchive iterable`  | :value:`[]`                       |
 +--------------------------------+-----------------------------+-----------------------------------+
 | An iterable of all directly imported libraries.                                                  |
 | The action will verify that all directly imported libraries were supplied, not allowing          |
 | transitive dependencies to satisfy imports. It will not check that all supplied libraries were   |
 | used though.                                                                                     |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`mode`                  | :type:`string`              | :value:`NORMAL_MODE`              |
-+--------------------------------+-----------------------------+-----------------------------------+
-| Controls the compilation setup affecting things like enabling profilers and sanitizers.          |
-| See `compilation modes`_ for more information about the allowed values.                          |
-+--------------------------------+-----------------------------+-----------------------------------+
 | :param:`out_lib`               | :type:`File`                | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
 | The archive file that should be produced.                                                        |
@@ -566,78 +626,22 @@
 The cover function adds an action that runs ``go tool cover`` on a set of source files
 to produce copies with cover instrumentation.
 
-Returns a tuple of the covered source list and the cover vars.
+Returns a tuple of a covered GoSource with the required source files processed for cover and
+the cover vars that were added.
 
 Note that this removes most comments, including cgo comments.
 
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
+| :param:`source`                | :type:`GoSource`            | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`sources`               | :type:`File iterable`       | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| An iterable of Go source files.                                                                  |
-| These Must be pure .go files that are ready to be passed to compile_, no assembly or cgo is      |
-| allowed.                                                                                         |
-+--------------------------------+-----------------------------+-----------------------------------+
-
-
-library
-~~~~~~~
-
-This emits actions to compile Go code into an archive.
-It supports embedding, cgo dependencies, coverage, and assembling and packing .s files.
-
-It returns a tuple of GoLibrary_ and GoSourceList_.
-
-+--------------------------------+-----------------------------+-----------------------------------+
-| **Name**                       | **Type**                    | **Default value**                 |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`srcs`                  | :type:`File iterable`       | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| An iterable of Go source Files to be compiled.                                                   |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`deps`                  | :type:`GoLibrary iterable`  | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The list of direct dependencies of this package.                                                 |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`cgo_info`              | :type:`CgoInfo`             | :value:`None`                     |
-+--------------------------------+-----------------------------+-----------------------------------+
-| An optional CgoInfo provider for this library.                                                   |
-| There may be at most one of these among the library and its embeds.                              |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`embed`                 | :type:`GoSourceList list`   | :value:`[]`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| Sources, dependencies, and other information from these are combined with the package            |
-| being compiled.                                                                                  |
-| Used to build internal test packages.                                                            |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`want_coverage`         | :type:`boolean`             | :value:`False`                    |
-+--------------------------------+-----------------------------+-----------------------------------+
-| A bool indicating whether sources should be instrumented for coverage.                           |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`importpath`            | :type:`string`              | :value:`""`                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| The import path this package represents.                                                         |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`importable`            | :type:`boolean`             | :value:`True`                     |
-+--------------------------------+-----------------------------+-----------------------------------+
-| A bool indicating whether the package can be imported by other libraries.                        |
+| The source object to process. Any source files in the object that have been marked as needing    |
+| coverage will be processed and substiuted in the returned GoSource.                              |
 +--------------------------------+-----------------------------+-----------------------------------+
 
 
@@ -651,23 +655,14 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`library`               | :type:`GoLibrary`           | |mandatory|                       |
+| :param:`archive`               | :type:`GoArchive`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
 | The library to link.                                                                             |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`mode`                  | :type:`string`              | :value:`NORMAL_MODE`              |
-+--------------------------------+-----------------------------+-----------------------------------+
-| Controls the compilation setup affecting things like enabling profilers and sanitizers.          |
-| See `compilation modes`_ for more information about the allowed values.                          |
-+--------------------------------+-----------------------------+-----------------------------------+
 | :param:`executable`            | :type:`File`                | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
 | The binary to produce.                                                                           |
@@ -692,13 +687,9 @@
 +--------------------------------+-----------------------------+-----------------------------------+
 | **Name**                       | **Type**                    | **Default value**                 |
 +--------------------------------+-----------------------------+-----------------------------------+
-| :param:`ctx`                   | :type:`string`              | |mandatory|                       |
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
-| The current rule context, used to generate the actions.                                          |
-+--------------------------------+-----------------------------+-----------------------------------+
-| :param:`go_toolchain`          | :type:`the Go toolchain`    | |mandatory|                       |
-+--------------------------------+-----------------------------+-----------------------------------+
-| This must be the same Go toolchain object you got this function from.                            |
+| This must be the same GoContext object you got this function from.                               |
 +--------------------------------+-----------------------------+-----------------------------------+
 | :param:`in_lib`                | :type:`File`                | |mandatory|                       |
 +--------------------------------+-----------------------------+-----------------------------------+
@@ -719,3 +710,107 @@
 | An additional archive whose objects will be appended to the output.                              |
 | This can be an ar file in either common form or either the bsd or sysv variations.               |
 +--------------------------------+-----------------------------+-----------------------------------+
+
+
+
+args
+~~~~
+
+This creates a new args object, using the ctx.args method, and the populates it with the standard
+arguments used by all the go toolchain builders.
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This must be the same GoContext object you got this function from.                               |
++--------------------------------+-----------------------------+-----------------------------------+
+
+declare_file
+~~~~~~~~~~~~
+
+This is the equivalent of ctx.actions.declare_file except it uses the current build mode to make
+the filename unique between configurations.
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This must be the same GoContext object you got this function from.                               |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`path`                  | :type:`string`              | :value:`""`                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| A path for this file, including the basename of the file.                                        |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`ext`                   | :type:`string`              | :value:`""`                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| The extension to use for the file.                                                               |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`name`                  | :type:`string`              | :value:`""`                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| A name to use for this file. If path is not present, this becomes a prefix to the path.          |
+| If this is not set, the current rule name is used in it's place.                                 |
++--------------------------------+-----------------------------+-----------------------------------+
+
+library_to_source
+~~~~~~~~~~~~~~~~~
+
+This is used to build a GoSource object for a given GoLibrary in the current build mode.
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This must be the same GoContext object you got this function from.                               |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`attr`                  | :type:`ctx.attr`            | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| The attributes of the rule being processed, in a normal rule implementation this would be        |
+| ctx.attr.                                                                                        |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`library`               | :type:`GoLibrary`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| The GoLibrary_ that you want to build a GoSource_ object for in the current build mode.          |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`coverage_instrumented` | :type:`bool`                | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This controls whether cover is enabled for this specific library in this mode.                   |
+| This should generally be the value of ctx.coverage_instrumented()                                |
++--------------------------------+-----------------------------+-----------------------------------+
+
+new_library
+~~~~~~~~~~~
+
+This creates a new GoLibrary.
+You can add extra fields to the go library by providing extra named parameters to this function,
+they will be visible to the resolver when it is invoked.
+
++--------------------------------+-----------------------------+-----------------------------------+
+| **Name**                       | **Type**                    | **Default value**                 |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`go`                    | :type:`GoContext`           | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This must be the same GoContext object you got this function from.                               |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`resolver`              | :type:`function`            | :value:`None`                     |
++--------------------------------+-----------------------------+-----------------------------------+
+| This is the function that gets invoked when converting from a GoLibrary to a GoSource.           |
+| See resolver_ for a                                                                              |
+| The function's signature must be                                                                 |
+|                                                                                                  |
+| .. code:: bzl                                                                                    |
+|                                                                                                  |
+|     def _testmain_library_to_source(go, attr, source, merge)                                     |
+|                                                                                                  |
+| attr is the attributes of the rule being processed                                               |
+| source is the dictionary of GoSource fields being generated                                      |
+| merge is a helper you can call to merge                                                          |
++--------------------------------+-----------------------------+-----------------------------------+
+| :param:`importable`            | :type:`bool`                | |mandatory|                       |
++--------------------------------+-----------------------------+-----------------------------------+
+| This controls whether the GoLibrary_ is supposed to be importable. This is generally only false  |
+| for the "main" libraries that are built just before linking.                                     |
++--------------------------------+-----------------------------+-----------------------------------+
diff --git a/proto/compiler.bzl b/proto/compiler.bzl
index e0c2ea4..be6fb3d 100644
--- a/proto/compiler.bzl
+++ b/proto/compiler.bzl
@@ -12,33 +12,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "declare_file",
-    "sets",
-)
-load("@io_bazel_rules_go//go/private:providers.bzl",
+load("@io_bazel_rules_go//go:def.bzl",
+    "go_context",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-)
-
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
+load("@io_bazel_rules_go//go/private:common.bzl", # TODO: @skylib?
+    "sets",
 )
 
 GoProtoCompiler = provider()
 
-def go_proto_compile(ctx, compiler, proto, imports, importpath):
+def go_proto_compile(go, compiler, proto, imports, importpath):
   go_srcs = []
   outpath = None
   for src in proto.direct_sources:
-    out = declare_file(ctx, path=importpath+"/"+src.basename[:-len(".proto")], ext=compiler.suffix)
+    out = go.declare_file(go, path=importpath+"/"+src.basename[:-len(".proto")], ext=compiler.suffix)
     go_srcs.append(out)
     if outpath == None:
         outpath = out.dirname[:-len(importpath)]
-  args = ctx.actions.args()
+  args = go.actions.args()
   args.add([
       "--protoc", compiler.protoc,
       "--importpath", importpath,
@@ -50,7 +42,7 @@
   args.add(go_srcs, before_each = "--expected")
   args.add(imports, before_each = "--import")
   args.add(proto.direct_sources, map_fn=_all_proto_paths)
-  ctx.actions.run(
+  go.actions.run(
       inputs = sets.union([
           compiler.go_protoc,
           compiler.protoc,
@@ -83,9 +75,9 @@
 
 
 def _go_proto_compiler_impl(ctx):
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
-  library = new_go_library(ctx)
-  source = library_to_source(ctx, ctx.attr, library, mode)
+  go = go_context(ctx)
+  library = go.new_library(go)
+  source = go.library_to_source(go, ctx.attr, library, ctx.coverage_instrumented())
   return [
       GoProtoCompiler(
           deps = ctx.attr.deps,
@@ -126,7 +118,7 @@
             cfg = "host",
             default = Label("@com_github_google_protobuf//:protoc"),
         ),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = [
         "@io_bazel_rules_go//go:toolchain",
diff --git a/proto/def.bzl b/proto/def.bzl
index 7f8ae10..b0704d6 100644
--- a/proto/def.bzl
+++ b/proto/def.bzl
@@ -12,18 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@io_bazel_rules_go//go/private:common.bzl",
-    "go_importpath",
-    "sets",
-)
-load("@io_bazel_rules_go//go/private:providers.bzl",
+load("@io_bazel_rules_go//go:def.bzl",
+    "go_context",
     "GoLibrary",
 )
-load("@io_bazel_rules_go//go/private:rules/helpers.bzl",
-    "new_go_library",
-    "library_to_source",
-    "get_source",
-    "merge_embed",
+load("@io_bazel_rules_go//go/private:common.bzl",
+    "sets",
 )
 load("@io_bazel_rules_go//go/private:rules/prefix.bzl",
     "go_prefix_default",
@@ -31,9 +25,6 @@
 load("@io_bazel_rules_go//proto:compiler.bzl",
     "GoProtoCompiler",
 )
-load("@io_bazel_rules_go//go/private:mode.bzl",
-    "get_mode",
-)
 
 GoProtoImports = provider()
 
@@ -53,28 +44,25 @@
     attr_aspects = ["deps", "embed"],
 )
 
-def _proto_library_to_source(ctx, attr, source):
-  compiler = attr.compiler[GoProtoCompiler]
-  merge_embed(source, attr.compiler)
+def _proto_library_to_source(go, attr, source, merge):
+  merge(source, attr.compiler)
 
 def _go_proto_library_impl(ctx):
-  mode = get_mode(ctx, ctx.attr._go_toolchain_flags)
+  go = go_context(ctx)
   compiler = ctx.attr.compiler[GoProtoCompiler]
-  importpath = go_importpath(ctx)
-  go_srcs = compiler.compile(ctx,
+  importpath = go._inferredpath #TODO: Drop this as soon as the attribute is mandatory
+  go_srcs = compiler.compile(go,
     compiler = compiler,
     proto = ctx.attr.proto.proto,
     imports = get_imports(ctx.attr),
     importpath = importpath,
   )
-  go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"]
-  library = new_go_library(ctx,
+  library = go.new_library(go,
       resolver=_proto_library_to_source,
       srcs=go_srcs,
   )
-  source = library_to_source(ctx, ctx.attr, library, mode)
-  archive = go_toolchain.actions.archive(ctx, go_toolchain, source)
-
+  source = go.library_to_source(go, ctx.attr, library, False)
+  archive = go.archive(go, source)
   return [
       library, source, archive,
       DefaultInfo(
@@ -93,7 +81,7 @@
         "gc_goopts": attr.string_list(),
         "compiler": attr.label(providers = [GoProtoCompiler], default = "@io_bazel_rules_go//proto:go_proto"),
         "_go_prefix": attr.label(default = go_prefix_default),
-        "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
     toolchains = [
         "@io_bazel_rules_go//go:toolchain",
diff --git a/tests/bazel_tests.bzl b/tests/bazel_tests.bzl
index a7f4ce7..14fb75e 100644
--- a/tests/bazel_tests.bzl
+++ b/tests/bazel_tests.bzl
@@ -1,5 +1,9 @@
-load("@io_bazel_rules_go//go/private:go_repository.bzl", "env_execute")
-load("@io_bazel_rules_go//go/private:common.bzl", "declare_file")
+load("@io_bazel_rules_go//go/private:context.bzl",
+    "go_context",
+)
+load("@io_bazel_rules_go//go/private:go_repository.bzl",
+    "env_execute"
+)
 
 # _bazelrc is the bazel.rc file that sets the default options for tests
 _bazelrc = """
@@ -64,7 +68,8 @@
 CURRENT_VERSION = "current"
 
 def _bazel_test_script_impl(ctx):
-  script_file = declare_file(ctx, ext=".bash")
+  go = go_context(ctx)
+  script_file = go.declare_file(go, ext=".bash")
 
   if ctx.attr.go_version == CURRENT_VERSION:
     register = 'go_register_toolchains()\n'
@@ -86,9 +91,9 @@
     workspace_content += _basic_workspace.format()
     workspace_content += register
 
-  workspace_file = declare_file(ctx, path="WORKSPACE.in")
+  workspace_file = go.declare_file(go, path="WORKSPACE.in")
   ctx.actions.write(workspace_file, workspace_content)
-  build_file = declare_file(ctx, path="BUILD.in")
+  build_file = go.declare_file(go, path="BUILD.in")
   ctx.actions.write(build_file, ctx.attr.build)
 
   targets = ["@" + ctx.workspace_name + "//" + ctx.label.package + t if t.startswith(":") else t for t in ctx.attr.targets]
@@ -128,7 +133,9 @@
         "config": attr.string(default="isolate"),
         "_bazelrc": attr.label(allow_files=True, single_file=True, default="@bazel_test//:bazelrc"),
         "_settings": attr.label(default = Label("@bazel_test//:settings")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
+    toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
 
 def bazel_test(name, command = None, args=None, targets = None, go_version = None, tags=[], externals=[], workspace="", build="", check="", config=None):
@@ -166,7 +173,8 @@
   )
 
 def _md5_sum_impl(ctx):
-  out = declare_file(ctx, ext=".md5")
+  go = go_context(ctx)
+  out = go.declare_file(go, ext=".md5")
   arguments = ctx.actions.args()
   arguments.add(["-output", out.path])
   arguments.add(ctx.files.srcs)
@@ -184,7 +192,9 @@
     attrs = {
         "srcs": attr.label_list(allow_files=True),
         "_md5sum":  attr.label(allow_files=True, single_file=True, default=Label("@io_bazel_rules_go//go/tools/builders:md5sum")),
+        "_go_context_data": attr.label(default=Label("@io_bazel_rules_go//:go_context_data")),
     },
+    toolchains = ["@io_bazel_rules_go//go:toolchain"],
 )
 
 def _test_environment_impl(ctx):
diff --git a/tests/cross/cross_test.go b/tests/cross/cross_test.go
index b0c155b..4280202 100644
--- a/tests/cross/cross_test.go
+++ b/tests/cross/cross_test.go
@@ -41,7 +41,7 @@
 		"executable",
 		"x86-64",
 	}},
-	{"windows_amd64_pure_stripped/cross", []string{
+	{"windows_amd64_pure_stripped/cross.exe", []string{
 		"PE32+",
 		"Windows",
 		"executable",
diff --git a/tests/custom_go_toolchain/BUILD.bazel b/tests/custom_go_toolchain/BUILD.bazel
index 20587d2..234afcf 100644
--- a/tests/custom_go_toolchain/BUILD.bazel
+++ b/tests/custom_go_toolchain/BUILD.bazel
@@ -24,7 +24,7 @@
     targets = [":go_default_test"],
     workspace = """
 
-load("@io_bazel_rules_go//go/private:toolchain.bzl", "go_download_sdk")
+load("@io_bazel_rules_go//go:def.bzl", "go_download_sdk")
 load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies")
 
 go_download_sdk(