mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/go, cmd/cgo: support older versions of gccgo that lack cgo.Incomplete
Test whether gccgo/GoLLVM supports cgo.Incomplete. If it doesn't, use a local definition rather than importing it. Roll back 426496, which skipped a gccgo test, as it now works. For #46731 Fixes #54761 Change-Id: I8bb2ad84c317094495405e178bf5c9694f82af56 Reviewed-on: https://go-review.googlesource.com/c/go/+/446260 Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
91a1f0d918
commit
3c17053bba
7 changed files with 93 additions and 12 deletions
|
|
@ -498,6 +498,9 @@ The following options are available when running cgo directly:
|
||||||
The -fgo-prefix option to be used with gccgo.
|
The -fgo-prefix option to be used with gccgo.
|
||||||
-gccgopkgpath path
|
-gccgopkgpath path
|
||||||
The -fgo-pkgpath option to be used with gccgo.
|
The -fgo-pkgpath option to be used with gccgo.
|
||||||
|
-gccgo_define_cgoincomplete
|
||||||
|
Define cgo.Incomplete locally rather than importing it from
|
||||||
|
the "runtime/cgo" package. Used for old gccgo versions.
|
||||||
-godefs
|
-godefs
|
||||||
Write out input file in Go syntax replacing C package
|
Write out input file in Go syntax replacing C package
|
||||||
names with real values. Used to generate files in the
|
names with real values. Used to generate files in the
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ var nameToC = map[string]string{
|
||||||
"complexdouble": "double _Complex",
|
"complexdouble": "double _Complex",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var incomplete = "_cgopackage.Incomplete"
|
||||||
|
|
||||||
// cname returns the C name to use for C.s.
|
// cname returns the C name to use for C.s.
|
||||||
// The expansions are listed in nameToC and also
|
// The expansions are listed in nameToC and also
|
||||||
// struct_foo becomes "struct foo", and similarly for
|
// struct_foo becomes "struct foo", and similarly for
|
||||||
|
|
@ -2565,7 +2567,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||||
// get writebarrier-ed or adjusted during a stack copy. This should handle
|
// get writebarrier-ed or adjusted during a stack copy. This should handle
|
||||||
// all the cases badPointerTypedef used to handle, but hopefully will
|
// all the cases badPointerTypedef used to handle, but hopefully will
|
||||||
// continue to work going forward without any more need for cgo changes.
|
// continue to work going forward without any more need for cgo changes.
|
||||||
tt.Go = c.Ident("_cgopackage.Incomplete")
|
tt.Go = c.Ident(incomplete)
|
||||||
typedef[name.Name] = &tt
|
typedef[name.Name] = &tt
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -2592,7 +2594,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||||
}
|
}
|
||||||
tt.Go = g
|
tt.Go = g
|
||||||
if c.incompleteStructs[tag] {
|
if c.incompleteStructs[tag] {
|
||||||
tt.Go = c.Ident("_cgopackage.Incomplete")
|
tt.Go = c.Ident(incomplete)
|
||||||
}
|
}
|
||||||
typedef[name.Name] = &tt
|
typedef[name.Name] = &tt
|
||||||
}
|
}
|
||||||
|
|
@ -2640,7 +2642,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||||
if c.badVoidPointerTypedef(dt) {
|
if c.badVoidPointerTypedef(dt) {
|
||||||
// Treat this typedef as a pointer to a _cgopackage.Incomplete.
|
// Treat this typedef as a pointer to a _cgopackage.Incomplete.
|
||||||
s := *sub
|
s := *sub
|
||||||
s.Go = c.Ident("*_cgopackage.Incomplete")
|
s.Go = c.Ident("*" + incomplete)
|
||||||
sub = &s
|
sub = &s
|
||||||
// Make sure we update any previously computed type.
|
// Make sure we update any previously computed type.
|
||||||
if oldType := typedef[name.Name]; oldType != nil {
|
if oldType := typedef[name.Name]; oldType != nil {
|
||||||
|
|
@ -2656,7 +2658,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||||
// Make sure we update any previously computed type.
|
// Make sure we update any previously computed type.
|
||||||
name := "_Ctype_struct_" + strct.StructName
|
name := "_Ctype_struct_" + strct.StructName
|
||||||
if oldType := typedef[name]; oldType != nil {
|
if oldType := typedef[name]; oldType != nil {
|
||||||
oldType.Go = c.Ident("_cgopackage.Incomplete")
|
oldType.Go = c.Ident(incomplete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3196,7 +3198,7 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
|
||||||
// non-pointers in this type.
|
// non-pointers in this type.
|
||||||
// TODO: Currently our best solution is to find these manually and list them as
|
// TODO: Currently our best solution is to find these manually and list them as
|
||||||
// they come up. A better solution is desired.
|
// they come up. A better solution is desired.
|
||||||
// Note: DEPRECATED. There is now a better solution. Search for _cgopackage.Incomplete in this file.
|
// Note: DEPRECATED. There is now a better solution. Search for incomplete in this file.
|
||||||
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||||
if c.badCFType(dt) {
|
if c.badCFType(dt) {
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
|
||||||
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
|
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
|
||||||
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
|
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
|
||||||
var gccgoMangler func(string) string
|
var gccgoMangler func(string) string
|
||||||
|
var gccgoDefineCgoIncomplete = flag.Bool("gccgo_define_cgoincomplete", false, "define cgo.Incomplete for older gccgo/GoLLVM")
|
||||||
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
||||||
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
||||||
var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||||
|
|
@ -253,6 +254,14 @@ func main() {
|
||||||
objabi.AddVersionFlag() // -V
|
objabi.AddVersionFlag() // -V
|
||||||
objabi.Flagparse(usage)
|
objabi.Flagparse(usage)
|
||||||
|
|
||||||
|
if *gccgoDefineCgoIncomplete {
|
||||||
|
if !*gccgo {
|
||||||
|
fmt.Fprintf(os.Stderr, "cgo: -gccgo_define_cgoincomplete without -gccgo\n")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
incomplete = "_cgopackage_Incomplete"
|
||||||
|
}
|
||||||
|
|
||||||
if *dynobj != "" {
|
if *dynobj != "" {
|
||||||
// cgo -dynimport is essentially a separate helper command
|
// cgo -dynimport is essentially a separate helper command
|
||||||
// built into the cgo binary. It scans a gcc-produced executable
|
// built into the cgo binary. It scans a gcc-produced executable
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,13 @@ func (p *Package) writeDefs() {
|
||||||
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
||||||
}
|
}
|
||||||
if *importRuntimeCgo {
|
if *importRuntimeCgo {
|
||||||
fmt.Fprintf(fgo2, "import _cgopackage \"runtime/cgo\"\n\n")
|
if !*gccgoDefineCgoIncomplete {
|
||||||
fmt.Fprintf(fgo2, "type _ _cgopackage.Incomplete\n") // prevent import-not-used error
|
fmt.Fprintf(fgo2, "import _cgopackage \"runtime/cgo\"\n\n")
|
||||||
|
fmt.Fprintf(fgo2, "type _ _cgopackage.Incomplete\n") // prevent import-not-used error
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(fgo2, "//go:notinheap\n")
|
||||||
|
fmt.Fprintf(fgo2, "type _cgopackage_Incomplete struct{ _ struct{ _ struct{} } }\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if *importSyscall {
|
if *importSyscall {
|
||||||
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
|
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
|
||||||
|
|
|
||||||
|
|
@ -2953,6 +2953,9 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||||
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
|
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
|
||||||
cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
|
cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
|
||||||
}
|
}
|
||||||
|
if !BuildToolchain.(gccgoToolchain).supportsCgoIncomplete(b) {
|
||||||
|
cgoflags = append(cgoflags, "-gccgo_define_cgoincomplete")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch cfg.BuildBuildmode {
|
switch cfg.BuildBuildmode {
|
||||||
|
|
|
||||||
|
|
@ -617,3 +617,63 @@ func (tools gccgoToolchain) gccgoCleanPkgpath(b *Builder, p *load.Package) strin
|
||||||
|
|
||||||
return gccgoToSymbolFunc(gccgoPkgpath(p))
|
return gccgoToSymbolFunc(gccgoPkgpath(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
gccgoSupportsCgoIncompleteOnce sync.Once
|
||||||
|
gccgoSupportsCgoIncomplete bool
|
||||||
|
)
|
||||||
|
|
||||||
|
const gccgoSupportsCgoIncompleteCode = `
|
||||||
|
package p
|
||||||
|
|
||||||
|
import "runtime/cgo"
|
||||||
|
|
||||||
|
type I cgo.Incomplete
|
||||||
|
`
|
||||||
|
|
||||||
|
// supportsCgoIncomplete reports whether the gccgo/GoLLVM compiler
|
||||||
|
// being used supports cgo.Incomplete, which was added in GCC 13.
|
||||||
|
func (tools gccgoToolchain) supportsCgoIncomplete(b *Builder) bool {
|
||||||
|
gccgoSupportsCgoIncompleteOnce.Do(func() {
|
||||||
|
fail := func(err error) {
|
||||||
|
fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err)
|
||||||
|
base.SetExitStatus(2)
|
||||||
|
base.Exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpdir := b.WorkDir
|
||||||
|
if cfg.BuildN {
|
||||||
|
tmpdir = os.TempDir()
|
||||||
|
}
|
||||||
|
f, err := os.CreateTemp(tmpdir, "*_gccgo_cgoincomplete.go")
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
fn := f.Name()
|
||||||
|
f.Close()
|
||||||
|
defer os.Remove(fn)
|
||||||
|
|
||||||
|
if err := os.WriteFile(fn, []byte(gccgoSupportsCgoIncompleteCode), 0644); err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
on := strings.TrimSuffix(fn, ".go") + ".o"
|
||||||
|
if cfg.BuildN || cfg.BuildX {
|
||||||
|
b.Showcmd(tmpdir, "%s -c -o %s %s || true", tools.compiler(), on, fn)
|
||||||
|
// Since this function affects later builds,
|
||||||
|
// and only generates temporary files,
|
||||||
|
// we run the command even with -n.
|
||||||
|
}
|
||||||
|
cmd := exec.Command(tools.compiler(), "-c", "-o", on, fn)
|
||||||
|
cmd.Dir = tmpdir
|
||||||
|
var buf strings.Builder
|
||||||
|
cmd.Stdout = &buf
|
||||||
|
cmd.Stderr = &buf
|
||||||
|
err = cmd.Run()
|
||||||
|
if out := buf.String(); len(out) > 0 {
|
||||||
|
b.showOutput(nil, tmpdir, b.fmtcmd(tmpdir, "%s -c -o %s %s", tools.compiler(), on, fn), buf.String())
|
||||||
|
}
|
||||||
|
gccgoSupportsCgoIncomplete = err == nil
|
||||||
|
})
|
||||||
|
return gccgoSupportsCgoIncomplete
|
||||||
|
}
|
||||||
|
|
|
||||||
9
src/cmd/go/testdata/script/build_overlay.txt
vendored
9
src/cmd/go/testdata/script/build_overlay.txt
vendored
|
|
@ -83,11 +83,6 @@ go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -tr
|
||||||
exec ./print_trimpath_gccgo$GOEXE
|
exec ./print_trimpath_gccgo$GOEXE
|
||||||
stdout ^\.[/\\]printpath[/\\]main.go
|
stdout ^\.[/\\]printpath[/\\]main.go
|
||||||
|
|
||||||
go build -compiler=gccgo -overlay overlay.json -o main_call_asm_gccgo$GOEXE ./call_asm
|
|
||||||
exec ./main_call_asm_gccgo$GOEXE
|
|
||||||
! stdout .
|
|
||||||
|
|
||||||
skip 'broken as of CL 421879: see https://go.dev/issue/54761'
|
|
||||||
|
|
||||||
go build -compiler=gccgo -overlay overlay.json -o main_cgo_replace_gccgo$GOEXE ./cgo_hello_replace
|
go build -compiler=gccgo -overlay overlay.json -o main_cgo_replace_gccgo$GOEXE ./cgo_hello_replace
|
||||||
exec ./main_cgo_replace_gccgo$GOEXE
|
exec ./main_cgo_replace_gccgo$GOEXE
|
||||||
|
|
@ -101,6 +96,10 @@ go build -compiler=gccgo -overlay overlay.json -o main_cgo_angle_gccgo$GOEXE ./
|
||||||
exec ./main_cgo_angle_gccgo$GOEXE
|
exec ./main_cgo_angle_gccgo$GOEXE
|
||||||
stdout '^hello cgo\r?\n'
|
stdout '^hello cgo\r?\n'
|
||||||
|
|
||||||
|
go build -compiler=gccgo -overlay overlay.json -o main_call_asm_gccgo$GOEXE ./call_asm
|
||||||
|
exec ./main_call_asm_gccgo$GOEXE
|
||||||
|
! stdout .
|
||||||
|
|
||||||
|
|
||||||
-- m/go.mod --
|
-- m/go.mod --
|
||||||
// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly)
|
// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue