DUB による D 言語開発 Tips
DUB とはD 言語のためのパッケージ管理ツールです。
多分 Clojure の lein や Scala の sbt に近いです。
基本的な使い方は、このページによくまとまっています
D言語でビルドツールDUBを用いて便利なライブラリをより簡単に利用する
本稿では、そこに書いてない便利な使い方をまとめます。
ローカルにあるライブラリとの連携
- dub パッケージの利用
DUB プロジェクトでは主に DUB リポジトリに登録されたリモートなパッケージをよく使うと思いますが、ローカルに用意した DUB パッケージを追加するときは、dub.jsonにバージョンではなくパスを書きます。
"dependencies": {
    "mir": { "path": "./mir" },
    "ggplotd": ">=0.4.5",
    ...
}
これで、再帰的にきちんと依存解決してくれます、便利。 きちんとローカルのパッケージもバージョン管理をするためには、git submodule などを利用すると良いと思います。
fork して自前パッチを当てたmirパッケージを使用したd-svmパッケージの例
- ライブラリファイル(*.so等)の利用
例えばデータベースや CUDA ライブラリなどパスの通ったものを、
リンカオプション-lcudaをつけて渡したいことがあります。
そんなときは、libsオプションを使います。
"libs": [
    "cuda",
    "nvrtc",
    "cudart"
]
さらに複雑なオプションが必要なときは、dflagsオプションでコンパイラに渡すこともできます。
"dflags" : [
    "-J/usr/local/cuda/include/"
]
ちなみに-Jオプションはコンパイル時にファイルを読むimport(filename)でパスを通すオプションで、
コンパイル時にCヘッダーファイルを読んでD言語用のラッパーを生成するときなどに使います。
単体テストの実行
D 言語には言語機能として、単体テスト(unittest)やカバレッジ計測がサポートされています。
import mir.ndslice;
auto diag(S)(S s, long k=0) {
  auto sk = k >= 0 ?  s[0 .. $, k .. $] : s[-k .. $, 0 .. $];
  return sk.diagonal;
}
unittest {
  //  -------
  // | 0 1 2 |
  // | 3 4 5 |
  //  -------
  auto a = iota(2, 3).canonical;
  assert(a.diag == [0, 4]);
  assert(a.diag(1) == [1, 5]);
  assert(a.diag(-1) == [3]);
}
コマンド dub testやdub test -b unittest-covで、パッケージ内全体のテスト実行やカバレッジ計測(結果は*.lstファイルに出力)できます。これだけでも十分に便利ですが、外部のサービスと連携するとさらに便利です。
外部サービスとの連携
BitbucketやGitHubリポジトリのREADMEによく、このようなバッジ
を見かけると思います。具体的にはTravisという自動で様々な環境(OS, コンパイラ...)でテストを行うCIと、 テストのカバレッジを見やすくしてくれる Coveralls というサービスをよく使います。 さらに他の人からも簡単に使えるように、dubのWebページに登録することも多いでしょう。
- Travis CI, Coveralls
Travis CI, Coveralls
にGitHubなどのアカウントでログインして既存のリポジトリを追加できます。
あまり知られていませんが、TravisではLinuxだけでなくOSXも動きます。
Coverallsとの連携には doveralls というツールがおすすめです。
次のような.travis.ymlファイルをGitリポジトリの配下におくといい感じにやってくれます。
os:
  - linux
  - osx
language: d
d:
  - ldc-1.1.0
  - dmd
install:
  - dub fetch doveralls
script:
  - dub test -b unittest-cov
  - dub run doveralls
もし、プライベートであったり、GPGPUなどTravisでは実行できないようなライブラリを作っている場合は、 ローカルでテストを実行して、カバレッジ計測だけCoverallsを利用したいということがあると思います。 その場合は、ローカルで次のようなシェルコマンドを打つと良いでしょう。
$ dub fetch doveralls
$ dub test -b unittest-cov
$ dub run doveralls -- -t <coverallsのrepo_token>
- DUB レポジトリの登録
DUB ではアカウントを作って下記のページから自作パッケージを追加できます。 GitHubとBitbucketに登録されているリポジトリから登録できます。
https://code.dlang.org/my_packages
git の tag を打つ必要があります、GitHubのリリースページなどから打つとよいでしょう。
これで、他のパッケージから簡単に登録したパッケージのモジュールをimportして呼び出せます。
一つの完結したプロジェクトではあまり使いませんが、D言語にはpublic import や package.d という便利な機能があります。外部から呼ばれるパッケージでは、それらを駆使すると良いでしょう。
https://dlang.org/spec/module.html
ドキュメントの生成
D 言語には Javadoc みたいなコード中のコメント(ddoc)によるドキュメント生成が、unittestみたいに言語機能としてサポートされています。
http://www.kmonos.net/alang/d/ddoc.html
http://dlang.org/spec/ddoc.html
http://stackoverflow.com/questions/29762668/using-dub-to-build-documentation
dub でサポートされた方法は2つあります,
- dmd コンパイラの機能を使う: 
dub build --build=docs - 標準ライブラリPhobos のドキュメント生成に使われる ddox: 
dub build --build=ddox 
ところで、ddox は筆者の環境ではビルドできませんでしたので、dmdコンパイラの機能を使っています。こんな感じで /++ +/ (複数行) や /// (一行) を使ってドキュメントを書くと(正確にはかかなくても多少自動生成されます)、
/++
construct new uninitialized slice with specified shape and element type
Params:
    length = elements of shape
Returns:
    new uninitialized slice
+/
auto empty(E=double, size_t N)(size_t[N] length...) {
  return uninitializedSlice!E(length);
}
///
unittest {
  auto e = empty!int(2, 3);
  assert(e.shape == [2, 3]);
  static assert(is(DeepElementType!(typeof(e)) == int));
}
いい感じに unittest なども Examples として表示してくれたりします。 この辺はBDDなどの考え方と相性が良いのではないでしょうか?
例: https://shigekikarita.github.io/numir/
ちなみにGithub では Pages という設定で、docsディレクトリにhtmlファイルを置くと
ウェブページをホストしてくれるので便利です。
まとめ
DUBはあまりドキュメント化されていない部分もあって、stackoverflowやgithubリポジトリを掘り返しながら、まとめました。DUBはパッケージマネージャとしては優秀ですが、ビルドシステムとしてはMakeなどと比べると制限がつよくて、シェルスクリプトなどがdub.jsonにかけると便利かなとは思います。D言語は言語機能として便利な機能(単体テスト、カバレッジ計測、ドキュメント生成)がサポートされているのは最高ですね。