D on Linux でSocketを使う時の注意

何やらInternetAddressクラスの初期化部分で抜けてる所があるらしい。

import std.stdio;
import std.stream;
import std.socket;
import std.socketstream;

int main( string[] args ) {

  auto l_SS = new SocketStream( new TcpSocket( new InternetAddress("twitter.com", 80) ) );
  l_SS.writeString( "hoge" ); // WriteException:unable to write to stream
  ...
  return 0;
}

こんな例外を吐く。


↓解決方法

import std.stdio;
import std.stream;
import std.socket;
import std.socketstream;

class MyInternetAddress: InternetAddress
{
        this(string addr, ushort port)
        {
                sin.sin_family = AddressFamily.INET;
                super(addr, port);
        }

        this(uint addr, ushort port)
        {
                sin.sin_family = AddressFamily.INET;
                super(addr, port);
        }

        this(ushort port)
        {
                sin.sin_family = AddressFamily.INET;
                super(port);
        }
}

int main( string[] args ) {

  auto l_SS = new SocketStream( new TcpSocket( new MyInternetAddress("twitter.com", 80) ) );
  l_SS.writeString( "hoge" ); // OK!
  ...
  return 0;
}

InternetAddressクラスを継承したMyクラスを作り、
その初期化部分で sin.sin_family = AddressFamily.INET; を入れてやれば良い。


詳細はこちら。
http://d.puremagic.com/issues/show_bug.cgi?id=2835

Socketアドオンをビルドする

どうにか動くようになったっぽいのでメモメモ。


・Socket
 まずここからlibevent-1.4.9を落とす。
 解凍して、出来たフォルダ(libevent-1.4.9-stable)をMinGWのHomedirにコピー。
 以下複数ファイルを修正。

[~/stevedekorte-io/addons/Socket/source/IoSocket.c]
Line:422 -if (errorNumber == ECONNRESET) IoSocket_close(self, locals, m);
         +//if (errorNumber == ECONNRESET) IoSocket_close(self, locals, m);
Line:423 +if (errorNumber == WSAECONNRESET) IoSocket_close(self, locals, m);
[~/stevedekorte-io/addons/Socket/source/IPAddress.h]
Line:30 -typedef SSIZE_T ssize_t;
        +//typedef SSIZE_T ssize_t;
[~/stevedekorte-io/addons/Socket/source/Socket.h]
Line:30 -typedef SSIZE_T ssize_t;
        +//typedef SSIZE_T ssize_t;
[~/libevent-1.4.9-stable/evutil.c]
Line:73 +
Line:74 +WSADATA wsaData;
Line:75 +WSAStartup(2, &wsaData);
Line:76 +
Line:77 =int listener = -1;
Line:78 =int connector = -1;
...
...

Line:143 +WSACleanup();
Line:144 +
Line:145 =return 0;

Line:160 +WSACleanup();
Line:161 =return -1;
$ cd ~/libevent-1.4.9-stable
$ configure CC=gcc --prefix=c:/msys/1.0/mingw
$ make
$ make install
$ cd ../stevedekorte-io
$ make CC=gcc Socket

Socketアドオンのmakeで警告がいくつか出るけど、気にしないで大丈夫だと思う。
とりあえず
Io> aString := URL with("http://www.yahoo.com/") fetch
でドバーっとyahooトップのソースが表示されればオーケーでしょう。


あぁ、長かった。
これでまたio熱が強くなったぞ。


[2009/03/23 追記]
結局何が原因だったかを明記してなかった。
原因はwinsockの初期化をしてなかったので、socket生成が100%失敗していた。
なので上記部分で初期化処理・終了処理を書き加えた。
しかし呼び出し毎にwinsockを初期化してるのってどうなんだろう・・・?



書いてて気になったので調べたら、/addons/Socket/source/Socket.cに
WSAStartup〜WSACleanupしてる所があった。
こりゃまずいかもしれん。

ioLanguageのAddonをビルドする。

こっちも梃子摺ったので、やった事メモ。
今回はSGMLとZlibをビルドしてみる。


SGML
 こっちはコマンドだけで書けたからスッキリ。

$ cd ~/stevedekorte-io/addons/SGML/source/libsgml-1.1.4
$ configure
$ make
$ mkdir /mingw/include/sgml
$ cp -v ./include/* /mingw/include/sgml/.
$ cp -v ./libsgml.a /mingw/lib/.
$ cd ../../
$ mv build.io build.io.back
$ cat > build.io
AddonBuilder clone do(
    dependsOnLib("sgml")
    dependsOnHeader("sgml/libsgml.h")
)
^D

・Zlib
 まずここからzlibを落とし、解凍する。

[include/zconf.h]
Line:289 -#  include     /* for SEEK_* and off_t */
         +//#  include     /* for SEEK_* and off_t */
