简体   繁体   English

跨平台 C++ 在 C# .net Core/5 应用

[英]Cross platform C++ in C# .net Core/5 application

With the introduction of .net Core, and more recently, .net 5, cross-platform .net/C# is relatively easy.随着 .net Core 以及最近的 .net 5 的推出,跨平台的 .net/C# 相对容易。 With this in mind, I'm working towards an application that would use .net 5/C#, but there is some code that I want to keep in the C++/native domain.考虑到这一点,我正在开发一个使用 .net 5/C# 的应用程序,但是我想将一些代码保留在 C++/native 域中。 With C# only, one can even publish to other platforms from the development one.仅使用 C#,甚至可以从开发者发布到其他平台。 I'm willing to give up on that.我愿意就此放弃。

Now, how can one keep the project cross-platform?现在,如何保持项目跨平台?

I've been looking everywhere an there doesn't seem to be a great option anywhere...我一直在到处寻找,似乎在任何地方都没有一个很好的选择......

Maybe this solution from Xamarin ?也许这个解决方案来自 Xamarin I'm not sure it'll translate to Desktop, or that it can be automatized on a CI/CD...我不确定它会转化为桌面,或者它可以在 CI/CD 上自动化......

But other than that, everybody seems to get away with their own janky way.但除此之外,每个人似乎都以自己的笨拙方式逃脱了。

Does anybody have pointers about C(++)/C# integration that's cross platform?有人对跨平台的 C(++)/C# 集成有什么建议吗?

Edit 1:编辑1:

My problem is not to make the interop per se.我的问题不是使互操作本身。 I have successfully used SWIG and I know about P/Invoke, C-compatible ABIs and etc.我已经成功使用了 SWIG,并且我了解 P/Invoke、C 兼容的 ABI 等。

My problem is build system/deployment.我的问题是构建系统/部署。 So far I have to copy files around.到目前为止,我必须复制文件。 But how can one have an integrated build system?但是如何才能拥有一个集成的构建系统呢? I want that when building my dotnet app for the C++ libraries to compile, for example.例如,我希望在为 C++ 库构建我的 dotnet 应用程序时进行编译。

You can have C++/C# without any problems.您可以毫无问题地使用 C++/C#。 But the "bridge" methods between the C++ side and the C# side must accept/return plain C types/structs.但是 C++ 端和 C# 端之间的“桥接”方法必须接受/返回普通的 C 类型/结构。 You can't pass around std::xxxx full stop .你不能绕过std::xxxx full stop You can pass around char *str , struct { int Foo, int Bar } , int[] and so on (but still there is a little complexity, depending on how it is done).您可以传递char *strstruct { int Foo, int Bar }int[]等等(但仍然有一点复杂性,具体取决于它是如何完成的)。

I maintain a github of examples about marshaling strings and structs from/to C/C++ to C# on .NET Framework/.NET Core.我在 .NET Framework/.NET Core 上维护了一个github示例,其中包含从/到 C/C++ 到 C# 的编组字符串和结构的示例。 The project is built for Visual Studio, so there are some "microsoftnesses" inside, but the basic ideas can be copied-pasted onto other C platforms easily.该项目是为 Visual Studio 构建的,因此内部有一些“微软特性”,但可以轻松地将基本思想复制粘贴到其他 C 平台上。

