Background: My MonoMac app uses a custom build of sqlite3.0.8.6.dylib.
I need the exact steps to have MyApp.app use this dylib.
Here are some steps I took:
Copied the dylib to MyApp.app/Contents/SharedSupport. (Related question: is this the preferred location for 3rd party dylibs or is MyApp.app/Contents/Frameworks preferred?)
Changed the installed name for the library so that it matches its new location.
MyApp.app/Contents/SharedSupport> otool -L libsqlite3.0.8.6.dylib
libsqlite3.0.8.6.dylib:
@executable_path/../SharedSupport/libsqlite3.0.8.6.dylib (compatibility version 9.0.0, current version 9.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
Problems
- MyApp.app/Contents/MacOS/MyApp does not reference the dylib directly, so I can't use install_name_tool to point to the new library location. I believe that the library is referenced by System.Data.Sqlite.dll.
- I thought of overriding DYLD_FALLBACK_LIBRARY_PATH in the launcher script but MonoMac now uses a binary launcher (MyApp.app/Contents/MacOS/MyApp), not a script, so I'm out of luck there.
Would the MonoMac gods please help with what must be a simple solution? I've spent a couple of months, on and off, trying to get this to work.
And please provide exact steps - this problem is all about the details.
Have a look at my answer to this question:
Setting path of the Native Library for DllImport on Mono for Mac
The binary launcher comes from monodevelop/main/build/MacOSX/monostub.m.
You can use either MyApp.app/Contents/Frameworks
or some other path, the important part is not to use any path names in your [DllImport]
but instead add the <dllmap>
using @executable_path
to your app.config
like I explained in that other answer.
There's a also a link to a test app on github in there.
Detailed Instructions
Pick a path inside the MyApp.app
to install your native dll, for instance Contents/SharedSupport/sqlite3.0.8.6.dylib
.
Compute the relative path from the directory where the managed assembly is located to the native .dll
and prepend @executable_path
to it.
For instance, if your managed assembly is in
Contents/MonoBundle/MyApp.exe
and the native dll in
Contents/SharedSupport/sqlite3.0.8.6.dylib
, then it's
@executable_path/../SharedSupport/sqlite3.0.8.6.dylib
.
Change the installed name of the library to this relative path using install_name_tool
.
Add a new MyApp.exe.config
file to your project, containing
<configuration>
<dllmap dll="sqlite" target="@executable_path/../SharedSupport/sqlite3.0.8.6.dylib" />
</configuration>
Use the path that you computed in step 2. for the target
field. Right-click the file in MonoDevelop, select "Quick Properties" from the context menu and enable "Copy to Output directory". This will copy the file into the Contents/MonoBundle
directory, so it sits right next to your MyApp.exe
.
Use [DllImport ("sqlite")]
to reference this in your code.
When another library references it
When another library, for instance Mono.Data.Sqlite.dll
references it, it get a little bit more complicated.
Use the same steps as above, but you need to figure out which name that other library is using in its [DllImport]
to reference the native library and put that into the <dllimport dll="..." />
. You can either look for the [DllImport]
statements in the source code or run monodis
on the assembly and search for pinvokeimpl
, for instance:
// method line 679
.method assembly static hidebysig pinvokeimpl ("sqlite3" as "sqlite3_create_function" cdecl )
default int32 sqlite3_create_function (native int db, unsigned int8[] strName, int32 nArgs, int32 nType, native int pvUser, class Mono.Data.Sqlite.SQLiteCallback func, class Mono.Data.Sqlite.SQLiteCallback fstep, class Mono.Data.Sqlite.SQLiteFinalCallback ffinal) cil managed preservesig
{
// Method begins at RVA 0x0
} // end of method UnsafeNativeMethods::sqlite3_create_function
So Mono.Data.Sqlite.dll
is using "sqlite3" to reference the native dll, so your MyApp.exe.config
file will look like this:
<configuration>
<dllmap dll="sqlite3" target="@executable_path/../SharedSupport/sqlite3.0.8.6.dylib" />
</configuration>
Be careful if you're using mono. @executable_path will return the path to the mono binary, instead of the actual .EXE executable. This should work correctly with Xamarin though.
You can try manually loading the sqlite
dylib
.
[DllImport ("/usr/lib/libSystem.dylib")]
public static extern IntPtr dlopen (string path, int mode);
IntPtr p = dlopen("libsqlite3.0.8.6.dylib", 0);
Of course correctly resolving the path to your dylib
.