Line:290 +"  include 

 include/*.h を /msys/1.0/mingw/include/ 以下にコピー。
 lib/libz.a を /msys/1.0/mingw/lib/ 以下にコピー。
 tar.bz2と出来たフォルダ(bin・include・lib・share)は消してOK。




Vista+MinGWでやったら、途中からsh.exeがstackdump吐きまくりになった。
参った。


Zlibの部分書いているときに、「$ rm -rv ~bin 」ってやって一回Mingw環境を殺した。
~ と binの間の / が抜けていたせいだ、出来るならもうrmコマンドは封印しようと思った。
皆さんも気をつけましょう(汗

ioLanguageのgit最新版を、MinGWでビルドする。

前回(http://d.hatena.ne.jp/ottu/20090205)の内容からまた少し変わってるっぽい。
MinGW構築までは同じだけど、ioのgitは結構頻繁に更新されているらしく
毎度ちょっとずつ修正箇所が変わる。
詳しく書くの面倒になってきたから、メモ程度で。


/msys/1.0/mingw/include/math.h

Line:534 -extern double __cdecl log2 (double);
         +//extern double __cdecl log2 (double);

~/stevedekorte-io/libs/iovm/source/IoFile.c

Line:32 -#include 
         +//#include 

Line:35  -#include  /* ok, this isn't ANSI */
         +//#include  /* ok, this isn't ANSI */
Line:36  +#include 

Line:239 -  IONUMBER(WEXITSTATUS(exitStatus)));
         +  IONUMBER( ( (exitStatus >> 8) & 0xff) ) );

~/stevedekorte-io/libs/iovm/source/IoDirectory.c

Line:23 -#include  /* ok, this isn't ANSI */
        +//#include  /* ok, this isn't ANSI */
Line:24 +#include 

~/stevedekorte-io/build/AddonBuilder.io

Line:48 -if(platform == "mingw", searchPrefixes append("/mingw"))
        +if//(platform == "mingw", searchPrefixes append("/mingw"))
Line:49 +if(platform == "mingw", searchPrefixes append("/msys/1.0/mingw"))


これでコンパイル通った。
MinGWには sys/wait.h が無いので、そこの部分を直接修正してみた。
多分これで動くはずだが・・・自信は無いです:-p


ちなみにこの話題、ここでも出てた。
やはり同じ悩みを持つ人がいたか。


これで勝つる?


【2009/03/19 修正】
追記途中で一部の文章が消えてしまったので、後半内容が変わってます・・・。

続・wxDを使う

