yxhl

导航

统计

CGO Swig 使用笔记

Cgo Swig 指北

官网: https://www.swig.org/

Linux 编译 Swig

先下载到 swig 的压缩包解压

必要条件

  • Autoconf 2.58 or higher
  • Automake 1.7.2 or higher
  • A working C and C++ compiler.
  • Bison 3.5.0 or higher (to generate the SWIG parser).
  • Libpcre (regular expressions library dependency)

通常方法,如果系统中带有足够的编译条件,直接配置安装到系统中

$ tar -xf swig-4.2.0.tar.gz
$ cd swig-4.2.0
$ ./configure
$ make
$ make install

但是在实际工作中,不大可能直接安装到编译服务器中,需要打包到项目里。

安装目录指定

通过 ./configure 的参数 --prefix 指定后续安装的目录

$ ./configure --prefix=/projects_path/bin
$ make
$ make install

编译完成会在 prefix 指向的目录下生成 swig 的可执行文件和代码示例,这些生成文件不能移动,否则会出现路径不对导致的报错。

补充 PCRE2 依赖

可能系统中没有这个依赖,我们需要去官网下载最新的版本,然后放置到 swig 的源码文件夹中,再执行脚本仅给 swig 提供 pcre 的支持,例如:

$ cp ./pcre2-10.44.tar.gz ./swig-4.2.0
$ cd swig-4.2.0
$ Tools/pcre-build.sh

补充 Bison 依赖

系统中可能没有合适的 Bison 版本,我们可以自行编译使用。https://ftp.gnu.org/gnu/bison/

下载合适的 Bison >3.5.0 版本

tar -xf bison-3.8.tar.gz
cd bison-3.8 && ./configure --enable-relocatable --prefix=/bison && make && make install DESTDIR=$HOME/bin

编译完成 Bison 后,在编译 swig 前设置 PATH 变量就好了

为 C/C++ 程序生成 CGO 接口文件

Swig 通过一个后缀为 *.i 的描述文件来生成接口,这个描述文件包含 swig 特殊指令和以及 C/C++ 标准描述语句。

常用参数

  • %module:每个 SWIG 接口都有一个 module 参数来描述生成接口的模块名称,在 CGO 中可以等价于生成的 GO 文件的 package 的名称。
  • %{...%}:括号包裹的内容,会被原封不动的拷贝到 wrapper 文件中,一般用于给包装文件引用源码头文件。
  • %rename (dest_type) source_type:将 source_type 重命名为 dest_type ,用来生成转换后的接口,可以用于对不支持的嵌套 union 结构体等不支持的嵌套类型的重命名接口生成。注意这个 %rename 参数要位于 %include 之前,否则不会进行替换当中的内容。
  • %ignore:用于忽略一些函数或者参数的包装转换,可以用于对未实现内容的略过。
  • %include:这个命令用于给 SWIG 引入需要包装转换的头文件,SWIG 会包装转换头文件中包含的函数声明,为 C++ 类生成一对 NewXxxxDeleteXxxx 的创建删除接口(脱离 GO 的 GC)等。
  • %feature:用于启用某些 SWIG 特性,例如 flatnested
    • flatnested:针对不支持嵌套的语言,生成非嵌套的内容。
%feature ("flatnested");
%include "xxxx.h"
%feature("flatnested", "");
  • %insert(cgo_comment):用于直接在 CGO 包装文件中插入注释,例如给 CGO 文件插入链接参数 %insert(cgo_comment) %{#cgo LDFLAGS: -L./ -lmylib -ldl%}
  • %insert(go_wrapper):用于在 CGO 包装文件中插入内容,可以搭配 ignore 使用。可以对一些被 SWIG 跳过的冲突变量进行补充,由于一些宏定义会被 SWIG 自动替换成变量,但是可能存在冲突,此时就可以根据生成时的冲突提示,手动补充这些变量。或者编写插入一些自定义的补充函数以此集成封装。
  • 此外还可以编写一些结构体让 SWIG 帮助生成接口,对于无法或不便于整体用 %include 导入的头文件,可以利用这个方法部分生成包装方法。

包装命令

  • 例如针对 C++ 生成 CGO 包装
$ ./swig -go -gccgo -c++ -intgosize 64 swig_my.i

执行后会在当前目录下自动生成包装文件 xxxx.cxx 和一个 CGO 的接口文件。

建议可以通过 Makefile 等方式将引用到的 C/C++ 头文件拷贝到同一路径中,避免其他项目引用这个包装工程时,编译出现无法找到头文件的情况。

示例

这个示例针对 mylib.h 的头文件做 CGO 的包装,由于带有相同名称的嵌套的结构体,在使用 SWIG 4.2.1 版本时,这些嵌套的结构不会被标记正确的名称,所以在包装文件中,使用了 rename 来重命名符号,让包装器生成正确的 CGO 接口。

  • mylib.h
// mylib.h
typedef struct My_Struct_1 {
short choise;
union _union {
short choise_1;
short choise_2;
} u;
} My_Struct_1;
typedef struct My_Struct_2 {
short choise;
union _union {
short choise_3;
short choise_4;
} u;
} My_Struct_2;
  • my_swig.i
%module mylib
%rename (My_Struct_1_union) My_Struct_1::_union;
%rename (My_Struct_2_union) My_Struct_2::_union;
%{
#include "mylib.h"
%}
%feature ("flatnested");
%include "mylib.h"
%feature ("flatnested", "");
%insert(cgo_comment) %{
#cgo LDFLAGS: -L./ -lmylib -ldl
%}

常见包装警告和对应处理

  • xxxx.h: Warning 325: Nested union not currently supported (_union ignored)

嵌套联合结构不支持,可以对该头文件使用非嵌套特性

# my_swig.i
%feature ("flatnested");
%include "xxxx.h"
%feature("flatnested", "");
  • xxxx.h: Warning 890: Ignoring 'STRUCT_present' due to Go name ('Present') conflict with 'OTHERSTRUCT_present'

结构体宏定义在包装时,由于包装器命名不完全导致冲突,可以手动插入变量定义解决缺失问题

# my_swig.i
%insert(go_wrapper) %{
const STRUCT_present int = 0x01
const OTHERSTRUCT_present int = 0x02
}
  • xxxx.h: Warning 890: Ignoring '_union' due to Go name ('X_union') conflict with '_union'

结构体中嵌套匿名结构体时,包装没有生成正确的名称,可以通过 %rename 重命名再让包装器进行包装

%rename (My_Struct_1_union) My_Struct_1::_union;
%rename (My_Struct_2_union) My_Struct_2::_union;

posted on   花狸狸  阅读(65)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签
点击右上角即可分享
微信分享提示