【问题标题】:Cross platform c++ integrated with c# in Linux and Windows在 Linux 和 Windows 中与 c# 集成的跨平台 c++
【发布时间】: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 我也不认识

标签: c# c++ shared-libraries cross-platform dllimport


【解决方案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", ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-17
    • 2017-08-13
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 2013-11-11
    • 2012-03-01
    • 1970-01-01
    相关资源
    最近更新 更多