【问题标题】:Wrapping multiple C++ .dlls with multiple C# .dlls用多个 C# .dll 包装多个 C++ .dll
【发布时间】:2017-01-19 14:41:30
【问题描述】:

我正在开发一个项目,用 C# 包装多 dll C++ SDK,试图用单独的 C# dll 包装每个原始 C++ dll。我遇到了一个问题,如果 C++ 库 A 中的一些常用符号在 C++ 库 B 和 C 中使用,则无法换行。由于这是 C++ 中非常常见的场景,显然我错过了一些琐碎的事情。花了几天时间后,我仍然不知所措,如果能帮助我继续前进,我将不胜感激。

以下简单示例重现了该问题: - 类 Point 应该在库 A 中定义 - 类 Triangle 应该在使用 A 的库 B 中定义 - Quadrange 类应该在使用 A 的库 C 中定义

"MyPoint.h"
class  MyPoint
{
public:

    MyPoint(double theX, double theY) : myX(theX), myY(theY) {}

    double X() const { return myX; }
    double& X() { return myX; }

    double Y() const { return myY; }
    double& Y() { return myY; }

private:

    double myX;
    double myY;
};

"MyTriangle.h"
#include "MyPoint.h"

class MyTriangle
{
public:

    MyTriangle(const MyPoint& theP1, const MyPoint& theP2, const MyPoint& theP3) :
        myP1(theP1),
        myP2(theP2),
        myP3(theP3) {}

    MyPoint P1() const { return myP1; }
    MyPoint& P1() { return myP1; }

    MyPoint P2() const { return myP2; }
    MyPoint& P2() { return myP2; }

    MyPoint P3() const { return myP3; }
    MyPoint& P3() { return myP3; }

private:

    MyPoint myP1;
    MyPoint myP2;
    MyPoint myP3;
};

"MyQuadrangle.h"
#include "MyPoint.h"

class MyQuadrangle
{
public:

    MyQuadrangle(const MyPoint& theP1, const MyPoint& theP2, const MyPoint& theP3, const MyPoint& theP4) :
        myP1(theP1),
        myP2(theP2),
        myP3(theP3),
        myP4(theP4) {}

    MyPoint P1() const { return myP1; }
    MyPoint& P1() { return myP1; }

    MyPoint P2() const { return myP2; }
    MyPoint& P2() { return myP2; }

    MyPoint P3() const { return myP3; }
    MyPoint& P3() { return myP3; }

    MyPoint P4() const { return myP4; }
    MyPoint& P4() { return myP4; }

private:

    MyPoint myP1;
    MyPoint myP2;
    MyPoint myP3;
    MyPoint myP4;

};

三角形和四边形分别设置了三个点和四个点。 因此,两个类(MyTriangle 和 MyQuadrangle)都使用类 MyPoint。 所有三个类都是单独包装的。对于每个类都有自己的接口文件:

"MyPoint.i"
%module MyPointWrapper
%{
#include "MyPoint.h"
%}
%include <windows.i>
%include "MyPoint.h"

"MyTriangle.i"
%module MyTriangleWrapper
%{
#include "MyTriangle.h"
%}
%include "MyPoint.i"
%include "MyTriangle.h"

"MyQuadrangle.i"
%module MyQuadrangleWrapper
%{
#include "MyQuadrangle.h"
%}
%include "MyPoint.i"
%include "MyQuadrangle.h"

为每个文件编写了命令行界面: C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -namespace geometry -outdir C:\Geometrics\MyPointNet\Generated MyPoint.i C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -命名空间几何 -I"C:\Geometrics\MyPointcpp" -outdir C:\Geometrics\MyTriangleNet\Generated MyTriangle.i C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -namespace geometry -I"C:\Geometrics\MyPointcpp" -outdir C:\Geometrics\MyQuadrangleNet\Generated MyQuadrangle.i

当我在 C# 中使用 MyPoint 类时:

using System;
using geometry;

namespace Example
{
        class Program
        {
            static void Main(string[] args)
            {
                MyPoint P = new MyPoint (3, 4, 5);
            }
        }
}

