在 Linux 和 Windows 中与 c# 集成的跨平台 c++

Cross platform c++ integrated with c# in Linux and Windows

我在 c++ 中有以下代码来确定 os

中的可用 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复制到调试文件夹。一切正常

for Linux 我使用 g++ -o hello.so hello.cpp 在 Opensuse 上编译它 并将 .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 文件,它都找不到它。

根据[man7]: GCC(1) (man gcc):

-shared

Produce a shared object which can then be linked with other objects to form an executable. Not all systems support this option. For predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you specify this linker option.[1]

因此,您的命令没有生成共享对象或库 (.so),而是生成可执行文件(即使名为 hello.so )。如果您尝试 运行 它,您将看到 main 的输出。
要解决问题,请将构建命令更改为:

g++ -shared -fPIC -o hello.so hello.cpp

其他备注:

  • 不知道为什么要创建函数 extern
  • 关于__declspec(dllexport),处理它跨平台的常用方法是通过宏。有很多例子(我也有几个),这里是一个: (DLL00_EXPORT macro)
  • 在命名方面,通常一个库——我们称它为“example”——将被命名为libexample.so。为了向后兼容,许多 libs 仍然这样命名,我个人只看到一个优点:链接时,只指定短版本 (-lexample) 而不是它的名字。
    如果您决定更改名称,请务必同时更新您的 C# 代码:[DllImport("libhello.so", ...