cmd/go: remove support for -buildmode=shared

It never worked in module mode (or with a read-only GOROOT).
A proposal to drop it was filed (and approved) in
https://golang.org/issue/47788.

Fixes #47788

Change-Id: I0c12f38eb0c5dfe9384fbdb49ed202301fa4273d
Reviewed-on: https://go-review.googlesource.com/c/go/+/359096
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Bryan C. Mills 2021-10-27 14:29:29 -04:00
parent ffd2284db0
commit 68bd5121ee
44 changed files with 30 additions and 1786 deletions

View file

@ -89,6 +89,13 @@ Do not send CLs removing the interior tags from such phrases.
package. package.
</p> </p>
<p><!-- golang.org/issue/47788 -->
The <code>go</code> command no longer supports <code>-linkshared</code>
and <code>-buildmode=shared</code>.
(<code>shared<code> building and linking has never worked in module mode or
when <code>GOROOT</code> is not writable.)
<p>
<p> <p>
TODO: complete this section, or delete if not needed TODO: complete this section, or delete if not needed
</p> </p>

View file

@ -1,78 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package shared_test
import (
"io"
"os"
"path/filepath"
"strings"
)
// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
//
// TODO: Once we no longer need to support the misc module in GOPATH mode,
// factor this function out into a package to reduce duplication.
func overlayDir(dstRoot, srcRoot string) error {
dstRoot = filepath.Clean(dstRoot)
if err := os.MkdirAll(dstRoot, 0777); err != nil {
return err
}
srcRoot, err := filepath.Abs(srcRoot)
if err != nil {
return err
}
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
if err != nil || srcPath == srcRoot {
return err
}
suffix := strings.TrimPrefix(srcPath, srcRoot)
for len(suffix) > 0 && suffix[0] == filepath.Separator {
suffix = suffix[1:]
}
dstPath := filepath.Join(dstRoot, suffix)
perm := info.Mode() & os.ModePerm
if info.Mode()&os.ModeSymlink != 0 {
info, err = os.Stat(srcPath)
if err != nil {
return err
}
perm = info.Mode() & os.ModePerm
}
// Always copy directories (don't symlink them).
// If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() {
return os.MkdirAll(dstPath, perm|0200)
}
// If the OS supports symlinks, use them instead of copying bytes.
if err := os.Symlink(srcPath, dstPath); err == nil {
return nil
}
// Otherwise, copy the bytes.
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
if err != nil {
return err
}
_, err = io.Copy(dst, src)
if closeErr := dst.Close(); err == nil {
err = closeErr
}
return err
})
}

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
package dep2
import "testshared/depBase"
var W int = 1
var hasProg depBase.HasProg
type Dep2 struct {
depBase.Dep
}
func G() int {
return depBase.F() + 1
}

View file

@ -1,22 +0,0 @@
package dep3
// The point of this test file is that it references a type from
// depBase that is also referenced in dep2, but dep2 is loaded by the
// linker before depBase (because it is earlier in the import list).
// There was a bug in the linker where it would not correctly read out
// the type data in this case and later crash.
import (
"testshared/dep2"
"testshared/depBase"
)
type Dep3 struct {
dep depBase.Dep
dep2 dep2.Dep2
}
func D3() int {
var x Dep3
return x.dep.X + x.dep2.X
}

View file

@ -1,10 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gc
#include "textflag.h"
TEXT ·ImplementedInAsm(SB),NOSPLIT,$0-0
RET

View file

@ -1,37 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package depBase
import (
"os"
"reflect"
)
var SlicePtr interface{} = &[]int{}
var V int = 1
var HasMask []string = []string{"hi"}
type HasProg struct {
array [1024]*byte
}
type Dep struct {
X int
}
func (d *Dep) Method() int {
// This code below causes various go.itab.* symbols to be generated in
// the shared library. Similar code in ../exe/exe.go results in
// exercising https://golang.org/issues/17594
reflect.TypeOf(os.Stdout).Elem()
return 10
}
func F() int {
defer func() {}()
return V
}

View file

@ -1,9 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gccgo
package depBase
func ImplementedInAsm() {}

View file

@ -1,9 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build gc
package depBase
func ImplementedInAsm()

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
//go:noinline
func div(x, y uint32) uint32 {
return x / y
}
func main() {
a := div(97, 11)
if a != 8 {
panic("FAIL")
}
}

View file