出现一个错误,指出每个类都包含一种 MyPoint: 'MyPoint' 类型同时存在于 'MyTriangleNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 和 'MyPointNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

如何避免这种情况,但在 C# 中拥有三个功能齐全的类,条件是每个类都将单独包装?

【问题讨论】:

  • 我回滚了这个问题 - 由于缺乏 C#/Windows 知识,您所做的编辑是我的测试/答案的错误,而不是您问题中的(非常好的)细节,最好把它写得更像百科全书条目而不是交互式调试会话。

标签: c# c++ swig


【解决方案1】:

您几乎已经完成了,但是要简单地引用现有代码而不生成更多代码,您需要使用 %import "modulename.i" 而不是 %include,因此您的 .i 文件变为:

MyPoint.i:

%module MyPointWrapper
%{
#include "MyPoint.h"
%}
%include "MyPoint.h"

MyQuadrangle.i:

%module MyQuadrangleWrapper
%{
#include "MyQuadrangle.h"
%}
%import "MyPoint.i"
%include "MyQuadrangle.h"

MyTriangle.i:

%module MyTriangleWrapper
%{
#include "MyTriangle.h"
%}
%import "MyPoint.i"
%include "MyTriangle.h"

无论如何,我都不是 C# 专家,所以我希望您必须使用 %typemap(csimports) 或其他东西来确保,例如MyTriangle.cs 知道如何使用非限定名称来引用它所指的 MyPoint 类型,但至少当我在 Linux 上使用 Mono 测试它时,构建了一个似乎不需要的单个可执行文件:

#!/bin/bash
swig3.0 -csharp -c++ -namespace geometry -outdir MyPointNet MyPoint.i
swig3.0 -csharp -c++ -namespace geometry -outdir MyTriangleNet MyTriangle.i
swig3.0 -csharp -c++ -namespace geometry -outdir MyQuadrangleNet MyQuadrangle.i

g++ -Wall -Wextra -o libMyPointWrapper.so MyPoint_wrap.cxx -shared -fPIC
g++ -Wall -Wextra -o libMyQuadrangleWrapper.so MyQuadrangle_wrap.cxx -shared -fPIC
g++ -Wall -Wextra -o libMyTriangleWrapper.so MyTriangle_wrap.cxx -shared -fPIC

mcs run.cs */*.cs && ./run.exe

一旦我更改了您的示例用法以调用存在的 MyPoint (2-arg) 的构造函数,所有工作正常。我还在以下位置添加了对 MyTriangle 的快速测试:

MyTriangle T = new MyTriangle(P,P,P);

此外,要跨多个程序集进行这项工作,您还需要在a little more work, as outlined in the documentation, to change 中查看从internalpublic 的一些内部结构。您只需要在导入的模块中执行此操作,因此在此实例中 MyPoint.i 变为:

%module MyPointWrapper
SWIG_CSBODY_PROXY(public, public, SWIGTYPE)
SWIG_CSBODY_TYPEWRAPPER(public, public, public, SWIGTYPE)
%{
#include "MyPoint.h"
%}
%include "MyPoint.h"

请注意,文档提出了一些比仅仅公开它更好的解决方法。如果是我的生产代码,我会调查这些。

【讨论】:

  • 非常感谢您提供提示。在我将 %module 添加到 Triangle.i 文件后,我遇到了从为 Triangle 生成的代码(与 Qudrangle 相同)中访问 MyPoint 类的方法的问题。对原始帖子进行了更详细的编辑。
  • @KKrill 如果您使用-Wall 运行SWIG,它会警告很多关于internal 是C# 中的保留字。我的猜测是与此有关。
  • 实际上可能不是,似乎这是我以前没有经验的一些 C# 模块。会再挖一点。
  • 知道了。即将进行一项编辑。事实证明,这正是我在使用 Mono 编译之前提到的问题,但文档中已经有了更简洁的解决方案。
  • 非常感谢您的详细解答。它帮助我解决了我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多