Я пишу кросс-платформенную библиотеку .NET, которая использует некоторый неуправляемый код. В статическом конструкторе моего класса обнаружена платформа, и соответствующая неуправляемая библиотека извлекается из встроенного ресурса и сохраняется в каталоге temp, аналогично коду, указанному в qaru.site/info/16728/....
Чтобы библиотека могла быть найдена, когда она не находится в PATH, я явно загружаю ее после ее сохранения в файл temp. В Windows это отлично работает с LoadLibrary
из kernel32.dll. Я пытаюсь сделать то же самое с dlopen
в Linux, но я получаю DllNotFoundException
, когда дело доходит до загрузки методов P/Invoke позже.
Я проверил, что библиотека libindexfile.so успешно сохраняется в каталоге temp и что вызов dlopen
завершается успешно. Я углубился в моно источник, чтобы попытаться выяснить, что происходит, и я думаю, что это может сводиться к тому, будет ли следующий вызов dlopen
будет просто повторно использовать ранее загруженную библиотеку. (Конечно, предполагая, что мой наивный маневр через моно-источник сделал правильные выводы).
Вот форма того, что я пытаюсь сделать:
// actual function that we're going to p/invoke to
[DllImport("indexfile")]
private static extern IntPtr openIndex(string pathname);
const int RTLD_NOW = 2; // for dlopen flags
const int RTLD_GLOBAL = 8;
// its okay to have imports for the wrong platforms here
// because nothing will complain until I try to use the
// function
[DllImport("libdl.so")]
static extern IntPtr dlopen(string filename, int flags);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string filename);
static IndexFile()
{
string libName = "";
if (IsLinux)
libName += "libindexfile.so";
else
libName += "indexfile.dll";
// [snip] -- save embedded resource to temp dir
IntPtr handle = IntPtr.Zero;
if (IsLinux)
handle = dlopen(libPath, RTLD_NOW|RTLD_GLOBAL);
else
handle = LoadLibrary(libPath);
if (handle == IntPtr.Zero)
throw new InvalidOperationException("Couldn't load the unmanaged library");
}
public IndexFile(String path)
{
// P/Invoke to the unmanaged function
// currently on Linux this throws a DllNotFoundException
// works on Windows
IntPtr ptr = openIndex(path);
}
Update:
Похоже, что последующие вызовы LoadLibrary
в Windows выглядят, чтобы увидеть, была ли DLL с тем же именем уже загружена, а затем использует этот путь. Например, в следующем коде оба вызова LoadLibrary
возвращают действительный дескриптор:
int _tmain(int argc, _TCHAR* argv[])
{
LPCTSTR libpath = L"D:\\some\\path\\to\\library.dll";
HMODULE handle1 = LoadLibrary(libpath);
printf("Handle: %x\n", handle1);
HMODULE handle2 = LoadLibrary(L"library.dll");
printf("Handle: %x\n", handle2);
return 0;
}
Если то же самое происходит с dlopen
в Linux, второй вызов завершится неудачно, так как он не предполагает, что библиотека с тем же именем будет на одном пути. Есть ли способ обойти это?