Lopson Lopson - 1 year ago 127
C Question

Using Go on existing C project

I have a program entirely written in C that uses multiple object

(.o)
files in it. These files are all packed inside an archive file
(.a)
which, in turn, is used at compile-time of the program's main
(.c)
file.

I want to write a new file for this project in Go. My idea is to write this
.go
file and then create an object
(.o)
file from it. Afterwards, I want to put this object file inside the already mentioned archive
(.a)
file.

This basically means that I want to call Go functions from a C program. I've read this question, and while it showed me that what I want is possible via GCCGO, it's not 100% clear as to how to do it.

Even with the most basic of tests, I get errors during the linking phase. More specifically, here's one of such basic example:




printString.go

package main

import
(
"fmt"
)

func PrintString(buff string) int {
fmt.Printf(buff)
return 1
}


c_caller.c

#define _GNU_SOURCE
#include <stdio.h>

extern int PrintString(char*) __asm__ ("print.main.PrintString");

int main() {
char *string_to_pass= NULL;
asprintf(&string_to_pass, "This is a test.");

int result= PrintString(string_to_pass);
if(result) {printf("Everything went as expected!\n");}
else {printf("Uh oh, something went wrong!\n");}

return result;
}


Compiling

In order to compile the Go file, I used this command:

gccgo -c printString.go -o printString.o -fgo-prefix=print -Wall -Werror -march=native


In order to compile the entire thing, I used this command:

gccgo -o main c_caller.c printString.o -Wall -Werror -march=native


The return message I'm getting is:

/usr/lib64/libgo.so.4.0.0: undefined reference to `main.main'
/usr/lib64/libgo.so.4.0.0: undefined reference to `__go_init_main'
collect2: error: ld returned 1 exit status


Which means that GCCGO's expecting a main function in the Go file instead of the C one.

Using the
--static-libgo
,
-static
and
-Wl,-R,/path/to/libgo.so's_folder
options on the second command yield a different result:

/usr/bin/ld: cannot find -lgo
collect2: error: ld returned 1 exit status


Which makes no sense, since I have the LD_LIBRARY_PATH environment variable properly pointing to libgo.so's folder.




I realize that I'm probably doing something wrong here, but I just can't see what that is. There's next to no examples of GCCGO and its interaction with C out there, and the only reference I could find was this page, which I personally feel like it's not enough.

I ask kindly for some advice on this matter and thank you for your time. :)

Answer Source

This may not be what you want, but in Go 1.5, that's coming this August, you'll be able to build C-compatible libraries with the go tool. So with this in your _main.c

#include <stdio.h>

int main()
{
    char *string_to_pass = NULL;
    if (asprintf(&string_to_pass, "This is a test.") < 0) {
        printf("asprintf fail");
        return -1;
    }

    PrintString(string_to_pass);
    return 0;
}

and this in your main.go

package main

import "C"
import "fmt"

//export PrintString
func PrintString(cs *C.char) {
    s := C.GoString(cs)
    fmt.Println(s)
}

func main() {}

You can do, for static library:

go build -buildmode c-archive -o mygopkg.a
gcc -o main _main.c mygopkg.a -lpthread

For shared library:

go build -buildmode c-shared -o mygopkg.so
LD_RUN_PATH=$(pwd) gcc -o main _main.c mygopkg.so -lpthread

(LD_RUN_PATH is here to make the linker look for the shared library in the same directory you're building.)

See the Go execution modes design document for more info.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download