前にも同じ話題を書いた訳ですが、(http://d.hatena.ne.jp/ottu/20081102/1225651704)
また色々と変わった事があったので書き直し。


今回もインストールするフォルダとかは僕の環境で書いてしまうので、
参考にされる方は各々の環境に合わせて下さい。




D1.040/D2.025 からdmdフォルダの階層が変わったりしてるので、dmdのインストールから。


D公式(http://www.digitalmars.com/d/index.html)から、
最新dmd.zip と dmc.zip を取ってきて、適当なフォルダに解凍。
ex.) C:\Installed_Programs\dmd\D1\dmd
   C:\Installed_Programs\dmd\D1\dm


wxD公式(http://wxd.sourceforge.net/)から最新版(現行はwxd-014)、
wxWidgets公式(http://www.wxwidgets.org/)から対応版(今回はwxWidgets-2.8.9)、
をそれぞれ取ってきて、適当なフォルダに解凍。
ex.) C:\Installed_Programs\dmd\D1\wxd
   C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9


C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\build\msw に以下のバッチを作り、実行。

[build.bat]
SET PATH=C:\Installed_Programs\dmd\D1\dmd\windows\bin;C:\Installed_Programs\dmd\D1dm\bin;%PATH%
make -f makefile.dmc
pause


C:\Installed_Programs\dmd\D1\wxd に以下のバッチを作り、実行。

[build.bat]
SET PATH=C:\Installed_Programs\dmd\D1\dmd\windows\bin;C:\Installed_Programs\dmd\D1dm\bin;%PATH%
SET WXDIR=C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9
make
pause


C:\Installed_Programs\dmd\D1\wxd/Samples/Hello
に以下のバッチとリソースファイルを作り、バッチを実行。

[build.bat]
SET PATH=C:\Installed_Programs\dmd\D1\dmd\windows\bin;C:\Installed_Programs\dmd\D1dm\bin;%PATH%
SET WXDIR=C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9


dmd Hello.d ^
    @Libs.rsc


del *.obj
del *.map


pause
[Libs.rsc]
-version=wx28
-version=__WXMSW__
-version=ANSI
-IC:\Installed_Programs\dmd\D1\wxd
C:\Installed_Programs\dmd\D1\wxd\wxd.lib
C:\Installed_Programs\dmd\D1\wxd\wxc.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxbase28d.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxbase28d_xml.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxbase28d_net.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_core.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_adv.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_html.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_xrc.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_aui.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_media.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_qa.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxmsw28d_richtext.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxtiffd.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxjpegd.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxpngd.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxzlibd.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxregexd.lib
C:\Installed_Programs\dmd\D1\wxWidgets-2.8.9\lib\dmc_lib\wxexpatd.lib
kernel32.lib
user32.lib
gdi32.lib
comdlg32.lib
winspool.lib
winmm.lib
shell32.lib
comctl32.lib
ole32.lib
oleaut32.lib
uuid.lib
rpcrt4.lib
advapi32.lib
wsock32.lib
odbc32.lib
-L/EXETYPE:NT
-L/SU:WINDOWS:4.0

出来たexeを実行してみる。
動いたら喜ぶ。やったー!



前回のエントリでは Libs.rsc 辺りが全然分かっていなかったのでうやむやになっている所があったが、
今回最後に作ったバッチとリソースファイルを再利用すれば、そこら辺の問題も解決。


ちなみにwxDのサンプル、いくつか動かないのがあった。
原因はよくわからん。


gtkDはマルチスレッドがよく分からなかったので、wxDの働きには期待している。

Cで書かれたDLLをDから使えるようにする

ちょっと分かってきた気がするので、一応メモ。
(ちなみにC++で書かれたDLLについては分かりません!Cで書かれたもの専用です。)



1: まず対象のDLLと、それを使う為にincludeするヘッダファイル(.h)を準備する。
    (例として hoge.dll、hoge.h とする。)


2: Dの公式から
    ・implib(Basic Utilities) http://www.digitalmars.com/download/freecompiler.html
    ・htod(1.0/2.0) http://www.digitalmars.com/d/1.0/htod.html
             http://www.digitalmars.com/d/2.0/htod.html (同じものかも?)
   を拾ってくる。


3: 2で拾ってきたものを解凍して、
   Dの開発環境( /dm、/dmd )に階層が合うように上書き保存。


4: htodを使って、1のヘッダを変換する。
    ex)>htod hoge.h
   するとヘッダを同じフォルダ内に、同名の.dファイルができる。(この例だとhoge.d)


5: implibを使って、DLLから.libを作る。
    ex)>implib /system hoge.lib hoge.dll
   /systemは呪文。忘れると.lib自体は作れても使用できない。
   hoge.lib は出力名。 DLLと同じ名前 + .lib にしておけば間違いない。
   hoge.dll は1で準備したDLL。 


6: 1のDLLを使ってるサンプルコードなどを何処かから調達して、Dで書き直す。
    (ポインタ部分を直したり、includeをimportにしたり、etc...)


7: 6で書いたコード(仮にmain.dとする)と、
   1で拾ってきたhoge.dll、
   4で作ったhoge.d、
   5で作ったhoge.lib
   をひとつのフォルダに纏めて、ビルドする。
    ex)dmd main.d hoge.h hoge.lib


8: ビルドがこけたら修正して再度ビルド。
   通るまで繰り返す。
   .exeが出来たら実行してみて、動作を確認する。




以上くらいでしょうか。


4のhtodは結構細かい所まで面倒を見てくれる(ヘッダ内のマクロ展開等)ので、
手作業の修正はほんの細かい部分だけで大丈夫では無いかと思われます。


5の/systemは、僕自身が忘れて酷い目を見たので・・・忘れないように!



一応この手順で変換したexpatは使えている(まだバグあると思うけど)ので、
CのDLL使いたいけど、方法が分からない!という方は是非やってみてください。
意外と簡単です。


もし間違い等ございましたら、コメントでも何でも良いので
ご連絡頂けると助かります。

MinGW用にGLUTをコンパイル。

http://vision.kuee.kyoto-u.ac.jp/~nob/doc/opengl/opengl.html
こちらのサイト様を参考にさせて頂きながらコンパイルを進めるのだが、
僕の環境では
 sal.h
 vadefs.h
 crtdefs.h
 crtdbg.h
の4つが見つからないと言われたので
VisualStudioの include から引っ張ってきて
"C:\msys\1.0\mingw\include" へコピーした。


で、makeが通ると glut-3.7.6\lib\glut\libglut32.a が出来るので、
"C:\msys\1.0\mingw\lib" へコピー。


後は glut-3.7.6\include\GL\glut.h を
"C:\msys\1.0\mingw\include" へコピー。


これで ioLanguage のAddons用のGLUTが準備できた。
後は Image Addon を準備してやれば Windows + ioLanguage + OpenGL が出来るようになるはず。
夢に近づいた。