How to set search path for dllimport in mono?
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:
GetSystemDirectory()
function to get the path of this directory. GetWindowsDirectory()
function to get the path of this directory. and Linux:
LD_LIBRARY_PATH
environment variable. This is a frequently-used way to allow native shared libraries to be found by a CLI program. /etc/ld.so.cache
. /etc/ld.so.cache
is created by editing /etc/ld.so.conf
and running ldconfig(8)
. Editing /etc/ld.so.conf
is the preferred way to search additional directories, as opposed to using LD_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 into LD_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:
SetDllDirectory()
on Windows? What does DllImportAttribute
actually do in Mono? DllImport
rather than platform specific APIs such as LoadLibrary()
and dlopen()
? Unfortunately the answer is that this behaviour is different between Mono on Linux, and .Net on windows, so you are just going to have to deal with that.
The best option, if you know where each DLL is located (eg you can put this into a config file), is to load each one explicitly yourself using LoadLibrary
or dlopen
. This must be done prior to the first call to a DllImport
function. DllImport
then need not specify a path.
This way you know exactly which DLL you are getting, and can load them in whatever order is correct, if this is an issue.
If for some reason you really don't want to do that, I suggest you create a function like MySetDllDirectory
which on Windows calls SetDllDirectory
and on Linux sets LD_LIBRARY_PATH
. In this way the changes can be isolated to a single module.