winwaed
winwaed

Reputation: 7829

Calling a static C/C++ library from Go

I'm still on the learning curve with Go, but I've managed to compile and run a Go program that includes a C object file. The objective is to call an existing static C++ library. The call will be a bit like a command line invocation - so a simple C wrapper function is perfectly acceptable, and arguably simpler. Unfortunately, I cannot get Go to recognize this wrapper!

I've simplified my code to the following...

package main

// #cgo CFLAGS: -I. -g -Wall
// #cgo LDFLAGS: -L. -lSMHeatmapLib
// #include <stdlib.h>
// #include "ExternalJSON.h"
import "C"

import (
    "fmt"
    "unsafe"
)
    
const MAX_RETURN_BUFFER int = 8192
    
func main() {
    var result_str string;

    in_json := "The cat sat on the mat"
    
    in_buff := C.CString(in_json)
    defer C.free(unsafe.Pointer(in_buff))

    in_sz := C.int( len(in_json) )

    out_buff := C.malloc( C.sizeof_char * MAX_RETURN_BUFFER )
    defer C.free(unsafe.Pointer(out_buff) )
        
    sz := C.RunWithJSON(in_buff,in_sz, (*C.char)(out_buff),MAX_RETURN_BUFFER);

    b:= C.GoBytes(out_buff,sz)

    result_str = string(b)
    fmt.Printf("Return: >%s<\n", result_str)
}

ExternalJSON.h is as follows:

int RunWithJSON( char* in, int in_len, char* out, int max_out);

And ExternalJSON.c:

#include "ExternalJSON.h"

int RunWithJSON( char* in, int in_len, char* out, int max_out)
{
  for (int i=0; i<in_len; i++)
    {
      out[in_len-1-i] = in[i];
    }
  
  int olen = in_len;
  // and add a marker on the end
  out[olen++] = '#';
  out[olen++] = '\0';
  return olen;
}

(ie. just a simple test at the moment: String in, String out. As you can guess we'll be working with JSON later) This is built with gcc. (the rest of the library is C++ and uses g++) For the final link I use:

ar rcs $(TARGET) $(OBJS)

To remove the potential for any path issues, I copy the static library and ExternalJSON.h to the same directory as main.go .

Building with go build, the result is:

# _/my/path/main
/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_750343fded39_Cfunc_RunWithJSON':
/tmp/go-build/cgo-gcc-prolog:58: undefined reference to `RunWithJSON'
collect2: error: ld returned 1 exit status

Why can't go see the function definition in the library?

Yes I saw: How do you statically link a c library in go using cgo? but the suggested command line invocation of go build did not work either.

Upvotes: 2

Views: 88

Answers (1)

winwaed
winwaed

Reputation: 7829

Yes the function was being compiled as a C++ name, even though it was entirely C with no object references.

There are two solutions:

  1. Compile the code as pure C using gcc instead of g++. The file has to be pure C though, and the intention is to use it as an interface to the underlying C++ library.

  2. Use extern "C", eg:

extern "C" {    
  int myFunction (char* wibble) { 
     // Do stuff with C++
  }
}

This lets you compile the source file as C++ (essential if you're going to use objects), but everything in the extern "C" { } (eg. the wrapper function myFunction ) is still accessible externally from Go.

Upvotes: 0

Related Questions