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

Posted

技术标签:

【中文标题】C# .net Core/5 应用程序中的跨平台 C++【英文标题】:Cross platform C++ in C# .net Core/5 application 【发布时间】:2021-01-30 12:48:27 【问题描述】:

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

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

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

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

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

有人对跨平台的 C(++)/C# 集成有意见吗?

编辑 1:

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

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

【问题讨论】:

【参考方案1】:

您可以毫无问题地使用 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 平台上。

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

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

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

    在Linux下使用BSTRSAFEARRAY有一些限制(主要问题是C端没有互惠方法),所以如果你想跨平台编程使用它们是个坏主意(但没有一个人使用它们)

【讨论】:

我非常了解 ABI,extern "C" 并让事情成为函数而不是为简单的 FFI 分类。还有诸如 SWIG 和 CppSharp 之类的东西。您展示的仍然是 vcxproj,因此无法为 Linux 或 MacOS 构建。我对跨平台感兴趣,这就是问题的重点。 @RuiOliveira 扩展了回复。我从来没有使用过这两个库,但是每次我看到用 SWIG 完成的事情时,解决任何存在的问题都是一件痛苦的事情。如果必须导出的“表面”非常大(数十种方法),那么使用这样的库可能是一个好主意。如果您只需要导出少数方法(更常见的场景),那么它们可能被夸大了,并引入了复杂性并隐藏了应该明确的内容。 感谢所有建议,但我的问题实际上不在于如何连接 C#/C++。这真的是关于如何以跨平台和自动的方式构建这样一个项目。 @RuiOliveira 最后是你的项目。我可以对你说的是:目前在 SO 上有 170 个关于 [Swig] + [C#](加上这个)的问题。如果您在使用 Swig 时遇到问题,则只能靠自己。对于 [CppSharp] 来说,情况更糟。我想6个问题。祝你好运! ?【参考方案2】:

分为三个方面:

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

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

【讨论】:

构建和部署肯定是我的问题。您对此有见解吗? 是的,当然,但是如果没有关于您的项目的更多信息,很难给出建议。通常,您需要对跨平台构建进行某种设置,并使用统一的命名、位、依赖管理等约定。CMake 和 VcPkg 是您的朋友。

以上是关于C# .net Core/5 应用程序中的跨平台 C++的主要内容,如果未能解决你的问题,请参考以下文章

迁移到 .Net Core 5 - 生成的 .config 文件的名称已更改

在 asp.net core 5 MVC 视图中从 C# 代码调用 JavaScript 函数

C# jQuery Ajax 数据表 ASP.NET Core 5 MVC

C# - 单元测试 - 初始化私有字段 - ASP.NET Core 5 - NUnit 测试

C# ASP.NET Core 5.0 - 为啥在使用 [Authorization] 时甚至不调用该方法

使用C# 探索 ML.NET 中的不同机器学习任务