diff options
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r-- | src/cmd/cgo/doc.go | 22 | ||||
-rw-r--r-- | src/cmd/cgo/gcc.go | 108 | ||||
-rw-r--r-- | src/cmd/cgo/main.go | 29 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 11 |
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) |