Go language provides a pseudo-package called "C"
to interface with C libraries. This package allows the Go program to call C functions and use C data types. To use C functions in Go, we can use the "import C"
statement to import the C functions and data types into the Go program.
The C functions and data types can be accessed using the dot notation, for example, C.function_name()
. To interface with C libraries, we can use `cgo`, which is a tool that generates Go code that can interact with C code.
/*
#include <stdlib.h>
*/
import "C"
Cgo
recognizes this comment above. Any lines starting with #cgo
followed a space character are removed; these become directives for cgo
.
C is a "pseudo-package" which means it is a special name interpreted by cgo as a reference to C's namespace.
The remaining lines are used as a header when compiling the C parts of the package. In this case, those lines are just a single #include
statement, but they can be almost any C code. The #cgo
directives are used to provide flags for the compiler and linker when building the C parts of the package.
When the Go tool sees that one or more Go files use the special import "C", it will look for other non-Go files in the directory and compile them as part of the Go package.
- Any .c, .s, .S or .sx files will be compiled with the C compiler. Any .cc, .cpp, or .cxx files will be compiled with the C++ compiler.
- Any .f, .F, .for or .f90 files will be compiled with the fortran compiler.
- Any .h, .hh, .hpp, or .hxx files will not be compiled separately, but, if these header files are changed, the package (including its non-Go source files) will be recompiled.
{% hint style="info" %} Note that changes to files in other directories do not cause the package to be recompiled, so all non-Go source code for the package should be stored in the package directory, not in subdirectories. {% endhint %}
"#include <foo/bar.h>" will always find the local version in preference to any other version.
cgo tool is enabled by default, but it is disabled by default when cross-compiling as well as when the CC env variable is unset and the default C compiler(gcc or clang) cannot be found on the system PATH.
Override the default by setting the `CGO_ENABLED` env variable
- 1 to enable
- 0 to disable
Setting CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm) environment variable for supporting Cross-compiling
If the program uses any //export
directives, then the C code in the comment may only include declarations (extern int f();
), not definitions (int f() { return 1; }
). You can use //export
directives to make Go functions accessible to C code.
As Go doesn't have support for C's union type in the general case, C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
Go code cannot refer to zero-sized fields that occur at the end of non-empty C structs.
Cgo translates C types into equivalent unexported Go types. Because the translations are unexported, a Go package should not expose C types in its exported API: a C type used in one Go package is different from the same C type used in another.
Calling C function pointers is currently not supported
C doesn’t have an explicit string type. Strings in C are represented by a zero-terminated array of chars.
So, here are the conversion functions:
{% hint style="info" %} These conversions make a copy of the string data {% endhint %}
- C.CString
- C.GoString
- C.GoStringN
package print
// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"
func Print(s string) {
cs := C.CString(s)
C.fputs(cs, (*C.FILE)(C.stdout))
C.free(unsafe.Pointer(cs))
}
Memory allocations made by C code are not known to Go's memory manager. When you create a C string with C.CString
(or any C memory allocation) you must remember to free the memory when you're done with it by calling C.free.
func Print(s string) {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
C.fputs(cs, (*C.FILE)(C.stdout))
}
To build cgo
packages, just use go build
or go install
as usual.
{% embed url="https://www.swig.org/Doc3.0/Go.html" %}
{% embed url="https://go.dev/blog/cgo" %}