AI智能
改变未来

Sharing Golang packages to C and Go


Sharing Golang packages to C and Go

Sun, Aug 23, 2015

programming languages tutorial

The latest Go 1.5 version is out. As part of the new features, 

Go compiler

 can compile packages as a shared libraries.

It accepts 

-buildmode

 argument that determines how a package is compiled. These are the following options:

  • archive

    : Build the listed non-main packages into .a files. Packages named main are ignored.

  • c-archive

    : Build the listed main package, plus all packages it imports, into a C archive file.

  • c-shared

    : Build the listed main packages, plus all packages that they import, into C shared libraries.

  • shared

    : Combine all the listed non-main packages into a single shared library.

  • exe

    : Build the listed main packages and everything they import into executables. Packages not named main are ignored.

By default, listed main packages are built into executables and listed non-main packages are built into .a files.

In this article we will explore two major ways to share libraries between Go and C:

Using shared library in Go

Assume that 

GOPATH

 contains this structure:

.├── calc│   └── calc.go└── cashier└── main.go

The 

calc

 package contains a set of functions that do arithmetic opertaions:

// filename: calc.gopackage calcfunc Sum(x, y int) int {return x + y}

Before compile any shared library, the standard builtin packages should be installed as shared library. This will allow any other shared library to link with them.

$ go install -buildmode=shared -linkshared std

Then the 

calc

 package can be compiled as shared library linked to 

std

 libraries:

$ go install -buildmode=shared -linkshared calc

Due to a issue, building and installing shared library should be from 

$GOPATH/src

.

Lets use the shared library 

calc

 in the 

cashier

 application:

// package: cashier// filename: main.gopackage mainimport \"calc\"import \"fmt\"func main() {fmt.Println(\"Cashier Application\")fmt.Printf(\"Result: %d\\n\", calc.Sum(5, 10))}

The application should be compiled and linked with 

calc

 library with the following command:

$ go build -linkshared -o app cashier

The output of executing the application is:

$ ./appCashier ApplicationResult: 15

Note that this feature is available on 

linux/amd64

 platform or when 

gccgo

 compiler is used.

Using shared Go library in C

Go functions can be executed from C applications. They should be exported by using the following comment line:

//export <your_function_name>

In the code snippet below, the function 

SayHello

 and 

SayBye

 are exported:

// package name: nautiluspackage mainimport \"C\"import \"fmt\"//export SayHellofunc SayHello(name string) {fmt.Printf(\"Nautilus says: Hello, %s!\\n\", name)}//export SayByefunc SayBye() {fmt.Println(\"Nautilus says: Bye!\")}func main() {// We need the main function to make possible// CGO compiler to compile the package as C shared library}

The packaged should be compiled with 

buildmode

 flags 

c-shared

 or 

c-archive

:

// as c-shared library$ go build -buildmode=c-shared -o nautilus.a nautilus.go
// as c-archive$ go build -buildmode=c-archive -o nautilus.a nautilus.go

As result the 

GO

 compiler will produce a static/dynamic 

C

 library 

nautilus.a

 and header file 

nautilus.h

. The header file contains type definitions that marshall and unmarshall data between 

Go

 and 

C

:

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 __complex float GoComplex64;typedef __complex double GoComplex128;typedef struct { 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 __cplusplusextern \"C\" {#endifextern void SayHello(GoString p0);extern void SayBye();#ifdef __cplusplus}#endif

The header file 

nautilus.h

 shoulde be imported from every 

C

 application that executed 

SayHello

 and 

SayBye

 functions.

In the example below, the 

SayHello

 function is called with parameter of type

GoString

. It includes 

char*

 field and its length.

// filename: _wale.c#include \"nautilus.h\"#include <stdio.h>int main() {printf(\"This is a C Application.\\n\");GoString name = {\"Jack\", 4};SayHello(name);SayBye();return 0;}

The 

_wale.c

 file is compiled with the following command:

$ gcc -o _wale _wale.c nautilus.a

Execution produce the following output:

$ ./waleThis is a C Application.Nautilus says: Hello, Jack!Nautilus says: Bye!

Conclusion

Sharing libraries between 

C

 and 

Go

 gives opportunity to build greater and better application by using the best from both worlds. This provides to a legacy system a modern language that can improve their maintainance costs and business needs. It maximize code reusability in the 

Go

 ecosystem.

转载于:Go语言/3cwYg4

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Sharing Golang packages to C and Go