原色奈良阪

LinuxのdialogコマンドをWindowsで使いたくなったので。

まあcygwinならいいかもしれないけどMinGWで出来てこそでしょ。

ちなみにdialogってのはCUI環境である程度グラフィカルなダイアログっぽい見た目を実現して、なんかのウィザードとかを作りやすくするコマンド。 ArchLinuxやSlackware、さらにFreeBSDのインストールスクリプト、カーネルの設定画面などでおなじみのやつです。

参考ページは以下とかのとおり。

問題

とりあえずdialogはncursesに依存しているのだが、ncursesのWindows対応はないそうで、それまで試行錯誤するのは手間過ぎる。

そこでWindowsでも使えるcurses系でPDCursesというのがあるらしいので、そっちに差し替えてやってみることにした。

下準備

故意のダウンロード。

MinGW
基本。
make
GNU make。今回はMinGWの類のmingw32-makeを使用した。
dialog
ソースがほしかったのでとりあえずman page末尾の作者名Thomas E. Dickeyを検索したら超有名だった。ncursesとかxtermとかlynxとか。
PDCurses
なんかpdc34dll*がいろいろあってちがいがわからんのだがとりあえずpdc34dllw.zipでうまくいった。

configureとmake

dialogはオーソドックスな./configure->make->make installの類でビルドするようにできている。

が、MinGWを手動導入したのでautoconfとかは入れておらずconfigureするのがめんどかったので、ここでひとつArchLinuxをたちあげてそっちでconfigureしたものをもってくることにした。

ncursesが入っている環境でオプションつけずにconfigureしてできたファイルのうちmakefileとdlg_config.hをもってきた。なお当然ながらArchLinux上でmakeは普通に通った。

で、試行錯誤しながらその2つをいじってmakemakeしていくと通ったので、修正手順と現物をとりあえず公開することにする。

修正手順

まずとりあえずconfigureした素のmakefileとdlg_config.hは以下。

このまんまmakeするとまず./dialog.h:59:21: fatal error: ncurses.h: No such file or directoryと出る。 dialog.hを確認するとifdefでncurses.hかcurses.hか他かを選ぶ仕様になっているので#define HAVE_NCURSES_H 1とかをdlg_config.hから削除しPDCursesのcurses.hを選ぶようにする。

今度は当然curses.hがないといわれるのでPDCursesのファイル一式curses.h, panel.h, pdcurses.dll, pdcurses.libをコピって来る (makefileのCPPFLAGS-IC:\path\pdcursesLDFLAGS-LC:\path\pdcursesを追加でもよい。あとreimpいらなかった。)。

同様にunctrl.hがないといわれるので#define HAVE_UNCTRL_H 1を削除。

今度は

