CGO Swig 使用笔记
Cgo Swig 指北
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++ 类生成一对NewXxxx
和DeleteXxxx
的创建删除接口(脱离 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;
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签