summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/doc.go22
-rw-r--r--src/cmd/cgo/gcc.go108
-rw-r--r--src/cmd/cgo/main.go29
-rw-r--r--src/cmd/cgo/out.go11
4 files changed, 54 insertions, 116 deletions
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 955b7c495..a1b02d4be 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -70,7 +70,7 @@ assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
- n, err := C.atoi("abc")
+ n, err := C.sqrt(-1)
_, err := C.voidFunc()
In C, a function argument written as a fixed size array
@@ -463,7 +463,7 @@ The directives are:
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
- A side effect of the cgo_dynamic_import directive with a
+ A side effect of the cgo_import_dynamic directive with a
library is to make the final binary depend on that dynamic
library. To get the dependency without importing any specific
symbols, use _ for local and remote.
@@ -472,7 +472,7 @@ The directives are:
#pragma cgo_import_dynamic _ _ "libc.so.6"
For compatibility with current versions of SWIG,
- #pragma dynimport is an alias for #pragma cgo_dynamic_import.
+ #pragma dynimport is an alias for #pragma cgo_import_dynamic.
#pragma cgo_dynamic_linker "<path>"
@@ -484,16 +484,16 @@ The directives are:
Example:
#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
-#pragma cgo_export <local> <remote>
+#pragma cgo_export_dynamic <local> <remote>
- In both internal and external linking modes, put the Go symbol
+ In internal linking mode, put the Go symbol
named <local> into the program's exported symbol table as
<remote>, so that C code can refer to it by that name. This
mechanism makes it possible for C code to call back into Go or
to share Go's data.
For compatibility with current versions of SWIG,
- #pragma dynexport is an alias for #pragma cgo_export.
+ #pragma dynexport is an alias for #pragma cgo_export_dynamic.
#pragma cgo_import_static <local>
@@ -505,6 +505,14 @@ The directives are:
Example:
#pragma cgo_import_static puts_wrapper
+#pragma cgo_export_static <local> <remote>
+
+ In external linking mode, put the Go symbol
+ named <local> into the program's exported symbol table as
+ <remote>, so that C code can refer to it by that name. This
+ mechanism makes it possible for C code to call back into Go or
+ to share Go's data.
+
#pragma cgo_ldflag "<arg>"
In external linking mode, invoke the host linker (usually gcc)
@@ -565,7 +573,7 @@ The directives in the 6c-compiled file are used according to the kind
of final link used.
In internal mode, 6l itself processes all the host object files, in
-particular foo.cgo2.o. To do so, it uses the cgo_dynamic_import and
+particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
cgo_dynamic_linker directives to learn that the otherwise undefined
reference to sin in foo.cgo2.o should be rewritten to refer to the
symbol sin with version GLIBC_2.2.5 from the dynamic library
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 4b0a521a8..bc7a6472f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -66,71 +66,16 @@ func cname(s string) string {
return s
}
-// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
-// preamble. Multiple occurrences are concatenated with a separating space,
-// even across files.
-func (p *Package) ParseFlags(f *File, srcfile string) {
+// DiscardCgoDirectives processes the import C preamble, and discards
+// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
+// way into _cgo_export.h.
+func (f *File) DiscardCgoDirectives() {
linesIn := strings.Split(f.Preamble, "\n")
linesOut := make([]string, 0, len(linesIn))
-
-NextLine:
for _, line := range linesIn {
l := strings.TrimSpace(line)
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
linesOut = append(linesOut, line)
- continue
- }
-
- l = strings.TrimSpace(l[4:])
- fields := strings.SplitN(l, ":", 2)
- if len(fields) != 2 {
- fatalf("%s: bad #cgo line: %s", srcfile, line)
- }
-
- var k string
- kf := strings.Fields(fields[0])
- switch len(kf) {
- case 1:
- k = kf[0]
- case 2:
- k = kf[1]
- switch kf[0] {
- case goos:
- case goarch:
- case goos + "/" + goarch:
- default:
- continue NextLine
- }
- default:
- fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
- }
-
- args, err := splitQuoted(fields[1])
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- for _, arg := range args {
- if !safeName(arg) {
- fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
- }
- }
-
- switch k {
-
- case "CFLAGS", "LDFLAGS":
- p.addToFlag(k, args)
-
- case "pkg-config":
- cflags, ldflags, err := pkgConfig(args)
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- p.addToFlag("CFLAGS", cflags)
- p.addToFlag("LDFLAGS", ldflags)
-
- default:
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
-
}
}
f.Preamble = strings.Join(linesOut, "\n")
@@ -139,47 +84,13 @@ NextLine:
// addToFlag appends args to flag. All flags are later written out onto the
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
- if oldv, ok := p.CgoFlags[flag]; ok {
- p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
- } else {
- p.CgoFlags[flag] = strings.Join(args, " ")
- }
+ p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
if flag == "CFLAGS" {
// We'll also need these when preprocessing for dwarf information.
p.GccOptions = append(p.GccOptions, args...)
}
}
-// pkgConfig runs pkg-config and extracts --libs and --cflags information
-// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err error) {
- for _, name := range packages {
- if len(name) == 0 || name[0] == '-' {
- return nil, nil, errors.New(fmt.Sprintf("invalid name: %q", name))
- }
- }
-
- args := append([]string{"pkg-config", "--cflags"}, packages...)
- stdout, stderr, ok := run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- cflags, err = splitQuoted(string(stdout))
- if err != nil {
- return
- }
-
- args = append([]string{"pkg-config", "--libs"}, packages...)
- stdout, stderr, ok = run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- ldflags, err = splitQuoted(string(stdout))
- return
-}
-
// splitQuoted splits the string s around each instance of one or more consecutive
// white space characters while taking into account quotes and escaping, and
// returns an array of substrings of s or an empty list if s contains only white space.
@@ -898,6 +809,15 @@ func (p *Package) gccDefines(stdin []byte) string {
func (p *Package) gccErrors(stdin []byte) string {
// TODO(rsc): require failure
args := p.gccCmd()
+
+ // GCC 4.8.0 has a bug: it sometimes does not apply
+ // -Wunused-value to values that are macros defined in system
+ // headers. See issue 5118. Adding -Wsystem-headers avoids
+ // that problem. This will produce additional errors, but it
+ // doesn't matter because we will ignore all errors that are
+ // not marked for the cgo-test file.
+ args = append(args, "-Wsystem-headers")
+
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
os.Stderr.Write(stdin)
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 7adc795de..9bd326e1d 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -33,7 +33,7 @@ type Package struct {
PtrSize int64
IntSize int64
GccOptions []string
- CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
+ CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
Written map[string]bool
Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
@@ -208,6 +208,15 @@ func main() {
p := newPackage(args[:i])
+ // Record CGO_LDFLAGS from the environment for external linking.
+ if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
+ args, err := splitQuoted(ldflags)
+ if err != nil {
+ fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
+ }
+ p.addToFlag("LDFLAGS", args)
+ }
+
// Need a unique prefix for the global C symbols that
// we use to coordinate between gcc and ourselves.
// We already put _cgo_ at the beginning, so the main
@@ -226,10 +235,9 @@ func main() {
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
- // Parse flags for all files before translating due to CFLAGS.
f := new(File)
f.ReadGo(input)
- p.ParseFlags(f, input)
+ f.DiscardCgoDirectives()
fs[i] = f
}
@@ -282,11 +290,6 @@ func main() {
// newPackage returns a new Package that will invoke
// gcc with the additional arguments specified in args.
func newPackage(args []string) *Package {
- // Copy the gcc options to a new slice so the list
- // can grow without overwriting the slice that args is in.
- gccOptions := make([]string, len(args))
- copy(gccOptions, args)
-
goarch = runtime.GOARCH
if s := os.Getenv("GOARCH"); s != "" {
goarch = s
@@ -309,12 +312,12 @@ func newPackage(args []string) *Package {
os.Setenv("LC_ALL", "C")
p := &Package{
- PtrSize: ptrSize,
- IntSize: intSize,
- GccOptions: gccOptions,
- CgoFlags: make(map[string]string),
- Written: make(map[string]bool),
+ PtrSize: ptrSize,
+ IntSize: intSize,
+ CgoFlags: make(map[string][]string),
+ Written: make(map[string]bool),
}
+ p.addToFlag("CFLAGS", args)
return p
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index a126cf17f..ee1d89142 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -31,7 +31,12 @@ func (p *Package) writeDefs() {
fflg := creat(*objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
+ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
+ if k == "LDFLAGS" {
+ for _, arg := range v {
+ fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
+ }
+ }
}
fflg.Close()
@@ -100,6 +105,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+ fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
cVars[n.C] = true
@@ -651,8 +657,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "#pragma cgo_export %s\n", goname)
+ fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
fmt.Fprintf(fc, "extern void ยท%s();\n\n", goname)
+ fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
fmt.Fprintf(fc, "void\n")
fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)