gcc -Wl,-rpath,/lib -L/lib version.o -o VERSION
c:/usr/mingw/bin/../lib/gcc/mingw32/4.7.2/../../../libmingw32.a(main.o):main.c:(.text.startup+0xa7): undefined reference to `WinMain@16'

と出て、色々試した結果

dialog$o \
$(OBJECTS) : $(srcdir)/dialog.h $(srcdir)/dlg_keys.h dlg_config.h VERSION

のVERSIONを削除すれば通ると判明。VERSIONはなんかVERSIONが書いてあるファイルだったのだがどんな影響が出たかは謎。VERSIONでるしな普通に。

これで結構通るがしばらくしてprgbox.c:105:38: error: 'SIGCHLD' undeclared (first use in this function)。LinuxのシグナルだがWindowsになさげなのかとりあえずdlg_config.hに#define SIGCHLD 1

さらにui_getc.c:43:22: fatal error: sys/wait.h: No such file or directory(Windowsにないシステム系ヘッダ)でdlg_config.hから#define HAVE_SYS_WAIT_H 1を削除するも

gcc -g -O2 -I. -I. -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR=\"/usr/local/share/locale\" -c ui_getc.c
ui_getc.c: In function 'check_inputs':
ui_getc.c:181:5: error: unknown type name 'fd_set'
ui_getc.c:204:11: error: 'fd_set' undeclared (first use in this function)
ui_getc.c:204:11: note: each undeclared identifier is reported only once for each function it appears in
ui_getc.c:204:19: error: expected expression before ')' token
ui_getc.c: In function 'valid_file':
ui_getc.c:297:16: error: 'F_GETFL' undeclared (first use in this function)
ui_getc.c: In function 'dlg_killall_bg':
ui_getc.c:616:18: error: 'SIGHUP' undeclared (first use in this function)
ui_getc.c:618:21: error: 'SIGQUIT' undeclared (first use in this function)
mingw32-make.exe: *** [ui_getc.o] Error 1
fd_setというのがソケット関連であると知り#include <winsock2.h>、SIGHUP、SIGQUITを定義。F_GETFLはfcntl関連のものと知っていろいろ調べた結果#define fcntl(x,y,z) 0でなんだか沈静化。

そしてついにリンクエラー

gcc -o dialog dialog.o -L. -ldialog -Wl,-rpath,/lib -L/lib -lncurses -lm
c:/usr/mingw/bin/../lib/gcc/mingw32/4.7.2/../../../../mingw32/bin/ld.exe: cannot find -lncurses
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe: *** [dialog] Error 1

とくるのでmakefileのLIBSLIBS = -lpdcurses -lm -lwsock32に。

するとまあ色々と

gcc -o dialog dialog.o -L. -ldialog -Wl,-rpath,/lib -L/lib -lpdcurses -lm -lwsock32
./libdialog.a(util.o): In function `open_terminal':
O:\_dialog\dialog-1.2-20121230/util.c:261: undefined reference to `ttyname'
O:\_dialog\dialog-1.2-20121230/util.c:263: undefined reference to `ttyname'
O:\_dialog\dialog-1.2-20121230/util.c:265: undefined reference to `ttyname'
./libdialog.a(prgbox.o): In function `dlg_popen':
O:\_dialog\dialog-1.2-20121230/prgbox.c:43: undefined reference to `pipe'
O:\_dialog\dialog-1.2-20121230/prgbox.c:44: undefined reference to `fork'
./libdialog.a(ui_getc.o): In function `dlg_killall_bg':
O:\_dialog\dialog-1.2-20121230/ui_getc.c:582: undefined reference to `fork'
O:\_dialog\dialog-1.2-20121230/ui_getc.c:585: undefined reference to `fork'
O:\_dialog\dialog-1.2-20121230/ui_getc.c:598: undefined reference to `waitpid'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe: *** [dialog] Error 1

出るのでdlg_config.hに

#define fork() 0
#define pipe(x) 0
#define ttyname(x) 1

と心無いことを書くと無事リンク成功し、

$ dialog
cdialog (ComeOn Dialog!) version 1.2-20121230
Copyright 2000-2011,2012 Thomas E. Dickey
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

* Display dialog boxes from shell scripts *

Usage: dialog <options> { --and-widget <options> }
where options are "common" options, followed by "box" options

...

と念願の表示が拝める。

修正版

で、それが出来上がったものがこちら。

結果とTODO

で、意気揚々とdialog.exe --backtitle backtitle --title title --msgbox "msgbox 5 73" 5 73した結果がこちら。

dialog --msgbox

ん?titleの位置おかしくね?ていうかはみでてね?

これ、LinuxとWindowsの罫線幅に起因する問題で、Linuxでは罫線が半角なのがWindowsでは全角罫線を使ってしまっているゆえに罫線の連続するところがはみ出てしまっているという構図。

不細工でなかなかちょっとアレなのだが、この問題を除いてもとのdialogと機能に差異はない(make testがないのでてきとうな判断だが)。カーソルもちゃんと動くし取得結果はSTDERRに出るし。

まあ、一応動いて互換性は保てるのでひとまずこれで満足し、記事を終わりたいと思う。気まぐれにこれの解決ができたらまた更新したい。また誰かが解決してくれるのも待ってる。

以上

なお一応ライセンスを設定しておいたほうがいいらしいのでdialogがLGPLだしここにあるコードはLGPLで使ってください。

Edited by Narazaka 2013/02/06