6

I have a C# application that uses SQLite and works fine on Windows.

The same Visual Studio project compiles fine in Xamarin Studio, but when running I get:

DllNotFoundException: SQLite.Interop.dll

Despite:

  • libsqlite3.0.dylib is in /usr/lib and also in the same folder as the executable and other DLLs
  • . is part of the $DYLD_LIBRARY_PATH
  • The executable and all SQLite-using DLLs have a matching <the_exe_or_dll_including_filename_extension>.config file containing:

<configuration> <dllmap dll="sqlite" target="libsqlite.0.dylib" os="osx"/> <dllmap dll="sqlite3" target="libsqlite3.0.dylib" os="osx"/> </configuration>

I also tried adding <dllmap dll="SQLite.Interop.dll" target="libsqlite3.0.dylib" os="osx"/>, not better.

What is the problem?

Nicolas Raoul
  • 58,567
  • 58
  • 222
  • 373
  • 1
    Two things: `OS X` doesn't use the `$PATH` variable that `Windows` does, and dynamic libraries are `dylibs`, not `dlls`. In order to make a `dll` work properly with mono and `OS X` it needs to be mapped using a `Dllmap`. – l'L'l Jul 01 '15 at 08:00
  • @l'L'l: [This software](https://github.com/aegif/CmisSync) uses SQLite on Mac with Mono and does not contain any `Dllmap`... still trying to find how it manages that. – Nicolas Raoul Jul 01 '15 at 08:07
  • Looks like it has a *few* [dllmaps](https://github.com/aegif/CmisSync/search?utf8=%E2%9C%93&q=dllmap), so I would imagine [interop.dll](https://github.com/aegif/CmisSync/search?utf8=%E2%9C%93&q=Interop.dll) might need it also. – l'L'l Jul 01 '15 at 08:28
  • @l'L'l: The software above has no Dllmap related to SQLite. If I were to add one, what library do you suggest to add? I can't find any OS X library on the SQLite websites, only standalone executables. – Nicolas Raoul Jul 01 '15 at 09:06
  • In the `dllmap` configuration section try adding: `` and `` – l'L'l Jul 01 '15 at 09:14
  • @l'L'l: Thanks for the tip! I spent the whole day trying that and related solutions, but no success so far... I updated the question to show what I have now. – Nicolas Raoul Jul 02 '15 at 09:27
  • I just happened to notice in the [config](https://github.com/aegif/CmisSync/blob/6435172a9b8e368cf9bac2eb4b1b275573433cc1/CmisSync/Mac/config#L16-L17) you already have ``, so it's a bit of a mystery why it's not working. – l'L'l Jul 04 '15 at 02:57
  • I am having the same problem on Linux with mono 4.4 using Mono.Data.Sqlite, but my project is NUnit test project. Any updates ? – shturm Sep 19 '16 at 04:53

2 Answers2

6

You can easily find where mono is looking for that native library by setting the MONO_LOG_LEVEL to debug and MONO_LOG_MASK filtering to only DLL related messages.

export MONO_LOG_LEVEL=debug
export MONO_LOG_MASK=dll
mono yourprogram.exe

or as a one liner so you do not have to unset env vars:

MONO_LOG_LEVEL=debug MONO_LOG_MASK=dll mono yourprogram.exe

Mono and the OS-X dynamic link editor ('man dyld' for details) does not require DYLD_LIBRARY_PATH to be set to the current directory ('.'). Note: Linux does require LD_LIBRARY_PATH to include the current directory, if that is your intention.

  • Move those dll map files out of the way to remove them from the equation.
  • Unset DYLD_LIBRARY_PATH
  • cd in the directory that contains your CIL based exe, dlls and native dylib(s)
  • MONO_LOG_LEVEL=debug MONO_LOG_MASK=dll mono yourprogram.exe

Using the native dll/shared library trace output you can track which library is not being found (or one of its dependancies) or if it is the wrong ARCH for your mono version.

If you are still having problems, we would need to know which SQLite library you are using the options that you are using to compile it (or the arch version if getting it via a Nuget). A posting your dll trace output would quickly solve things also.

Notes:

I am assuming you are using the System.Data.SQLite library and are compiling the the options "/p:UseInteropDll=true /p:UseSqliteStandard=false".

Mono includes a SQLite in it's default install, it is 32-bit on OS-X:

file /Library/Frameworks/Mono.framework/Versions/4.0.2/lib/libsqlite3.dylib
/Library/Frameworks/Mono.framework/Versions/4.0.2/lib/libsqlite3.dylib: Mach-O dynamically linked shared library i386

Assuming you are using the OS-X package installer from Mono, thus are getting the 32-bit version of Mono and thus need 32-bit versions of the native libraries.

>>file `which mono`
/usr/bin/mono: Mach-O executable i386

The /usr/lib/libsqlite3.0.dylib is a multi ARCH fat binary, so that library is not a problem, but your debug output might show another one that is a problem,

>>file /usr/lib/libsqlite3.0.dylib
libsqlite3.0.dylib: Mach-O universal binary with 3 architectures
libsqlite3.0.dylib (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64
libsqlite3.0.dylib (for architecture i386): Mach-O dynamically linked shared library i386
libsqlite3.0.dylib (for architecture x86_64h):  Mach-O 64-bit dynamically linked shared library x86_64
SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • 1
    I am not compiling with "/p:UseInteropDll=true /p:UseSqliteStandard=false". If there is a standard easy way to use SQLite on Mono/Mac I am all for using it :-) – Nicolas Raoul Jul 06 '15 at 02:36
  • "file which mono" says `/usr/bin/mono: Mach-O executable i386` indeed. – Nicolas Raoul Jul 06 '15 at 03:07
  • "file /usr/lib/libsqlite3.0.dylib" also outputs the same as yours. – Nicolas Raoul Jul 06 '15 at 03:09
  • I see that from another question you are now trying to use Mono's supplied SQLite, but if you are trying to use "System.Data.SQLite". The nuget version of System.Data.SQLite does not come with xplat native shared libraries, but you can compile the library to use the native libraries supplied on Linux or OS-X by using their build instructions: http://system.data.sqlite.org/index.html/doc/trunk/www/build.wiki#mono – SushiHangover Jul 06 '15 at 17:58
  • Actually I tried removing DYLD_LIBRARY_PATH and the map files, and now it just does not compile anymore, so I am quite desperate... so I try various things. Really I just want to do a few read/writes, I thought it would be easy but I can't find any clear instructions. I will try again now. – Nicolas Raoul Jul 07 '15 at 02:43
3

You need to build and supply SQLite.Interop.dll (or more precisely libSQLite.Interop.dylib). The Mono distribution packages don't include it, probably because it's native code and really needs to be built on the target platform.

System.Data.SQLite on Windows uses a mixed mode approach (Managed data adapter + sqlite native code in one assembly). Mono however doesn't really support mixed mode assemblies.

So on MacOS there are two alternatives when it comes to building System.Data.SQLite on Windows:

  1. Use interop dll.
  2. Use libsqlite.x.x.dylib.

Both of these are native code and need to be built on the Mac.

Interop is Windows com speak so it's a bit disconcerting to see it used in a MacOS context. What this native dll is is the sqlite source code compiled up with some additional native code that can be P\Invoked by System.Data.SQLite. There are some benefits to using the interop dll as opposed to the sqlite dylib.

System.Data.SQLite ships with a copy of the relevant SQLite native source code in ./SQLite.Interop/src.core. You can build the interop library by running compile-interop-assembly-release.sh on the Mac. This will build libSQLite.Interop.dylib. Drop that in beside System.Data.SQLite and you should be good to go.

If you turn on Mono dll tracing you can watch the loader (see mono 4.8.0 loader.c) searching for the dll in various locations and with various name substitutions. Eventually it finds our dylib. It is also possible to use a dllmap entry in the System.Data.SQLite.dll.config file to direct the runtime to the dll. In my case Mono is on my app bundle so I have:

<dllmap dll="SQLite.Interop.dll" target="@executable_path/../Mono/libSQLite.Interop.dylib" os="!windows"/>

The dllmap target argument is passed to dlopen() so @executable_path et al are all usable.

I prefer this approach as it goes into the repo and provides some insight into what is going on when there's a foul up.

Jonathan Mitchell
  • 1,339
  • 12
  • 17
  • Thanks for this answer ! I've done exactly what you've described but I always get this error when I launch my app : System.EntryPointNotFoundException: Unable to find an entry point named "sqlite3_rekey" in DLL "sqlite3" Do you happen to know why ? I've tried to add the DSQLITE_HAS_CODEC in the compile file but it doesn't seem to help – user2088807 Jul 20 '18 at 14:35
  • Have you tried turning on Mono dll tracing? My usage case still works fine (but I am not on the very latest build of Mono as yet) so I suggest you just keep poking at it until something clicks. – Jonathan Mitchell Jul 21 '18 at 14:19