2021/08/15(日) [n年前の日記]
#2 [ruby] Ruby の fiddle がDLLをロードしてくれない
Ruby の fiddle が DLL をロードしてくれない問題に遭遇して悩んでいたり。コレってバグなの? それとも仕様なの?
◎ 経緯。 :
Ruby でサウンドファイルを再生できるらしい、sfml-audio-fiddle という拡張ライブラリを見かけて、試用してみたいと思ったのですけど。
_sfml-audio-fiddleの紹介 - Qiita
_sfml-audio-fiddle | RubyGems.org | コミュニティのGemホスティングサービス
_bggd/sfml-audio-fiddle: fiddle(ruby's FFI) binding for SFML2 Audio functions.
_CSFML (SFML / Download / Bindings)
Windows10 x64 21H1 + Ruby 2.6.8 x86, 2.7.4 x86, 3.0.2 x86 上で動作確認。gem でインストール。
しかし、require "sfml/audio" しただけでエラーが出てしまって。csfml-audio-2.dll 2.5.1 は、Rubyスクリプトと同じ場所に置いてある状態。
これが Ruby 2.3.3 x86 上なら、require "sfml/audio" してもエラーが出ない…。今時の Ruby (2.6.8, 2.7.4, 3.0.2) ではエラーが出る。
どうして今時の Ruby + fiddle は、カレントディレクトリに置いてある DLL がロードできないのだろうと…。セキュリティ関係の何かであえて読み込めない仕様にしてあるとか?
_sfml-audio-fiddleの紹介 - Qiita
_sfml-audio-fiddle | RubyGems.org | コミュニティのGemホスティングサービス
_bggd/sfml-audio-fiddle: fiddle(ruby's FFI) binding for SFML2 Audio functions.
_CSFML (SFML / Download / Bindings)
Windows10 x64 21H1 + Ruby 2.6.8 x86, 2.7.4 x86, 3.0.2 x86 上で動作確認。gem でインストール。
gem install sfml-audio-fiddle
しかし、require "sfml/audio" しただけでエラーが出てしまって。csfml-audio-2.dll 2.5.1 は、Rubyスクリプトと同じ場所に置いてある状態。
これが Ruby 2.3.3 x86 上なら、require "sfml/audio" してもエラーが出ない…。今時の Ruby (2.6.8, 2.7.4, 3.0.2) ではエラーが出る。
どうして今時の Ruby + fiddle は、カレントディレクトリに置いてある DLL がロードできないのだろうと…。セキュリティ関係の何かであえて読み込めない仕様にしてあるとか?
◎ 関連してるかもしれない情報をメモ。 :
環境変数 RUBY_DLL_PATH とか、関数 add_dll_directory が関係するかも、みたいな話も見かけたのでメモ。
_Windows の Ruby の fiddle で lib○○.dll が読み込めない時、何をチェックすればよいでしょうか? - スタック・オーバーフロー
_How can I load Windows DLL files with Ruby fiddle? - Stack Overflow
_For gem developers - oneclick/rubyinstaller2 Wiki
_Windows の Ruby の fiddle で lib○○.dll が読み込めない時、何をチェックすればよいでしょうか? - スタック・オーバーフロー
_How can I load Windows DLL files with Ruby fiddle? - Stack Overflow
_For gem developers - oneclick/rubyinstaller2 Wiki
◎ 色々試してみた。 :
Windows版の Ruby において、DLLを検索するパスは、環境変数PATHとは一致してないらしい…。一応、DLL検索パスを変更する手もあるらしいけど…。
方法その1。RubyInstaller::Runtime.add_dll_directory() を使うことで、DLLの検索パスを追加できるらしいので試してみた。
_01_require_sfml_audio.rb
方法その2。Windows API の SetDllDirectory() を使ってDLLの検索パスを指定することもできるらしい。これも試してみた。
_02_require_sfml_audio2.rb
方法その3。sfml-audio-fiddle の audio.rb をカレントディレクトリにコピーして、dlload のあたりで絶対パスを指定するように修正して試してみたりもした。
_03_require_sfml_audio3.rb
_sfmlaudio.rb
しかし、どの方法でもエラーが出る…。
方法その1。RubyInstaller::Runtime.add_dll_directory() を使うことで、DLLの検索パスを追加できるらしいので試してみた。
_01_require_sfml_audio.rb
puts "env RUBY_DLL_PATH = #{ENV["RUBY_DLL_PATH"]}" my_dll_dir_path = File.expand_path("..", __FILE__) puts "my_dll_dir_path = #{my_dll_dir_path}" RubyInstaller::Runtime.add_dll_directory(my_dll_dir_path) require "sfml/audio"
方法その2。Windows API の SetDllDirectory() を使ってDLLの検索パスを指定することもできるらしい。これも試してみた。
_02_require_sfml_audio2.rb
require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'kernel32.dll' include Fiddle::Win32Types extern 'int SetDllDirectory(LPCSTR)' end my_dll_dir_path = File.expand_path("..", __FILE__) WinAPI.SetDllDirectory(my_dll_dir_path) require "sfml/audio"
方法その3。sfml-audio-fiddle の audio.rb をカレントディレクトリにコピーして、dlload のあたりで絶対パスを指定するように修正して試してみたりもした。
_03_require_sfml_audio3.rb
require_relative "sfmlaudio"
_sfmlaudio.rb
しかし、どの方法でもエラーが出る…。
◎ CSFMLのバージョンも関係していたらしい。 :
Ruby 2.3.3 ではエラーが出なかったから、てっきり CSFML の .dll のバージョンは合っているのだろうと思い込んでいたけど、試しに色々変えてみたらバージョンによってエラーが出たり出なかったりすることに気づいた。
利用できるDLLのバージョンと、利用できないDLLのバージョンがあるっぽいな…。
ただ、前述の方法でDLL検索パスを変更しないと、どのみちエラーが出る…。
- CSFML 2.0 32bit (csfml-audio-2.dll, libsndfile-1.dll, openal32.dll) : エラーが出ない。
- CSFML 2.1 32bit (csfml-audio-2.dll, libsndfile-1.dll, openal32.dll) : エラーが出ない。
- CSFML 2.2 32bit (csfml-audio-2.dll, libsndfile-1.dll, openal32.dll) : エラーが出る。
- CSFML 2.5.1 32bit (csfml-audio-2.dll) : エラーが出る。
利用できるDLLのバージョンと、利用できないDLLのバージョンがあるっぽいな…。
ただ、前述の方法でDLL検索パスを変更しないと、どのみちエラーが出る…。
[ ツッコむ ]
以上です。