summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-03-26 16:50:58 +0200
committerOndřej Surý <ondrej@sury.org>2012-03-26 16:50:58 +0200
commit519725bb3c075ee2462c929f5997cb068e18466a (patch)
tree5b162e8488ad147a645048c073577821b4a2bee9 /src/cmd/cgo
parent842623c5dd2819d980ca9c58048d6bc6ed82475f (diff)
downloadgolang-upstream-weekly/2012.03.22.tar.gz
Imported Upstream version 2012.03.22upstream-weekly/2012.03.22
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/doc.go13
-rw-r--r--src/cmd/cgo/main.go3
-rw-r--r--src/cmd/cgo/out.go107
3 files changed, 113 insertions, 10 deletions
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index f6a14ae08..1bb48f44e 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -44,6 +44,11 @@ For example:
// #include <png.h>
import "C"
+The CGO_CFLAGS and CGO_LDFLAGS environment variables are added
+to the flags derived from these directives. Package-specific flags should
+be set using the directives, not the environment variables, so that builds
+work in unmodified environments.
+
Within the Go file, C identifiers or field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
@@ -111,13 +116,13 @@ Not all Go types can be mapped to C types in a useful way.
Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
-The standard package makefile rules in Make.pkg automate the
-process of using cgo. See $GOROOT/misc/cgo/stdio and
-$GOROOT/misc/cgo/gmp for examples.
+The standard package construction rules of the go command
+automate the process of using cgo. See $GOROOT/misc/cgo/stdio
+and $GOROOT/misc/cgo/gmp for examples.
Cgo does not yet work with gccgo.
See "C? Go? Cgo!" for an introduction to using cgo:
-http://blog.golang.org/2011/03/c-go-cgo.html
+http://golang.org/doc/articles/c_go_cgo.html
*/
package documentation
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index a8be7be7d..7449f04c4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -136,6 +136,7 @@ var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C
var objDir = flag.String("objdir", "", "object directory")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "go", "prefix of symbols generated by gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var goarch, goos string
@@ -147,7 +148,7 @@ func main() {
// cgo -dynimport is essentially a separate helper command
// built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
- // imported libraries. The Make.pkg rules for cgo prepare an
+ // imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 4dc0f8454..814250c2e 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -107,7 +107,11 @@ func (p *Package) writeDefs() {
}
}
- p.writeExports(fgo2, fc, fm)
+ if *gccgo {
+ p.writeGccgoExports(fgo2, fc, fm)
+ } else {
+ p.writeExports(fgo2, fc, fm)
+ }
fgo2.Close()
fc.Close()
@@ -280,8 +284,13 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
conf.Fprint(fgo2, fset, d)
fmt.Fprintf(fgo2, "{\n")
+ fmt.Fprintf(fgo2, "\tsyscall.SetErrno(0)\n")
fmt.Fprintf(fgo2, "\tr := %s(%s)\n", cname, strings.Join(paramnames, ", "))
- fmt.Fprintf(fgo2, "\treturn r, syscall.GetErrno()\n")
+ fmt.Fprintf(fgo2, "\te := syscall.GetErrno()\n")
+ fmt.Fprintf(fgo2, "\tif e != 0 {\n")
+ fmt.Fprintf(fgo2, "\t\treturn r, e\n")
+ fmt.Fprintf(fgo2, "\t}\n")
+ fmt.Fprintf(fgo2, "\treturn r, nil\n")
fmt.Fprintf(fgo2, "}\n")
// declare the C function.
fmt.Fprintf(fgo2, "//extern %s\n", n.C)
@@ -411,10 +420,20 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i := range n.FuncType.Params {
+ for i, t := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
+ // We know the type params are correct, because
+ // the Go equivalents had good type params.
+ // However, our version of the type omits the magic
+ // words const and volatile, which can provoke
+ // C compiler warnings. Silence them by casting
+ // all pointers to void*. (Eventually that will produce
+ // other warnings.)
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -563,8 +582,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname)
- fmt.Fprintf(fc, "extern void ·%s();\n", goname)
- fmt.Fprintf(fc, "\nvoid\n")
+ fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+ 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)
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
@@ -613,6 +633,83 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
}
}
+// Write out the C header allowing C code to call exported gccgo functions.
+func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+ fgcc := creat(*objDir + "_cgo_export.c")
+ fgcch := creat(*objDir + "_cgo_export.h")
+ _ = fgcc
+
+ fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
+ fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
+
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ gccgoSymbolPrefix := strings.Map(clean, *gccgoprefix)
+
+ for _, exp := range p.ExpFunc {
+ // TODO: support functions with receivers.
+ fn := exp.Func
+ fntype := fn.Type
+
+ if !ast.IsExported(fn.Name.Name) {
+ fatalf("cannot export unexported function %s with gccgo", fn.Name)
+ }
+
+ cdeclBuf := new(bytes.Buffer)
+ resultCount := 0
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) { resultCount++ })
+ switch resultCount {
+ case 0:
+ fmt.Fprintf(cdeclBuf, "void")
+ case 1:
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s", t.C)
+ })
+ default:
+ // Declare a result struct.
+ fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
+ }
+
+ // The function name.
+ fmt.Fprintf(cdeclBuf, " "+exp.ExpName)
+ gccgoSymbol := fmt.Sprintf("%s.%s.%s", gccgoSymbolPrefix, p.PackageName, exp.Func.Name)
+ fmt.Fprintf(cdeclBuf, " (")
+ // Function parameters.
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprintf(cdeclBuf, ", ")
+ }
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
+ })
+ fmt.Fprintf(cdeclBuf, ")")
+ cdecl := cdeclBuf.String()
+
+ fmt.Fprintf(fgcch, "extern %s __asm__(\"%s\");\n", cdecl, gccgoSymbol)
+ // Dummy declaration for _cgo_main.c
+ fmt.Fprintf(fm, "%s {}\n", cdecl)
+ }
+}
+
// Call a function for each entry in an ast.FieldList, passing the
// index into the list and the type.
func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {