TL;DR: Call Rust code from Go using FFI
This repository shows how, by combining cgo
and Rust's FFI capabilities, we can call
Rust code from Go.
Two ways of achieving this are presented in this repository: with a dynamic library, and with a static library.
Run make run-all
to see Rust Go
in action, building and running two
binaries, one where the Rust code is compiled as a dynamic (sometimes also
referred to as a 'shared') library, and one where it is compiled as a static
library.
You should see the following output:
$ make run-all
Compiling libc v0.2.132
Compiling hello v0.1.0 (/home/user/rust-plus-golang/lib/hello)
Finished release [optimized] target(s) in 0.1s
Hello world!
(this is code from the dynamic library)
Finished release [optimized] target(s) in 0.00s
Hello world!
(this is code from the static library)
You will also find the binaries ./main_dynamic
and ./main_static
in your
current working directory.
The Rust code is packaged up into a dynamic library and a static library, and
the two Go binaries then call these using cgo
.
Andrew Oppenlander's article on creating a Rust dynamic library is a great introduction to this topic.
- Begin by creating a
lib
directory, where you will keep your Rust libraries. - Then, create a C header file for your library. See the example
hello.h
. - All that is left to do is to add some
cgo
-specific comments to your Go code. These comments tellcgo
where to find the library and its headers.
The following cgo
comments are required to use a dynamic library:
/*
#cgo LDFLAGS: -L./lib -lhello
#include "./lib/hello.h"
*/
import "C"
You must also pass the -ldflags
option to go build
(see the build-dynamic
target in
the Makefile
).
See main_dynamic.go
For a static library, an additional -ldl
LDFLAGS
flag is sometimes
necessary. This flag will link the dl
library.
/*
#cgo LDFLAGS: ./lib/libhello.a -ldl
#include "./lib/hello.h"
*/
import "C"
There should not be a newline between
*/
andimport "C"
.
See the build-static
target in the Makefile
and main_dynamic.go
.