Reputation: 2679
I have the following code in c++ to determine available RAM in os
#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);
}
and the following code in 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();
}
}
Then in windows I compile c++ code using g++ --shared -o hello.dll hello.cpp
and copy the dll to debug folder. everything is ok.
for Linux I compile it on Opensuse using g++ -o hello.so hello.cpp
and copy the .so
file into the debug but it doesn't work.
I get the exception
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
I added the .so
file dir path to LD_LIBRARY_PATH using LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/CallCDll/bin/Debug/netcoreapp2.2
but doesn't work.
What Should I do? Wherever I copy the .so
file, it cannot find it.
Upvotes: 3
Views: 1148
Reputation: 41116
According to [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, your command didn't generate a shared object or library (.so), but an executable (even if named hello.so). If you try running it, you'll see the output from main.
To fix things, change your build command to:
g++ -shared -fPIC -o hello.so hello.cpp
Other notes:
Don't know why you made your functions extern
Regarding __declspec(dllexport)
, the common way of handling it cross platform is via a macro. There are many examples (I too have several), here's one: [SO]: Python ctypes to return an array of function pointers (@CristiFati's answer) - DLL00_EXPORT macro (or even more generic - as it handles building a static library as well: [SO]: Linker error when calling a C function from C++ code in different VS2010 project (@CristiFati's answer))
In terms of naming, usually a library - let's call it "example" - will be named libexample.so. Many libs are still named like that for backwards compatibility: one advantage is when linking against it, only specify the short version (-lexample) instead of its name. Check [SO]: Why are some Windows dll names prefixed by lib (@CristiFati's answer) for more details.
If you decide to change the name, make sure to update your C# code as well: [DllImport("libhello.so", ...
Upvotes: 3