There are some additional complexities when you want to do a fully multiplaform project (I didn't think about crossplatforming when I wrote those examples):当您想做一个完全多平台的项目时,还有一些额外的复杂性(我在编写这些示例时没有考虑跨平台):

  1. The encoding of strings: in the examples I show that you can use utf-8 strings easily, but it is still a pain, because on Windows the Windows API don't support utf-8 and are tailored for wchar_t (you can't CreateFile with an utf-8 filename). The encoding of strings: in the examples I show that you can use utf-8 strings easily, but it is still a pain, because on Windows the Windows API don't support utf-8 and are tailored for wchar_t (you can't CreateFile with an utf-8文件名)。 On the opposite side on Linux everyone uses char* and nearly no one uses wchar_t* (to give the same example, filesystems on Linux are agnostic about character sets , so the open primitive and the fopen method can accept char* that can be utf-8 encoded), so deciding how to handle char / wchar_t in a crossplatform way is a pain. On the opposite side on Linux everyone uses char* and nearly no one uses wchar_t* (to give the same example, filesystems on Linux are agnostic about character sets , so the open primitive and the fopen method can accept char* that can be utf-8 encoded ),因此决定如何以跨平台方式处理char / wchar_t是一件痛苦的事情。 If I had to do it, I would probably define the TCHAR macro to be char on Linux, wchar_t on Windows, use it everywhere, and use the LPTStr marshalling option for strings, and the Auto methods for the Marshal class ( Marshal.PtrToStringAuto for example). If I had to do it, I would probably define the TCHAR macro to be char on Linux, wchar_t on Windows, use it everywhere, and use the LPTStr marshalling option for strings, and the Auto methods for the Marshal class ( Marshal.PtrToStringAuto for例子)。 The .NET Core considers LPTStr / xxxAuto to be char* on Linux and wchar_t* on Windows. .NET 内核将LPTStr / xxxAuto视为 Linux 上的char*和 Windows 上的wchar_t*

  2. While on Windows there is a great deluge of memory allocators (the main ones used by .NET Core in interop are the CoTaskMemAlloc for memory and the SysAllocString for strings, but there are niche (useles) things like GlobalHAlloc ), on Linux .NET Core uses directly malloc . While on Windows there is a great deluge of memory allocators (the main ones used by .NET Core in interop are the CoTaskMemAlloc for memory and the SysAllocString for strings, but there are niche (useles) things like GlobalHAlloc ), on Linux .NET Core uses directly malloc This is important for freeing memory allocated "from the other side", and it increases the complexity if you want to be able to let the marshaller free automatically the memory.这对于释放“从另一侧”分配的 memory 很重要,如果您希望能够让编组器自动释放 memory,则会增加复杂性。 But in the end it is always a good idea to expose a memory deallocator from the C/C++ side, because before or later you'll have to free memory allocated in the C/C++ side.但最终,从 C/C++ 端公开 memory 释放器总是一个好主意,因为在此之前或之后,您必须释放在 C/C++ 端分配的 memory。 And while possible I think it is a bad idea to let the marshaller free automagically the memory allocated C/C++ side (because you don't have control on the operation, and you can't easily debug it).虽然可能,但我认为让编组器自动释放 memory 分配的 C/C++ 端是一个坏主意(因为您无法控制操作,并且无法轻松调试它)。 So no char* Foo() translated in C# with string Foo() : it is possible to do it, but the .NET marshaller will use CoTaskMemFree to free it.所以没有char* Foo()string Foo()在 C# 中翻译:可以这样做,但是 .NET 编组器将使用CoTaskMemFree来释放它。 There are other ways to do it, or you can do it manually ( IntPtr Foo() and then you convert and free the IntPtr explicitly).还有其他方法可以做到这一点,或者您可以手动进行( IntPtr Foo() ,然后显式转换并释放IntPtr )。

  3. There are some limitations about using BSTR and SAFEARRAY under Linux (the main problem is that there are no reciprocal methods C side), so if you want to program crossplatform it is a bad idea using them (but no one uses them)在 Linux 下使用BSTRSAFEARRAY有一些限制(主要问题是没有互惠方法 C 端),所以如果你想跨平台编程使用它们是个坏主意(但没有人使用它们)

There are three aspects:有三个方面:

  1. The .NET/native interop .NET/本机互操作
  2. The deployment and packaging of the native component library原生组件库的部署和打包
  3. Deployment of the entire application bundle, ie the managed and native parts部署整个应用程序包,即托管和本地部分

Obviously you need to maintain versions and builds of your native component for all supported platforms.显然,您需要为所有受支持的平台维护本机组件的版本和构建。 That is a challenge on its own but not related to using it from .NET.这本身就是一个挑战,但与从 .NET 使用它无关。 With regard to 1) you will need to provide an API for your native library which is compatible with the standardized PInvoke specification.关于 1),您需要为与标准化 PInvoke 规范兼容的本机库提供 API。 This might be challenging depending on what your component does and might cause trouble if not done right.这可能具有挑战性,具体取决于您的组件所做的事情,如果做得不好,可能会导致麻烦。 If you can, prefer pure managed code only, if you are ready for the challenge, proceed!如果可以,请只选择纯托管代码,如果您已准备好迎接挑战,请继续!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM