Interoperability
Call Go from C
Bind C declarations to Go symbols and model Go multi-value returns.Maintained byC2Go contributorsc2go_linkname binds a C declaration to a named Go symbol. The C signature is the compiler’s ABI description of that Go function, so it must match exactly.
Bind a normal Go function
Suppose package example.com/mathx contains:
package mathx
func Double(value int) int { return value * 2 }
Declare and call it from C:
#include <c2go.h>
extern __c2go_intptr go_double(__c2go_intptr)
c2go_linkname("example.com/mathx.Double");
c2go_extern __c2go_intptr answer(void) {
return go_double(21);
}
For an ordinary Go function, omit the optional ABI selector. C2Go creates an alias and wrapper that bridge to the Go internal ABI.
Symbols in the current package
The C declaration always spells the complete Go symbol name. Clang then uses -fc2go-package to decide whether that target belongs to the package being generated. Compiling the example above with -fc2go-package=example.com/mathx resolves example.com/mathx.Double to a package-local LLVM and Plan 9 symbol instead of a cross-package reference. The complete linkname remains in IR and manifest metadata for auditing and generation checks.
Do not pass the import path to c2go-bind again. The binder reads it from the manifest; use the optional --pkgname override only when the Go source package name differs from the path base.
Bind an existing ABI0 symbol
Use C2GO_GOABI0 only when the target already exposes a Go ABI0 entry point:
extern void *runtime_alloc(const void *, __SIZE_TYPE__)
c2go_linkname("github.com/c2gohq/c2go_libc.GCMalloc", C2GO_GOABI0);
This selector requests a direct reference rather than a generated internal-ABI bridge. It is not a general performance switch. <c2go.h> already exposes this runtime entry as gc_malloc; the alias above only illustrates the ABI selector and should not replace that public API.
Receive multiple Go results
Describe one Go result slot per C struct field:
func DivMod(a, b int32) (int32, int32) {
return a / b, a % b
}
struct DivMod {
int quotient;
int remainder;
};
extern struct DivMod go_divmod(int, int)
c2go_linkname("example.com/mathx.DivMod")
c2go_returntype(struct DivMod);
The fields become independent Go ABI result slots; C2Go does not pass a hidden sret pointer. Every field must fit one supported slot: a scalar, pointer, floating-point value, or supported C2Go aggregate.
Functions and variables
c2go_linkname can bind both functions and variables. In either case, the complete Go symbol name in the C declaration and -fc2go-package are build contracts. Refactoring the Go package or symbol without updating them together produces a link failure.
Current boundary
For C ABI libraries rather than Go symbols, use native library imports.