C# .net Core/5 应用程序中的跨平台 C++

时间:2021-01-30 12:48:27

标签: c# c++ .net-core swig

随着 .net Core 以及最近的 .net 5 的推出,跨平台 .net/C# 变得相对容易。 考虑到这一点,我正在开发一个将使用 .net 5/C# 的应用程序,但我想将一些代码保留在 C++/本机域中。仅使用 C#,甚至可以从开发版本发布到其他平台。我愿意放弃。

现在,如何保持项目跨平台?

我一直在寻找任何地方似乎都没有一个很好的选择...

也许this solution from Xamarin?我不确定它会转换为桌面,或者它可以在 CI/CD 上自动化...

但除此之外,每个人似乎都以自己的笨拙方式逃脱。

有人对跨平台的 C(++)/C# 集成有什么建议吗?

编辑 1:

我的问题不是让互操作本身。我已经成功地使用了 SWIG,并且我知道 P/Invoke、C 兼容的 ABI 等等。

我的问题是构建系统/部署。到目前为止,我必须复制文件。但是如何才能拥有一个集成的构建系统呢?例如,我希望在为 C++ 库构建我的 dotnet 应用程序时进行编译。

2 个答案:

答案 0 :(得分:2)

您可以毫无问题地使用 C++/C#。但是 C++ 端和 C# 端之间的“桥梁”方法必须接受/返回普通的 C 类型/结构。 你不能绕过std::xxxx句号。您可以传递 char *strstruct { int Foo, int Bar }int[] 等(但仍然有一些复杂性,这取决于它是如何完成的)。

我维护了一个 github 示例,这些示例关于在 .NET Framework/.NET Core 上从/到 C/C++ 到 C# 封送字符串和结构。该项目是为 Visual Studio 构建的,所以里面有一些“微软性”,但基本思想可以很容易地复制粘贴到其他 C 平台上。

当你想做一个完全多平台的项目时,还有一些额外的复杂性(我在写这些例子时没有考虑跨平台):

  1. 字符串的编码:在示例中我展示了您可以轻松使用 utf-8 字符串,但这仍然很痛苦,因为在 Windows 上,Windows API 不支持 utf-8 并且是为wchar_t(您不能使用 utf-8 文件名 CreateFile)。在 Linux 的另一边,每个人都使用 char* 而几乎没有人使用 wchar_t*(举相同的例子,filesystems on Linux are agnostic about character sets,所以 open 原语和 {{1} } 方法可以接受可以是 utf-8 编码的 fopen),因此决定如何以跨平台方式处理 char*/char 是一件痛苦的事情。如果必须这样做,我可能会将 wchar_t 宏定义为 Linux 上的 TCHAR,Windows 上的 char,在任何地方使用它,并使用 wchar_t 编组选项对于字符串,以及 LPTStr 类的 Auto 方法(例如 Marshal)。 .NET Core 认为 Marshal.PtrToStringAuto/LPTStr 在 Linux 上为 xxxAuto,在 Windows 上为 char*

  2. 虽然在 Windows 上有大量的内存分配器(.NET Core 在互操作中使用的主要分配器是用于内存的 wchar_t* 和用于字符串的 CoTaskMemAlloc,但也有利基 (useles) 之类的东西 SysAllocString),在 Linux .NET Core 上直接使用 GlobalHAlloc。这对于释放“从另一端”分配的内存很重要,如果您希望能够让编组器自动释放内存,它会增加复杂性。但最终,从 C/C++ 端公开内存释放器总是一个好主意,因为之前或之后您必须释放在 C/C++ 端分配的内存。虽然可能,但我认为让编组器自动释放分配给 C/C++ 端的内存是一个坏主意(因为您无法控制操作,并且无法轻松调试它)。所以没有 malloc 在 C# 中用 char* Foo() 翻译:这是可能的,但 .NET 编组器将使用 string Foo() 来释放它。还有其他方法可以执行此操作,或者您可以手动执行此操作(CoTaskMemFree 然后您显式转换并释放 IntPtr Foo())。

  3. Linux下使用IntPtrBSTR有一些限制(主要问题是C端没有对等方法),所以如果要跨平台编程使用它们的坏主意(但没有人使用它们)

答案 1 :(得分:1)

三个方面:

  1. .NET/本机互操作
  2. 原生组件库的部署和打包
  3. 部署整个应用程序包,即托管部分和本机部分

显然,您需要为所有支持的平台维护本机组件的版本和构建。这本身就是一个挑战,但与从 .NET 使用它无关。关于 1),您需要为您的本机库提供一个与标准化 PInvoke 规范兼容的 API。这可能具有挑战性,具体取决于您的组件的功能,如果做得不好,可能会导致麻烦。如果可以,只选择纯托管代码,如果您已准备好迎接挑战,请继续!