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