CGO, which stands for "C Go," is a feature in the Go programming language that allows you to call C functions directly from Go code. This capability is particularly useful when you need to leverage existing C libraries or when performance-critical sections of your application require low-level access to system resources.
In this tutorial, we'll explore how to use CGO effectively, including setting up your environment, writing and compiling CGO code, and best practices for integrating C code into Go applications.
Before diving into CGO, ensure you have the following:
To use CGO, you need to have a C compiler installed on your system. Most Unix-like systems come with GCC pre-installed. If not, you can install it using your package manager:
sudo apt-get update
sudo apt-get install build-essential
brew install gcc
You can download and install MinGW-w64, which includes a GCC compiler.
Let's start with a simple example of calling a C function from Go. We'll create a C library that calculates the factorial of a number and then call this function from Go.
Create a file named factorial.c:
// factorial.c
#include <stdio.h>
int factorial(int n) {
if (n <= 1)
return 1;
else
return n * factorial(n - 1);
}
Create a header file factorial.h for the C code:
// factorial.h
#ifndef FACTORIAL_H
#define FACTORIAL_H
int factorial(int n);
#endif // FACTORIAL_H
Now, let's write the Go code that uses CGO to call the factorial function from the C library. Create a file named main.go:
// main.go
package main
/*
#cgo LDFLAGS: -L. -lfactorial
#include "factorial.h"
*/
import (
"C"
"fmt"
)
func main() {
n := C.int(5)
result := C.factorial(n)
fmt.Printf("Factorial of %d is %d\n", n, result)
}
To compile the Go code with CGO enabled, you need to have the C library compiled first. Assuming your C files are in the same directory as main.go, follow these steps:
Compile the C code into a shared library:
gcc -shared -o libfactorial.so factorial.c
Run the Go program:
go run main.go
You should see the output:
Factorial of 5 is 120
In the main.go file, you'll notice special comments that start with /* #cgo ... */. These are CGO directives that provide instructions to the Go compiler on how to compile and link C code.
#cgo LDFLAGS: -L. -lfactorial: This directive tells the linker where to find the shared library (libfactorial.so) and its name.#include "factorial.h": This directive includes the C header file, allowing Go to know about the C functions.CGO supports passing complex data types between Go and C, but it requires careful handling to ensure data integrity. For example, you can pass pointers and structs:
package main
/*
#include <stdlib.h>
typedef struct {
int x;
int y;
} Point;
Point* create_point(int x, int y) {
Point* p = (Point*)malloc(sizeof(Point));
p->x = x;
p->y = y;
return p;
}
void free_point(Point* p) {
free(p);
}
*/
import (
"C"
"fmt"
)
func main() {
point := C.create_point(C.int(10), C.int(20))
fmt.Printf("Point: (%d, %d)\n", point.x, point.y)
C.free_point(point)
}
You can also call Go functions from C code. This is useful for integrating Go's concurrency model or other high-level features into your C code:
package main
/*
#include <stdio.h>
extern void printMessage();
void callGoFunction() {
printMessage();
}
*/
import (
"C"
)
//export printMessage
func printMessage() {
fmt.Println("Hello from Go!")
}
func main() {
C.callGoFunction()
}
CGO is a powerful feature in Go that allows you to leverage existing C libraries and access low-level system resources. By following best practices and understanding the intricacies of CGO, you can effectively integrate C code into your Go applications.
Remember, while CGO provides flexibility and performance benefits, it also introduces complexity and potential security risks. Use it judiciously and always prioritize safety and maintainability in your code.