GoCompilePkg: include export headers in cgo_exports when needed (#2130)

For packages built with cgo in "c-archive" or "c-shared" modes, we'll
now include the generated "_cgo_export.h" (a.k.a. "_cgo_install.h")
headers in GoArchive.cgo_exports. This lets them be picked up by
go_binary_c_archive_shared, which concatenates all of them with a
genrule. That probably isn't correct (it's not what the Go command
does), but it restores old behavior at least.

Also, fixed tests which were happy with an empty header.

Fixes #2128
diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl
index 9e9dfb9..3962b2c 100644
--- a/go/private/actions/archive.bzl
+++ b/go/private/actions/archive.bzl
@@ -23,6 +23,8 @@
 )
 load(
     "@io_bazel_rules_go//go/private:mode.bzl",
+    "LINKMODE_C_ARCHIVE",
+    "LINKMODE_C_SHARED",
     "mode_string",
 )
 load(
@@ -58,6 +60,7 @@
         out_export = None
     searchpath = out_lib.path[:-len(lib_name)]
     testfilter = getattr(source.library, "testfilter", None)
+    out_cgo_export_h = None  # set if cgo used in c-shared or c-archive mode
 
     direct = [get_archive(dep) for dep in source.deps]
     runfiles = source.runfiles
@@ -92,6 +95,8 @@
                 cxxopts = cxxopts,
                 clinkopts = clinkopts,
             )
+            if go.mode.link in (LINKMODE_C_SHARED, LINKMODE_C_ARCHIVE):
+                out_cgo_export_h = go.declare_file(go, path = "_cgo_install.h")
             cgo_deps = cgo.deps
             runfiles = runfiles.merge(cgo.runfiles)
             emit_compilepkg(
@@ -103,6 +108,7 @@
                 archives = direct,
                 out_lib = out_lib,
                 out_export = out_export,
+                out_cgo_export_h = out_cgo_export_h,
                 gc_goopts = source.gc_goopts,
                 cgo = True,
                 cgo_inputs = cgo.inputs,
@@ -204,6 +210,10 @@
     x_defs = dict(source.x_defs)
     for a in direct:
         x_defs.update(a.x_defs)
+    cgo_exports = list(source.cgo_exports)
+    if out_cgo_export_h:
+        cgo_exports.append(out_cgo_export_h)
+    cgo_exports = sets.union(cgo_exports, *[a.cgo_exports for a in direct])
     return GoArchive(
         source = source,
         data = data,
@@ -213,7 +223,7 @@
         transitive = sets.union([data], *[a.transitive for a in direct]),
         x_defs = x_defs,
         cgo_deps = sets.union(cgo_deps, *[a.cgo_deps for a in direct]),
-        cgo_exports = sets.union(source.cgo_exports, *[a.cgo_exports for a in direct]),
+        cgo_exports = cgo_exports,
         runfiles = runfiles,
         mode = go.mode,
     )
diff --git a/go/private/actions/compilepkg.bzl b/go/private/actions/compilepkg.bzl
index c6bbb0b..6030293 100644
--- a/go/private/actions/compilepkg.bzl
+++ b/go/private/actions/compilepkg.bzl
@@ -49,6 +49,7 @@
         cgo_archives = [],
         out_lib = None,
         out_export = None,
+        out_cgo_export_h = None,
         gc_goopts = [],
         testfilter = None):  # TODO: remove when test action compiles packages
     if sources == None:
@@ -84,6 +85,9 @@
         inputs.append(go.nogo)
         inputs.extend([archive.data.export_file for archive in archives if archive.data.export_file])
         outputs.append(out_export)
+    if out_cgo_export_h:
+        args.add("-cgoexport", out_cgo_export_h)
+        outputs.append(out_cgo_export_h)
     if testfilter:
         args.add("-testfilter", testfilter)
 
diff --git a/go/providers.rst b/go/providers.rst
index 6275f75..f62945e 100644
--- a/go/providers.rst
+++ b/go/providers.rst
@@ -247,7 +247,7 @@
 +--------------------------------+-----------------------------------------------------------------+
 | :param:`file`                  | :type:`File`                                                    |
 +--------------------------------+-----------------------------------------------------------------+
-| The archive file produced when this library is coimpiled.                                        |
+| The archive file produced when this library is compiled.                                         |
 +--------------------------------+-----------------------------------------------------------------+
 | :param:`srcs`                  | :type:`tuple of File`                                           |
 +--------------------------------+-----------------------------------------------------------------+
diff --git a/tests/core/c_linkmodes/add.go b/tests/core/c_linkmodes/add.go
index bbb6aee..35084fe 100644
--- a/tests/core/c_linkmodes/add.go
+++ b/tests/core/c_linkmodes/add.go
@@ -1,5 +1,6 @@
 package main
 
+// #define CGO_EXPORT_H_EXISTS
 import "C"
 
 //export GoAdd
diff --git a/tests/core/c_linkmodes/add_test_archive.c b/tests/core/c_linkmodes/add_test_archive.c
index 1f1dbae..1e585a4 100644
--- a/tests/core/c_linkmodes/add_test_archive.c
+++ b/tests/core/c_linkmodes/add_test_archive.c
@@ -1,6 +1,10 @@
 #include <assert.h>
 #include "tests/core/c_linkmodes/adder_archive.h"
 
+#ifndef CGO_EXPORT_H_EXISTS
+#error cgo header did not include define
+#endif
+
 int main(int argc, char** argv) {
     assert(GoAdd(42, 42) == 84);
     return 0;
diff --git a/tests/core/c_linkmodes/add_test_shared.c b/tests/core/c_linkmodes/add_test_shared.c
index 6d8558f..2f57712 100644
--- a/tests/core/c_linkmodes/add_test_shared.c
+++ b/tests/core/c_linkmodes/add_test_shared.c
@@ -1,6 +1,10 @@
 #include <assert.h>
 #include "tests/core/c_linkmodes/adder_shared.h"
 
+#ifndef CGO_EXPORT_H_EXISTS
+#error cgo header did not include define
+#endif
+
 int main(int argc, char** argv) {
     assert(GoAdd(42, 42) == 84);
     return 0;