elixir-sqlite / exqlite

An SQLite3 driver for Elixir
https://hexdocs.pm/exqlite
MIT License
208 stars 47 forks source link

sqlite3_nif: Unspecified error #226

Closed voltagex closed 1 year ago

voltagex commented 1 year ago

Using Windows 10, exqite appears to build correctly, but I get sqlite3_nif: Unspecified error when trying to run {:ok, conn} = Exqlite.Sqlite3.open(":memory:")

c:\git\test-elixir\playground>mix deps.get
-> Running mix loadconfig (inside Playground.MixProject)
<- Ran mix loadconfig in 0ms
-> Running mix deps.get (inside Playground.MixProject)
-> Running mix archive.check (inside Playground.MixProject)
<- Ran mix archive.check in 0ms
Resolving Hex dependencies...
Resolution completed in 0.117s
New:
  connection 1.1.0
  db_connection 2.4.3
  elixir_make 0.7.3
  exqlite 0.12.0
  telemetry 1.1.0
* Getting exqlite (Hex package)
  Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/exqlite-0.12.0.tar)
* Getting db_connection (Hex package)
  Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/db_connection-2.4.3.tar)
* Getting elixir_make (Hex package)
  Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/elixir_make-0.7.3.tar)
* Getting connection (Hex package)
  Using locally cached package (c:/Users/Adam/.hex/packages/hexpm/connection-1.1.0.tar)
* Getting telemetry (Hex package)
  Fetched package (https://repo.hex.pm/tarballs/telemetry-1.1.0.tar)
-> Running mix will_recompile (inside Playground.MixProject)
<- Ran mix will_recompile in 1ms
<- Ran mix deps.get in 1044ms

c:\git\test-elixir\playground>iex -S mix
-> Running mix loadconfig (inside Playground.MixProject)
<- Ran mix loadconfig in 0ms
-> Running mix run (inside Playground.MixProject)
-> Running mix app.start (inside Playground.MixProject)
-> Running mix app.config (inside Playground.MixProject)
-> Running mix compile (inside Playground.MixProject)
-> Running mix loadpaths (inside Playground.MixProject)
-> Running mix archive.check (inside Playground.MixProject)
<- Ran mix archive.check in 0ms
-> Running mix deps.loadpaths (inside Playground.MixProject)
-> Running mix deps.precompile (inside Playground.MixProject)
<- Ran mix deps.precompile in 2ms
==> connection
-> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
-> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
<- Ran mix loadpaths in 0ms
-> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
-> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
<- Ran mix compile.yecc in 1ms
-> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
<- Ran mix compile.leex in 0ms
-> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
<- Ran mix compile.erlang in 0ms
-> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
Compiling 1 file (.ex)
<- Ran mix compile.elixir in 194ms
-> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Connection.Mixfile)
Generated connection app
<- Ran mix compile.app in 3ms
<- Ran mix compile.all in 212ms
<- Ran mix compile in 213ms
===> Expanded command sequence to be run: []
===> Running provider: do
===> Expanded command sequence to be run: [app_discovery,{bare,compile}]
===> Running provider: app_discovery
===> Found top-level apps: [telemetry]
        using config: [{src_dirs,["src"]},{lib_dirs,["apps/*","lib/*","."]}]
===> Running provider: {bare,compile}
===> Compile (untagged)
===> Running hooks for compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {pre_hooks, []}.
===> Running hooks for erlc_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {pre_hooks, []}.
===> Analyzing applications...
===> Compiling telemetry
===> compile options: {erl_opts, [debug_info]}.
===> files to analyze ["c:/git/test-elixir/playground/deps/telemetry/src/telemetry_sup.erl",
                       "c:/git/test-elixir/playground/deps/telemetry/src/telemetry_handler_table.erl",
                       "c:/git/test-elixir/playground/deps/telemetry/src/telemetry_app.erl",
                       "c:/git/test-elixir/playground/deps/telemetry/src/telemetry.erl"]
