2014/12/28(日) [n年前の日記]
#1 [dxruby][ruby] ayame.soのビルドでまだハマり中
ハマり中。
◎ midi.hのエラーの件。 :
midi.h でエラーが出る理由は分かった。MinGW の gcc/g++ はソースファイルが UTF8 であることを前提にして動作してるけど、ソースファイルの文字コードがSJISだった。そこが原因。
てなわけで、ソースファイル側とコンパイラ側の文字コードが合ってなくて、日本語コメントが悪さしちゃって、意味不明なエラーが出る時もあるよ、ってことで。勉強になりました。
ググったところ、MinGW でSJISのソースファイルをコンパイルするときは、
_MinGW gccでSJIS文字を扱う方法 - はけの徒然日記
_MinGW (gcc) で ShiftJis で書かれたソースプログラムをコンパイル可能にする方法 - seclan のほえほえルーム
そして、 _README.EXT.ja - Documentation for Ruby 2.1.0 によると、extconf 内で C/C++コンパイラにオプションを渡すには、
今回は、extconf.rb の最初の方に、以下を追加した。よく分かってないけど、「<< 'hoge'」で、変数の中身に 'hoge' を「追加」するのだと思う。
これで midi.h がエラーを出さなくなった。
- midi.h の中の、変数や関数の記述位置を、単に上や下にずらしてみたら、エラーメッセージが変わってきて。「なんじゃこりゃあ!(松田優作風に)」と大困惑。
- その程度の変更で結果が変わるということは、コンパイラがソースコードをそもそも正しく読めてない可能性が。
- それってもしかすると日本語コメント部分にダメ文字でも含まれてんじゃねえの? そして、ソレ以降でグチャグチャになって読まれてんじゃねえの?
- つまり、ソースファイルの文字コードの問題かも。
- SJISファイルをUTF8で保存し直してみたら、そのファイルではエラーが出なくなった。
てなわけで、ソースファイル側とコンパイラ側の文字コードが合ってなくて、日本語コメントが悪さしちゃって、意味不明なエラーが出る時もあるよ、ってことで。勉強になりました。
ググったところ、MinGW でSJISのソースファイルをコンパイルするときは、
-finput-charset=CP932 -fexec-charset=CP932を gcc、g++ に与えればいいらしい。
_MinGW gccでSJIS文字を扱う方法 - はけの徒然日記
_MinGW (gcc) で ShiftJis で書かれたソースプログラムをコンパイル可能にする方法 - seclan のほえほえルーム
そして、 _README.EXT.ja - Documentation for Ruby 2.1.0 によると、extconf 内で C/C++コンパイラにオプションを渡すには、
$CFLAGS: コンパイル時に追加的に指定するフラグ(-Oなど) $CPPFLAGS: プリプロセッサに追加的に指定するフラグ(-Iや-Dなど) $LDFLAGS: リンク時に追加的に指定するフラグ(-Lなど) $objs: リンクされるオブジェクトファイル名のリストを使えばいい模様。
今回は、extconf.rb の最初の方に、以下を追加した。よく分かってないけど、「<< 'hoge'」で、変数の中身に 'hoge' を「追加」するのだと思う。
$CPPFLAGS << ' -finput-charset=CP932 -fexec-charset=CP932 'g++ に、「文字コードはコレね」と伝えているのだと思う。
これで midi.h がエラーを出さなくなった。
◎ リンカがエラーを出す件。 :
しかし、まだまだエラーが。
おそらく timeGetTime なる関数がどこかにあるはず…と思って grep してみたけど、呼び出しはされてるのに、どこでも定義されてない。どゆこと?
ayame.so ではなく、Ayame.dll のソースファイル群に対しても grep してみたけど、そっちも timeGetTime という文字列は無い。どゆこと?
ググってみたら、 _timeGetTime 関数 というページに遭遇。ああ、なるほど、これが Windows のマルチメディアタイマー ―― 1msの精度で時間測定できるぜ、ってやつでしたか…。
_Linux日記: MinGWでx264、ffmpegをビルド によると…。
_Linker not linking timeGetTime (solved) - For Beginners - GameDev.net によれば、-lwinmm をつけろ、とか、-libwinmm.a をつけろ、とか書いてある。
extconf.rb の最初のほうに、以下を追加してみた。
通った! ayame.so が一応できてるっぽい。
> ruby extconf.rb checking for main() in -ldsound... yes checking for main() in -lole32... yes creating Makefile
> make generating ayame-i386-mingw32.def compiling ayame_ruby.cpp ayame_ruby.cpp: In function 'void Init_ayame()': ayame_ruby.cpp:422:73: warning: deprecated conversion from string constant to 'TCHAR* {aka char*}' [-Wwrite-strings] compiling midi.cpp compiling VoiceElement.cpp compiling VoiceElementAyame.cpp linking shared-object ayame.so ayame_ruby.o:ayame_ruby.cpp:(.text+0xe75): undefined reference to `_imp__timeGetTime@0' ayame_ruby.o:ayame_ruby.cpp:(.text+0xecb): undefined reference to `_imp__timeBeginPeriod@4' c:/ruby/ruby_devkit/devkit200/mingw/bin/../lib/gcc/i686-w64-mingw32/4.7.2/../../../../i686-w64-mingw32/bin/ld.exe: ayame_ruby.o: bad reloc address 0xe in section `.text$_ZN13CVoiceElementD2Ev[__ZN13CVoiceElementD2Ev]' collect2.exe: error: ld returned 1 exit status make: *** [ayame.so] Error 1「ayame_ruby.o で _imp__timeGetTime@0 や _imp__timeBeginPeriod@4 は定義されてねえよ」と怒られてるのだろうか…?
おそらく timeGetTime なる関数がどこかにあるはず…と思って grep してみたけど、呼び出しはされてるのに、どこでも定義されてない。どゆこと?
ayame.so ではなく、Ayame.dll のソースファイル群に対しても grep してみたけど、そっちも timeGetTime という文字列は無い。どゆこと?
ググってみたら、 _timeGetTime 関数 というページに遭遇。ああ、なるほど、これが Windows のマルチメディアタイマー ―― 1msの精度で時間測定できるぜ、ってやつでしたか…。
_Linux日記: MinGWでx264、ffmpegをビルド によると…。
configureのログを眺めていたらlibrtmpのチェックのところでundefined reference 'timeGetTime@0'とか出ていて、この辺の関数はwinmmにあるもののようです。winmm なるものが timeGetTime を持ってるらしい。
_Linker not linking timeGetTime (solved) - For Beginners - GameDev.net によれば、-lwinmm をつけろ、とか、-libwinmm.a をつけろ、とか書いてある。
extconf.rb の最初のほうに、以下を追加してみた。
$LDFLAGS << ' -lwinmm 'リンカオプションとして -lwinmm を渡す、ということだと思うけど。
> ruby extconf.rb checking for main() in -ldsound... yes checking for main() in -lole32... yes creating Makefile > make generating ayame-i386-mingw32.def compiling ayame_ruby.cpp ayame_ruby.cpp: In function 'void Init_ayame()': ayame_ruby.cpp:422:73: warning: deprecated conversion from string constant to 'TCHAR* {aka char*}' [-Wwrite-strings] compiling midi.cpp compiling VoiceElement.cpp compiling VoiceElementAyame.cpp linking shared-object ayame.so
通った! ayame.so が一応できてるっぽい。
◎ そして、動かない。 :
できあがった ayame.so をオリジナル版の ayame.so の代わりに置いてから、Ayame/Ruby に添付されてる sample1.rb を実行。
オリジナル版と比べるとファイルサイズが半分ほど。何かがごっそり抜けてるのかな。
ふと。devkitvars.bat を実行した状態で ruby sample1.rb を実行すると、上記の「モジュール見つからねえよ」エラーが出ずにDXRubyのウインドウが開くことに気付いた。もっとも、音は全く鳴らないけれど。…もしかして、静的リンクだかスタティックリンクだかが関係してるのかな?
_久しぶりに MinGW をインストールし直したら - メモ@wantora に、静的リンクにするオプションがあった。extconf.rb を修正。
ruby extconf.rb を実行して Makefile を作り直してから、make clean と make を実行。ayame.so ができた。この版なら、「モジュールがねえよ」とは言われずに済む。相変わらず音は鳴らないけれど。
> pik 200 Select which Ruby you want: 1. 200: ruby 2.0.0p451 (2014-02-24) [i386-mingw32] 2. 200: ruby 2.0.0p353 (2013-11-22) [i386-mswin32_100] ? 1 > ruby sample1.rb sample1.rb:3:in `require_relative': 126: 指定されたモジュールが見つかりません。 - C:/home/pr g/ruby/test_make_so/ayame/ayame.so (LoadError) from sample1.rb:3:in `<main>'ダメだあ。
オリジナル版と比べるとファイルサイズが半分ほど。何かがごっそり抜けてるのかな。
ふと。devkitvars.bat を実行した状態で ruby sample1.rb を実行すると、上記の「モジュール見つからねえよ」エラーが出ずにDXRubyのウインドウが開くことに気付いた。もっとも、音は全く鳴らないけれど。…もしかして、静的リンクだかスタティックリンクだかが関係してるのかな?
_久しぶりに MinGW をインストールし直したら - メモ@wantora に、静的リンクにするオプションがあった。extconf.rb を修正。
$LDFLAGS << ' -static-libgcc -static-libstdc++ -lwinmm '
ruby extconf.rb を実行して Makefile を作り直してから、make clean と make を実行。ayame.so ができた。この版なら、「モジュールがねえよ」とは言われずに済む。相変わらず音は鳴らないけれど。
◎ Visual C++じゃないと無理なのかな。 :
DXRuby作者様が、
ayame.so って Ayame.dll を呼び出すことしかしない役だろうから、Ayame.dll はビルドできないけど ayame.so だけなら MinGW64 でビルドできるのかなーと素人考えで思って試してたけど、やっぱりコレ、うすうす思ってたけど Visual C++ でビルドしないとダメなのか…。Ayame.dll が VS C++ 2008 でビルドされてるらしいから、ayame.so も VS C++ 2008 で…ということですかね…。
さておき。
サンプル単位で指定云々は、どうせ「イントロ→ループ」を指定したいぐらいに作り込みたい人は、ループ開始と終わりの波形の辻褄を合わせないとノイズになるから波形編集ソフトとにらめっこするはずで、だったらそのままサンプル単位指定でも苦にはならないはず、と個人的には思ったり。
mingw64では結局Ayameのlibが読めないのでそのままではビルドできないと言及してくれて。
ayame.so って Ayame.dll を呼び出すことしかしない役だろうから、Ayame.dll はビルドできないけど ayame.so だけなら MinGW64 でビルドできるのかなーと素人考えで思って試してたけど、やっぱりコレ、うすうす思ってたけど Visual C++ でビルドしないとダメなのか…。Ayame.dll が VS C++ 2008 でビルドされてるらしいから、ayame.so も VS C++ 2008 で…ということですかね…。
さておき。
Ayameで最後まで再生した場合に戻る位置を指定することはできたようだ。インターフェイスをちょっと考えないとあかんけども。
しかし単位がよくわからんな。サンプル単位かしらん?InSampleって書いてあるし。わかる人にはわかるって感じか。と仰られているので、きっとそのうちループ開始位置の指定ができる ayame.so が公開されるものと期待。これで、 _DXRuby Advent Calendar 2014 ゲーム・プログラミングとサウンドについて で挙げられてる項目の一つは実装済み扱いになるはず…。
サンプル単位で指定云々は、どうせ「イントロ→ループ」を指定したいぐらいに作り込みたい人は、ループ開始と終わりの波形の辻褄を合わせないとノイズになるから波形編集ソフトとにらめっこするはずで、だったらそのままサンプル単位指定でも苦にはならないはず、と個人的には思ったり。
◎ 2014/12/29追記。 :
この記事をアップした直後、昨日の日記へのコメントで、解決策のアレコレを教えていただけてることに気付いたり。ありがたや! 感謝なのです。もうちょっと試してみよう…。
[ ツッコむ ]
以上、1 日分です。