Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 1 | # Introduction |
| 2 | |
| 3 | First, http://golang.org/cmd/cgo is the primary cgo documentation. |
| 4 | |
| 5 | There is also a good introduction article at http://golang.org/doc/articles/c_go_cgo.html. |
| 6 | |
| 7 | ## The basics |
| 8 | |
| 9 | If a Go source file imports ` "C" `, it is using cgo. The Go file will have access to anything appearing in the comment immediately preceding the line ` import "C" `, and will be linked against all other cgo comments in other Go files, and all C files included in the build process. |
| 10 | |
| 11 | Note that there must be no blank lines in between the cgo comment and the import statement. |
| 12 | |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 13 | To access a symbol originating from the C side, use the package name ` C `. That is, if you want to call the C function ` printf() ` from Go code, you write ` C.printf() `. Since variable argument methods like printf aren't supported yet (issue [975](https://github.com/golang/go/issues/975)), we will wrap it in the C method "myprint": |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 14 | |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 15 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 16 | package cgoexample |
| 17 | |
| 18 | /* |
| 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | |
| 22 | void myprint(char* s) { |
Jxck | 9f1e2a0 | 2016-05-09 14:40:47 +0900 | [diff] [blame] | 23 | printf("%s\n", s); |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 24 | } |
| 25 | */ |
| 26 | import "C" |
| 27 | |
| 28 | import "unsafe" |
| 29 | |
| 30 | func Example() { |
| 31 | cs := C.CString("Hello from stdio\n") |
| 32 | C.myprint(cs) |
| 33 | C.free(unsafe.Pointer(cs)) |
| 34 | } |
| 35 | ``` |
| 36 | |
| 37 | ## Calling Go functions from C |
| 38 | |
| 39 | It is possible to call both top-level Go functions and function variables from C code invoked from Go code using cgo. |
| 40 | |
| 41 | ### Global functions |
| 42 | |
| 43 | Go makes its functions available to C code through use of a special ` //export ` comment. |
| 44 | Note: you can't define any C functions in preamble if you're using exports. |
| 45 | |
| 46 | For example, there are two files, foo.c and foo.go: |
| 47 | foo.go contains: |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 48 | |
| 49 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 50 | package gocallback |
| 51 | |
| 52 | import "fmt" |
| 53 | |
| 54 | /* |
| 55 | #include <stdio.h> |
| 56 | extern void ACFunction(); |
| 57 | */ |
| 58 | import "C" |
| 59 | |
| 60 | //export AGoFunction |
| 61 | func AGoFunction() { |
| 62 | fmt.Println("AGoFunction()") |
| 63 | } |
| 64 | |
| 65 | func Example() { |
| 66 | C.ACFunction() |
| 67 | } |
| 68 | ``` |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 69 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 70 | foo.c contains: |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 71 | |
| 72 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 73 | #include "_cgo_export.h" |
| 74 | void ACFunction() { |
| 75 | printf("ACFunction()\n"); |
| 76 | AGoFunction(); |
| 77 | } |
| 78 | ``` |
| 79 | |
| 80 | ### Function variables |
| 81 | |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 82 | The following code shows an example of invoking a Go callback from C code. Because of the [pointer passing rules](https://golang.org/cmd/cgo/#hdr-Passing_pointers) Go code can not pass a function value directly to C. Instead it is necessary to use an indirection. This example uses a registry with a mutex, but there are many other ways to map from a value that can be passed to C to a Go function. |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 83 | |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 84 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 85 | package gocallback |
| 86 | |
| 87 | import ( |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 88 | "fmt" |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 89 | "sync" |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 90 | ) |
| 91 | |
| 92 | /* |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 93 | extern void go_callback_int(int foo, int p1); |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 94 | |
| 95 | // normally you will have to define function or variables |
| 96 | // in another separate C file to avoid the multiple definition |
| 97 | // errors, however, using "static inline" is a nice workaround |
| 98 | // for simple functions like this one. |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 99 | static inline void CallMyFunction(int foo) { |
| 100 | go_callback_int(foo, 5); |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 101 | } |
| 102 | */ |
| 103 | import "C" |
| 104 | |
| 105 | //export go_callback_int |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 106 | func go_callback_int(foo C.int, p1 C.int) { |
| 107 | fn := lookup(int(foo)) |
| 108 | fn(p1) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | func MyCallback(x C.int) { |
| 112 | fmt.Println("callback with", x) |
| 113 | } |
| 114 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 115 | func Example() { |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 116 | i := register(MyCallback) |
| 117 | C.CallMyFunction(C.int(i)) |
| 118 | unregister(i) |
| 119 | } |
| 120 | |
| 121 | var mu sync.Mutex |
| 122 | var index int |
| 123 | var fns = make(map[int]func(C.int)) |
| 124 | |
| 125 | func register(fn func(C.int)) int { |
| 126 | mu.Lock() |
| 127 | defer mu.Unlock() |
| 128 | index++ |
Ian Lance Taylor | 0a404a1 | 2016-06-03 11:03:43 -0700 | [diff] [blame] | 129 | for fns[index] != nil { |
| 130 | index++ |
| 131 | } |
Ian Lance Taylor | 19c2987 | 2016-06-02 12:14:05 -0700 | [diff] [blame] | 132 | fns[index] = fn |
| 133 | return index |
| 134 | } |
| 135 | |
| 136 | func lookup(i int) func(C.int) { |
| 137 | mu.Lock() |
| 138 | defer mu.Unlock() |
| 139 | return fns[i] |
| 140 | } |
| 141 | |
| 142 | func unregister(i int) { |
| 143 | mu.Lock() |
| 144 | defer mu.Unlock() |
| 145 | delete(fns, i) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 146 | } |
| 147 | ``` |
| 148 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 149 | ### Function pointer callbacks |
| 150 | |
| 151 | C code can call exported Go functions with their explicit name. But if a C-program wants a function pointer, a gateway function has to be written. This is because we can't take the address of a Go function and give that to C-code since the cgo tool will generate a stub in C that should be called. The following example shows how to integrate with C code wanting a function pointer of a give type. |
| 152 | |
| 153 | Place these source files under _$GOPATH/src/ccallbacks/_. Compile and run with: |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 154 | |
| 155 | ```console |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 156 | $ gcc -c clibrary.c |
| 157 | $ ar cru libclibrary.a clibrary.o |
Erwin Driessens | 61a22ba | 2015-09-14 01:05:39 +0200 | [diff] [blame] | 158 | $ go build |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 159 | $ ./ccallbacks |
| 160 | Go.main(): calling C function with callback to us |
| 161 | C.some_c_func(): calling callback with arg = 2 |
| 162 | C.callOnMeGo_cgo(): called with arg = 2 |
| 163 | Go.callOnMeGo(): called with arg = 2 |
| 164 | C.some_c_func(): callback responded with 3 |
| 165 | ``` |
| 166 | |
| 167 | **goprog.go** |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 168 | |
| 169 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 170 | package main |
| 171 | |
| 172 | /* |
| 173 | #cgo CFLAGS: -I . |
| 174 | #cgo LDFLAGS: -L . -lclibrary |
| 175 | |
| 176 | #include "clibrary.h" |
| 177 | |
| 178 | int callOnMeGo_cgo(int in); // Forward declaration. |
| 179 | */ |
| 180 | import "C" |
| 181 | |
| 182 | import ( |
| 183 | "fmt" |
| 184 | "unsafe" |
| 185 | ) |
| 186 | |
| 187 | //export callOnMeGo |
| 188 | func callOnMeGo(in int) int { |
| 189 | fmt.Printf("Go.callOnMeGo(): called with arg = %d\n", in) |
| 190 | return in + 1 |
| 191 | } |
| 192 | |
| 193 | func main() { |
| 194 | fmt.Printf("Go.main(): calling C function with callback to us\n") |
| 195 | C.some_c_func((C.callback_fcn)(unsafe.Pointer(C.callOnMeGo_cgo))) |
| 196 | } |
| 197 | ``` |
| 198 | |
| 199 | **cfuncs.go** |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 200 | |
| 201 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 202 | package main |
| 203 | |
| 204 | /* |
| 205 | |
| 206 | #include <stdio.h> |
| 207 | |
| 208 | // The gateway function |
| 209 | int callOnMeGo_cgo(int in) |
| 210 | { |
| 211 | printf("C.callOnMeGo_cgo(): called with arg = %d\n", in); |
Jaana Burcu Dogan | 69b7bf5 | 2016-07-29 13:55:27 -0700 | [diff] [blame] | 212 | int callOnMeGo(int); |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 213 | return callOnMeGo(in); |
| 214 | } |
| 215 | */ |
| 216 | import "C" |
| 217 | ``` |
| 218 | |
| 219 | **clibrary.h** |
emersion | c05f124 | 2018-07-07 22:38:42 +0100 | [diff] [blame] | 220 | |
| 221 | ```c |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 222 | #ifndef CLIBRARY_H |
| 223 | #define CLIBRARY_H |
| 224 | typedef int (*callback_fcn)(int); |
| 225 | void some_c_func(callback_fcn); |
| 226 | #endif |
| 227 | ``` |
| 228 | |
| 229 | **clibrary.c** |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 230 | |
emersion | c05f124 | 2018-07-07 22:38:42 +0100 | [diff] [blame] | 231 | ```c |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 232 | #include <stdio.h> |
| 233 | |
| 234 | #include "clibrary.h" |
| 235 | |
| 236 | void some_c_func(callback_fcn callback) |
| 237 | { |
| 238 | int arg = 2; |
| 239 | printf("C.some_c_func(): calling callback with arg = %d\n", arg); |
| 240 | int response = callback(2); |
| 241 | printf("C.some_c_func(): callback responded with %d\n", response); |
| 242 | } |
| 243 | ``` |
| 244 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 245 | ## Go strings and C strings |
| 246 | |
| 247 | Go strings and C strings are different. Go strings are the combination of a length and a pointer to the first character in the string. C strings are just the pointer to the first character, and are terminated by the first instance of the null character, ` '\0' `. |
| 248 | |
| 249 | Go provides means to go from one to another in the form of the following three functions: |
| 250 | * ` func C.CString(goString string) *C.char ` |
| 251 | * ` func C.GoString(cString *C.char) string ` |
| 252 | * ` func C.GoStringN(cString *C.char, length C.int) string ` |
| 253 | |
| 254 | One important thing to remember is that ` C.CString() ` will allocate a new string of the appropriate length, and return it. That means the C string is not going to be garbage collected and it is up to **you** to free it. A standard way to do this follows. |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 255 | |
| 256 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 257 | // #include <stdlib.h> |
| 258 | import "C" |
| 259 | import "unsafe" |
| 260 | ... |
| 261 | var cmsg *C.char = C.CString("hi") |
| 262 | defer C.free(unsafe.Pointer(cmsg)) |
| 263 | // do something with the C string |
| 264 | ``` |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 265 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 266 | Of course, you aren't required to use ` defer ` to call ` C.free() `. You can free the C string whenever you like, but it is your responsibility to make sure it happens. |
| 267 | |
| 268 | ## Turning C arrays into Go slices |
| 269 | |
| 270 | C arrays are typically either null-terminated or have a length kept elsewhere. |
| 271 | |
| 272 | Go provides the following function to make a new Go byte slice from a C array: |
| 273 | * ` func C.GoBytes(cArray unsafe.Pointer, length C.int) []byte ` |
| 274 | |
Ian Lance Taylor | eaa92d7 | 2015-12-04 14:41:43 -0800 | [diff] [blame] | 275 | To create a Go slice backed by a C array (without copying the original data), one needs to acquire this length at runtime and use a type conversion to a pointer to a very big array and then slice it to the length that you want (also remember to set the cap if you're using Go 1.2 or later), for example (see http://play.golang.org/p/XuC0xqtAIC for a runnable example): |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 276 | |
| 277 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 278 | import "C" |
| 279 | import "unsafe" |
| 280 | ... |
| 281 | var theCArray *C.YourType = C.getTheArray() |
| 282 | length := C.getTheArrayLength() |
Ayke | 036c78a | 2019-01-22 20:01:03 +0100 | [diff] [blame] | 283 | slice := (*[1 << 28]C.YourType)(unsafe.Pointer(theCArray))[:length:length] |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 284 | ``` |
| 285 | |
Ian Lance Taylor | eaa92d7 | 2015-12-04 14:41:43 -0800 | [diff] [blame] | 286 | It is important to keep in mind that the Go garbage collector will not interact with this data, and that if it is freed from the C side of things, the behavior of any Go code using the slice is nondeterministic. |
| 287 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 288 | ## Common Pitfalls |
| 289 | ### Struct Alignment Issues |
| 290 | As Go doesn't support packed struct (e.g., structs where maximum alignment is 1 byte), you can't |
Harrison Thorne | 4999ed8 | 2019-03-12 16:29:44 -0600 | [diff] [blame] | 291 | use packed C struct in Go. Even if your program passes compilation, it won't do what you want. |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 292 | To use it, you have to read/write the struct as byte array/slice. |
| 293 | |
| 294 | Another problem is that some types has lower alignment requirement than their counterpart in Go, |
| 295 | and if that type happens to be aligned in C but not in Go rules, that struct simply can't be represented |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 296 | in Go. An example is this ([issue 7560](https://github.com/golang/go/issues/7560)): |
| 297 | |
| 298 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 299 | struct T { |
| 300 | uint32_t pad; |
| 301 | complex float x; |
| 302 | }; |
| 303 | ``` |
| 304 | Go's complex64 has an alignment of 8-byte, where as C has only 4-byte (because C treats the |
| 305 | complex float internally as a ` struct { float real; float imag; } `, not a basic type), this T struct simply |
| 306 | doesn't have a Go representation. For this case, if you control the layout of the struct, move the |
| 307 | complex float so that it is also aligned to 8-byte is better, and if you're not willing to move it, |
| 308 | use this form will force it to align to 8-byte (and waste 4-byte): |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 309 | |
| 310 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 311 | struct T { |
| 312 | uint32_t pad; |
| 313 | __attribute__((align(8))) complex float x; |
| 314 | }; |
| 315 | ``` |
nathany | 86c47cc | 2014-12-10 09:43:20 -0800 | [diff] [blame] | 316 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 317 | However, if you don't control the struct layout, you will have to define accessor C functions for |
| 318 | that struct because cgo won't be able to translate that struct into equivalent Go struct. |
| 319 | |
| 320 | ### ` //export ` and definition in preamble |
| 321 | If a Go source file uses any ` //export ` directives, then the C code in the comment may only include declarations (` extern int f(); `), not definitions (` int f() { return 1; } ` or ` int n; `). |
| 322 | Note: you can use ` static inline ` trick to work around this restriction for tiny functions defined |
| 323 | in the preamble (see above for a complete example). |
| 324 | |
| 325 | ### Windows |
| 326 | |
William Cotton | 35515bc | 2018-10-12 00:52:37 +0200 | [diff] [blame] | 327 | In order to use cgo on Windows, you'll also need to first install a gcc compiler (for instance, mingw-w64) and have gcc.exe (etc.) in your PATH environment variable before compiling with cgo will work. |
| 328 | |
| 329 | ### environmental variables |
William Cotton | a126352 | 2018-10-12 01:17:06 +0200 | [diff] [blame] | 330 | Go os.Getenv() doesn't see variables set by C.setenv() |
| 331 | |
William Cotton | 35515bc | 2018-10-12 00:52:37 +0200 | [diff] [blame] | 332 | |
| 333 | ### tests |
| 334 | _test.go files can't use cgo. |