===>      Compiled telemetry_app.erl
===>      Compiled telemetry_sup.erl
===>      Compiled telemetry_handler_table.erl
===>      Compiled telemetry.erl
===> Running hooks for erlc_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {post_hooks, []}.
===> Running hooks for app_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {pre_hooks, []}.
===> Running hooks for app_compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {post_hooks, []}.
===> Running hooks for compile in app telemetry (c:/git/test-elixir/playground/deps/telemetry) with configuration:
===>    {post_hooks, []}.
==> db_connection
-> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
-> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
<- Ran mix loadpaths in 0ms
-> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
-> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
<- Ran mix compile.yecc in 0ms
-> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
<- Ran mix compile.leex in 0ms
-> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
<- Ran mix compile.erlang in 0ms
-> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
Compiling 14 files (.ex)
<- Ran mix compile.elixir in 706ms
-> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside DBConnection.Mixfile)
Generated db_connection app
<- Ran mix compile.app in 1ms
<- Ran mix compile.all in 723ms
<- Ran mix compile in 724ms
==> elixir_make
-> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
-> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
<- Ran mix loadpaths in 0ms
-> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
-> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
<- Ran mix compile.yecc in 0ms
-> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
<- Ran mix compile.leex in 0ms
-> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
<- Ran mix compile.erlang in 0ms
-> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
Compiling 6 files (.ex)
<- Ran mix compile.elixir in 199ms
-> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside ElixirMake.Mixfile)
Generated elixir_make app
<- Ran mix compile.app in 0ms
<- Ran mix compile.all in 222ms
<- Ran mix compile in 222ms
==> exqlite
-> Running mix compile --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
-> Running mix loadpaths --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
<- Ran mix loadpaths in 0ms
-> Running mix compile.all --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
-> Running mix compile.elixir_make --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)

Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

        del /f /q priv
Could Not Find c:\git\test-elixir\playground\deps\exqlite\priv
        erl -noshell -s init stop -eval "io:setopts(standard_io, [{encoding, unicode}]), io:format(\"ERTS_INCLUDE_PATH=~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)])." > Makefile.auto.win
        nmake -                   -F Makefile.win priv\sqlite3_nif.dll

Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

        if NOT EXIST "priv" mkdir "priv"
        cl -I"c:/Program Files/Erlang OTP/usr/include" -DNDEBUG=1 -DSQLITE_OMIT_DEPRECATED=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_RBU=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS3=1 -DENABLE_UPDATE_DELETE_LIMIT=1 -DENABLE_STAT4=1 -DENABLE_SOUNDEX=1 -DENABLE_LOAD_EXTENSION=1 -DENABLE_FTS3_PARENTHESIS=1 -DALLOW_COVERING_INDEX_SCAN=1 -DHAVE_USLEEP=1 -DSQLITE_DQS=0 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_USE_URI=1 -DSQLITE_THREADSAFE=1 -Ic_src -EHsc -O2  -I"c:/Program Files/Erlang OTP/erts-13.0.4/include/" -LD -MD -Fepriv\sqlite3_nif.dll c_src\sqlite3.c  c_src\sqlite3_nif.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.34.31937 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

sqlite3.c
sqlite3_nif.c
Generating Code...
Microsoft (R) Incremental Linker Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/dll
/implib:priv\sqlite3_nif.lib
/out:priv\sqlite3_nif.dll
sqlite3.obj
sqlite3_nif.obj
   Creating library priv\sqlite3_nif.lib and object priv\sqlite3_nif.exp
<- Ran mix compile.elixir_make in 7901ms
-> Running mix compile.yecc --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
<- Ran mix compile.yecc in 0ms
-> Running mix compile.leex --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
<- Ran mix compile.leex in 0ms
-> Running mix compile.erlang --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
<- Ran mix compile.erlang in 0ms
-> Running mix compile.elixir --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
Compiling 13 files (.ex)
<- Ran mix compile.elixir in 359ms
-> Running mix compile.app --from-mix-deps-compile --no-archives-check --no-warnings-as-errors (inside Exqlite.MixProject)
Generated exqlite app
<- Ran mix compile.app in 1ms
<- Ran mix compile.all in 8311ms
<- Ran mix compile in 8312ms
==> playground
-> Running mix will_recompile (inside Playground.MixProject)
<- Ran mix will_recompile in 0ms
<- Ran mix deps.loadpaths in 11010ms
<- Ran mix loadpaths in 11011ms
-> Running mix compile.all (inside Playground.MixProject)
-> Running mix compile.yecc (inside Playground.MixProject)
<- Ran mix compile.yecc in 0ms
-> Running mix compile.leex (inside Playground.MixProject)
<- Ran mix compile.leex in 0ms
-> Running mix compile.erlang (inside Playground.MixProject)
<- Ran mix compile.erlang in 0ms
-> Running mix compile.elixir (inside Playground.MixProject)
Compiling 1 file (.ex)
<- Ran mix compile.elixir in 22ms
-> Running mix compile.app (inside Playground.MixProject)
Generated playground app
<- Ran mix compile.app in 1ms
<- Ran mix compile.all in 29ms
-> Running mix compile.protocols (inside Playground.MixProject)
<- Ran mix compile.protocols in 226ms
<- Ran mix compile in 11281ms
<- Ran mix app.config in 11282ms
<- Ran mix app.start in 11288ms
<- Ran mix run in 11290ms
Interactive Elixir (1.14.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, conn} = Exqlite.Sqlite3.open(":memory:")
** (UndefinedFunctionError) function Exqlite.Sqlite3NIF.open/2 is undefined (module Exqlite.Sqlite3NIF is not available)
    (exqlite 0.12.0) Exqlite.Sqlite3NIF.open(':memory:', 6)
    iex:1: (file)
