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 *str
、struct 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下使用BSTR
和SAFEARRAY
有一些限制(主要问题是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 测试