From db9229def8bb23cf254e5027eaf9b5914220e621 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 28 Jul 2011 12:39:50 -0400 Subject: [PATCH] cgo: add GoBytes, fix gmp example Fixes #1640. Fixes #2007. R=golang-dev, adg CC=golang-dev https://golang.org/cl/4815063 --- misc/cgo/gmp/gmp.go | 4 ++-- misc/cgo/stdio/file.go | 1 + src/cmd/cgo/ast.go | 4 ++++ src/cmd/cgo/doc.go | 16 ++++++++++++++++ src/cmd/cgo/gcc.go | 8 ++++++++ src/cmd/cgo/out.go | 15 +++++++++++++-- src/pkg/runtime/runtime.h | 1 + src/pkg/runtime/string.goc | 10 ++++++++++ 8 files changed, 55 insertions(+), 4 deletions(-) diff --git a/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go index 10933498db8..3dbc022ce53 100644 --- a/misc/cgo/gmp/gmp.go +++ b/misc/cgo/gmp/gmp.go @@ -265,7 +265,7 @@ func (z *Int) Mod(x, y *Int) *Int { func (z *Int) Lsh(x *Int, s uint) *Int { x.doinit() z.doinit() - C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s)) + C.mpz_mul_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s)) return z } @@ -273,7 +273,7 @@ func (z *Int) Lsh(x *Int, s uint) *Int { func (z *Int) Rsh(x *Int, s uint) *Int { x.doinit() z.doinit() - C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s)) + C.mpz_div_2exp(&z.i[0], &x.i[0], C.mp_bitcnt_t(s)) return z } diff --git a/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go index 021cbf909ca..ab1e88436c9 100644 --- a/misc/cgo/stdio/file.go +++ b/misc/cgo/stdio/file.go @@ -42,3 +42,4 @@ func (f *File) Flush() { } var Greeting = C.GoString(C.greeting) +var Gbytes = C.GoBytes(unsafe.Pointer(C.greeting), C.int(len(Greeting))) diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 46e33686d20..73b7313d675 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -189,6 +189,10 @@ func (f *File) saveExport(x interface{}, context string) { error(c.Pos(), "export missing name") } + if name != n.Name.Name { + error(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name) + } + f.ExpFunc = append(f.ExpFunc, &ExpFunc{ Func: n, ExpName: name, diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 064725c1d5d..63413825af5 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -52,6 +52,7 @@ C.char, C.schar (signed char), C.uchar (unsigned char), C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), C.long, C.ulong (unsigned long), C.longlong (long long), C.ulonglong (unsigned long long), C.float, C.double. +The C type void* is represented by Go's unsafe.Pointer. To access a struct, union, or enum type directly, prefix it with struct_, union_, or enum_, as in C.struct_stat. @@ -68,6 +69,21 @@ C compilers are aware of this calling convention and adjust the call accordingly, but Go cannot. In Go, you must pass the pointer to the first element explicitly: C.f(&x[0]). +A few special functions convert between Go and C types +by making copies of the data. In pseudo-Go definitions: + + // Go string to C string + func C.CString(string) *C.char + + // C string to Go string + func C.GoString(*C.char) string + + // C string, length to Go string + func C.GoStringN(*C.char, C.int) string + + // C pointer, length to Go []byte + func C.GoBytes(unsafe.Pointer, C.int) []byte + 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. diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index a4d83f1e7fe..7ec4d8ccf96 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1140,6 +1140,14 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { t.Align = c.ptrSize break } + if dt.Name == "_GoBytes_" { + // Special C name for Go []byte type. + // Knows slice layout used by compilers: pointer, length, cap. + t.Go = c.Ident("[]byte") + t.Size = c.ptrSize + 4 + 4 + t.Align = c.ptrSize + break + } name := c.Ident("_Ctypedef_" + dt.Name) t.Go = name // publish before recursive call sub := c.Type(dt.Type) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 1dde2d935d9..9c962b8ff9e 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -236,7 +236,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { printer.Fprint(fgo2, fset, d) fmt.Fprintf(fgo2, "\n") - if name == "CString" || name == "GoString" || name == "GoStringN" { + if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" { // The builtins are already defined in the C prolog. return } @@ -316,7 +316,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { name := n.Mangle - if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] { + if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] { // The builtins are already defined in the C prolog, and we don't // want to duplicate function definitions we've already done. return @@ -646,6 +646,8 @@ func (p *Package) cgoType(e ast.Expr) *Type { } return r } + error(e.Pos(), "unrecognized Go type %s", t.Name) + return &Type{Size: 4, Align: 4, C: c("int")} case *ast.SelectorExpr: id, ok := t.X.(*ast.Ident) if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { @@ -679,8 +681,10 @@ __cgo_size_assert(double, 8) const builtinProlog = ` typedef struct { char *p; int n; } _GoString_; +typedef struct { char *p; int n; int c; } _GoBytes_; _GoString_ GoString(char *p); _GoString_ GoStringN(char *p, int l); +_GoBytes_ GoBytes(void *p, int n); char *CString(_GoString_); ` @@ -704,6 +708,13 @@ void FLUSH(&s); } +void +·_Cfunc_GoBytes(int8 *p, int32 l, Slice s) +{ + s = runtime·gobytes((byte*)p, l); + FLUSH(&s); +} + void ·_Cfunc_CString(String s, int8 *p) { diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 50c2b0eeca2..15b1e8eb9d8 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -413,6 +413,7 @@ void* runtime·mal(uintptr); String runtime·catstring(String, String); String runtime·gostring(byte*); String runtime·gostringn(byte*, int32); +Slice runtime·gobytes(byte*, int32); String runtime·gostringnocopy(byte*); String runtime·gostringw(uint16*); void runtime·initsig(int32); diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc index 34b167791e4..e0daac49ab6 100644 --- a/src/pkg/runtime/string.goc +++ b/src/pkg/runtime/string.goc @@ -74,6 +74,16 @@ runtime·gostringn(byte *str, int32 l) return s; } +Slice +runtime·gobytes(byte *p, int32 n) +{ + Slice sl; + + sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0); + runtime·memmove(sl.array, p, n); + return sl; +} + String runtime·gostringnocopy(byte *str) {