在 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 变量?

Linux中与DNS相关的内容

day01_linux中与Oracle有关的内核参数详解

C# 如何正确设置 Windows 8 任务管理器的程序集标题?

在 C# 中与网页交互

在 C# 中与 Google Admin SDK 集成