I am trying to package the following ruby script with OCRA (I am on Windows 10, Ruby 2.6):
require 'sqlite3'
puts SQLite3::VERSION
Running this in cmd works properly:
C:\Users\monday\Documents\projects\sqlite3_test>script.rb
1.4.2
When I package script.rb
the following way:
ocra --gem-full=sqlite3 --dll sqlite3.dll script.rb --output script.exe --verbose
I have added sqlite3.dll
and sqlite3.def
to my PATH
and into C:\Ruby26-x64\bin
as per various suggestions on SO and GitHub.
Here is the error that pops up when I run the resulting script.exe
:
C:\Users\monday\Documents\projects\sqlite3_test>script.exe
Traceback (most recent call last):
2: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/src/script.rb:1:in `<main>'
1: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- sqlite3 (LoadError)
6: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/src/script.rb:1:in `<main>'
5: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
4: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `rescue in require'
3: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `require'
2: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3.rb:4:in `<top (required)>'
1: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- sqlite3/2.6/sqlite3_native (LoadError)
7: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/src/script.rb:1:in `<main>'
6: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
5: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `rescue in require'
4: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `require'
3: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3.rb:2:in `<top (required)>'
2: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3.rb:6:in `rescue in <top (required)>'
1: from C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': 126: The specified module could not be found. - C:/Users/monday/AppData/Local/Temp/ocr7747.tmp/lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/sqlite3_native.so (LoadError)
I am sure that lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/sqlite3_native.so
is present in the temporary folder, judging by OCRA's output:
...
m lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3.rb
m lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/constants.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/database.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/errors.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/pragmas.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/resultset.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/sqlite3_native.so <<< HERE!
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/statement.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/translator.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/value.rb
a lib/ruby/gems/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/version.rb
...
What am I missing?
After some research I found out that the error message The specified module could not be found.
means that the program might be missing required DLLs. Now that sqlite3_native.so
is present, I presumed that it is that program that is missing DLLs. Running dumpbin
on it gave the following results:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community>dumpbin /dependents C:\Ruby26-x64\lib\ruby\gems\2.6.0\gems\sqlite3-1.4.2\lib\sqlite3\sqlite3_native.so
Microsoft (R) COFF/PE Dumper Version 14.22.27905.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C:\Ruby26-x64\lib\ruby\gems\2.6.0\gems\sqlite3-1.4.2\lib\sqlite3\sqlite3_native.so
File Type: DLL
Image has the following dependencies:
x64-msvcrt-ruby260.dll
KERNEL32.dll
msvcrt.dll
libsqlite3-0.dll
...
Apparently, libsqlite3-0.dll
was never detected by OCRA, and thus never moved into temporary folder's bin/
directory. A quick search revealed that libsqlite3-0.dll
is indeed present on my machine at C:\Ruby26-x64\msys64\mingw64\bin
. I moved it to C:\Ruby26-x64\bin
, and ran OCRA with the following options:
ocra --dll libsqlite3-0.dll script.rb --output script.exe
Later, I realized that OCRA is now able to detect this DLL on its own:
=== Adding ruby executable ruby.exe
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libgmp-10.dll
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libffi-6.dll
=== Adding detected DLL C:/Ruby26-x64/bin/libsqlite3-0.dll <<<< HERE!
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libgcc_s_seh-1.dll
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libwinpthread-1.dll
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/zlib1.dll
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libssl-1_1-x64.dll
=== Adding detected DLL C:/Ruby26-x64/bin/ruby_builtin_dlls/libcrypto-1_1-x64.dll
=== Adding external manifest C:/Ruby26-x64/bin/ruby_builtin_dlls/ruby_builtin_dlls.manifest
So, finally:
ocra script.rb --output script.exe
Works properly, and there is no need for sqlite3.dll
.
This seems to be quite a universal solution, as I was able to make puma run from within OCRA-packaged script by adding required DLLs to Ruby installation's bin/
folder.