@ -1,45 +0,0 @@
package main
import (
"os"
"reflect"
"runtime"
"testshared/depBase"
)
// Having a function declared in the main package triggered
// golang.org/issue/18250
func DeclaredInMain() {
}
type C struct {
}
func F() *C {
return nil
}
var slicePtr interface{} = &[]int{}
func main() {
defer depBase.ImplementedInAsm()
// This code below causes various go.itab.* symbols to be generated in
// the executable. Similar code in ../depBase/dep.go results in
// exercising https://golang.org/issues/17594
reflect.TypeOf(os.Stdout).Elem()
runtime.GC()
depBase.V = depBase.F() + 1
var c *C
if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
panic("bad reflection results, see golang.org/issue/18252")
}
sp := reflect.New(reflect.TypeOf(slicePtr).Elem())
s := sp.Interface()
if reflect.TypeOf(s) != reflect.TypeOf(slicePtr) {
panic("bad reflection results, see golang.org/issue/18729")
}
}

View file

@ -1,8 +0,0 @@
package main
import "testshared/dep2"
func main() {
d := &dep2.Dep2{}
dep2.W = dep2.G() + 1 + d.Method()
}

View file

@ -1,7 +0,0 @@
package main
import "testshared/dep3"
func main() {
dep3.D3()
}

View file

@ -1,8 +0,0 @@
package main
/*
*/
import "C"
func main() {
}

View file

@ -1,9 +0,0 @@
package explicit
import (
"testshared/implicit"
)
func E() int {
return implicit.I()
}

View file

@ -1,37 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that GC data is generated correctly for global
// variables with types defined in a shared library.
// See issue 39927.
// This test run under GODEBUG=clobberfree=1. The check
// *x[i] == 12345 depends on this debug mode to clobber
// the value if the object is freed prematurely.
package main
import (
"fmt"
"runtime"
"testshared/gcdata/p"
)
var x p.T
func main() {
for i := range x {
x[i] = new(int)
*x[i] = 12345
}
runtime.GC()
runtime.GC()
runtime.GC()
for i := range x {
if *x[i] != 12345 {
fmt.Printf("x[%d] == %d, want 12345\n", i, *x[i])
panic("FAIL")
}
}
}

View file

@ -1,7 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type T [10]*int

View file

