今流行りの DUB を使ってみた

公式 URL
http://code.dlang.org/
Github
https://github.com/rejectedsoftware/dub
日本語解説(とてもありがたい)
http://codelogy.org/archives/2013/09/%E3%80%90d%E8%A8%80%E8%AA%9E%E3%80%91d%E8%A8%80%E8%AA%9E%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%E3%80%81dub.html
http://qiita.com/yasei_no_otoko/items/2724eebab10f5cd0a02f


開発環境が Arch Linux なので、dmdとか dubとかは

$ yaourt -S dlang dub

で導入。
ちなみに community package なので yaourt は必須では無いです。


使用方法について。
上記の URL読めば大抵の使い方は分かる。

project $ dub init test
Successfully created an empty project in '/home/user/Programming/D/project/test'.
project $ cd test 
test $ ls
package.json  public  source  views
test $ cat package.json 
{
	"name": "test",
	"description": "An example project skeleton",
	"homepage": "http://example.org",
	"copyright": "Copyright © 2000, Your Name",
	"authors": [
		"Your Name"
	],
	"dependencies": {
	}
}
test $ ls source 
app.d
test $ cat source/app.d 
import std.stdio;

void main()
{ 
	writeln("Edit source/app.d to start your project.");
}


必要なライブラリ等の情報は package.json の dependenciesに書いて、
エントリポイントになる app.dにコードを書いていく感じ。


プロジェクトの中で

test $ dub

とか叩くとコンパイルから実行までやってくれる。

test $ dub build

とか叩くと package.json の "name" で実行ファイルが作成される。


dependenciesに列挙したライブラリは
/home/user/.dub/packages の中に保存されるので、
綺麗にしたかったら .dubとか丸々消してしまえば良いのかな。


で、dub使って気になったのが
野良 github repositoryとかは登録出来ないっぽい?という事。
http://code.dlang.org/ に登録すれば引っ張ってこれるのだろうけど、
其処まででも無いかなぁと思ったので
ローカルにある外部ライブラリなり外部ソースコードを一緒にコンパイルする方法調べた。


結論としては、package.json
"importPaths":[ path, ... ]
"sourceFiles":[ file, ... ]
"sourcePaths":[ path, ... ]
辺りの Key Value Pair を登録しといてやるとよしなにやってくれるっぽい。

test $ ls ../../mylib/adjustxml 
README.md  adjustxml.d

こんなライブラリがあったとする。


"importPaths" に関して

  • 列挙した path に -Iを付けてコンパイラに渡してくれる。
