Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Go code in an existing C project

Tags:

c

go

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.

The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)

Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.

However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)

I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?

The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"

like image 871
dreadiscool Avatar asked Aug 25 '15 23:08

dreadiscool


People also ask

Can you use C libraries in go?

Go allows linking against C libraries or pasting in in-line code.

Is go fast as C?

While compile-time is dependant on what you're actually coding, Go is significantly faster to compile over C++. Since your code needs to be compiled before it's run and compiled again after every change you make, compile-time matters for coding speed.

Does go use C?

Go does not require any C libraries if that's what you're asking.


1 Answers

To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:

package main  import (     "C"     "fmt" )  //export PrintInt func PrintInt(x int) {     fmt.Println(x) }  func main() {} 

The important things to note are:

  • The package needs to be called main
  • You need to have a main function, although it can be empty.
  • You need to import the package C
  • You need special //export comments to mark the functions you want callable from C.

I can compile it as a C callable static library with the following command:

go build -buildmode=c-archive foo.go 

The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):

... typedef long long GoInt64; ... typedef GoInt64 GoInt; ... extern void PrintInt(GoInt p0); ... 

So that's enough to call the exported function. We can write a simple C program that calls it like so:

#include "foo.h"  int main(int argc, char **argv) {     PrintInt(42);     return 0; } 

We can compile it with a command like:

gcc -pthread foo.c foo.a -o foo 

The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.

like image 137
James Henstridge Avatar answered Oct 05 '22 22:10

James Henstridge