跨语言调用神器SWIG介绍与使用入门
suiw9 2024-11-14 19:11 18 浏览 0 评论
安装#
依赖 PCRE 库
Copyapt-get install libpcre2-dev
下载安装
Copy$ ./configure
$ make
$ make install
介绍#
SWIG 是一个软件开发工具,能够简化不同编程语言与 C 和 C++ 程序连接的开发任务。
简而言之,SWIG 是一款编译器,它可以获取 C/C++ 声明并创建访问这些声明所需的包装器,从而可从包括 Perl、Python、Tcl、Ruby、Guile 和 Java 在内的其他语言访问这些声明。SWIG 通常不需要修改现有代码,而且通常只需几分钟即可构建一个可用的接口。
本质上,SWIG 是一个为生成代码而设计的工具,该工具可以让各种其他编程语言调用 C/C++ 代码。这些更高级的编程语言是 SWIG 代码生成器的目标语言,而 C 或 C++ 是输入语言。在运行 SWIG 时必须指定一种目标语言。这将为 C/C++ 和指定的目标语言生成代码,以便相互进行接口
这种将 C/C++ 与许多不同目标语言连接的能力是 SWIG 的核心优势和特性之一。
从一个c库开始#
假设,这里有一个c代码,我们要提供给python和golang、java等调用。
下面是代码:
Copy/* File : example.c */
double My_variable = 3.0;
/* Compute factorial of n */
int fact(int n) {
if (n <= 1)
return 1;
else
return n*fact(n-1);
}
/* Compute n mod m */
int my_mod(int n, int m) {
return(n % m);
}
你或许会想,是不是要先学习下python扩展如何写,JNI如何搞,cgo如何弄。。
但是,当你有了SWIG,这一切就变得更简单了。开始之前,我们首先需要编写一个swig接口.
swig接口#
swig接口,你可以理解为就像pb文件一样,要先定义一套标准的接口(interface),然后swig负责根据这个swig interface,去生成连接其他语言的胶水代码。
Copy%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);
- 接口文件包含 C 函数原型和变量声明。
- %module 指令定义了 SWIG 将创建的模块的名称。
- {% %} 块提供了一个位置,用于将其他代码(如 C 头文件或附加 C 声明)插入到生成的 C 包装器代码中
接口就绪后,我们可以来生成对应语言的胶水代码了。
python调用c#
首先通过swig -{lang} example.i 生成wrap胶水代码。
Copyswig -python example.i
这里会生成;
- example_wrap.c 连接c代码的wrap
- example.py 可以类比GRPC生成的访问wrap的代码。
我们来看下生成的包装代码example_wrap.c:
Copy/* ----------------------------------------------------------------------------
* This file was automatically generated by SWIG (https://www.swig.org).
* Version 4.1.1
*
* Do not make changes to this file unless you know what you are doing - modify
* the SWIG interface file instead.
* ----------------------------------------------------------------------------- */
/* source: example.i */
#define SWIG_VERSION 0x040101
#define SWIGGO
#define SWIGMODULE example
/* -----------------------------------------------------------------------------
* This section contains generic SWIG labels for method/variable
* declarations/attributes, and other compiler dependent labels.
* ----------------------------------------------------------------------------- */
/* template workaround for compilers that cannot correctly implement the C++ standard */
#ifndef SWIGTEMPLATEDISAMBIGUATOR
# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
# define SWIGTEMPLATEDISAMBIGUATOR template
# elif defined(__HP_aCC)
/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
# define SWIGTEMPLATEDISAMBIGUATOR template
# else
# define SWIGTEMPLATEDISAMBIGUATOR
# endif
#endif
/* inline attribute */
#ifndef SWIGINLINE
# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
# define SWIGINLINE inline
# else
# define SWIGINLINE
# endif
#endif
/* attribute recognised by some compilers to avoid 'unused' warnings */
#ifndef SWIGUNUSED
# if defined(__GNUC__)
# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
# define SWIGUNUSED __attribute__ ((__unused__))
# else
# define SWIGUNUSED
# endif
# elif defined(__ICC)
# define SWIGUNUSED __attribute__ ((__unused__))
# else
# define SWIGUNUSED
# endif
#endif
#ifndef SWIG_MSC_UNSUPPRESS_4505
# if defined(_MSC_VER)
# pragma warning(disable : 4505) /* unreferenced local function has been removed */
# endif
#endif
#ifndef SWIGUNUSEDPARM
# ifdef __cplusplus
# define SWIGUNUSEDPARM(p)
# else
# define SWIGUNUSEDPARM(p) p SWIGUNUSED
# endif
#endif
/* internal SWIG method */
#ifndef SWIGINTERN
# define SWIGINTERN static SWIGUNUSED
#endif
/* internal inline SWIG method */
#ifndef SWIGINTERNINLINE
# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
#endif
/* exporting methods */
#if defined(__GNUC__)
# if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
# ifndef GCC_HASCLASSVISIBILITY
# define GCC_HASCLASSVISIBILITY
# endif
# endif
#endif
#ifndef SWIGEXPORT
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
# if defined(STATIC_LINKED)
# define SWIGEXPORT
# else
# define SWIGEXPORT __declspec(dllexport)
# endif
# else
# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
# define SWIGEXPORT __attribute__ ((visibility("default")))
# else
# define SWIGEXPORT
# endif
# endif
#endif
/* calling conventions for Windows */
#ifndef SWIGSTDCALL
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
# define SWIGSTDCALL __stdcall
# else
# define SWIGSTDCALL
# endif
#endif
/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
#endif
/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
# define _SCL_SECURE_NO_DEPRECATE
#endif
/* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */
#if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES)
# define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#endif
/* Intel's compiler complains if a variable which was never initialised is
* cast to void, which is a common idiom which we use to indicate that we
* are aware a variable isn't used. So we just silence that warning.
* See: https://github.com/swig/swig/issues/192 for more discussion.
*/
#ifdef __INTEL_COMPILER
# pragma warning disable 592
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
typedef ptrdiff_t intgo;
typedef size_t uintgo;
# if !defined(__clang__) && (defined(__i386__) || defined(__x86_64__))
# define SWIGSTRUCTPACKED __attribute__((__packed__, __gcc_struct__))
# else
# define SWIGSTRUCTPACKED __attribute__((__packed__))
# endif
typedef struct { char *p; intgo n; } _gostring_;
typedef struct { void* array; intgo len; intgo cap; } _goslice_;
static void Swig_free(void* p) {
free(p);
}
static void* Swig_malloc(int c) {
return malloc(c);
}
/* Put headers and other declarations here */
extern double My_variable;
extern int fact(int);
extern int my_mod(int n, int m);
#ifdef __cplusplus
extern "C" {
#endif
void _wrap_Swig_free_example_c8af3355f0aa50cc(void *_swig_go_0) {
void *arg1 = (void *) 0 ;
arg1 = *(void **)&_swig_go_0;
Swig_free(arg1);
}
void *_wrap_Swig_malloc_example_c8af3355f0aa50cc(intgo _swig_go_0) {
int arg1 ;
void *result = 0 ;
void *_swig_go_result;
arg1 = (int)_swig_go_0;
result = (void *)Swig_malloc(arg1);
*(void **)&_swig_go_result = (void *)result;
return _swig_go_result;
}
void _wrap_My_variable_set_example_c8af3355f0aa50cc(double _swig_go_0) {
double arg1 ;
arg1 = (double)_swig_go_0;
My_variable = arg1;
}
double _wrap_My_variable_get_example_c8af3355f0aa50cc() {
double result;
double _swig_go_result;
result = (double)My_variable;
_swig_go_result = result;
return _swig_go_result;
}
intgo _wrap_fact_example_c8af3355f0aa50cc(intgo _swig_go_0) {
int arg1 ;
int result;
intgo _swig_go_result;
arg1 = (int)_swig_go_0;
result = (int)fact(arg1);
_swig_go_result = result;
return _swig_go_result;
}
intgo _wrap_my_mod_example_c8af3355f0aa50cc(intgo _swig_go_0, intgo _swig_go_1) {
int arg1 ;
int arg2 ;
int result;
intgo _swig_go_result;
arg1 = (int)_swig_go_0;
arg2 = (int)_swig_go_1;
result = (int)my_mod(arg1,arg2);
_swig_go_result = result;
return _swig_go_result;
}
#ifdef __cplusplus
}
#endif
可以看到,自动生成的wrap代码为interface里的函数,变量都生成了包装函数,通过extern "C"实现wrap函数导出,后续的其他编程语言可以通过访问这些导出的wrap函数,实现访问原来的c函数。
编译模块#
我们现在来生成一个python代码模块。
Copy
[root@dev swig_demo]#gcc -c -fpic example.c example_wrap.c -I/root/anaconda3/include/python3.9
[root@dev swig_demo]#gcc -shared example.o example_wrap.o -o _example.so
[root@dev swig_demo]#ll
total 244
drwxr-xr-x 3 root root 4096 Jan 18 19:40 ./
drwxr-xr-x 4 root root 4096 Jan 18 19:28 ../
-rw-r--r-- 1 root root 203 Jan 18 19:28 example.c
-rw-r--r-- 1 root root 244 Jan 18 19:29 example.i
-rw-r--r-- 1 root root 1560 Jan 18 19:39 example.o
-rw-r--r-- 1 root root 2101 Jan 18 19:36 example.py
-rwxr-xr-x 1 root root 52480 Jan 18 19:39 _example.so*
-rw-r--r-- 1 root root 110727 Jan 18 19:36 example_wrap.c
-rw-r--r-- 1 root root 53240 Jan 18 19:39 example_wrap.o
[root@dev swig_demo]#python3
Python 3.9.13 (main, Aug 25 2022, 23:26:10)
[GCC 11.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> example.fact(4)
24
>>> example.my_mod(23, 7)
2
>>> example.cvar.My_variable + 4.5
7.5
>>>
- swig -python example.i 会生成一个c包装代码example_wrap.c 和python 库代码example.py
- example.py 里的函数定义和interface一致,实际上里面有代码去访问之前生成的wrap接口。
- gcc -c -fpic example.c example_wrap.c -I/root/anaconda3/include/python3.9 这里编译代码,需要指定下python include代码,根据实际位置指定
与CMake等build system集成#
swig支持与cmake等集成,我们编写一个cmakelists.txt文件
CopyFIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})
FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SWIG_FLAGS "")
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(example python example.i example.c)
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})
编译:
Copy[root@dev swig_demo]#mkdir build
[root@dev swig_demo]#cd build/
[root@dev build]#cmake ..
[root@dev build]#make
Scanning dependencies of target example_swig_compilation
[ 25%] Swig compile example.i for python
[ 25%] Built target example_swig_compilation
[ 50%] Building CXX object CMakeFiles/_example.dir/CMakeFiles/_example.dir/examplePYTHON_wrap.o
[ 75%] Building C object CMakeFiles/_example.dir/example.o
[100%] Linking CXX shared module _example.so
[100%] Built target _example
[root@dev build]#ls
CMakeCache.txt CMakeFiles cmake_install.cmake example.py _example.so Makefile
[root@dev build]#ll
total 104
drwxr-xr-x 3 root root 4096 Jan 18 19:51 ./
drwxr-xr-x 4 root root 4096 Jan 18 19:50 ../
-rw-r--r-- 1 root root 15949 Jan 18 19:50 CMakeCache.txt
drwxr-xr-x 7 root root 4096 Jan 18 19:51 CMakeFiles/
-rw-r--r-- 1 root root 1662 Jan 18 19:51 cmake_install.cmake
-rw-r--r-- 1 root root 2101 Jan 18 19:51 example.py
-rwxr-xr-x 1 root root 57472 Jan 18 19:51 _example.so*
-rw-r--r-- 1 root root 6688 Jan 18 19:51 Makefile
golang调用c#
Go 并不支持直接调用用 C/C++ 编写的函数。cgo 程序可用于生成调用 C 代码的包装器,但目前没有直接调用 C++ 代码的简单方式。SWIG 填补了这一空白。
默认情况下 SWIG 会生成可以直接被 go build 使用的文件。 Go 需要大于1.2 版本。
同样上面的example.i, 我们可以
Copyswig -go example.i
go install
上面的命令,会生成example.go
Copy/* ----------------------------------------------------------------------------
* This file was automatically generated by SWIG (https://www.swig.org).
* Version 4.1.1
*
* Do not make changes to this file unless you know what you are doing - modify
* the SWIG interface file instead.
* ----------------------------------------------------------------------------- */
// source: example.i
package example
/*
#define intgo swig_intgo
typedef void *swig_voidp;
#include <stddef.h>
#include <stdint.h>
typedef ptrdiff_t intgo;
typedef size_t uintgo;
typedef struct { char *p; intgo n; } _gostring_;
typedef struct { void* array; intgo len; intgo cap; } _goslice_;
extern void _wrap_Swig_free_example_c8af3355f0aa50cc(uintptr_t arg1);
extern uintptr_t _wrap_Swig_malloc_example_c8af3355f0aa50cc(swig_intgo arg1);
extern void _wrap_My_variable_set_example_c8af3355f0aa50cc(double arg1);
extern double _wrap_My_variable_get_example_c8af3355f0aa50cc(void);
extern swig_intgo _wrap_fact_example_c8af3355f0aa50cc(swig_intgo arg1);
extern swig_intgo _wrap_my_mod_example_c8af3355f0aa50cc(swig_intgo arg1, swig_intgo arg2);
#undef intgo
*/
import "C"
import "unsafe"
import _ "runtime/cgo"
import "sync"
type _ unsafe.Pointer
var Swig_escape_always_false bool
var Swig_escape_val interface{}
type _swig_fnptr *byte
type _swig_memberptr *byte
func getSwigcptr(v interface { Swigcptr() uintptr }) uintptr {
if v == nil {
return 0
}
return v.Swigcptr()
}
type _ sync.Mutex
func Swig_free(arg1 uintptr) {
_swig_i_0 := arg1
C._wrap_Swig_free_example_c8af3355f0aa50cc(C.uintptr_t(_swig_i_0))
}
func Swig_malloc(arg1 int) (_swig_ret uintptr) {
var swig_r uintptr
_swig_i_0 := arg1
swig_r = (uintptr)(C._wrap_Swig_malloc_example_c8af3355f0aa50cc(C.swig_intgo(_swig_i_0)))
return swig_r
}
func SetMy_variable(arg1 float64) {
_swig_i_0 := arg1
C._wrap_My_variable_set_example_c8af3355f0aa50cc(C.double(_swig_i_0))
}
func GetMy_variable() (_swig_ret float64) {
var swig_r float64
swig_r = (float64)(C._wrap_My_variable_get_example_c8af3355f0aa50cc())
return swig_r
}
func Fact(arg1 int) (_swig_ret int) {
var swig_r int
_swig_i_0 := arg1
swig_r = (int)(C._wrap_fact_example_c8af3355f0aa50cc(C.swig_intgo(_swig_i_0)))
return swig_r
}
func My_mod(arg1 int, arg2 int) (_swig_ret int) {
var swig_r int
_swig_i_0 := arg1
_swig_i_1 := arg2
swig_r = (int)(C._wrap_my_mod_example_c8af3355f0aa50cc(C.swig_intgo(_swig_i_0), C.swig_intgo(_swig_i_1)))
return swig_r
}
可以看到,生成的代码默认还是通过cgo去调用swig生成的包装器wrap代码。
本质上,SWIG和我们常用的GRPC起到类似的作用:-)
总结#
SWIG 建立起java、python等其他高级编程语言调用c/c++ 代码的桥梁,可以不用了解JNI、cgo等复杂的跨语言调用知识,实现一次编写接口,同步生成多语言接口。
关注作者
欢迎关注作者, 一起交流软件开发
相关推荐
- 5款Syslog集中系统日志常用工具对比推荐
-
一、为何要集中管理Syslog?Syslog由Linux/Unix系统及其他网络设备生成,广泛分布于整个网络。因其包含关键信息,可用于识别网络中的恶意活动,所以必须对其进行持续监控。将Sys...
- 跨平台、多数据库支持的开源数据库管理工具——DBeaver
-
简介今天给大家推荐一个开源的数据库管理工具——DBeaver。它支持多种数据库系统,包括Mysql、Oracle、PostgreSQL、SLQLite、SQLServer等。DBeaver的界面友好...
- 强烈推荐!数据库管理工具:Navicat Premium 16.3.2 (64位)
-
NavicatPremium,一款集数据迁移、数据库管理、SQL/查询编辑、智能设计、高效协作于一体的全能数据库开发工具。无论你是MySQL、MariaDB、MongoDB、SQLServer、O...
- 3 年 Java 程序员还玩不转 MongoDB,网友:失望
-
一、什么场景使用MongoDB?...
- 拯救MongoDB管理员的GUI工具大赏:从菜鸟到极客的生存指南
-
作为一名在NoSQL丛林中披荆斩棘的数据猎人,没有比GUI工具更称手的瑞士军刀了。本文将带你围观五款主流MongoDB管理神器的特性与暗坑,附赠精准到扎心的吐槽指南一、MongoDBCompass:...
- mongodb/redis/neo4j 如何自己打造一个 web 数据库可视化客户端?
-
前言最近在做neo4j相关的同步处理,因为产线的可视化工具短暂不可用,发现写起来各种脚本非常麻烦。...
- solidworks使用心得,纯干货!建议大家收藏
-
SolidWorks常见问题...
- 统一规约-关乎数字化的真正实现(规范统一性)
-
尽管数字化转型的浪潮如此深入人心,但是,对于OPCUA和TSN的了解却又甚少,这难免让人质疑其可实现性,因为,如果缺乏统一的语义互操作规范,以及更为具有广泛适用的网络与通信,则数字化实际上几乎难以具...
- Elasticsearch节点角色配置详解(Node)
-
本篇文章将介绍如下内容:节点角色简介...
- 产前母婴用品分享 篇一:我的母婴购物清单及单品推荐
-
作者:DaisyH8746在张大妈上已经混迹很久了,有事没事看看“什么值得买”已渐渐成了一种生活习惯,然而却从来没有想过自己要写篇文章发布上来,直到由于我产前功课做得“太过认真”(认真到都有点过了,...
- 比任何人都光彩照人的假期!水润、紧致的肌肤护理程序
-
图片来源:谜尚愉快的假期临近了。身心振奋的休假季节。但是不能因为这种心情而失去珍贵的东西,那就是皮肤健康。炙热的阳光和强烈的紫外线是使我们皮肤老化的主犯。因此,如果怀着快乐的心情对皮肤置之不理,就会使...
- Arm发布Armv9边缘AI计算平台,支持运行超10亿参数端侧AI模型
-
中关村在线2月27日消息,Arm正式发布Armv9边缘人工智能(AI)计算平台。据悉,该平台以全新的ArmCortex-A320CPU和领先的边缘AI加速器ArmEthos-U85NPU为核心...
- 柔性——面向大规模定制生产的数字化实现的基本特征
-
大规模定制生产模式的核心是柔性,尤其是体现在其对定制的要求方面。既然是定制,并且是大规模的定制,对于制造系统的柔性以及借助于数字化手段实现的柔性,就提出了更高的要求。面向大规模定制生产的数字化业务管控...
- 创建PLC内部标准——企业前进的道路
-
作者:FrankBurger...
- 标准化编程之 ----------- 西门子LPMLV30测试总结
-
PackML乃是由OMAC开发且被ISA所采用的自动化标准TR88.00.02,能够更为便捷地传输与检索一致的机器数据。PackML的主要宗旨在于于整个工厂车间倡导通用的“外观和感觉”,...
你 发表评论:
欢迎- 一周热门
-
-
Linux:Ubuntu22.04上安装python3.11,简单易上手
-
宝马阿布达比分公司推出独特M4升级套件,整套升级约在20万
-
MATLAB中图片保存的五种方法(一)(matlab中保存图片命令)
-
别再傻傻搞不清楚Workstation Player和Workstation Pro的区别了
-
Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
-
如何提取、修改、强刷A卡bios a卡刷bios工具
-
Element Plus 的 Dialog 组件实现点击遮罩层不关闭对话框
-
日本组合“岚”将于2020年12月31日停止团体活动
-
SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索
-
tinymce 号称富文本编辑器世界第一,大家同意么?
-
- 最近发表
-
- 5款Syslog集中系统日志常用工具对比推荐
- 跨平台、多数据库支持的开源数据库管理工具——DBeaver
- 强烈推荐!数据库管理工具:Navicat Premium 16.3.2 (64位)
- 3 年 Java 程序员还玩不转 MongoDB,网友:失望
- 拯救MongoDB管理员的GUI工具大赏:从菜鸟到极客的生存指南
- mongodb/redis/neo4j 如何自己打造一个 web 数据库可视化客户端?
- solidworks使用心得,纯干货!建议大家收藏
- 统一规约-关乎数字化的真正实现(规范统一性)
- Elasticsearch节点角色配置详解(Node)
- 产前母婴用品分享 篇一:我的母婴购物清单及单品推荐
- 标签列表
-
- dialog.js (57)
- importnew (44)
- windows93网页版 (44)
- yii2框架的优缺点 (45)
- tinyeditor (45)
- qt5.5 (60)
- windowsserver2016镜像下载 (52)
- okhttputils (51)
- android-gif-drawable (53)
- 时间轴插件 (56)
- docker systemd (65)
- slider.js (47)
- android webview缓存 (46)
- pagination.js (59)
- loadjs (62)
- openssl1.0.2 (48)
- velocity模板引擎 (48)
- pcre library (47)
- zabbix微信报警脚本 (63)
- jnetpcap (49)
- pdfrenderer (43)
- fastutil (48)
- uinavigationcontroller (53)
- bitbucket.org (44)
- python websocket-client (47)