Use another language to call a function: Difference between revisions
Content deleted Content added
Line 278: | Line 278: | ||
Output: |
Output: |
||
<pre> |
<pre> |
||
Here am I |
|||
</pre> |
|||
=== Alternative Method === |
|||
As of Go 1.5, this is now possible without modifying the C code thanks to the addition of buildmodes. Buildmodes allow Go code to be compiled to standard C libraries (both dynamic and static). |
|||
The Go code for this task is as follows: |
|||
<lang go> |
|||
// This buildmode requires the package to be main |
|||
package main |
|||
// Import C so we can export the function to C and use C types |
|||
//#include <stdlib.h> // for size_t |
|||
import "C" |
|||
// Import reflect and unsafe so we can wrap the C array in a Go slice |
|||
import "reflect" |
|||
import "unsafe" |
|||
// This buildmode also requires a main function, but it is never actually called |
|||
func main() {} |
|||
// The message to copy into the buffer |
|||
const msg = "Here am I" |
|||
// Here we declare the Query function using C types and export it to C |
|||
//export Query |
|||
func Query(buffer *C.char, length *C.size_t) C.int { |
|||
// Check there is enough space in the buffer |
|||
if int(*length) < len(msg) { |
|||
return 0 |
|||
} |
|||
// Wrap the buffer in a slice to make it easier to copy into |
|||
sliceHeader := reflect.SliceHeader { |
|||
Data: uintptr(unsafe.Pointer(buffer)), |
|||
Len: len(msg), |
|||
Cap: len(msg), |
|||
} |
|||
bufferSlice := *(*[]byte)(unsafe.Pointer(&sliceHeader)) |
|||
// Iterate through the message and copy it to the buffer, byte by byte |
|||
for i:=0;i<len(msg);i++ { |
|||
bufferSlice[i] = msg[i] |
|||
} |
|||
// Set length to the amount of bytes we copied |
|||
(*length) = C.size_t(len(msg)) |
|||
return 1 |
|||
} |
|||
</lang> |
|||
Assuming this is saved to query.go (and that the C code is saved as main.c) it can be compiled with: |
|||
<pre> |
|||
$ go build -buildmode=c-shared query.go |
|||
$ gcc main.c -L. -lquery -o main |
|||
</pre> |
|||
This creates a library file, a header file for the library (not used) and an executable dynamically linked to the library file. |
|||
The executable can be run with: |
|||
<pre> |
|||
$ LD_LIBRARY_PATH=. ./main |
|||
Here am I |
Here am I |
||
</pre> |
</pre> |