cmd/link, cmd/dist, internal/platform: consolidate c-archive support

Make all the tests for whether -buildmode=c-archive is supported consistent.
Base this on the historical code, on whether cmd/compile supports -shared,
and whether cmd/link permits the mode.

Change-Id: Ib996546906f698ade4c32b8e6c705838e4ad4b90
Reviewed-on: https://go-review.googlesource.com/c/go/+/463984
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 10bca33..d8c5983 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -1141,6 +1141,7 @@
 	return false
 }
 
+// supportedBuildMode reports whether the given build mode is supported.
 func (t *tester) supportedBuildmode(mode string) bool {
 	pair := goos + "-" + goarch
 	switch mode {
@@ -1148,13 +1149,24 @@
 		if !t.extLink() {
 			return false
 		}
-		switch pair {
-		case "aix-ppc64",
-			"darwin-amd64", "darwin-arm64", "ios-arm64",
-			"linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
-			"freebsd-amd64",
-			"windows-amd64", "windows-386":
+		switch goos {
+		case "aix", "darwin", "ios", "windows":
 			return true
+		case "linux":
+			switch goarch {
+			case "386", "amd64", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "riscv64", "s390x":
+				return true
+			default:
+				// Other targets do not support -shared,
+				// per ParseFlags in
+				// cmd/compile/internal/base/flag.go.
+				// For c-archive the Go tool passes -shared,
+				// so that the result is suitable for inclusion
+				// in a PIE or shared library.
+				return false
+			}
+		case "freebsd":
+			return goarch == "amd64"
 		}
 		return false
 	case "c-shared":
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 336cb33..b1774f8 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -27,6 +27,8 @@
 	BuildModePlugin
 )
 
+// Set implements flag.Value to set the build mode based on the argument
+// to the -buildmode flag.
 func (mode *BuildMode) Set(s string) error {
 	badmode := func() error {
 		return fmt.Errorf("buildmode %s not supported on %s/%s", s, buildcfg.GOOS, buildcfg.GOARCH)
diff --git a/src/internal/platform/supported.go b/src/internal/platform/supported.go
index 86c9f07..d8c5b7e 100644
--- a/src/internal/platform/supported.go
+++ b/src/internal/platform/supported.go
@@ -100,9 +100,28 @@
 		return true
 
 	case "c-archive":
-		// TODO(bcmills): This seems dubious.
-		// Do we really support c-archive mode on js/wasm‽
-		return platform != "linux/ppc64"
+		switch goos {
+		case "aix", "darwin", "ios", "windows":
+			return true
+		case "linux":
+			switch goarch {
+			case "386", "amd64", "arm", "armbe", "arm64", "arm64be", "ppc64le", "riscv64", "s390x":
+				// linux/ppc64 not supported because it does
+				// not support external linking mode yet.
+				return true
+			default:
+				// Other targets do not support -shared,
+				// per ParseFlags in
+				// cmd/compile/internal/base/flag.go.
+				// For c-archive the Go tool passes -shared,
+				// so that the result is suitable for inclusion
+				// in a PIE or shared library.
+				return false
+			}
+		case "freebsd":
+			return goarch == "amd64"
+		}
+		return false
 
 	case "c-shared":
 		switch platform {