Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save metacritical/e5d624715363ffe0370dbf247594e6b5 to your computer and use it in GitHub Desktop.
Save metacritical/e5d624715363ffe0370dbf247594e6b5 to your computer and use it in GitHub Desktop.
Embedding GoLang into a Ruby application - Blogpost to Magrathealabs

I am passionate about ruby, but to date it is complicated to implement more complex data structures. In general, data structures in interpreted languages become incredibly slow compared to compiled languages.

This is one of the reasons I was interested in using GoLang code snippets within the ruby environment. For this, I studied how to export compiled golang codes to shared libraries.

For those who do not know the operation of the shared libraries, they work in a similar way as the dll files in windows, however it is a native code with a direct interface to the C compiler.

Note: Windows uses the DLL system, and in this case, this does not necessarily have to be in native code. One example is DLLs with C #, which runs on a virtual machine. Because I do not use windows, I ended up not testing if it is possible to perform these steps on this operating system.

1. Create your GoLang library!

It would be like any library, but it must have some peculiar characteristics.

Preparing the environment

You need GoLang 1.5 or higher.

Use C language types

For signing external functions to your library, you will need to use the C language typing. For the rest of the code you can convert to the standard GoLang typing.

To do this include library:

import "C"

Function export signature

You need to tell the golang compiler which functions will be public in the library. For this you should create a comment above your function.

import "C"

//export MyAdd
func my_add(a, b C.int) C.int {
   return a + b
}


func main() {
// This is necessary for the compiler.
// You can add something that will be executed when engaging your library to the interpreter.
}

Remember that the exported functions must be in your main package.

Note: I know that the Golang standard for function names is not this, but it is the default for functions in C and Ruby. For this reason, I got used to writing the functions that will be exported to the same pattern.

Compile

Just type:

  go build -o my_lib.so -buildmode=c-shared my_file.go

Writing the interface with the shared library in ruby

There are more efficient ways to write native Ruby code, but this is the most readable and efficient way I've found.

Preparing the environment

You need to be in an environment **ix. That is, linux or MacOS. We will need these two systems because the gem we will use only guarantees its operation in these two environments.

Add to your gemfile the following line:

  gem 'ffi'

Or of course, install manually: gem install ffi

Create a module for your library

Just create a module and write your function signatures inside the ruby package. This will act as your library .h file.

require 'ffi'

module Foo
  extend FFI::Library
  ffi_lib './my_lib.so'

  attach_function :my_add, [:int, :int], :int
end

puts Foo.my_add(2, 2)
# => 4

What I noticed using native code in GoLang?

Running the native code is very fast, however, the interface call is not so fast.

It's great to use this to solve complex computational problems which involve dynamic programming, graphs, ad hoc and others. Some issues I solved in go lang took a thousandths of seconds compared to seconds in ruby.

Another point is the care when writing the exported functions. The C functions have no garbage collector!

Parallelism in GoLang is MUCH BETTER than in Ruby. Think about it carefully and lovingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment