首页 > 其他分享 >跨语言调用神器SWIG介绍与使用入门

跨语言调用神器SWIG介绍与使用入门

时间:2024-01-18 20:24:55浏览次数:28  
标签:__ 入门 int SWIG example 神器 wrap root swig

安装

依赖 PCRE 库

apt-get install libpcre2-dev

下载安装

$ ./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等调用。

下面是代码:

/* 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,去生成连接其他语言的胶水代码。

%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胶水代码。

swig -python example.i

这里会生成;

  • example_wrap.c 连接c代码的wrap
  • example.py 可以类比GRPC生成的访问wrap的代码。

我们来看下生成的包装代码example_wrap.c

/* ----------------------------------------------------------------------------
 * 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代码模块。



[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文件

FIND_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})

编译:

[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, 我们可以

swig -go example.i
go install

上面的命令,会生成example.go

/* ----------------------------------------------------------------------------
 * 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等复杂的跨语言调用知识,实现一次编写接口,同步生成多语言接口。

标签:__,入门,int,SWIG,example,神器,wrap,root,swig
From: https://www.cnblogs.com/xiaoqi/p/17973315/SWIG

相关文章

  • Web前端新手入门系列:案例1 招商银行页面的制作
    一次比较复杂的网页设计(对初学者而言)效果图代码可能不太符合规范,但效果差不多(HTML部分<!DOCTYPEhtml><htmllang="en"xmlns="http://www.w3.org/1999/xhtml"><head><metacharset="utf-8"/><title>招商银行</title>&......
  • xapian 搜索引擎介绍与使用入门
    Xapian是一个开源搜索引擎库,使用C++编写,并提供绑定(bindings )以允许从多种编程语言使用。它是一个高度适应性的工具包,允许开发人员轻松地将高级索引和搜索功能添加到自己的应用程序中。Xapian支持多种加权模型和丰富的布尔查询运算符。最新稳定版本是1.4.24,发布于2023年......
  • Istio从入门到精通—— 安装 —— Kubernetes 删除 istio-system namesapce 时候,出现
    Kubernetes删除istio-systemnamesapce时候,出现Terminating解决办法当你在Kubernetes中遇到无法删除处于Terminating状态的命名空间时,可能是由于该命名空间中仍有活跃的资源或服务。要解决这个问题,你可以尝试以下几个步骤:一、常规方法检查命名空间中的活跃资源:......
  • 入门Linux运维工程师需要掌握的知识点和工具以及技能
    Linux系统的学习,可以选用redhat或centos,特别是centos在企业中用得最多,当然还会有其它版本的,比如Ubuntu等,根据自己的工作情况和兴趣来定。当然不同发行版本主要是包上的区别以及一些命令的差异,其他内核上的东西都大同小异。对于刚入门或准备入门Linux运维的来说,整理总结了以下10个......
  • 【云原生】Docker入门 -- 阿里云服务器环境下安装Docker
    【云原生】Docker入门--阿里云服务器环境下安装Docker:https://wanghuichen.blog.csdn.net/article/details/125139901?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-125139901-blog-132249920.235%5Ev40%5Ep......
  • MyBatis学习记录之MyBatis入门程序
    MyBatis学习记录之MyBatis入门程序前言这篇文章是我第二次学习b站老杜的MyBatis相关课程所进行的学习记录,算是对课程内容及笔记的二次整理,以自己的理解方式进行二次记录,其中理解可能存在错误,欢迎且接受各位大佬们的批评指正;关于本笔记,只是我对于相关知识遗忘时快速查阅了解使......
  • 入门培训
    #include<bit/stdc++.h>//万能头文件#defineintlonglong//信息学竞赛界流传着一句话”十年竞赛一场空,不开longlong见祖宗“usingnamespacestd;signedmain(){printf("welcometoACAlgorithmCommunity");return0;}计算机精神RTFM:readthefriendlym......
  • GIn入门
    Gin入门1.Gin安装goget-ugithub.com/gin-gonic/gin2.将gin引入到代码中:import"github.com/gin-gonic/gin"2.1(可选)如果使用诸如http.StatusOK之类的常量,则需要引入net/http包:import"net/http"2.2初始化gomodgomodinit/*生成go.mod文件,此命令会在当......
  • 软件自动化测试入门攻略
    京东购买:https://item.jd.com/14351742.html 自荐"《软件自动化测试入门攻略》一书是作者花费了近两年时间完成的一本大作,专门为入门、入行人员编写,无论你是初学者,还是想转型、转专业学习软件自动化测试,本书都适合你。书中充分考虑到新手入门自动化测试的特点,从工具学习入......
  • MIT 6.S081入门 lab0 操作系统环境及其配置
    MIT6.S081入门lab0操作系统环境及其配置闲话由于不是正经计算机专业出身,但是又想做Linux内核/驱动开发,因此赶在暑假实习开始前把操作系统的课程补习一下。之前自学的linux的驱动系统入门的笔记在这个寒假也会整理并发布(包括U-boot移植和驱动/应用开发入门)。实验环境Ubuntu-......