summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-03-04 21:27:36 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-03-04 21:27:36 +0100
commit04b08da9af0c450d645ab7389d1467308cfc2db8 (patch)
treedb247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/cmd/cgo
parent917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff)
downloadgolang-04b08da9af0c450d645ab7389d1467308cfc2db8.tar.gz
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/ast.go26
-rw-r--r--src/cmd/cgo/doc.go506
-rw-r--r--src/cmd/cgo/gcc.go143
-rw-r--r--src/cmd/cgo/godefs.go2
-rw-r--r--src/cmd/cgo/main.go19
-rw-r--r--src/cmd/cgo/out.go338
-rw-r--r--src/cmd/cgo/util.go53
7 files changed, 923 insertions, 164 deletions
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 381e606ef..dbae3b7b1 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -78,7 +78,7 @@ func (f *File) ReadGo(name string) {
}
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
- f.Preamble += cg.Text() + "\n"
+ f.Preamble += commentText(cg) + "\n"
}
}
}
@@ -131,6 +131,30 @@ func (f *File) ReadGo(name string) {
f.AST = ast2
}
+// Like ast.CommentGroup's Text method but preserves
+// leading blank lines, so that line numbers line up.
+func commentText(g *ast.CommentGroup) string {
+ if g == nil {
+ return ""
+ }
+ var pieces []string
+ for _, com := range g.List {
+ c := string(com.Text)
+ // Remove comment markers.
+ // The parser has given us exactly the comment text.
+ switch c[1] {
+ case '/':
+ //-style comment (no newline at the end)
+ c = c[2:] + "\n"
+ case '*':
+ /*-style comment */
+ c = c[2 : len(c)-2]
+ }
+ pieces = append(pieces, c)
+ }
+ return strings.Join(pieces, "")
+}
+
// Save references to C.xxx for later processing.
func (f *File) saveRef(x interface{}, context string) {
n, ok := x.(*ast.Expr)
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 1bb48f44e..955b7c495 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -65,11 +65,13 @@ struct_, union_, or enum_, as in C.struct_stat.
Go structs cannot embed fields with C types.
-Any C function that returns a value may be called in a multiple
-assignment context to retrieve both the return value and the
-C errno variable as an error. For example:
+Any C function (even void functions) may be called in a multiple
+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")
+ _, err := C.voidFunc()
In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
@@ -83,7 +85,8 @@ by making copies of the data. In pseudo-Go definitions:
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
- // freed, such as by calling C.free.
+ // freed, such as by calling C.free (be sure to include stdlib.h
+ // if C.free is needed).
func C.CString(string) *C.char
// C string to Go string
@@ -113,6 +116,11 @@ copied from the cgo input files. Functions with multiple
return values are mapped to functions returning a struct.
Not all Go types can be mapped to C types in a useful way.
+Using //export in a file places a restriction on the preamble:
+since it is copied into two different C output files, it must not
+contain any definitions, only declarations. Definitions must be
+placed in preambles in other files, or in C source files.
+
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.
@@ -125,4 +133,492 @@ Cgo does not yet work with gccgo.
See "C? Go? Cgo!" for an introduction to using cgo:
http://golang.org/doc/articles/c_go_cgo.html
*/
-package documentation
+package main
+
+/*
+Implementation details.
+
+Cgo provides a way for Go programs to call C code linked into the same
+address space. This comment explains the operation of cgo.
+
+Cgo reads a set of Go source files and looks for statements saying
+import "C". If the import has a doc comment, that comment is
+taken as literal C code to be used as a preamble to any C code
+generated by cgo. A typical preamble #includes necessary definitions:
+
+ // #include <stdio.h>
+ import "C"
+
+For more details about the usage of cgo, see the documentation
+comment at the top of this file.
+
+Understanding C
+
+Cgo scans the Go source files that import "C" for uses of that
+package, such as C.puts. It collects all such identifiers. The next
+step is to determine each kind of name. In C.xxx the xxx might refer
+to a type, a function, a constant, or a global variable. Cgo must
+decide which.
+
+The obvious thing for cgo to do is to process the preamble, expanding
+#includes and processing the corresponding C code. That would require
+a full C parser and type checker that was also aware of any extensions
+known to the system compiler (for example, all the GNU C extensions) as
+well as the system-specific header locations and system-specific
+pre-#defined macros. This is certainly possible to do, but it is an
+enormous amount of work.
+
+Cgo takes a different approach. It determines the meaning of C
+identifiers not by parsing C code but by feeding carefully constructed
+programs into the system C compiler and interpreting the generated
+error messages, debug information, and object files. In practice,
+parsing these is significantly less work and more robust than parsing
+C source.
+
+Cgo first invokes gcc -E -dM on the preamble, in order to find out
+about simple #defines for constants and the like. These are recorded
+for later use.
+
+Next, cgo needs to identify the kinds for each identifier. For the
+identifiers C.foo and C.bar, cgo generates this C program:
+
+ <preamble>
+ void __cgo__f__(void) {
+ #line 1 "cgo-test"
+ foo;
+ enum { _cgo_enum_0 = foo };
+ bar;
+ enum { _cgo_enum_1 = bar };
+ }
+
+This program will not compile, but cgo can look at the error messages
+to infer the kind of each identifier. The line number given in the
+error tells cgo which identifier is involved.
+
+An error like "unexpected type name" or "useless type name in empty
+declaration" or "declaration does not declare anything" tells cgo that
+the identifier is a type.
+
+An error like "statement with no effect" or "expression result unused"
+tells cgo that the identifier is not a type, but not whether it is a
+constant, function, or global variable.
+
+An error like "not an integer constant" tells cgo that the identifier
+is not a constant. If it is also not a type, it must be a function or
+global variable. For now, those can be treated the same.
+
+Next, cgo must learn the details of each type, variable, function, or
+constant. It can do this by reading object files. If cgo has decided
+that t1 is a type, v2 and v3 are variables or functions, and c4, c5,
+and c6 are constants, it generates:
+
+ <preamble>
+ typeof(t1) *__cgo__1;
+ typeof(v2) *__cgo__2;
+ typeof(v3) *__cgo__3;
+ typeof(c4) *__cgo__4;
+ enum { __cgo_enum__4 = c4 };
+ typeof(c5) *__cgo__5;
+ enum { __cgo_enum__5 = c5 };
+ typeof(c6) *__cgo__6;
+ enum { __cgo_enum__6 = c6 };
+
+ long long __cgo_debug_data[] = {
+ 0, // t1
+ 0, // v2
+ 0, // v3
+ c4,
+ c5,
+ c6,
+ 1
+ };
+
+and again invokes the system C compiler, to produce an object file
+containing debug information. Cgo parses the DWARF debug information
+for __cgo__N to learn the type of each identifier. (The types also
+distinguish functions from global variables.) If using a standard gcc,
+cgo can parse the DWARF debug information for the __cgo_enum__N to
+learn the identifier's value. The LLVM-based gcc on OS X emits
+incomplete DWARF information for enums; in that case cgo reads the
+constant values from the __cgo_debug_data from the object file's data
+segment.
+
+At this point cgo knows the meaning of each C.xxx well enough to start
+the translation process.
+
+Translating Go
+
+[The rest of this comment refers to 6g and 6c, the Go and C compilers
+that are part of the amd64 port of the gc Go toolchain. Everything here
+applies to another architecture's compilers as well.]
+
+Given the input Go files x.go and y.go, cgo generates these source
+files:
+
+ x.cgo1.go # for 6g
+ y.cgo1.go # for 6g
+ _cgo_gotypes.go # for 6g
+ _cgo_defun.c # for 6c
+ x.cgo2.c # for gcc
+ y.cgo2.c # for gcc
+ _cgo_export.c # for gcc
+ _cgo_main.c # for gcc
+
+The file x.cgo1.go is a copy of x.go with the import "C" removed and
+references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx.
+The definitions of those identifiers, written as Go functions, types,
+or variables, are provided in _cgo_gotypes.go.
+
+Here is a _cgo_gotypes.go containing definitions for C.flush (provided
+in the preamble) and C.puts (from stdio):
+
+ type _Ctype_char int8
+ type _Ctype_int int32
+ type _Ctype_void [0]byte
+
+ func _Cfunc_CString(string) *_Ctype_char
+ func _Cfunc_flush() _Ctype_void
+ func _Cfunc_puts(*_Ctype_char) _Ctype_int
+
+For functions, cgo only writes an external declaration in the Go
+output. The implementation is in a combination of C for 6c (meaning
+any gc-toolchain compiler) and C for gcc.
+
+The 6c file contains the definitions of the functions. They all have
+similar bodies that invoke runtime·cgocall to make a switch from the
+Go runtime world to the system C (GCC-based) world.
+
+For example, here is the definition of _Cfunc_puts:
+
+ void _cgo_be59f0f25121_Cfunc_puts(void*);
+
+ void
+ ·_Cfunc_puts(struct{uint8 x[1];}p)
+ {
+ runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
+ }
+
+The hexadecimal number is a hash of cgo's input, chosen to be
+deterministic yet unlikely to collide with other uses. The actual
+function _cgo_be59f0f25121_Cfunc_puts is implemented in a C source
+file compiled by gcc, the file x.cgo2.c:
+
+ void
+ _cgo_be59f0f25121_Cfunc_puts(void *v)
+ {
+ struct {
+ char* p0;
+ int r;
+ char __pad12[4];
+ } __attribute__((__packed__)) *a = v;
+ a->r = puts((void*)a->p0);
+ }
+
+It extracts the arguments from the pointer to _Cfunc_puts's argument
+frame, invokes the system C function (in this case, puts), stores the
+result in the frame, and returns.
+
+Linking
+
+Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
+they need to be linked into the final binary, along with the libraries
+they might depend on (in the case of puts, stdio). 6l has been
+extended to understand basic ELF files, but it does not understand ELF
+in the full complexity that modern C libraries embrace, so it cannot
+in general generate direct references to the system libraries.
+
+Instead, the build process generates an object file using dynamic
+linkage to the desired libraries. The main function is provided by
+_cgo_main.c:
+
+ int main() { return 0; }
+ void crosscall2(void(*fn)(void*, int), void *a, int c) { }
+ void _cgo_allocate(void *a, int c) { }
+ void _cgo_panic(void *a, int c) { }
+
+The extra functions here are stubs to satisfy the references in the C
+code generated for gcc. The build process links this stub, along with
+_cgo_export.c and *.cgo2.c, into a dynamic executable and then lets
+cgo examine the executable. Cgo records the list of shared library
+references and resolved names and writes them into a new file
+_cgo_import.c, which looks like:
+
+ #pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
+ #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+ #pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
+ #pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
+ #pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
+ #pragma cgo_import_dynamic _ _ "libpthread.so.0"
+ #pragma cgo_import_dynamic _ _ "libc.so.6"
+
+In the end, the compiled Go package, which will eventually be
+presented to 6l as part of a larger program, contains:
+
+ _go_.6 # 6g-compiled object for _cgo_gotypes.go *.cgo1.go
+ _cgo_defun.6 # 6c-compiled object for _cgo_defun.c
+ _all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c
+ _cgo_import.6 # 6c-compiled object for _cgo_import.c
+
+The final program will be a dynamic executable, so that 6l can avoid
+needing to process arbitrary .o files. It only needs to process the .o
+files generated from C files that cgo writes, and those are much more
+limited in the ELF or other features that they use.
+
+In essence, the _cgo_import.6 file includes the extra linking
+directives that 6l is not sophisticated enough to derive from _all.o
+on its own. Similarly, the _all.o uses dynamic references to real
+system object code because 6l is not sophisticated enough to process
+the real code.
+
+The main benefits of this system are that 6l remains relatively simple
+(it does not need to implement a complete ELF and Mach-O linker) and
+that gcc is not needed after the package is compiled. For example,
+package net uses cgo for access to name resolution functions provided
+by libc. Although gcc is needed to compile package net, gcc is not
+needed to link programs that import package net.
+
+Runtime
+
+When using cgo, Go must not assume that it owns all details of the
+process. In particular it needs to coordinate with C in the use of
+threads and thread-local storage. The runtime package, in its own
+(6c-compiled) C code, declares a few uninitialized (default bss)
+variables:
+
+ bool runtime·iscgo;
+ void (*libcgo_thread_start)(void*);
+ void (*initcgo)(G*);
+
+Any package using cgo imports "runtime/cgo", which provides
+initializations for these variables. It sets iscgo to 1, initcgo to a
+gcc-compiled function that can be called early during program startup,
+and libcgo_thread_start to a gcc-compiled function that can be used to
+create a new thread, in place of the runtime's usual direct system
+calls.
+
+[NOTE: From here down is planned but not yet implemented.]
+
+Internal and External Linking
+
+The text above describes "internal" linking, in which 6l parses and
+links host object files (ELF, Mach-O, PE, and so on) into the final
+executable itself. Keeping 6l simple means we cannot possibly
+implement the full semantics of the host linker, so the kinds of
+objects that can be linked directly into the binary is limited (other
+code can only be used as a dynamic library). On the other hand, when
+using internal linking, 6l can generate Go binaries by itself.
+
+In order to allow linking arbitrary object files without requiring
+dynamic libraries, cgo will soon support an "external" linking mode
+too. In external linking mode, 6l does not process any host object
+files. Instead, it collects all the Go code and writes a single go.o
+object file containing it. Then it invokes the host linker (usually
+gcc) to combine the go.o object file and any supporting non-Go code
+into a final executable. External linking avoids the dynamic library
+requirement but introduces a requirement that the host linker be
+present to create such a binary.
+
+Most builds both compile source code and invoke the linker to create a
+binary. When cgo is involved, the compile step already requires gcc, so
+it is not problematic for the link step to require gcc too.
+
+An important exception is builds using a pre-compiled copy of the
+standard library. In particular, package net uses cgo on most systems,
+and we want to preserve the ability to compile pure Go code that
+imports net without requiring gcc to be present at link time. (In this
+case, the dynamic library requirement is less significant, because the
+only library involved is libc.so, which can usually be assumed
+present.)
+
+This conflict between functionality and the gcc requirement means we
+must support both internal and external linking, depending on the
+circumstances: if net is the only cgo-using package, then internal
+linking is probably fine, but if other packages are involved, so that there
+are dependencies on libraries beyond libc, external linking is likely
+to work better. The compilation of a package records the relevant
+information to support both linking modes, leaving the decision
+to be made when linking the final binary.
+
+Linking Directives
+
+In either linking mode, package-specific directives must be passed
+through to 6l. These are communicated by writing #pragma directives
+in a C source file compiled by 6c. The directives are copied into the .6 object file
+and then processed by the linker.
+
+The directives are:
+
+#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
+
+ In internal linking mode, allow an unresolved reference to
+ <local>, assuming it will be resolved by a dynamic library
+ symbol. The optional <remote> specifies the symbol's name and
+ possibly version in the dynamic library, and the optional "<library>"
+ names the specific library where the symbol should be found.
+
+ In the <remote>, # or @ can be used to introduce a symbol version.
+
+ Examples:
+ #pragma cgo_import_dynamic puts
+ #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
+ 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.
+
+ Example:
+ #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 cgo_dynamic_linker "<path>"
+
+ In internal linking mode, use "<path>" as the dynamic linker
+ in the final binary. This directive is only needed from one
+ package when constructing a binary; by convention it is
+ supplied by runtime/cgo.
+
+ Example:
+ #pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+#pragma cgo_export <local> <remote>
+
+ In both internal and external linking modes, 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 cgo_import_static <local>
+
+ In external linking mode, allow unresolved references to
+ <local> in the go.o object file prepared for the host linker,
+ under the assumption that <local> will be supplied by the
+ other object files that will be linked with go.o.
+
+ Example:
+ #pragma cgo_import_static puts_wrapper
+
+#pragma cgo_ldflag "<arg>"
+
+ In external linking mode, invoke the host linker (usually gcc)
+ with "<arg>" as a command-line argument following the .o files.
+ Note that the arguments are for "gcc", not "ld".
+
+ Example:
+ #pragma cgo_ldflag "-lpthread"
+ #pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
+
+A package compiled with cgo will include directives for both
+internal and external linking; the linker will select the appropriate
+subset for the chosen linking mode.
+
+Example
+
+As a simple example, consider a package that uses cgo to call C.sin.
+The following code will be generated by cgo:
+
+ // compiled by 6g
+
+ type _Ctype_double float64
+ func _Cfunc_sin(_Ctype_double) _Ctype_double
+
+ // compiled by 6c
+
+ #pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6"
+
+ #pragma cgo_import_static _cgo_gcc_Cfunc_sin
+ #pragma cgo_ldflag "-lm"
+
+ void _cgo_gcc_Cfunc_sin(void*);
+
+ void
+ ·_Cfunc_sin(struct{uint8 x[16];}p)
+ {
+ runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
+ }
+
+ // compiled by gcc, into foo.cgo2.o
+
+ void
+ _cgo_gcc_Cfunc_sin(void *v)
+ {
+ struct {
+ double p0;
+ double r;
+ } __attribute__((__packed__)) *a = v;
+ a->r = sin(a->p0);
+ }
+
+What happens at link time depends on whether the final binary is linked
+using the internal or external mode. If other packages are compiled in
+"external only" mode, then the final link will be an external one.
+Otherwise the link will be an internal one.
+
+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
+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
+"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
+runtime dynamic linker.
+
+In external mode, 6l does not process any host object files, in
+particular foo.cgo2.o. It links together the 6g- and 6c-generated
+object files, along with any other Go code, into a go.o file. While
+doing that, 6l will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
+is okay, because 6l also processes the cgo_import_static directive and
+knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
+object file, so 6l does not treat the missing symbol as an error when
+creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
+provided to the host linker by foo2.cgo.o, which in turn will need the
+symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
+knows that the eventual host link command must include the -lm
+argument, so that the host linker will be able to find 'sin' in the
+math library.
+
+6l Command Line Interface
+
+The go command and any other Go-aware build systems invoke 6l
+to link a collection of packages into a single binary. By default, 6l will
+present the same interface it does today:
+
+ 6l main.a
+
+produces a file named 6.out, even if 6l does so by invoking the host
+linker in external linking mode.
+
+By default, 6l will decide the linking mode as follows: if the only
+packages using cgo are those on a whitelist of standard library
+packages (net, os/user, runtime/cgo), 6l will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and 6l
+will use external linking mode. The first rule means that a build of
+the godoc binary, which uses net but no other cgo, can run without
+needing gcc available. The second rule means that a build of a
+cgo-wrapped library like sqlite3 can generate a standalone executable
+instead of needing to refer to a dynamic library. The specific choice
+can be overridden using a command line flag: 6l -cgolink=internal or
+6l -cgolink=external.
+
+In an external link, 6l will create a temporary directory, write any
+host object files found in package archives to that directory (renamed
+to avoid conflicts), write the go.o file to that directory, and invoke
+the host linker. The default value for the host linker is $CC, split
+into fields, or else "gcc". The specific host linker command line can
+be overridden using a command line flag: 6l -hostld='gcc -ggdb'
+
+These defaults mean that Go-aware build systems can ignore the linking
+changes and keep running plain '6l' and get reasonable results, but
+they can also control the linking details if desired.
+
+*/
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 98a847e6f..4b0a521a8 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -391,9 +391,9 @@ func (p *Package) guessKinds(f *File) []*Name {
b.WriteString(builtinProlog)
b.WriteString(f.Preamble)
b.WriteString("void __cgo__f__(void) {\n")
- b.WriteString("#line 0 \"cgo-test\"\n")
+ b.WriteString("#line 1 \"cgo-test\"\n")
for i, n := range toSniff {
- fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
+ fmt.Fprintf(&b, "%s; /* #%d */\nenum { _cgo_enum_%d = %s }; /* #%d */\n", n.C, i, i, n.C, i)
}
b.WriteString("}\n")
stderr := p.gccErrors(b.Bytes())
@@ -423,14 +423,18 @@ func (p *Package) guessKinds(f *File) []*Name {
if err != nil {
continue
}
+ i = (i - 1) / 2
what := ""
switch {
default:
continue
- case strings.Contains(line, ": useless type name in empty declaration"):
+ case strings.Contains(line, ": useless type name in empty declaration"),
+ strings.Contains(line, ": declaration does not declare anything"),
+ strings.Contains(line, ": unexpected type name"):
what = "type"
isConst[i] = false
- case strings.Contains(line, ": statement with no effect"):
+ case strings.Contains(line, ": statement with no effect"),
+ strings.Contains(line, ": expression result unused"):
what = "not-type" // const or func or var
case strings.Contains(line, "undeclared"):
error_(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
@@ -508,7 +512,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "\t0,\n")
}
}
- fmt.Fprintf(&b, "\t0\n")
+ // for the last entry, we can not use 0, otherwise
+ // in case all __cgodebug_data is zero initialized,
+ // LLVM-based gcc will place the it in the __DATA.__common
+ // zero-filled section (our debug/macho doesn't support
+ // this)
+ fmt.Fprintf(&b, "\t1\n")
fmt.Fprintf(&b, "};\n")
d, bo, debugData := p.gccDebug(b.Bytes())
@@ -596,7 +605,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// Record types and typedef information.
var conv typeConv
- conv.Init(p.PtrSize)
+ conv.Init(p.PtrSize, p.IntSize)
for i, n := range names {
if types[i] == nil {
continue
@@ -618,7 +627,9 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
delete(n.Type.EnumValues, k)
- } else if n.Kind == "const" && i < len(enumVal) {
+ }
+ // Prefer debug data over DWARF debug output, if we have it.
+ if n.Kind == "const" && i < len(enumVal) {
n.Const = fmt.Sprintf("%#x", enumVal[i])
}
}
@@ -637,7 +648,14 @@ func (p *Package) rewriteRef(f *File) {
n.Kind = "var"
}
if n.Mangle == "" {
- n.Mangle = "_C" + n.Kind + "_" + n.Go
+ // When using gccgo variables have to be
+ // exported so that they become global symbols
+ // that the C code can refer to.
+ prefix := "_C"
+ if *gccgo && n.Kind == "var" {
+ prefix = "C"
+ }
+ n.Mangle = prefix + n.Kind + "_" + n.Go
}
}
@@ -662,9 +680,6 @@ func (p *Package) rewriteRef(f *File) {
break
}
if r.Context == "call2" {
- if r.Name.FuncType.Result == nil {
- error_(r.Pos(), "assignment count mismatch: 2 = 0")
- }
// Invent new Name for the two-result function.
n := f.Name["2"+r.Name.Go]
if n == nil {
@@ -720,23 +735,30 @@ func (p *Package) rewriteRef(f *File) {
}
}
-// gccName returns the name of the compiler to run. Use $GCC if set in
+// gccName returns the name of the compiler to run. Use $CC if set in
// the environment, otherwise just "gcc".
-func (p *Package) gccName() (ret string) {
- if ret = os.Getenv("GCC"); ret == "" {
- ret = "gcc"
+func (p *Package) gccName() string {
+ // Use $CC if set, since that's what the build uses.
+ if ret := os.Getenv("CC"); ret != "" {
+ return ret
}
- return
+ // Fall back to $GCC if set, since that's what we used to use.
+ if ret := os.Getenv("GCC"); ret != "" {
+ return ret
+ }
+ return "gcc"
}
-// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
+// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
func (p *Package) gccMachine() []string {
switch goarch {
case "amd64":
return []string{"-m64"}
case "386":
return []string{"-m32"}
+ case "arm":
+ return []string{"-marm"} // not thumb
}
return nil
}
@@ -755,9 +777,22 @@ func (p *Package) gccCmd() []string {
"-o" + gccTmp(), // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
- "-c", // do not link
- "-xc", // input language is C
+ "-c", // do not link
+ "-xc", // input language is C
+ }
+ if strings.Contains(p.gccName(), "clang") {
+ c = append(c,
+ "-ferror-limit=0",
+ // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
+ // doesn't have -Wno-unneeded-internal-declaration, so we need yet another
+ // flag to disable the warning. Yes, really good diagnostics, clang.
+ "-Wno-unknown-warning-option",
+ "-Wno-unneeded-internal-declaration",
+ "-Wno-unused-function",
+ "-Qunused-arguments",
+ )
}
+
c = append(c, p.GccOptions...)
c = append(c, p.gccMachine()...)
c = append(c, "-") //read input from standard input
@@ -795,15 +830,30 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
return d, f.ByteOrder, data
}
- // Can skip debug data block in ELF and PE for now.
- // The DWARF information is complete.
-
if f, err := elf.Open(gccTmp()); err == nil {
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
- return d, f.ByteOrder, nil
+ var data []byte
+ symtab, err := f.Symbols()
+ if err == nil {
+ for i := range symtab {
+ s := &symtab[i]
+ if s.Name == "__cgodebug_data" {
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
+ }
+ }
+ return d, f.ByteOrder, data
}
if f, err := pe.Open(gccTmp()); err == nil {
@@ -811,7 +861,20 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
- return d, binary.LittleEndian, nil
+ var data []byte
+ for _, s := range f.Symbols {
+ if s.Name == "_"+"__cgodebug_data" {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value:]
+ }
+ }
+ }
+ }
+ }
+ return d, binary.LittleEndian, data
}
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
@@ -889,16 +952,19 @@ type typeConv struct {
void ast.Expr
unsafePointer ast.Expr
string ast.Expr
+ goVoid ast.Expr // _Ctype_void, denotes C's void
ptrSize int64
+ intSize int64
}
var tagGen int
var typedef = make(map[string]*Type)
var goIdent = make(map[string]*ast.Ident)
-func (c *typeConv) Init(ptrSize int64) {
+func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
+ c.intSize = intSize
c.m = make(map[dwarf.Type]*Type)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
@@ -918,6 +984,7 @@ func (c *typeConv) Init(ptrSize int64) {
c.unsafePointer = c.Ident("unsafe.Pointer")
c.void = c.Ident("void")
c.string = c.Ident("string")
+ c.goVoid = c.Ident("_Ctype_void")
}
// base strips away qualifiers and typedefs to get the underlying type
@@ -988,6 +1055,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
+ // clang won't generate DW_AT_byte_size for pointer types,
+ // so we have to fix it here.
+ if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
+ dt.ByteSize = c.ptrSize
+ }
+
t := new(Type)
t.Size = dtype.Size()
t.Align = -1
@@ -1032,7 +1105,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
case *dwarf.BoolType:
t.Go = c.bool
- t.Align = c.ptrSize
+ t.Align = 1
case *dwarf.CharType:
if t.Size != 1 {
@@ -1163,11 +1236,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = name // publish before recursive calls
goIdent[name.Name] = name
switch dt.Kind {
- case "union", "class":
+ case "class", "union":
t.Go = c.Opaque(t.Size)
if t.C.Empty() {
t.C.Set("typeof(unsigned char[%d])", t.Size)
}
+ t.Align = 1 // TODO: should probably base this on field alignment.
typedef[name.Name] = t
case "struct":
g, csyntax, align := c.Struct(dt, pos)
@@ -1245,8 +1319,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
case *dwarf.VoidType:
- t.Go = c.void
+ t.Go = c.goVoid
t.C.Set("void")
+ t.Align = 1
}
switch dtype.(type) {
@@ -1334,7 +1409,9 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
}
var r *Type
var gr []*ast.Field
- if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
+ if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
+ gr = []*ast.Field{{Type: c.goVoid}}
+ } else if dtype.ReturnType != nil {
r = c.Type(dtype.ReturnType, pos)
gr = []*ast.Field{{Type: r.Go}}
}
@@ -1493,8 +1570,8 @@ func godefsFields(fld []*ast.Field) {
npad := 0
for _, f := range fld {
for _, n := range f.Names {
- if strings.HasPrefix(n.Name, prefix) && n.Name != prefix {
- n.Name = n.Name[len(prefix):]
+ if n.Name != prefix {
+ n.Name = strings.TrimPrefix(n.Name, prefix)
}
if n.Name == "_" {
// Use exported name instead.
@@ -1522,7 +1599,7 @@ func godefsFields(fld []*ast.Field) {
}
// fieldPrefix returns the prefix that should be removed from all the
-// field names when generating the C or Go code. For generated
+// field names when generating the C or Go code. For generated
// C, we leave the names as is (tv_sec, tv_usec), since that's what
// people are used to seeing in C. For generated Go code, such as
// package syscall's data structures, we drop a common prefix
@@ -1539,7 +1616,7 @@ func fieldPrefix(fld []*ast.Field) string {
// named, say, _pad in an otherwise prefixed header.
// If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
// still want to remove the tv_ prefix.
- // The check for "orig_" here handles orig_eax in the
+ // The check for "orig_" here handles orig_eax in the
// x86 ptrace register sets, which otherwise have all fields
// with reg_ prefixes.
if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
index fec70a334..20376170d 100644
--- a/src/cmd/cgo/godefs.go
+++ b/src/cmd/cgo/godefs.go
@@ -180,7 +180,7 @@ func (p *Package) cdefs(f *File, srcfile string) string {
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
- s := line[len("type ") : len(line)-len(" struct {")]
+ s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
printf("typedef struct %s %s;\n", s, s)
}
}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 60165961a..7adc795de 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -31,6 +31,7 @@ type Package struct {
PackageName string // name of package
PackagePath string
PtrSize int64
+ IntSize int64
GccOptions []string
CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
Written map[string]bool
@@ -129,12 +130,19 @@ var ptrSizeMap = map[string]int64{
"arm": 4,
}
+var intSizeMap = map[string]int64{
+ "386": 4,
+ "amd64": 8,
+ "arm": 4,
+}
+
var cPrefix string
var fset = token.NewFileSet()
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
var dynout = flag.String("dynout", "", "write -dynobj output to this file")
+var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
// These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and
@@ -144,8 +152,10 @@ 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 gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
+var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
+var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
var goarch, goos string
func main() {
@@ -287,7 +297,11 @@ func newPackage(args []string) *Package {
}
ptrSize := ptrSizeMap[goarch]
if ptrSize == 0 {
- fatalf("unknown $GOARCH %q", goarch)
+ fatalf("unknown ptrSize for $GOARCH %q", goarch)
+ }
+ intSize := intSizeMap[goarch]
+ if intSize == 0 {
+ fatalf("unknown intSize for $GOARCH %q", goarch)
}
// Reset locale variables so gcc emits English errors [sic].
@@ -296,6 +310,7 @@ func newPackage(args []string) *Package {
p := &Package{
PtrSize: ptrSize,
+ IntSize: intSize,
GccOptions: gccOptions,
CgoFlags: make(map[string]string),
Written: make(map[string]bool),
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 5dfc16a02..a126cf17f 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -14,6 +14,7 @@ import (
"go/printer"
"go/token"
"os"
+ "sort"
"strings"
)
@@ -26,6 +27,8 @@ func (p *Package) writeDefs() {
fc := creat(*objDir + "_cgo_defun.c")
fm := creat(*objDir + "_cgo_main.c")
+ var gccgoInit bytes.Buffer
+
fflg := creat(*objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
@@ -50,19 +53,33 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ if *importSyscall {
+ fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ }
if !*gccgo && *importRuntimeCgo {
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
}
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
- fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int) { *dst = syscall.Errno(x) }\n")
+ if *importSyscall {
+ fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
+ }
- for name, def := range typedef {
+ typedefNames := make([]string, 0, len(typedef))
+ for name := range typedef {
+ typedefNames = append(typedefNames, name)
+ }
+ sort.Strings(typedefNames)
+ for _, name := range typedefNames {
+ def := typedef[name]
fmt.Fprintf(fgo2, "type %s ", name)
conf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+ if *gccgo {
+ fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
+ } else {
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+ }
if *gccgo {
fmt.Fprintf(fc, cPrologGccgo)
@@ -70,6 +87,8 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fc, cProlog)
}
+ gccgoSymbolPrefix := p.gccgoSymbolPrefix()
+
cVars := make(map[string]bool)
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
@@ -86,7 +105,12 @@ func (p *Package) writeDefs() {
cVars[n.C] = true
}
- fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
+ if *gccgo {
+ fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
+ fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
+ } else {
+ fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
+ }
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fgo2, "var %s ", n.Mangle)
@@ -116,6 +140,14 @@ func (p *Package) writeDefs() {
p.writeExports(fgo2, fc, fm)
}
+ init := gccgoInit.String()
+ if init != "" {
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
+ fmt.Fprintln(fc, "static void init(void) {")
+ fmt.Fprint(fc, init)
+ fmt.Fprintln(fc, "}")
+ }
+
fgo2.Close()
fc.Close()
}
@@ -131,6 +163,15 @@ func dynimport(obj string) {
}
if f, err := elf.Open(obj); err == nil {
+ if *dynlinker {
+ // Emit the cgo_dynamic_linker line.
+ if sec := f.Section(".interp"); sec != nil {
+ if data, err := sec.Data(); err == nil && len(data) > 1 {
+ // skip trailing \0 in data
+ fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
+ }
+ }
+ }
sym, err := f.ImportedSymbols()
if err != nil {
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
@@ -138,16 +179,16 @@ func dynimport(obj string) {
for _, s := range sym {
targ := s.Name
if s.Version != "" {
- targ += "@" + s.Version
+ targ += "#" + s.Version
}
- fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
+ fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Fprintf(stdout, "#pragma dynimport _ _ %q\n", l)
+ fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
}
return
}
@@ -161,14 +202,14 @@ func dynimport(obj string) {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
- fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", s, s, "")
+ fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Fprintf(stdout, "#pragma dynimport _ _ %q\n", l)
+ fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
}
return
}
@@ -180,7 +221,8 @@ func dynimport(obj string) {
}
for _, s := range sym {
ss := strings.Split(s, ":")
- fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
+ name := strings.Split(ss[0], "@")[0]
+ fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
}
return
}
@@ -247,6 +289,7 @@ func (p *Package) structType(n *Name) (string, int64) {
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
name := n.Go
gtype := n.FuncType.Go
+ void := gtype.Results == nil || len(gtype.Results.List) == 0
if n.AddError {
// Add "error" to return type list.
// Type list is known to be 0 or 1 element - it's a C function.
@@ -271,38 +314,58 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
if *gccgo {
// Gccgo style hooks.
- // we hook directly into C. gccgo goes not support cgocall yet.
- if !n.AddError {
- fmt.Fprintf(fgo2, "//extern %s\n", n.C)
- conf.Fprint(fgo2, fset, d)
- fmt.Fprint(fgo2, "\n")
- } else {
- // write a small wrapper to retrieve errno.
- cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
- paramnames := []string(nil)
- for i, param := range d.Type.Params.List {
- paramName := fmt.Sprintf("p%d", i)
- param.Names = []*ast.Ident{ast.NewIdent(paramName)}
- paramnames = append(paramnames, paramName)
+ fmt.Fprint(fgo2, "\n")
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ for i, param := range d.Type.Params.List {
+ paramName := fmt.Sprintf("p%d", i)
+ param.Names = []*ast.Ident{ast.NewIdent(paramName)}
+ paramnames = append(paramnames, paramName)
+ }
+
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+ fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
+ fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
+ if n.AddError {
+ fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n")
+ }
+ fmt.Fprint(fgo2, "\t")
+ if !void {
+ fmt.Fprint(fgo2, "r := ")
+ }
+ fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", "))
+
+ if n.AddError {
+ fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n")
+ fmt.Fprint(fgo2, "\tif e != 0 {\n")
+ fmt.Fprint(fgo2, "\t\treturn ")
+ if !void {
+ fmt.Fprint(fgo2, "r, ")
}
- 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, "\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)
- d.Name = ast.NewIdent(cname)
+ fmt.Fprint(fgo2, "e\n")
+ fmt.Fprint(fgo2, "\t}\n")
+ fmt.Fprint(fgo2, "\treturn ")
+ if !void {
+ fmt.Fprint(fgo2, "r, ")
+ }
+ fmt.Fprint(fgo2, "nil\n")
+ } else if !void {
+ fmt.Fprint(fgo2, "\treturn r\n")
+ }
+
+ fmt.Fprint(fgo2, "}\n")
+
+ // declare the C function.
+ fmt.Fprintf(fgo2, "//extern %s\n", n.C)
+ d.Name = ast.NewIdent(cname)
+ if n.AddError {
l := d.Type.Results.List
d.Type.Results.List = l[:len(l)-1]
- conf.Fprint(fgo2, fset, d)
- fmt.Fprint(fgo2, "\n")
}
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, "\n")
+
return
}
conf.Fprint(fgo2, fset, d)
@@ -317,6 +380,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
_, argSize = p.structType(n)
// C wrapper calls into gcc, passing a pointer to the argument frame.
+ fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fc, "void\n")
@@ -456,11 +520,13 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
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(fgcch, "%s\n", p.gccExportHeaderProlog())
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+ fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
+
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -552,7 +618,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
s += ")"
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
- fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
@@ -585,7 +651,7 @@ 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 dynexport %s %s\n", goname, goname)
+ fmt.Fprintf(fc, "#pragma cgo_export %s\n", goname)
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")
@@ -641,32 +707,22 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
- _ = fgcc
+
+ gccgoSymbolPrefix := p.gccgoSymbolPrefix()
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")
+ fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
- 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)
+ fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+
+ fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
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,
@@ -692,28 +748,135 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
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, " (")
+ cRet := cdeclBuf.String()
+
+ cdeclBuf = new(bytes.Buffer)
+ fmt.Fprintf(cdeclBuf, "(")
+ if fn.Recv != nil {
+ fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String())
+ }
// Function parameters.
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
- if i > 0 {
+ if i > 0 || fn.Recv != nil {
fmt.Fprintf(cdeclBuf, ", ")
}
t := p.cgoType(atype)
fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
})
fmt.Fprintf(cdeclBuf, ")")
- cdecl := cdeclBuf.String()
+ cParams := cdeclBuf.String()
+
+ goName := "Cgoexp_" + exp.ExpName
+ fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
+ fmt.Fprint(fgcch, "\n")
+
+ fmt.Fprint(fgcc, "\n")
+ fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+ fmt.Fprint(fgcc, "\t")
+ if resultCount > 0 {
+ fmt.Fprint(fgcc, "return ")
+ }
+ fmt.Fprintf(fgcc, "%s(", goName)
+ if fn.Recv != nil {
+ fmt.Fprint(fgcc, "recv")
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "p%d", i)
+ })
+ fmt.Fprint(fgcc, ");\n")
+ fmt.Fprint(fgcc, "}\n")
- fmt.Fprintf(fgcch, "extern %s __asm__(\"%s\");\n", cdecl, gccgoSymbol)
// Dummy declaration for _cgo_main.c
- fmt.Fprintf(fm, "%s {}\n", cdecl)
+ fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)
+
+ // For gccgo we use a wrapper function in Go, in order
+ // to call CgocallBack and CgocallBackDone.
+
+ // This code uses printer.Fprint, not conf.Fprint,
+ // because we don't want //line comments in the middle
+ // of the function types.
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprintf(fgo2, "func %s(", goName)
+ if fn.Recv != nil {
+ fmt.Fprint(fgo2, "recv ")
+ printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ }
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprintf(fgo2, ")")
+ if resultCount > 0 {
+ fmt.Fprintf(fgo2, " (")
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ printer.Fprint(fgo2, fset, atype)
+ })
+ fmt.Fprint(fgo2, ")")
+ }
+ fmt.Fprint(fgo2, " {\n")
+ fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n")
+ fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n")
+ fmt.Fprint(fgo2, "\t")
+ if resultCount > 0 {
+ fmt.Fprint(fgo2, "return ")
+ }
+ if fn.Recv != nil {
+ fmt.Fprint(fgo2, "recv.")
+ }
+ fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
}
}
+// Return the package prefix when using gccgo.
+func (p *Package) gccgoSymbolPrefix() string {
+ if !*gccgo {
+ return ""
+ }
+
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+
+ if *gccgopkgpath != "" {
+ return strings.Map(clean, *gccgopkgpath)
+ }
+ if *gccgoprefix == "" && p.PackageName == "main" {
+ return "main"
+ }
+ prefix := strings.Map(clean, *gccgoprefix)
+ if prefix == "" {
+ prefix = "go"
+ }
+ return prefix + "." + p.PackageName
+}
+
// 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)) {
@@ -742,8 +905,8 @@ func c(repr string, args ...interface{}) *TypeRepr {
var goTypes = map[string]*Type{
"bool": {Size: 1, Align: 1, C: c("GoUint8")},
"byte": {Size: 1, Align: 1, C: c("GoUint8")},
- "int": {Size: 4, Align: 4, C: c("GoInt")},
- "uint": {Size: 4, Align: 4, C: c("GoUint")},
+ "int": {Size: 0, Align: 0, C: c("GoInt")},
+ "uint": {Size: 0, Align: 0, C: c("GoUint")},
"rune": {Size: 4, Align: 4, C: c("GoInt32")},
"int8": {Size: 1, Align: 1, C: c("GoInt8")},
"uint8": {Size: 1, Align: 1, C: c("GoUint8")},
@@ -804,12 +967,21 @@ func (p *Package) cgoType(e ast.Expr) *Type {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
}
if t.Name == "string" {
- return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: c("GoString")}
+ // The string data is 1 pointer + 1 int, but this always
+ // rounds to 2 pointers due to alignment.
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
}
if t.Name == "error" {
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
}
if r, ok := goTypes[t.Name]; ok {
+ if r.Size == 0 { // int or uint
+ rr := new(Type)
+ *rr = *r
+ rr.Size = p.IntSize
+ rr.Align = p.IntSize
+ r = rr
+ }
if r.Align > p.PtrSize {
r.Align = p.PtrSize
}
@@ -898,18 +1070,21 @@ const cPrologGccgo = `
#include <stdint.h>
#include <string.h>
+typedef unsigned char byte;
+typedef intptr_t intgo;
+
struct __go_string {
const unsigned char *__data;
- int __length;
+ intgo __length;
};
typedef struct __go_open_array {
void* __values;
- int __count;
- int __capacity;
+ intgo __count;
+ intgo __capacity;
} Slice;
-struct __go_string __go_byte_array_to_string(const void* p, int len);
+struct __go_string __go_byte_array_to_string(const void* p, intgo len);
struct __go_open_array __go_string_to_byte_array (struct __go_string str);
const char *CString(struct __go_string s) {
@@ -917,23 +1092,25 @@ const char *CString(struct __go_string s) {
}
struct __go_string GoString(char *p) {
- int len = (p != NULL) ? strlen(p) : 0;
+ intgo len = (p != NULL) ? strlen(p) : 0;
return __go_byte_array_to_string(p, len);
}
-struct __go_string GoStringN(char *p, int n) {
+struct __go_string GoStringN(char *p, intgo n) {
return __go_byte_array_to_string(p, n);
}
-Slice GoBytes(char *p, int n) {
+Slice GoBytes(char *p, intgo n) {
struct __go_string s = { (const unsigned char *)p, n };
return __go_string_to_byte_array(s);
}
`
+func (p *Package) gccExportHeaderProlog() string {
+ return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
+}
+
const gccExportHeaderProlog = `
-typedef int GoInt;
-typedef unsigned int GoUint;
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
@@ -942,6 +1119,8 @@ typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
+typedef GoIntGOINTBITS GoInt;
+typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
@@ -952,4 +1131,5 @@ typedef struct { char *p; int n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
+typedef struct { void *data; int len; int cap; } GoSlice;
`
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index a0f216614..4e7800d12 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -5,9 +5,9 @@
package main
import (
+ "bytes"
"fmt"
"go/token"
- "io/ioutil"
"os"
"os/exec"
)
@@ -16,50 +16,17 @@ import (
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
- cmd, err := exec.LookPath(argv[0])
- if err != nil {
- fatalf("exec %s: %s", argv[0], err)
- }
- r0, w0, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r1, w1, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- r2, w2, err := os.Pipe()
- if err != nil {
- fatalf("%s", err)
- }
- p, err := os.StartProcess(cmd, argv, &os.ProcAttr{Files: []*os.File{r0, w1, w2}})
- if err != nil {
- fatalf("%s", err)
- }
- r0.Close()
- w1.Close()
- w2.Close()
- c := make(chan bool)
- go func() {
- w0.Write(stdin)
- w0.Close()
- c <- true
- }()
- go func() {
- stdout, _ = ioutil.ReadAll(r1)
- r1.Close()
- c <- true
- }()
- stderr, _ = ioutil.ReadAll(r2)
- r2.Close()
- <-c
- <-c
-
- state, err := p.Wait()
- if err != nil {
+ p := exec.Command(argv[0], argv[1:]...)
+ p.Stdin = bytes.NewReader(stdin)
+ var bout, berr bytes.Buffer
+ p.Stdout = &bout
+ p.Stderr = &berr
+ err := p.Run()
+ if _, ok := err.(*exec.ExitError); err != nil && !ok {
fatalf("%s", err)
}
- ok = state.Success()
+ ok = p.ProcessState.Success()
+ stdout, stderr = bout.Bytes(), berr.Bytes()
return
}