在 Linux 和 Windows 中与 c# 集成的跨平台 c++
Posted
技术标签:
【中文标题】在 Linux 和 Windows 中与 c# 集成的跨平台 c++【英文标题】:Cross platform c++ integrated with c# in Linux and Windows 【发布时间】:2019-09-02 11:41:27 【问题描述】:我在 c++ 中有以下代码来确定操作系统中的可用 RAM
#if defined(_WIN32)
#include <stdio.h>
#include <windows.h>
#include "string.h"
#include "setjmp.h"
#elif defined(__linux__)
#include "stdio.h"
#include "string.h"
#include <unistd.h>
#endif
extern "C"
unsigned long long getAvailableSystemMemory_Windows64();
unsigned long long getAvailableSystemMemory_Linux64();
#if defined(_WIN32)
__declspec(dllexport) extern unsigned long long getAvailableSystemMemory_Windows64()
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullAvailPhys / 1024 / 1024;
#elif defined(__linux__)
extern unsigned long long getAvailableSystemMemory_Linux64()
unsigned long long ps = sysconf(_SC_PAGESIZE);
unsigned long long pn = sysconf(_SC_AVPHYS_PAGES);
unsigned long long availMem = ps * pn;
return availMem / 1024 / 1024;
#endif
int main()
#if defined(_WIN32)
printf("%d", getAvailableSystemMemory_Windows64());
#elif defined(__linux__)
printf("%d", getAvailableSystemMemory_Linux64());
#endif
printf("MB");
int a;
scanf("This is the value %d", &a);
以及下面的c#代码
class Program
[DllImport("hello.dll", CallingConvention = CallingConvention.Cdecl)]
extern static long getAvailableSystemMemory_Windows64();
[DllImport("hello.so", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, EntryPoint = "getAvailableSystemMemory_Linux64")]
extern static long getAvailableSystemMemory_Linux64();
static void Main(string[] args)
long text = 0;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
text = getAvailableSystemMemory_Windows64();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
text = getAvailableSystemMemory_Linux64();
Console.WriteLine(text);
Console.WriteLine("Hello World!");
Console.ReadLine();
然后在 Windows 中,我使用 g++ --shared -o hello.dll hello.cpp
编译 c++ 代码并将 dll 复制到调试文件夹。一切正常。
对于 Linux,我在 Opensuse 上使用 g++ -o hello.so hello.cpp
编译它
并将.so
文件复制到调试中,但它不起作用。
我得到了例外
Unhandled Exception: System.DllNotFoundException: Unable to load shared
library 'hello.so' or one of its dependencies. In order to help diagnose
loading problems, consider setting the LD_DEBUG environment variable:
libhello.so.so: cannot dynamically load executable
at CallCDll.Program.getAvailableSystemMemory_Linux64()
at CallCDll.Program.Main(String[] args) in
/home/CallCDll/Program.cs:line 22
我使用LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/CallCDll/bin/Debug/netcoreapp2.2
将.so
文件目录路径添加到LD_LIBRARY_PATH 但不起作用。
我该怎么办?无论我将.so
文件复制到哪里,它都找不到它。
【问题讨论】:
我自己不是一个 Linux 人,但是,从错误消息看来,您不应该在DllImport
行中包含 .so
部分 - 系统正在寻找 hello.so.so
(.so:很好,他们添加了两次 - 呵呵)。
@Adrian 现在我得到Unhandled Exception: System.DllNotFoundException: Unable to load shared library 'hello' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libhello: cannot open shared object file: No such file or directory at CallCDll.Program.getAvailableSystemMemory_Linux64() at CallCDll.Program.Main(String[] args) in /home/CallCDll/Program.cs:line 22
该死的如果你这样做,该死的如果你不这样做!就像我说的,我不是一个真正的 Linux 人。但为什么它还要寻找“libhello”而不是“hello”?您是否尝试过简单地将您的 hello.so
重命名为 libhello.so.so
??
您是否将您的 C++ 函数声明为 extern "C"
以防止编译器损坏它?
@Adrian 我也不认识
【参考方案1】:
根据[man7]: GCC(1)(man gcc
):
-共享
生成一个共享对象,然后可以将其与其他对象链接以形成可执行文件。并非所有系统都支持此选项。为了获得可预测的结果,您还必须在指定此链接器选项时指定用于编译的同一组选项(-fpic、-fPIC 或模型子选项)。 [1 ]
因此,您的命令没有生成共享对象或库 (.so),而是生成了可执行文件(即使名为 hello.so)。如果您尝试运行它,您将看到 main 的输出。 要修复问题,请将构建命令更改为:
g++ -shared -fPIC -o hello.so hello.cpp
其他注意事项:
不知道为什么要创建函数extern 关于__declspec(dllexport)
,处理它的常用方法跨平台是通过宏。例子很多(我也有几个),这里有一个:[SO]: Python ctypes to return an array of function pointers (@CristiFati's answer)(DLL00_EXPORT 宏)
在命名方面,通常一个库 - 我们称之为“example” - 将被命名为 libexample.so 。许多 lib 仍然以向后兼容的方式命名,我个人只看到一个优点:在链接它时,只指定短版本(-lexample) 而不是它的名字。 如果您决定更改名称,请务必同时更新您的 C# 代码:[DllImport("libhello.so", ...
【讨论】:
以上是关于在 Linux 和 Windows 中与 c# 集成的跨平台 c++的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C# 中与输出在同一行中返回字符串和 int 变量?