Skip to content

Commit f70bd91

Browse files
cmd/cgo: use preprocessor macros to avoid prolog redefinitions
Avoid redefinition errors when a Go file uses a cgo comment to There is no particularly good reason to do this, but there is also no particularly good reason that it should fail. Fixes #27019 Change-Id: Icd6f8197a89be4ee6b03ddae675667998a8b4189 Reviewed-on: https://go-review.googlesource.com/c/152079 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent c042fed commit f70bd91

File tree

6 files changed

+130
-1
lines changed

6 files changed

+130
-1
lines changed

misc/cgo/testcshared/cshared_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,46 @@ func copyFile(t *testing.T, dst, src string) {
602602
t.Fatal(err)
603603
}
604604
}
605+
606+
func TestGo2C2Go(t *testing.T) {
607+
t.Parallel()
608+
609+
tmpdir, err := ioutil.TempDir("", "cshared-TestGo2C2Go")
610+
if err != nil {
611+
t.Fatal(err)
612+
}
613+
defer os.RemoveAll(tmpdir)
614+
615+
shlib := filepath.Join(tmpdir, "libtestgo2c2go."+libSuffix)
616+
run(t, gopathEnv, "go", "build", "-buildmode=c-shared", "-o", shlib, "go2c2go/go")
617+
618+
cgoCflags := os.Getenv("CGO_CFLAGS")
619+
if cgoCflags != "" {
620+
cgoCflags += " "
621+
}
622+
cgoCflags += "-I" + tmpdir
623+
624+
cgoLdflags := os.Getenv("CGO_LDFLAGS")
625+
if cgoLdflags != "" {
626+
cgoLdflags += " "
627+
}
628+
cgoLdflags += "-L" + tmpdir + " -ltestgo2c2go"
629+
630+
goenv := append(gopathEnv[:len(gopathEnv):len(gopathEnv)], "CGO_CFLAGS="+cgoCflags, "CGO_LDFLAGS="+cgoLdflags)
631+
632+
ldLibPath := os.Getenv("LD_LIBRARY_PATH")
633+
if ldLibPath != "" {
634+
ldLibPath += ":"
635+
}
636+
ldLibPath += tmpdir
637+
638+
runenv := append(gopathEnv[:len(gopathEnv):len(gopathEnv)], "LD_LIBRARY_PATH="+ldLibPath)
639+
640+
bin := filepath.Join(tmpdir, "m1") + exeSuffix
641+
run(t, goenv, "go", "build", "-o", bin, "go2c2go/m1")
642+
runExe(t, runenv, bin)
643+
644+
bin = filepath.Join(tmpdir, "m2") + exeSuffix
645+
run(t, goenv, "go", "build", "-o", bin, "go2c2go/m2")
646+
runExe(t, runenv, bin)
647+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "C"
8+
9+
//export GoFunc
10+
func GoFunc() int { return 1 }
11+
12+
func main() {}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
#include "libtestgo2c2go.h"
6+
7+
int CFunc(void) {
8+
return (GoFunc() << 8) + 2;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
// extern int CFunc(void);
8+
import "C"
9+
10+
import (
11+
"fmt"
12+
"os"
13+
)
14+
15+
func main() {
16+
got := C.CFunc()
17+
const want = (1 << 8) | 2
18+
if got != want {
19+
fmt.Printf("got %#x, want %#x\n", got, want)
20+
os.Exit(1)
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
// #include "libtestgo2c2go.h"
8+
import "C"
9+
10+
import (
11+
"fmt"
12+
"os"
13+
)
14+
15+
func main() {
16+
got := C.GoFunc()
17+
const want = 1
18+
if got != want {
19+
fmt.Printf("got %#x, want %#x\n", got, want)
20+
os.Exit(1)
21+
}
22+
}

src/cmd/cgo/out.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,7 @@ const builtinProlog = `
15551555
/* Define intgo when compiling with GCC. */
15561556
typedef ptrdiff_t intgo;
15571557
1558+
#define GO_CGO_GOSTRING_TYPEDEF
15581559
typedef struct { const char *p; intgo n; } _GoString_;
15591560
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
15601561
_GoString_ GoString(char *p);
@@ -1806,15 +1807,20 @@ void localCgoCheckResult(Eface val) {
18061807
// because _cgo_export.h defines GoString as a struct while builtinProlog
18071808
// defines it as a function. We don't change this to avoid unnecessarily
18081809
// breaking existing code.
1810+
// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
1811+
// error if a Go file with a cgo comment #include's the export header
1812+
// generated by a different package.
18091813
const builtinExportProlog = `
1810-
#line 1 "cgo-builtin-prolog"
1814+
#line 1 "cgo-builtin-export-prolog"
18111815
18121816
#include <stddef.h> /* for ptrdiff_t below */
18131817
18141818
#ifndef GO_CGO_EXPORT_PROLOGUE_H
18151819
#define GO_CGO_EXPORT_PROLOGUE_H
18161820
1821+
#ifndef GO_CGO_GOSTRING_TYPEDEF
18171822
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
1823+
#endif
18181824
18191825
#endif
18201826
`
@@ -1823,6 +1829,19 @@ func (p *Package) gccExportHeaderProlog() string {
18231829
return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
18241830
}
18251831

1832+
// gccExportHeaderProlog is written to the exported header, after the
1833+
// import "C" comment preamble but before the generated declarations
1834+
// of exported functions. This permits the generated declarations to
1835+
// use the type names that appear in goTypes, above.
1836+
//
1837+
// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
1838+
// error if a Go file with a cgo comment #include's the export header
1839+
// generated by a different package. Unfortunately GoString means two
1840+
// different things: in this prolog it means a C name for the Go type,
1841+
// while in the prolog written into the start of the C code generated
1842+
// from a cgo-using Go file it means the C.GoString function. There is
1843+
// no way to resolve this conflict, but it also doesn't make much
1844+
// difference, as Go code never wants to refer to the latter meaning.
18261845
const gccExportHeaderProlog = `
18271846
/* Start of boilerplate cgo prologue. */
18281847
#line 1 "cgo-gcc-export-header-prolog"
@@ -1852,7 +1871,9 @@ typedef double _Complex GoComplex128;
18521871
*/
18531872
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
18541873
1874+
#ifndef GO_CGO_GOSTRING_TYPEDEF
18551875
typedef _GoString_ GoString;
1876+
#endif
18561877
typedef void *GoMap;
18571878
typedef void *GoChan;
18581879
typedef struct { void *t; void *v; } GoInterface;

0 commit comments

Comments
 (0)