多命名空间SWIG接口文件同模块生成C# PINVOKE异常求助
问题描述
我有多个分属不同命名空间的C++文件及类,它们被编译为同一个DLL,希望通过SWIG接口生成对应的C# API。
C++源文件代码
FileCPP1.cpp
namespace First { class MyClass1 { public: MyClass1() = default; void HelloWorld(const std::string& msg) { cout << "Hello World!" << msg << endl;} }; }
FileCPP2.cpp
namespace Second { class MyClass2 { public: MyClass2() = default; void HelloWorldAgain(const std::string& msg) { cout << "Hello World again!" << msg << endl;} }; }
我的尝试操作
MyClass1.i
%include "std_string.i" %typemap(csclassmodifiers) First::MyClass1 namespace First { class MyClass1 { MyClass1(); void HelloWorld(const std::string& msg); }; }
编译命令:
swig.exe -c++ -csharp -DSWIG2_CSHARP -outdir CSFolder -namespace First -module Base
MyClass2.i
%include "std_string.i" %typemap(csclassmodifiers) Second::MyClass2 namespace Second{ class MyClass2 { MyClass2(); void HelloWorldAgain(const std::string& msg); }; }
编译命令:
swig.exe -c++ -csharp -DSWIG2_CSHARP -outdir CSFolder -namespace Second -module Base
Base.i
%module Base %include "MyClass1.i" %include "MyClass2.i"
编译命令:
swig.exe -c++ -csharp -DSWIG2_CSHARP -outdir CSFolder
我期望生成的BasePINVOKE.cs文件包含MyClass1和MyClass2的调用方法,但编译后仅随机出现其中一个类的调用方法,其余文件生成正常。将%include替换为%import后问题依旧,请问我哪里操作错误?
解决方案
问题出在两个核心错误:
单个
.i文件的语法错误:%typemap(csclassmodifiers)的用法完全错了,你直接写了C#类定义,这不是SWIG的正确语法。这个typemap是用来指定生成的C#类的修饰符(比如public),而非直接定义类结构。重复编译单个接口文件导致覆盖:你分别编译
MyClass1.i和MyClass2.i,两次都会生成同名的BasePINVOKE.cs,后面的编译会直接覆盖前面的文件,所以最终只会保留最后一次编译的类的方法。
正确的做法是只用一个主接口文件统一处理所有类,无需单独编译单个.i文件。
正确的接口文件写法
Base.i
%module Base // 引入std_string处理C++字符串到C#的映射 %include "std_string.i" // 为First命名空间的类指定C#命名空间和类修饰符 %typemap(csnamespace) First::MyClass1 "First" %typemap(csclassmodifiers) First::MyClass1 "public class" // 告诉SWIG要包含的C++头文件,用于解析类定义 %{ #include "FileCPP1.h" %} // 声明要暴露的First命名空间类 namespace First { class MyClass1 { public: MyClass1() = default; void HelloWorld(const std::string& msg); }; } // 为Second命名空间的类指定C#命名空间和类修饰符 %typemap(csnamespace) Second::MyClass2 "Second" %typemap(csclassmodifiers) Second::MyClass2 "public class" // 包含Second类的头文件 %{ #include "FileCPP2.h" %} // 声明要暴露的Second命名空间类 namespace Second { class MyClass2 { public: MyClass2() = default; void HelloWorldAgain(const std::string& msg); }; }
正确的编译命令
只需要运行一次SWIG编译主接口文件即可:
swig.exe -c++ -csharp -DSWIG2_CSHARP -outdir CSFolder -module Base
关键说明
%typemap(csnamespace)用来绑定C命名空间到对应的C#命名空间,保证生成的C#类结构和C一致。%{ ... %}块必须包含对应C++类的头文件,否则SWIG无法解析类的定义。- 绝对不要单独编译单个类的
.i文件,避免生成重复的PINVOKE文件互相覆盖。 - 最后要确保所有C++源文件编译打包成同一个DLL,SWIG生成的C#代码会调用这个DLL的导出函数。
内容的提问来源于stack exchange,提问作者Gennady
相关产品推荐
相关产品推荐

