2

How to use Golang Generated libgolang.a from C code to build C executable: test.exe:

these commands makes executable binary 'test' in Ubuntu x86-64 and works fine (but not in Windows x86-64):

go build -buildmode c-archive -o libgolang.a
gcc -o test _main.c libgolang.a -lpthread

with:
this is main.go file:

package main

import "C"
import "fmt"

//export Add
func Add(a, b uint64) uint64 {
    return a + b
}

func main() {
    fmt.Println("Hi")
}

and this is _main.c file:

#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"

int main()
{
    uint64_t a=10;
    uint64_t b=20;
    uint64_t c=Add(a,b);
    printf("%ld\n",c);
    return 0;
}

in Windows this command:

go build -buildmode c-archive -o libgolang.a

works fine and generates libgolang.a and libgolang.h files. libgolang.h:

/* Created by "go tool cgo" - DO NOT EDIT. */

/* package github.com/ARamazani/go/DLL */

/* Start of preamble from import "C" comments.  */




/* End of preamble from import "C" comments.  */


/* Start of boilerplate cgo prologue.  */

#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H

typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;

/*
  static assertion to make sure the file is being used on architecture
  at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];

typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;

#endif

/* End of boilerplate cgo prologue.  */

#ifdef __cplusplus
extern "C" {
#endif


extern GoUint64 Add(GoUint64 p0, GoUint64 p1);

#ifdef __cplusplus
}
#endif

but this command:

gcc -o test _main.c libgolang.a -lpthread

output:

libgolang.a(go.o):(.data+0x2150): undefined reference to `NtWaitForSingleObject'
libgolang.a(go.o):(.data+0x21b8): undefined reference to `WSAGetOverlappedResult'
libgolang.a(go.o):(.data+0x21d8): undefined reference to `timeBeginPeriod'
collect2.exe: error: ld returned 1 exit status

go version go1.7rc3 windows/amd64

I want to use this libgolang.a from C code to build C executable: test.exe

any workaround?

some useful links:

http://blog.ralch.com/tutorial/golang-sharing-libraries/
Using Go code in an existing C project
Using Go on existing C project

Community
  • 1
  • 1
  • This question is similar to [this one](http://stackoverflow.com/questions/37451700/access-golang-module-from-visual-c). – jnmoal Jun 25 '16 at 04:06
  • @jean-nicolas-moal: no it's not. –  Jul 18 '16 at 11:14
  • ok. Can you give us more information on what's happening on windows (build or runtime error)? – jnmoal Jul 23 '16 at 06:23
  • The first thing I can see is that your main.c file doesn't know the Go "Add" function. You should include the go generated header in your main.c. And go 1.7 is not out yet, why do you use it? The second thing, it seems that the linker doesn't find a library ("the undefined reference to" error), but I don't know those functions (I'm not a windows user) hope that someone has an idea for those linker errors. – jnmoal Jul 27 '16 at 11:45

2 Answers2

3

Finally found at least one way:
using this file main.go:

package main

import "C"
import "fmt"

//export Add
func Add(a, b uint64) uint64 {
    return a + b
}

func main() {
    fmt.Println("Hi")
}

run this command:

go build -buildmode c-archive -o libgolang.a

to generate libgolang.a and libgolang.h then using _main.c:

#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"

int main()
{
    uint64_t a=10;
    uint64_t b=20;
    uint64_t c=Add(a,b);
    printf("%ld\n",c);
    return 0;
}

this is the answer (this works for me):

gcc -o test _main.c libgolang.a -lWinMM -lntdll -lWS2_32

that test.exe created.

run:

test.exe

output:

30
0

The Microsoft Windows always trick us!

But for production code my suggestion is use the optimization compile commands below:

go build -ldflags "-s -w" -buildmode c-archive -o libgolang.a

The parameter -ldflags "-s -w", will reduze the final file size.

The "libgolang.a" shrink from 4.295.562 to 1.994.554.

And the "test.exe" shrink from 3.430.485 to 1.715.561.

I guess this is a desired behavior!