SQLite Forum

Loading bundled extensions in dotnet on linux
Login

Loading bundled extensions in dotnet on linux

(1) By marco6 on 2021-06-30 10:58:38 [source]

Hi everybody,

I'm trying to use the json1 extension in C# (dotnet core), in an application that should support both Linux and Windows.

A very dumb sample could be:

public static void Main(string[] args)
{
    using (var connection = new SQLiteConnection(new SQLiteConnectionStringBuilder {
        DataSource = ":memory:",
    }.ConnectionString)) {
        connection.Open();
        connection.EnableExtensions(true);
        connection.LoadExtension("SQLite.Interop.dll", "sqlite3_json_init");
        using (var command = new SQLiteCommand("SELECT json('[ 1,23,3   , 4]')", connection))
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                for (int i = 0; i < reader.FieldCount; i++) {
                    Console.Write("{0}: {1}, ", reader.GetName(i), reader.GetValue(i));
                }
                Console.WriteLine();
            }
        }
    }
}

Which works on Windows, but throws on Linux:

Unhandled exception. code = Error (1), message = System.Data.SQLite.SQLiteException (0x800007BF): SQL logic error
SQLite.Interop.dll.so: cannot open shared object file: No such file or directory
   at System.Data.SQLite.SQLite3.LoadExtension(String fileName, String procName)
   at System.Data.SQLite.SQLiteConnection.LoadExtension(String fileName, String procName)
   at test_api.Program.Main(String[] args) in <path>/Program.cs:line 33
   at test_api.Program.<Main>(String[] args)

The problem seems clear, but I don't have any idea on how to solve it without hardcoding paths/switching at runtime (or compile-time) on the OS/Architecture, which sounds like a very bad idea to me.

Thank you,

Marco Manino

(2) By Holger J (holgerj) on 2021-06-30 13:15:04 in reply to 1 [link] [source]

Probably the file your code tries to load SQLite.Interop.dll.so is actually named SQLite.Interop.so

Don't add the Windows specific file name extension on the Linux platform.

(3) By marco6 on 2021-07-01 09:05:37 in reply to 2 [link] [source]

Hi!

Thank you for your answer. :-)

Unfortunately, it doesn't work. If I remove the ".dll" part, it will break on both Linux and Windows.

The main reason is that if you inspect the output directory, all the "native" dependencies have been named after Windows.

For example, from any sqlite project dir

> ls -R bin/Release/net5.0/runtimes/
bin/Debug/net5.0/runtimes/:
linux-x64  osx-x64  win-x64  win-x86

bin/Debug/net5.0/runtimes/linux-x64:
native

bin/Debug/net5.0/runtimes/linux-x64/native:
SQLite.Interop.dll

bin/Debug/net5.0/runtimes/osx-x64:
native

bin/Debug/net5.0/runtimes/osx-x64/native:
SQLite.Interop.dll

bin/Debug/net5.0/runtimes/win-x64:
native

bin/Debug/net5.0/runtimes/win-x64/native:
SQLite.Interop.dll

bin/Debug/net5.0/runtimes/win-x86:
native

bin/Debug/net5.0/runtimes/win-x86/native:
SQLite.Interop.dll

I also checked the contents of the .nupkg this is the way it is intended to be.

(4) By marco6 on 2021-07-01 09:18:29 in reply to 2 [link] [source]

So, probably I should rephrase the question:

Given that in all the interops I can find bundled many extensions (json1, sequences, etc.. I can see the relevant exported symbols with OBJDUMP/nm like sqlite3_json_init and so on...), what is the recommended way to use them in a cross-platform environment? If there isn't, then why are them bundled at all?

Marco

(5) By mistachkin on 2021-07-01 18:32:33 in reply to 4 [link] [source]

Can you please try using the fully qualified file name for the "SQLite.Interop.dll" you wish to use?

(6) By marco6 on 2021-07-13 09:59:03 in reply to 5 [link] [source]

Sorry for the late reply.

How can I do that without hardcoding a path?

I know I could find some way to make sure the path is right in an installation, but it feels somewhat fragile.

It would be something like:

  • find out where the executable is (run-time);
  • find out on which OS I'm running on (run-time);
  • find out the architecture I'm running on (run-time);
  • build a path based on hardcoded values (compile-time).

This is IMHO very bad from the maintenance POV (nothing stops a minor sqlite update that doesn't change the public interface from changing those paths and crashing my distribution: that code would be relying on an implementation detail).

I think there should be a reasonably safer way to do that, otherwise, those extensions are mostly useless.

(7) By David Jones (vman59) on 2021-07-13 23:26:10 in reply to 6 [link] [source]

I'd probably add a table to the database (e.g. interop(init_func,OS,arch,path)) and if the select for init_func,OS,arch fails report a configuration error with steps needed to correct. Populating the table can be deferred until deployment.