Swig is a development tool that connects current C/C++ projects to other high-level languages. In plain English, it generates API code that can be called by other languages. For Go projects, he can directly generate corresponding CGO codes for C/C++ public project packaging. As Go application developers, they do not need to manually encapsulate CGO codes (written by others for you), thus reducing the cost of access parties.
Swig is not only designed for Go, but also works with advanced languages such as Python, Java, PHP, Javascript, etc. It can generate interfaces for the corresponding languages to facilitate quick application layer access.
This article focuses on swig and Go integration. If you are interested in other languages, check out the official documentation.
In practice, swig can be useful for large C++ projects. But for a small C project, using SWIG can complicate things, so it’s best to evaluate it on a case-by-case basis.
Installing swig
Linux installation directly download the source code to compile: www.swig.org/download.ht… Yum also provides swig packages, but the default version is older. MacOS can install swig directly using Brew Install swig. If you need another platform, check out the official documentation: swig Install
wget http://prdownloads.sourceforge.net/swig/swig-{versoin}.tar.gz && tar -zxvf
cd swig-*
./configure
make
sudo make install
Copy the code
Use the SWIG process
Swig is also not very complicated and consists of two main steps:
- define
swig
Swig interface file; - use
swig
The command line generates the corresponding language code; - Integrated use.
swig
Interface file
When using swig, you need to provide an interface file with the suffix. I or. Swig. This file is used to tell the specific operation logic of swig.
/* File : example.i */
%module example
%{
/* Put headers and other declarations here */
extern double My_variable;
extern int fact(int);
extern int my_mod(int n, int m);
%}
extern double My_variable;
extern int fact(int);
extern int my_mod(int n, int m);
Copy the code
/ *… */ represents the comment section.
%module represents the corresponding package name in GO. Finally, the corresponding CGO file will be converted into:
// example.go
package example
Copy the code
% {… %} represents the additional header file declaration variable or function declaration (if any) to be inserted, corresponding to the following section of the CGO file, which is no different from writing the CGO file directly:
/* extern void _wrap_My_variable_set_example_dffde00251d303fd(double arg1); extern double _wrap_My_variable_get_example_dffde00251d303fd(void); * /
import "C"
import "unsafe"
import _ "runtime/cgo"
Copy the code
Take the My_variable declared in example. I, and you’ll notice that the resulting code does not have the native My_variable name directly. Instead, it provides two wrapped getters and setters. Swig by default has a wrapper around the data types we want to expose, and the code is generated dynamically using the command line tool with the example. I interface file, so you can’t modify the code directly.
The reason for this is because SWIG requires additional data management, such as memory allocation, memory release, and so on. The user does not care about the memory management of these variables. Swig generates the corresponding memory management function method. Because for automatic memory management like GO and manual memory management like C, communication data memory management is not equal, just like the previous two sections of cGO code mentioned char * and other pointer type data memory release note problem.
The rest of example. I is a function method exposed to go. Swig generates the following three lines:
. extern double My_variable; extern int fact(int); extern int my_mod(int n, int m);Copy the code
The final example.go will generate a function method like the following:
/ / variable
func SetMy_variable(arg1 float64) {
_swig_i_0 := arg1
C._wrap_My_variable_set_example_dffde00251d303fd(C.double(_swig_i_0))
}
func GetMy_variable(a) (_swig_ret float64) {
var swig_r float64
swig_r = (float64)(C._wrap_My_variable_get_example_dffde00251d303fd())
return swig_r
}
/ / function
func Fact(arg1 int) (_swig_ret int) {
var swig_r int
_swig_i_0 := arg1
swig_r = (int)(C._wrap_fact_example_dffde00251d303fd(C.swig_intgo(_swig_i_0)))
return swig_r
}
// ...
Copy the code
Swig by default declares a set of getters and setters for each variable to manipulate the data. If you want the data to be readonly, you need to add the additional %immutable directive, which generates only getters. It applies to variables defined outside %{%} and %{%}.
/* Some read-only variables */
%immutable;
%inline %{
extern double My_variable;
%}
extern double My_variable;
Copy the code
Swig Operation command
The swig tool has the necessary command-line arguments for each integrated high-level language. To get the necessary arguments for Go:
-go
-cgo
-intgosize
Copy the code
If we want to generate a cGO file from example. I, we can do this:
swig -go -cgo -intgosize 64 example.i
Copy the code
The resulting file will look like this:
Example / ├ ─ ─ example. Go ├ ─ ─ example. I └ ─ ─ example_wrap. CCopy the code
Example.go is the code file that ultimately needs to be integrated in the GO language, and the accompanying example_wrap.c is the file that needs to be compiled in your common library.
The intGOsize parameter needs to tell the generator whether the current go compilation integer byte length is 64-bit or 32-bit. This is special. We can also guess the reason for this. The same problems can be encountered with native CGO coding.
Other Parameters
parameter | instructions |
---|---|
-cgo | The build file will act asgo tool cgo Input use,go1.5 Available after version, future will consider built-in as default parameter |
-intgosize |
Set up theGo int Type length,s Value of a32 or64 |
-package | Set the exported file package name, similar%module |
-use-shlib | Generate the shared library SO and export the GO project as a shared library to be useful |
-soname | Shared library name |
-gccgo | To selectgccgo When compiled, the default is only generated based ongc Compiler file |
-go-pkgpath | To selectgccgo Compiler time, setpkgpath |
-go-prefix | To selectgccgo Compiler time, set the path prefix. if-go-pkgpath If yes, this variable is ignored |
However, in practice, we found that it was possible not to use -cgo because we would normally build directly with go Build, which automatically recognizes the CGO code and selects the CGO tool to handle it. In addition, we generally use the built-in Go Compiler as the default compiler for compiling Go code, so the related GCCGO compiler is not used in many scenarios.
Integrated use of
With a basic understanding of SWIG, for the demonstration project above, suppose we have a C interface function that needs to be exposed to Go:
char* getName(a)
Copy the code
So we just need to implement this function function in C library, for example:
char* getName(a){
return "hello the swig";
}
Copy the code
Call this file example.c and place it in the example/ path with example. I.
%module example
%{
extern char* getName();
%}/* Extern char* getName(); /* extern char* getName();Copy the code
Note the code above, which exposes the Go function to the %{… %} is declared in the function matching, is necessary. Because the resulting file is essentially calling %{… The function declared in the %} code block.
As you can see from the figure above (red arrow) represents the resulting code, and the actual invocation becomes the steps shown by the green arrow.
Then run:
swig -go -intgosize 64 example/example.i
Copy the code
The final directory file structure is as follows:
Example ├ ─ ─ example. C ├ ─ ─ example. Go ├ ─ ─ example. I └ ─ ─ example_wrap. CCopy the code
The next step is to use the package directory directly in the Go code.
package main
import (
"cgo/example"
"fmt"
)
func main(a) {
fmt.Println(example.GetName())
}
Copy the code
The final output is as follows:
# go run main.go
hello the swig
Copy the code
The relevant data
swig
callcgo
Code examples:Github.com/swig/swig/t…swig
callcgo
Documents:Running SWIG with Go.