@ -1,71 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"testshared/globallib"
)
//go:noinline
func testLoop() {
for i, s := range globallib.Data {
if s != int64(i) {
panic("testLoop: mismatch")
}
}
}
//go:noinline
func ptrData() *[1<<20 + 10]int64 {
return &globallib.Data
}
//go:noinline
func testMediumOffset() {
for i, s := range globallib.Data[1<<16-2:] {
if s != int64(i)+1<<16-2 {
panic("testMediumOffset: index mismatch")
}
}
x := globallib.Data[1<<16-1]
if x != 1<<16-1 {
panic("testMediumOffset: direct mismatch")
}
y := &globallib.Data[1<<16-3]
if y != &ptrData()[1<<16-3] {
panic("testMediumOffset: address mismatch")
}
}
//go:noinline
func testLargeOffset() {
for i, s := range globallib.Data[1<<20:] {
if s != int64(i)+1<<20 {
panic("testLargeOffset: index mismatch")
}
}
x := globallib.Data[1<<20+1]
if x != 1<<20+1 {
panic("testLargeOffset: direct mismatch")
}
y := &globallib.Data[1<<20+2]
if y != &ptrData()[1<<20+2] {
panic("testLargeOffset: address mismatch")
}
}
func main() {
testLoop()
// SSA rules commonly merge offsets into addresses. These
// tests access global data in different ways to try
// and exercise different SSA rules.
testMediumOffset()
testLargeOffset()
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package globallib
// Data is large enough to that offsets into it do not fit into
// 16-bit or 20-bit immediates. Ideally we'd also try and overrun
// 32-bit immediates, but that requires the test machine to have
// too much memory.
var Data [1<<20 + 10]int64
func init() {
for i := range Data {
Data[i] = int64(i)
}
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "testshared/iface_a"
import "testshared/iface_b"
func main() {
if iface_a.F() != iface_b.F() {
panic("empty interfaces not equal")
}
if iface_a.G() != iface_b.G() {
panic("non-empty interfaces not equal")
}
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package iface_a
import "testshared/iface_i"
//go:noinline
func F() interface{} {
return (*iface_i.T)(nil)
}
//go:noinline
func G() iface_i.I {
return (*iface_i.T)(nil)
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package iface_b
import "testshared/iface_i"
//go:noinline
func F() interface{} {
return (*iface_i.T)(nil)
}
//go:noinline
func G() iface_i.I {
return (*iface_i.T)(nil)
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package iface_i
type I interface {
M()
}
type T struct {
}
func (t *T) M() {
}
// *T implements I

View file

@ -1,5 +0,0 @@
package implicit
func I() int {
return 42
}

View file

@ -1,10 +0,0 @@
package main
import (
"testshared/explicit"
"testshared/implicit"
)
func main() {
println(implicit.I() + explicit.E())
}

View file

@ -1,20 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package issue25065 has a type with a method that is
// 1) referenced in a method expression
// 2) not called
// 3) not converted to an interface
// 4) is a value method but the reference is to the pointer method
// These cases avoid the call to makefuncsym from typecheckfunc, but we
// still need to call makefuncsym somehow or the symbol will not be defined.
package issue25065
type T int
func (t T) M() {}
func F() func(*T) {
return (*T).M
}

View file

@ -1,11 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue30768lib
// S is a struct that requires a generated hash function.
type S struct {
A string
B int
}

View file

@ -1,22 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue30768_test
import (
"testing"
"testshared/issue30768/issue30768lib"
)
type s struct {
s issue30768lib.S
}
func Test30768(t *testing.T) {
// Calling t.Log will convert S to an empty interface,
// which will force a reference to the generated hash function,
// defined in the shared library.
t.Log(s{})
}

View file

@ -1,9 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
import "testshared/issue39777/b"
func F() { b.F() }

View file

@ -1,7 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package b
func F() {}

View file

@ -1,9 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
type ATypeWithALoooooongName interface { // a long name, so the type descriptor symbol name is mangled
M()
}

View file

@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package b
import "testshared/issue44031/a"
type T int
func (T) M() {}
var i = a.ATypeWithALoooooongName(T(0))
func F() {
i.M()
}

View file

@ -1,20 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "testshared/issue44031/b"
type t int
func (t) m() {}
type i interface{ m() } // test that unexported method is correctly marked
var v interface{} = t(0)
func main() {
b.F()
v.(i).m()
}

View file

@ -1,19 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
type A interface {
M()
}
//go:noinline
func TheFuncWithArgA(a A) {
a.M()
}
type ImplA struct{}
//go:noinline
func (A *ImplA) M() {}

View file

@ -1,14 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"testshared/issue47837/a"
)
func main() {
var vara a.ImplA
a.TheFuncWithArgA(&vara)
}

View file

@ -1,9 +0,0 @@
package main
func main() {
// This is enough to make sure that the executable references
// a type descriptor, which was the cause of
// https://golang.org/issue/25970.
c := make(chan int)
_ = c
}

View file

@ -762,9 +762,6 @@ func (t *tester) registerTests() {
if t.supportedBuildmode("c-shared") { if t.supportedBuildmode("c-shared") {
t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".") t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
} }
if t.supportedBuildmode("shared") {
t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".")
}
if t.supportedBuildmode("plugin") { if t.supportedBuildmode("plugin") {
t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".") t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
} }
@ -1047,12 +1044,6 @@ func (t *tester) supportedBuildmode(mode string) bool {
return true return true
} }
return false return false
case "shared":
switch pair {
case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
return true
}
return false
case "plugin": case "plugin":
// linux-arm64 is missing because it causes the external linker // linux-arm64 is missing because it causes the external linker
// to crash, see https://golang.org/issue/17138 // to crash, see https://golang.org/issue/17138

View file

@ -162,9 +162,6 @@
// flags has a similar effect. // flags has a similar effect.
// -ldflags '[pattern=]arg list' // -ldflags '[pattern=]arg list'
// arguments to pass on each go tool link invocation. // arguments to pass on each go tool link invocation.
// -linkshared
// build code that will be linked against shared libraries previously
// created with -buildmode=shared.
// -mod mode // -mod mode
// module download mode to use: readonly, vendor, or mod. // module download mode to use: readonly, vendor, or mod.
// By default, if a vendor directory is present and the go version in go.mod // By default, if a vendor directory is present and the go version in go.mod
@ -778,7 +775,6 @@
// Name string // package name // Name string // package name
// Doc string // package documentation string // Doc string // package documentation string
// Target string // install path // Target string // install path
// Shlib string // the shared library that contains this package (only set when -linkshared)
// Goroot bool // is this package in the Go root? // Goroot bool // is this package in the Go root?
// Standard bool // is this package part of the standard Go library? // Standard bool // is this package part of the standard Go library?
// Stale bool // would 'go install' do anything for this package? // Stale bool // would 'go install' do anything for this package?
@ -1799,11 +1795,6 @@
// non-main packages are built into .a files (the default // non-main packages are built into .a files (the default
// behavior). // behavior).
// //
// -buildmode=shared
// Combine all the listed non-main packages into a single shared
// library that will be used when building with the -linkshared
// option. Packages named main are ignored.
//
// -buildmode=exe // -buildmode=exe
// Build the listed main packages and everything they import into // Build the listed main packages and everything they import into
// executables. Packages not named main are ignored. // executables. Packages not named main are ignored.

View file

@ -726,11 +726,6 @@ are:
non-main packages are built into .a files (the default non-main packages are built into .a files (the default
behavior). behavior).
-buildmode=shared
Combine all the listed non-main packages into a single shared
library that will be used when building with the -linkshared
option. Packages named main are ignored.
-buildmode=exe -buildmode=exe
Build the listed main packages and everything they import into Build the listed main packages and everything they import into
executables. Packages not named main are ignored. executables. Packages not named main are ignored.

View file

@ -23,8 +23,8 @@ import (
"cmd/go/internal/load" "cmd/go/internal/load"
"cmd/go/internal/modinfo" "cmd/go/internal/modinfo"
"cmd/go/internal/modload" "cmd/go/internal/modload"
"cmd/go/internal/work"
"cmd/go/internal/str" "cmd/go/internal/str"
"cmd/go/internal/work"
) )
var CmdList = &base.Command{ var CmdList = &base.Command{
@ -56,7 +56,6 @@ to -f '{{.ImportPath}}'. The struct being passed to the template is:
Name string // package name Name string // package name
Doc string // package documentation string Doc string // package documentation string
Target string // install path Target string // install path
Shlib string // the shared library that contains this package (only set when -linkshared)
Goroot bool // is this package in the Go root? Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library? Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package? Stale bool // would 'go install' do anything for this package?

View file

@ -116,9 +116,6 @@ and test commands:
flags has a similar effect. flags has a similar effect.
-ldflags '[pattern=]arg list' -ldflags '[pattern=]arg list'
arguments to pass on each go tool link invocation. arguments to pass on each go tool link invocation.
-linkshared
build code that will be linked against shared libraries previously
created with -buildmode=shared.
-mod mode -mod mode
module download mode to use: readonly, vendor, or mod. module download mode to use: readonly, vendor, or mod.
By default, if a vendor directory is present and the go version in go.mod By default, if a vendor directory is present and the go version in go.mod

View file

@ -246,16 +246,20 @@ func buildModeInit() {
} }
ldBuildmode = "pie" ldBuildmode = "pie"
case "shared": case "shared":
pkgsFilter = pkgsNotMain if cfg.Goos == "linux" {
if gccgo { switch cfg.Goarch {
codegenArg = "-fPIC" case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
} else { // -buildmode=shared was supported on these platforms at one point, but
codegenArg = "-dynlink" // never really worked in module mode.
// Support was officially dropped as of Go 1.18.
// (See https://golang.org/issue/47788.)
base.Fatalf("-buildmode=shared no longer supported as of Go 1.18")
// TODO(#47788): Remove supporting code for -buildmode=shared.
// (For the Go 1.18 release, we will keep most of the code around but
// disabled to avoid merge conflicts in case we need to revert quickly.)
} }
if cfg.BuildO != "" {
base.Fatalf("-buildmode=shared and -o not supported together")
} }
ldBuildmode = "shared"
case "plugin": case "plugin":
pkgsFilter = oneMainPkg pkgsFilter = oneMainPkg
if gccgo { if gccgo {
@ -274,6 +278,15 @@ func buildModeInit() {
} }
if cfg.BuildLinkshared { if cfg.BuildLinkshared {
if cfg.Goos == "linux" {
switch cfg.Goarch {
case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
base.Fatalf("-linkshared no longer supported as of Go 1.18")
// TODO(#47788): Remove supporting code for linkshared.
// (For the Go 1.18 release, we will keep most of the code around but
// disabled to avoid merge conflicts in case we need to revert quickly.)
}
}
if !sys.BuildModeSupported(cfg.BuildToolchainName, "shared", cfg.Goos, cfg.Goarch) { if !sys.BuildModeSupported(cfg.BuildToolchainName, "shared", cfg.Goos, cfg.Goarch) {
base.Fatalf("-linkshared not supported on %s/%s\n", cfg.Goos, cfg.Goarch) base.Fatalf("-linkshared not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
} }

View file

@ -1,16 +0,0 @@
env GO111MODULE=on
# golang.org/issue/35759: 'go list -linkshared'
# panicked if invoked on a test-only package.
[!buildmode:shared] skip
go list -f '{{.ImportPath}}: {{.Target}} {{.Shlib}}' -linkshared .
stdout '^example.com: $'
-- go.mod --
module example.com
go 1.14
-- x.go --
package x

View file

@ -109,13 +109,6 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
} }
return false return false
case "shared":
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
return true
}
return false
case "plugin": case "plugin":
switch platform { switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le", case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",