iex(1)>
16:44:34.039 [warning] The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
{:error,
 {:load_failed,
  'Failed to load NIF library c:/git/test-elixir/playground/_build/dev/lib/exqlite/priv/sqlite3_nif: \'Unspecified error\''}}

iex(1)>
warmwaffles commented 1 year ago

Does it open for a file instead of just :memory?

warmwaffles commented 1 year ago

Can you specify v0.11.9 as the version and try? Perhaps the latest changed with v0.12.0 caused an issue.

voltagex commented 1 year ago

@warmwaffles unfortunately, no change with 0.11.9 and a database filename:

iex(1)> {:ok, conn} = Exqlite.Sqlite3.open(":memory:")
** (UndefinedFunctionError) function Exqlite.Sqlite3NIF.open/2 is undefined (module Exqlite.Sqlite3NIF is not available)
    (exqlite 0.11.9) Exqlite.Sqlite3NIF.open(':memory:', 6)
    iex:1: (file)
iex(1)>
11:15:07.663 [warning] The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
{:error,
 {:load_failed,
  'Failed to load NIF library c:/git/test-elixir/playground/_build/dev/lib/exqlite/priv/sqlite3_nif: \'Unspecified error\''}}

iex(1)> {:ok, conn} = Exqlite.Sqlite3.open("test.db")
** (UndefinedFunctionError) function Exqlite.Sqlite3NIF.open/2 is undefined (module Exqlite.Sqlite3NIF is not available)
    (exqlite 0.11.9) Exqlite.Sqlite3NIF.open('test.db', 6)
    iex:1: (file)

11:15:14.219 [warning] The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
{:error,
 {:load_failed,
  'Failed to load NIF library c:/git/test-elixir/playground/_build/dev/lib/exqlite/priv/sqlite3_nif: \'Unspecified error\''}}

iex(1)> {:ok, conn} = Exqlite.Sqlite3.open("test.db")

11:15:41.770 [warning] The on_load function for module Elixir.Exqlite.Sqlite3NIF returned:
{:error,
 {:load_failed,
  'Failed to load NIF library c:/git/test-elixir/playground/_build/dev/lib/exqlite/priv/sqlite3_nif: \'Unspecified error\''}}

** (UndefinedFunctionError) function Exqlite.Sqlite3NIF.open/2 is undefined (module Exqlite.Sqlite3NIF is not available)
    (exqlite 0.11.9) Exqlite.Sqlite3NIF.open('test.db', 6)
    iex:1: (file)
iex(1)>
voltagex commented 1 year ago

Found a problem, sqlite3_nif.dll is 32 bit, while erl.exe is 64 bit.

voltagex commented 1 year ago

That's strange, even when using the settings for a 64 bit compiler, a 32 bit DLL is generated.

voltagex commented 1 year ago

Fixed via the instructions at https://github.com/riverrun/comeonin/issues/75 - a 64 bit NIF was needed.

warmwaffles commented 1 year ago

@voltagex would you mind making a PR to the readme for special setup for windows? I think that would be beneficial to the next person.

voltagex commented 1 year ago

@voltagex would you mind making a PR to the readme for special setup for windows? I think that would be beneficial to the next person.

I can, but I'm still confused as to how the Makefile can call x64 host tools and produce an x86 DLL. Do you know anyone who would have more of an insight into the way NIFs work?

To be honest, this is the first time I've touched Erlang / Elixir.

I am also wondering if there's a way to get a better error message (the underlying error should have been something along the lines of "bad image format")

warmwaffles commented 1 year ago

There is a line in your compiler output that is really easy to miss

Microsoft (R) C/C++ Optimizing Compiler Version 19.34.31937 for x86

I wonder what your $CC is set to. I wish I knew how to build stuff more in Windows.

voltagex commented 1 year ago

You're right! Oops!

It seemed like even when opening "developer command prompt" for x64, I was getting the wrong compiler. The MSVC toolchain doesn't really use "$CC", but there is an equivalent vcvarsall.bat which sets the environment variables (mentioned by the other issue I linked)

warmwaffles commented 1 year ago

Yea normally when I am compiling stuff in windows, it's usually with CMake and it handles all that hoop jumping for me.