test $ cat package.json
{
    ...
    "importPaths": [
        "../../mylib/adjustxml"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -I../../mylib/adjustxml -Jviews source/app.d
Linking...
dmd -oftest temp.o -g


"sourceFiles" に関して

test $ cat package.json
{
    ...
    "sourceFiles": [
        "../../mylib/adjustxml/adjustxml.d"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -Isource -Jviews source/app.d ../../mylib/adjustxml/adjustxml.d
Linking...
dmd -oftest temp.o -g


"sourcePaths" に関して

  • 列挙した path に含まれている *.d を全てコンパイラに渡してくれる。
  • 気をつけなきゃいけない点?としては、sourcePaths使うと project/source を読みに行ってくれなくなるので、明示的に "source" ディレクトリを書いてやらねばならない。
test $ cat package.json
{
    ...
    "sourcePaths": [
        "../../mylib/adjustxml"
    ]
}
test $ dub build --verbose
... 省略 ...
Compiling...
dmd -c -oftemp.o -debug -g -wi -version=Have_test -Isource -Jviews source/app.d ../../mylib/adjustxml/adjustxml.d
Linking...
dmd -oftest temp.o -g


実はここらへん、配布されてるパッケージの package.json眺めると簡単に分かる。


はてな記法全然分からないから凄く読みづらい…
取り敢えず自分用メモとして残しておく感じで。


これから DUBが D言語の標準 package managerになっていくという流れっぽいので、
今のうちから慣れておくと後々ラクできるかも?

Scala勉強中

D言語で書いた Brainf*ckの処理系をそのまま Scalaで再実装。
両方もっと面白く書けるとは思うのだけど、それはそれ今後の課題と致します。(逃

import std.stdio;
import std.string : indexOf;
import std.algorithm;
import std.conv;
import std.range;
import std.array;

struct Source
{
    string code = "";
    uint   position = 0;
    uint[] jmps;

    char get()   { return code[ position++ ]; }
    bool empty() { return code.length == position; }
    void push()  { jmps ~= position; }
    void jamp()  { position = jmps[$-1]; }
    void pop()   { jmps = jmps[0..$-1]; }
}

unittest
{
    Source src = Source( "+-[><].," );
    assert( src.get == '+' );
    assert( src.get == '-' );
    assert( src.get == '[' );
    src.push;
    assert( src.position == 3 );
    assert( src.jmps == [3] );
    assert( src.get == '>' );
    assert( src.get == '<' );
    assert( src.position == 5 );
    assert( src.get == ']' );
    src.jamp();
    assert( src.position == 3 );
    assert( src.jmps == [3] );
    assert( src.get == '>' );
    assert( src.get == '<' );
    assert( src.position == 5 );
    src.pop;
    assert( src.jmps == [] );

}

struct Record
{
    uint[] tape = [0];
    uint   position = 0;

    void inc() { tape[ position ]++; }
    void dec() { if(tape[position]==0) throw new Exception("おこだよ!"); tape[position]--; }

    void next() { position++; if(tape.length <= position) tape ~= 0; }
    void prev() { if(position==0) throw new Exception("ダメなの!"); position--; }

    uint current() { return tape[ position ]; }
}

string exec( Source src, Record rec )
{
    string result = "";
    while( !src.empty )
    {
        char c = src.get;
        switch( c )
        //switch( src.get )
        {
            case '+' : { rec.inc; } break;
            case '-' : { rec.dec; } break;
            case '>' : { rec.next; } break;
            case '<' : { rec.prev; } break;
            case '[' : { src.push; } break;
            case ']' : { rec.current == 0 ? src.pop : src.jamp; } break;
            case '.' : { result ~= rec.current.to!char; } break;
            default : {} break;
        }        
    }
    return result;
}

unittest
{
    static Source src = Source( "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+." );
    static Record rec = Record();
    assert( exec( src, rec ) == "Hello, world!" );

    assert( 
        Source( ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+." ).exec( Record() )
        ==
        "Hello World!"
    );

    assert(
        Source( ">+++[>+++[<<++++++++>>-]<-]<.++>+++[>+++[<<+++>>-]<-]<.+++++++..+++.--->++[>++[>++[>++[>++[<<<<<-->>>>>-]<-]<-]<-]<-]<.+>+++[<---->-]<." ).exec( Record() )
        ==
        "Hello,!"
    );
}

void main( string[] args )
{
    Source( args[1] ).exec( Record() ).writeln;
    return;
}
import java.lang.String
import scala.collection.mutable._

class Source( code: String ) {
  var position = 0;
  var jmps:Stack[Int] = Stack()

  def get:Char      = { val result = code( position ); position += 1; result }
  def empty:Boolean = { code.length == position }
  def push          = { jmps = jmps.push( position ) }
  def jamp          = { position = jmps.last }
  def pop           = { jmps.pop }
}

class Record() {
  var position = 0
  var tape:ListBuffer[Int] = ListBuffer(0)

  def inc  = { tape( position ) += 1 }
  def dec  = { tape( position ) -= 1 }
  def next = { position += 1; if( tape.length <= position ) tape += 0 }
  def prev = { position -= 1 }

  def current:Int = { tape( position ) }
}

object bf2 {

    def exec( src: Source, rec: Record ): String = {
      var result = ""
      while( !src.empty ) {
        src.get match {
          case '+' => rec.inc
          case '-' => rec.dec
          case '>' => rec.next
          case '<' => rec.prev
          case '[' => src.push
          case ']' => if( rec.current == 0 ) src.pop else src.jamp
          case '.' => result += rec.current.toChar
          case _ => println("not match")
        }
      }
      result
    }

  def main( args: Array[ String ] ): Unit = {
    val src = new Source("+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.")
    val rec = new Record
    println( exec( src, rec ) )
  }
}

関数呼び出しのコストを見てみる

気になったので調べてみたついでに、メモしておく。

main.d

import std.string, std.range, std.algorithm, std.conv, std.array, std.stdio;

alias double[16] Matrix;

Matrix func( Matrix m ) { return m; }
Matrix func_rc( ref const Matrix m ) { return m; }
auto ref func_ar( Matrix m ) { return m; }
auto ref func_ar_rc( ref const Matrix m ) { return m; }
auto func_l = ( Matrix m ) => m;
auto func_l_rc = ( ref const Matrix m ) => m;
Matrix func_i( in Matrix m ) { return m; }
auto ref func_ar_i( in Matrix m ) { return m; }
auto func_l_i = ( in Matrix m ) => m;

void main( string[] args )
{
	Matrix m = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ];
	
	foreach( i; 0..1000000 ) func(m);
	foreach( i; 0..1000000 ) func_rc(m);
	foreach( i; 0..1000000 ) func_ar(m);
	foreach( i; 0..1000000 ) func_ar_rc(m);
	foreach( i; 0..1000000 ) func_l(m);
	foreach( i; 0..1000000 ) func_l_rc(m);
	foreach( i; 0..1000000 ) func_i(m);
	foreach( i; 0..1000000 ) func_ar_i(m);
	foreach( i; 0..1000000 ) func_l_i(m);
	
	return;
}


なコードを -profile付けてコンパイル

dmd main.d -profile

そして実行して吐いた trace.logを見る。



以下結果。
一回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    12540677     7605232     7605232     _Dmain
11000000      690005      690005           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
11000000      687401      687401           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
11000000      673076      673076           0     double[16] main.func_i(const(double[16]))
11000000      670352      670352           0     const(double[16]) main.func_ar_i(const(double[16]))
11000000      644416      644416           0     pure nothrow @safe double[16] main.__lambda1(double[16])
11000000      569693      569693           0     double[16] main.func_rc(ref const(double[16]))
11000000      516156      516156           0     double[16] main.func(double[16])
11000000      439182      439182           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
1000000       45160       45160           0     double[16] main.func_ar(double[16])


二回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    13766704     8394815     8394815     _Dmain
12000000      749979      749979           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
12000000      746487      746487           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
12000000      726993      726993           0     const(double[16]) main.func_ar_i(const(double[16]))
12000000      722372      722372           0     double[16] main.func_i(const(double[16]))
12000000      692746      692746           0     pure nothrow @safe double[16] main.__lambda1(double[16])
12000000      614376      614376           0     double[16] main.func_rc(ref const(double[16]))
12000000      561719      561719           0     double[16] main.func(double[16])
12000000      467464      467464           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
2000000       89749       89749           0     double[16] main.func_ar(double[16])


三回目

======== Timer Is 2935112 Ticks/Sec, Times are in Microsecs ========

  Num          Tree        Func        Per
  Calls        Time        Time        Call

      1    14996076     9190335     9190335     _Dmain
13000000      810349      810349           0     pure nothrow @safe const(double[16]) main.__lambda3(const(double[16]))
13000000      801379      801379           0     pure nothrow @safe const(double[16]) main.__lambda2(ref const(double[16]))
13000000      781782      781782           0     const(double[16]) main.func_ar_i(const(double[16]))
13000000      771946      771946           0     double[16] main.func_i(const(double[16]))
13000000      740717      740717           0     pure nothrow @safe double[16] main.__lambda1(double[16])
13000000      660759      660759           0     double[16] main.func_rc(ref const(double[16]))
13000000      606062      606062           0     double[16] main.func(double[16])
13000000      497636      497636           0     ref const(double[16]) main.func_ar_rc(ref const(double[16]))
3000000      135108      135108           0     double[16] main.func_ar(double[16])

"auto ref 返り値"って場合によっては実行効率かなり高くなるのか…
そして個人的には "ref const 引数" が "修飾無し引数" より効率悪くなる事の方が驚き。
というか悲しい。
以前コード書いてた時に ref const 修飾子付けたら実行速度上がった事があったから
ずっとそれを盲信して来たのだが…うん…


測定方法がこれで合ってるか確信無いので、
こんな結果も出ましたよってくらいに読み流しておいて下さい。

FreePascal と D でいちゃいちゃする


おけましておめでとうございました。
今年もよろしくお願いします。


最近は専ら FreePascal/Lazarus でしかプログラミングしてないのだけど
久し振りに D言語 も触りたいなと思った所で
何か良いネタは無いか…と探した所、ありました良いネタ。


Lazarus は Delphiマルチプラットフォーム版みたいなやつで、
フォームデザインなんかはマウスでぽちぽち出来たりします。
是非 D言語 でもそれを使いたい。
因みに Lazarus で使用されるコンポーネント群は LCL(Lazarus Component Library) と
呼ばれているのですが、マウスでポトペタは無理にしても、
せめて使い慣れたそれらを D言語 から使えたら…


という事で、それを実現するにはどうすれば良いかと。
取り敢えず定石として、LCL を shared library に纏めて D言語 から呼べるようにしたい。
幸い、FreePascal も D言語 も、C言語と親和性が高いので、どうにかなるんじゃね?


という事なのだが、そこら辺のノウハウが全く無いので
まず最初の一歩として
FreePascal で shared library の作成

D言語 からそれの呼び出し
だけやってみた。


・まず FreePascal 側で shared library を作る。
hoge.pas

library hoge;

{$mode objfpc}{$H+}

uses
  Classes
  { you can add units after this },
  sysutils;

var input1, input2 : Integer;

procedure SetData( i1, i2 : Integer ); cdecl;
begin
  input1:=i1;
  input2:=i2;
end;

function Calc:Integer; cdecl;
begin
  Result := input1+input2;
end;

exports
  SetData,
  Calc;

begin
end.

コンパイルする。

$ fpc hoge.pas
  →libhoge.so


D言語から libhoge.so を呼んでみる。
main.d

import std.stdio;

extern (C) {
    void SetData( int i1, int i2 );
    int Calc();
}

void main( string[] args ) {

    SetData( 100, 10 );
    writeln( Calc() );

    writeln("hoge!");

    return;
}


コンパイルする。

$ dmd main.d -Llibhoge.so


LD_LIBRARY_PATH に libhoge.so がある場所を教えておく。

$ export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:


実行する。

$ ./main
  110
  hoge!


出来た!嬉しい!
最初 cdecl を stdcall にしてて、
./main 実行した最後に SIGSEGV 吐かれて参ったりしてた。
とりあえず一歩前進。
ちくちくラッパー書いていこうかな。


あと僕も MBA 11inch 欲しいので。
MacBook Air 11インチ欲しい!


これで 去年の人 も卒業出来ました:-)

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

続・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使いたいけど、方法が分からない!という方は是非やってみてください。
意外と簡単です。


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