I'm developing an Unity app which needs to dynamically load native libraries from outside where the app is installed, for some reason I cannot set the absolute path to DllImport
before compiling (such as read the library path in a .txt at runtime and load it), and I don't want to use platform specific API such as LoadLibrary()
on Windows or dlopen
on Linux because it's inconvenient. And I have been struggled for several days.
I know that the search path can be adjusted by SetDllDirectory()
on Windows from this post, and it works well when testing on .NET Framework applications.
However, it does not work in Unity which is based on mono 2.0, it just throws DllNotFoundException
at runtime, but it works fine when I use absolute path in DllImport
or copy the dll into my Unity project (I'm sure that the code is same)
The next way I tried is environment variable, and it does not work on both .NET and Mono, this post explained that CLR never refreshes the environment during process execution.
The third way I tried is to load the native library with platform specific API such as LoadLibrary()
on Windows and dlopen()
on Linux first, and then Dllimport
may find that the library with same name has already been loaded, then it will use the load library to find function pointers, just as this post did. And I get the same result. The top answer of that question says we can write a wrapper class which uses platform specific API to explicitly load library and get functions pointers, instead of an approach focusing Dllimport
, but it is not what I want.
If my guess is right, according to mono's document, DllImportAttribute
calls LoadLibrary
or dlopen
internally at runtime to load a library into memory space. So it follows the search rules of specific OS platform, for example windows:
- The directory from which the application loaded.
- The current directory
- The system directory. Use the
GetSystemDirectory()
function to get the path of this directory. - The 16-bit system directory.
- The Windows directory. Use the
GetWindowsDirectory()
function to get the path of this directory. - The directories that are listed in the PATH environment variable.
and Linux:
- A colon-separated list of directories in the user’s
LD_LIBRARY_PATH
environment variable. This is a frequently-used way to allow native shared libraries to be found by a CLI program. - The list of libraries cached in
/etc/ld.so.cache
./etc/ld.so.cache
is created by editing/etc/ld.so.conf
and runningldconfig(8)
. Editing/etc/ld.so.conf
is the preferred way to search additional directories, as opposed to usingLD_LIBRARY_PATH
, as this is more secure (it’s more difficult to get a trojan library into/etc/ld.so.cache
than it is to insert it intoLD_LIBRARY_PATH
). /lib
, followed by/usr/lib
.
By the way, I also tried to set LD_LIBRARY_PATH
at runtime, but it does not work because LD_LIBRARY_PATH
will be parsed only once when a process started, which is similar to PATH
environment variable on Windows.
So my question is:
- Why does the same code performs differently on .NET Framework and Mono? Does Mono just ignore the effect of
SetDllDirectory()
on Windows? What doesDllImportAttribute
actually do in Mono? - Is there any way to adjust search path for Unity/Mono apps at runtime, just using
DllImport
rather than platform specific APIs such asLoadLibrary()
anddlopen()
?