[SWIG] HelloSWIG

编程入门 行业动态 更新时间:2024-10-11 17:22:45

[<a href=https://www.elefans.com/category/jswz/34/1695363.html style=SWIG] HelloSWIG"/>

[SWIG] HelloSWIG

文本代码地址:
原文地址:
SWIG系列笔记:

看完这篇文章,你能了解SWIG的原理,并知道如何简单的使用它。

文章目录

    • 第一步:编写cpp的代码
    • 第二步:编写SWIG的接口描述文件
        • simplePINVOKE.cs
        • simple.cs(接口文件)
        • 总结
    • 第三步:编译wrap.cxx文件
    • 第四步:C#调用
    • 附:为.i文件添加编译配置
    • 相关概念

A-HelloSWIG
├── simple
|   ├── example.h
│   ├── example.cpp 
│   ├── example.i
│   ├── simple.vcxproj
│   └── simple.vcxproj.filters
├── usesimple
|		├── Program.cs
|   └── usesimple.csproj
└── A-HelloSWIG.sln

新建一个名字为HelloSWIG的Visual studio工程


第一步:编写cpp的代码

创建一个名字为simple的子工程,类型改为动态库

编写C++代码

  1. .\simple\example.h
#pragma once
//全局变量
double Foo = 0;//函数
int gcd(int x, int y);
  1. .\simple\example.cpp
#include"example.h"#include<iostream>/* 计算正整数的最大公约数 */
int gcd(int x, int y) {int g;g = y;while (x > 0) {g = x;x = y % x;y = g;}return g;
}

编译simple子工程,生成simple.dll
此时的simple.dll内部包含了example.h的相关代码


第二步:编写SWIG的接口描述文件

SWIG的接口描述文件,是用来告诉SWIG,接口的导出内容、信息与规则等等。后缀名一般为.i

我们的目的是将example.h暴露给C#,让C#能够调用example.h
所以,需要根据example.h编写.i文件(即example.i

/* 模块名 */
%module simple/* 以下内容会被原封不动的,拷贝到*_wrap.cxx中 */
%{
//**************************************
//SWIG接口文件中拷贝过来的内容
extern int    gcd(int x, int y);
extern double Foo;
//**************************************
%}/* 指定需要解析的头文件,并生成包装器的代码 */
%include"example.h"

编写完.i文件之后,我们就能用命令行运行SWIG,生成包装代码和接口代码

swig.exe -c++ -csharp example.i

SWIG生成了以下文件

HelloSWIG
├── simple
|   ├── ...
│   ├── example_wrap.cxx
│   ├── simple.cs
|   └── simplePINVOKE.cs
├── ...
我们一个一个文件来看,看看SWIG做了些什么。<br />​<br />
<a name="zIHBh"></a>
#### example_wrap.cxx(包装器)
`example_wrap.cxx`其实就是`SWIG`名字中的`SW`。Simplified Wrapper简单的包装器。<br />它将`example.h`中的内容,简单的封装了一层,这一层将被C#(客户端语言)使用。
```cpp
//..... //前部分是SWIG的固定代码//**************************************
//SWIG接口文件中拷贝过来的内容
extern int    gcd(int x, int y);
extern double Foo;
//**************************************#ifdef __cplusplus
extern "C" {
#endifexample.h中的double Foo全局变量,SWIG为它包了一层
//Foo的设置函数
SWIGEXPORT void SWIGSTDCALL CSharp_Foo_set(double jarg1) {double arg1 ;arg1 = (double)jarg1; Foo = arg1;
}
//Foo的get函数
SWIGEXPORT double SWIGSTDCALL CSharp_Foo_get() {double jresult ;double result;result = (double)Foo;jresult = result; return jresult;
}example.h中的gcd,SWIG为它包了一层
SWIGEXPORT int SWIGSTDCALL CSharp_gcd(int jarg1, int jarg2) {int jresult ;int arg1 ;int arg2 ;int result;arg1 = (int)jarg1; arg2 = (int)jarg2; result = (int)gcd(arg1,arg2);jresult = result; return jresult;
}//....

simplePINVOKE.cs

simplePINVOKE.cs将从dll中装载C++相关代码,实现对C++的调用。

class simplePINVOKE {protected class SWIGExceptionHelper {//...}protected static SWIGExceptionHelper swigExceptionHelper = new SWIGExceptionHelper();public class SWIGPendingException {//...}protected class SWIGStringHelper {//...}static protected SWIGStringHelper swigStringHelper = new SWIGStringHelper();static simplePINVOKE() {}//从simple.dll中导入名为CSharp_Foo_set的函数//映射为C#的Foo_set函数[global::System.Runtime.InteropServices.DllImport("simple", EntryPoint="CSharp_Foo_set")]public static extern void Foo_set(double jarg1);//从simple.dll中导入CSharp_Foo_get函数//映射为C#的Foo_get函数[global::System.Runtime.InteropServices.DllImport("simple", EntryPoint="CSharp_Foo_get")]public static extern double Foo_get();//从simple.dll中导入CSharp_gcd函数,映射为C#的gcd函数[global::System.Runtime.InteropServices.DllImport("simple", EntryPoint="CSharp_gcd")]public static extern int gcd(int jarg1, int jarg2);
}


这里有一个重点:

  • DllImport("simple", EntryPoint="CSharp_Foo_set")中的simple其实就是.i文件中的模块名!
  • 所以,.i文件的模块名需要与*_wrap.cxx所在dll的名字相同

simple.cs(接口文件)

此文件可以说是SWIG名字中的I,即Interface,是C#使用C++代码的接口文件。

public class simple {public static double Foo {set {simplePINVOKE.Foo_set(value);} get {double ret = simplePINVOKE.Foo_get();return ret;} }public static int gcd(int x, int y) {int ret = simplePINVOKE.gcd(x, y);return ret;}
}

可以看出,这个文件,又是一个代理层。

  • 它将simplePINVOKE.cs又封装了一层,写了一个simple类,内部的接口与example.h完全相同。
  • 如此,在C#中使用,接口在C++中的一致!

这里也能发现一点。simple.cs的名字与.i中所指定的模块名相同。

总结

整体逻辑如下:

example.h <-- example_wrap.cxx <-- example_wrapperPINVOKE.cs <-- example_wrapper.cs <-- C# code(client)
C++代码		 C++代理层				C#从dll中加载C++的函数			C#的代理层				C#调用层

第三步:编译wrap.cxx文件

在上面的内容中(《simplePINVOKE.cs》),我们发现,SWIG生成的C#代码,会去模块名.dll中搜索对应的C++代码(如全局变量、函数、类)。
所以,我们要把*_wrap.cxx文件编译到模块名.dll中。

example_wrap.cxx加入到sample工程中,再次编译。


第四步:C#调用

创建一个C#工程(Visual C# > .NET Core > 控制台应用)。

将SWIG生成的C#文件加入进来(simple.cssimplePINVOKE.cs

编写测试用例:

        static void Main(string[] args){Console.WriteLine("Hello World!");// Call our gcd() functionint x = 42;int y = 105;int g = cppproject.gcd(x, y);Console.WriteLine("The gcd of " + x + " and " + y + " is " + g);// Manipulate the Foo global variable// Output its current valueConsole.WriteLine("Foo = " + cppproject.Foo);// Change its valuecppproject.Foo = 3.1415926;// See if the change took effectConsole.WriteLine("Foo = " + cppproject.Foo);Console.ReadLine();}

然后运行。
不出意外,你的程序会有一个异常(在simple.cs中)

System.TypeInitializationException:“The type initializer for 'simplePINVOKE' threw an exception.”DllNotFoundException: Unable to load DLL 'simple' or one of its dependencies: 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)

这其实是因为Csharp的工程加载不到simple.dll引起的。我们手动将simple.dll拷贝到csharp运行目录中即可(.\A-HelloSWIG\usesimple\bin\Debug\netcoreapp2.1



也可以为`simple`工程配置生成后事件,将生成的dll拷贝到指定目录下即可
1. 右键`simple`> 生成事件 > 生成后事件
2. 在命令行中输入:`copy "$(OutDir)$(projectname).dll" "$(SolutionDir)csharpproject/bin/$(Configuration)/netcoreapp2.1"`

附:为.i文件添加编译配置

如果更改了代码,就要打开命令行,重新运行SWIG命令,这很麻烦。
我们可以为.i文件添加编译配置,这样就不用在命令行运行SWIG命令了

编写完成后,需要做以下配置

  1. 右键.i文件 > 属性 > 常规 > 项类型 > 选择“自定义生成工具”
  2. 右键.i文件 > 属性 > 自定义生成工具 >
    1. 命令行:swig.exe -c++ -csharp %(FullPath)
    2. 输出:%(Filename)_wrap.cxx;%(Outputs)

配置完之后,右键example.i文件,点击“编译”
如此,就不用每次都打开命令行,运行命令了


相关概念

这里的C#,叫Target languages,目标语言

更多推荐

[SWIG] HelloSWIG

本文发布于:2024-03-06 02:53:08,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1714162.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:SWIG   HelloSWIG

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!