Embedded form
Let's take a look at the simplest example of cgo
package main //#include <stdio.h> import "C" func main() { C.puts(C.CString("Hello World")) }
output
Hello World
Call the common put function in C through "C package", and pass in the C string (equivalent to char *) that converts the string in go into C string through C.Cstring. In fact, "C" is not a package, but enables the go compiler cgo related functions through the import "C" statement, so that gcc also participates in the compilation. In this way, C code is written in the comments immediately above the import "C" statement, and C object calls are used in subsequent code. Of course, you can also call custom C functions in this way.
package main import "C" /*#include <stdio.h> void say_hello_with_name(char * name){ printf("hello %s\n", name); } */ import "C" func main() { C.say_hello_with_name(C.CString("oscar")) }
output
hello oscar
External C code
Although the built-in C code is very convenient, most use scenarios of cgo are that I have a C code library that needs to be reused, such as the stl library of C + +, or the encapsulated third-party dependency in linux c. At these times, you need some external C files h .c .cpp and so on go file mix. Let's take a look at the simplest example (calling the system account authentication of linux).
// auth.h int auth(char *user, char *passwd);
// auth.c #include <shadow.h> #include <stdio.h> #include <unistd.h> int auth(char *user, char *passwd){ char *obtpwd; struct spwd *spasswd; spasswd = getspnam(user); obtpwd = crypt(passwd, spasswd->sp_pwdp); if(strcmp(spasswd->sp_pwdp, obtpwd) == 0) return 0; else return 1; }
// main.go package main /* #cgo LDFLAGS: -lcrypt #include "auth.h" */ import "C" import "fmt" func main() { var username, password string fmt.Println("Please enter your username and password: ") _, _ = fmt.Scanln(&username, &password) rst := C.auth(C.CString(username), C.CString(password)) fmt.Println(rst) }
Ensure that the above three files run the go build -o main build project under the same go project directory# cgo LDFLAGS: -lcrypt this line is the compilation parameters cgo gives gcc. If the relevant compilation parameters and connection parameters are empty, it will be explained in the following article, - lcrypt means that libcrypt needs to be connected during compilation.
Note that this method of c-go mixed compilation is not recommended personally. cgo supports very poor construction of external c-chips. I can't specify the search path of c-chips in cgo through compilation parameters (header file is no problem), which means that when the c-chips called by the project have to be in the project root directory, it's too bad. Personally, I think if there are a large number of external libraries that depend on C language, please compile them separately. The C library is compiled into static or dynamic libraries using gcc. It's better to connect go during compilation. It's not troublesome to write a makefile for separate step-by-step compilation. Let's modify the compilation process slightly according to the above example.
1. Build libauth A static library
gcc -c -o auth.o -lcrypt auth.c ar rcs libauth.a auth.o
Get libauth a
2. For main Go slightly modified
package main /* #cgo CFLAGS: -I./ #cgo LDFLAGS: -L. -lauth -lcrypt #include "auth.h" */ import "C" import "fmt" func main() { var username, password string fmt.Println("Please enter your username and password: ") _, _ = fmt.Scanln(&username, &password) rst := C.auth(C.CString(username), C.CString(password)) fmt.Println(rst) }
The main modification here is the addition of libauth A link parameters of static library
3. Compilation
go build -o main main.go
You can complete the above steps and write a simple makefile
.PHONY : all all: main libauth.a: auth.c gcc -c -o auth.o -lcrypt auth.c ar rcs libauth.a auth.o main: main.go libauth.a go build -o main main.go clean: rm -f auth.o libauth.a main
This also makes the process of getting the product relatively simple and fast