研究で音声認識とかが必要なので、ViaVoice SDKを眺めてみる。今までは、Java Speech APIを使っていたんだが、機能不足に困ることが多々あった(とは言っても、今現在はその程度で十分だったりするので、半分興味本位の面は拭えないが……)。
で、ViaVoice SDKを落としてきたのはいいのだが、私はVisual C++はさわったことすらなかったので途方に暮れていると、「Cygwinコンパイルすればいいじゃん」というネタが思いついてさらに興味本位な展開に。……というわけで、本日の日記はそのメモです。はい。
今回対象にしたプログラムは、ViaVoice SDKについてくる「smdict」というディクテーション用のサンプルプログラムである。場所は、${インストールディレクトリ}\ViaVoice SDK\Samples\SMAPI\dictation\smdictにある。
まず、サンプルに必要なincludeファイルとライブラリを適当なディレクトリに移動。今回は、/usr/local/include/viavoiceと/usr/local/lib/viavoiceにコピー。この時、リンカに自動認識してもらうために、Windows用の「*.lib」ファイルを以下のようにして「lib*.a」という名前を変更する。


$ for name in *.lib; do mv ${name} lib${name%.a}; done
某所では、ranlibを使えとあったが、別に使わなくともよいようだ。
と、これだけで用意は完了したので、次にコンパイル。それほど依存関係はなく、調べた結果以下のようにすればよいようだ。(本当は一行)

$ gcc -I/usr/include/sys -I/usr/local/include/viavoice
-L/usr/local/lib/viavoice smdict.c -lsmapi -lgdi32
ただし、ここでエラー発生。ひとつは、SmAddCallbackなどの引数の型が合わないというもの。もうひとつは、プログラムの最後に変なゴミがあるというもの。後者は本当に変なものがあるのでエディタでただ削除すればよいが、後者は結局根本的な解決はできず「(void *)」キャストでごまかした。
[追記]これは、あとでヘッダファイルを確認してみたとところsmcall.hの定義とサンプル中の関数の定義が違っていたのが原因だった。たぶんVisual C++ではこのチェックはしないのだろう。
これでコンパイルは可能となる。で、実行してみたのが以下のスクリーンショット。左がもともと付いてきたexeファイル。もう片方がcygwinコンパイルしたものである。

見ての通り、なんかおかしい。メニューバーがないのである。なんでかな〜とWindowsプログラム未経験の私は悩んだのだが、同じディレクトリにあるrcファイルにそれらしき記述がある。検索してみると、このrcファイルにアイコンとかメニューバーの内容が記述できるらしい。で、cygwinではwindresというプログラムで変換できるらしいので、とにかく実行してみる。


$ windres smdict.rc smdict.o
windres: smdict.rc:13: parse error
十三行目には以下のように書いてある。

MENUITEM "E&xit" IDM_EXIT
う〜む、わけがわからん。プリプロセッサ展開がまずいのかとか小一時間悩んだ末このページの以下の行の記述に気付く。

MENUITEM "文字列", id
あれっ? カンマがあるじゃん。で、書き換えてコンパイルしてみると見事にリソースファイルをオブジェクトファイルにできた。こんなしょーもないことで悩んでいたのかとかなりへこむ私。とりあえず解決したので、あとはこの結果をコンパイル時に付け加えるだけ。(本当は一行)

$ gcc -I/usr/include/sys -I/usr/local/include/viavoice
-L/usr/local/lib/viavoice smdict.o smdict.c -lsmapi -lgdi32
これでひとまず完成なのだが、これだとcygwin用DLLが必要となるのでWindowsネイティブプログラムになるまでがんばってみる。とりあえず、ここに書いてある通りに調べてみる。

$ objdump -p a.exe | grep "DLL Name"
DLL Name: cygwin1.dll
DLL Name: GDI32.dll
DLL Name: KERNEL32.dll
DLL Name: USER32.dll
DLL Name: SMAPI.dll
このcygwin1.dllを排除すればよい。これには「-mno-cygwin」をつければよいようだ。すると以下のように、cygwin1.dllの代わりにmsvcrt.dllにリンクされる。

$ objdump -p a.exe | grep "DLL Name"
DLL Name: msvcrt.dll
...
で、やっとこれで完了……かとおもいきや大問題が、普通にコンソールから実行する場合には問題ないのだが、ダブルクリックして実行するとコンソールが一緒に立ち上がる。これはCygwin FAQに-mwindowsオプションを付けろと書いてあったので簡単に解決した。
ここまでたどり着くのには結構時間がかかったが、一度覚えてしまえば別になんてことない。Cygwinって本当にすごいかも。高い金だしてVisual C++なんて買う必要ないじゃないかなんて思ったり。