D言語でドキュメント生成する方法のまとめ

# 概要
各種ツールの紹介と、インストール方法(ビルド方法)、使用方法、適用例を紹介します。

- [標準の方法](https://dlang.org/spec/ddoc.html): 訓練されていなきゃ困難だけど、一番細かく作りこめる。
- [candydoc](http://www.dsource.org/projects/helix/wiki/CandyDoc): そこそこ簡単だけど、dubでの設定がムズイ。
- [ddox](https://github.com/rejectedsoftware/ddox): dubでサポートしている。改造例も紹介します。
- [adrdox](https://github.com/adamdruppe/adrdox): ビルドしないとだめで大変。dubにパッケージとして登録すると勝手にページが作られます。たぶん。
- [harbored-mod](https://github.com/dlang-community/harbored-mod): dubで簡単にビルド・利用ができます。
- [doxygen](http://www.doxygen.nl/): 特に特別な設定なく使えます(一部対応、とのことですが)。使ってる人見たことないです。

# はじめに
はたらき方改革が叫ばれている昨今、我々エンジニアにとっても業務効率化は重要視されています。これに対して設計業務の一端を自動化するのは非常に有益です。ドキュメントの自動生成やCASEツールの活用、テスト自動化などなど。
この中でも、D言語は詳細設計をソースコード内で行い、ドキュメントを自動生成する方法を標準でサポートしています。
しかしながら、標準の方法ですべてを行うのは大変です。具体的には、標準の方法では装飾なしのHTMLが生成されるだけで、スタイルシートやサイト内検索などのあれやこれやは提供してくれません。
そこで、ドキュメント化のためのツールがいくつか開発されています。
各ツールは、HTMLのひな形や、CSS、Javascriptによる検索などを提供して、そこそこ見栄えよく、利便性を備えたドキュメントの生成を行ってくれます。
本記事では、各種ドキュメント生成の方法をまとめます。

# 標準の方法
- [公式](https://dlang.org/spec/ddoc.html)
- [日本語](http://www.kmonos.net/alang/d/ddoc.html)

dmdに標準で搭載されているドキュメント生成方法です。詳細な使用方法は公式サイトを参照してください。
すごく簡単な方法として、以下のようにコメントを記載すると簡単です。

### とりあえず出力するだけ
```d
///
void foo() { }
```

コメントの中身がなくとも、このようにすることで生成されるドキュメントに関数名や引数などは出力されるので、関数名だけで内容が十分理解できるようなものはこれだけでも十分に効果があります。たとえば、`getFilename`とかいう関数名に「ファイル名を取得する」とかコメントをつけるのはあまりに自明すぎて馬鹿らしいですね。

### 概要だけのパターン
```d
/// fooの概要
void foo() { }
```

```d
/**********************************
 * fooの概要
 */
void foo() { }
```

書かないよりましって思ったらこう書きます。

### 直前のと同じ場合
```d
/// ditto
void foo() { }
```


### ちょっと詳細に書く
```d
/**********************************
 * fooの概要
 *
 * fooの詳細説明
 */
void foo() { }
```

概要と詳細説明の間に1行あけるのがポイントです。

### パラメータの説明とかしたい
```d
/**********************************
 * fooの概要
 *
 * fooの詳細説明
 * Params:
 *     x = パラメータxの説明
 * Returns:
 *     戻り値の説明
 */
int foo(int x) { return x + 1; }
```

ここまで記載するとそこそこ立派なドキュメントになりますね。ここでは`Params`と`Returns`を使用していますが、いろいろなブロックがあります。適宜使用するといいと思います。ただ、このような書き方だと、doxygenでドキュメント生成するときにはうまくレイアウトされません。

### こう書いてもいいです
```d
//////////////////////////
/// fooの概要
/// 
/// fooの詳細説明
void foo() { }
```

```d
/++
 + fooの概要
 + 
 + fooの詳細説明
 +/
void foo() { }
```
`/** */`の形式で書くのが嫌な場合はこれらでもいいです。ただ、Phobosは`/** */`のスタイルですので、こう書いている人は多いような気がします。

## 標準の方法のインストール方法
dmdの付属機能を使用するため、不要です。あえて言えば、makeなどができると便利だと思います。

## 標準の方法の使用方法

以下のコマンドにより、`src/main.d`から`doc/main.html`を生成することができます。

```sh
dmd main.d -D -o- -c src/main.d -Df doc/main.html
```

こうやって標準機能のドキュメント生成を行う場合は、Makefileを作成するケースが多いようですね。Phobosのドキュメントが個人的には見やすいように感じるので、あの体裁でもっと簡単に出力できるといいのですけど…。

## 標準の方法の適用例
- [Phobos](https://dlang.org/phobos/index.html)
- [dxml](http://jmdavisprog.com/docs/dxml/0.4.0/)
- [mir-algorithm](http://docs.algorithm.dlang.io/latest/index.html)

# CanDyDoc
- [公式](http://www.dsource.org/projects/helix/wiki/CandyDoc)
- [fork1 eldar](https://github.com/eldar/candydoc)
- [fork2 jacob-carlborg](https://github.com/jacob-carlborg/candydoc)

標準の方法だけだとCSSなどの体裁が整っておらず、またモジュールの一覧なども自動で生成されない不便です。そこで、モジュール一覧と簡単なCSS、HTMLのテンプレを使って見栄えのいいものにしましょう、というのがCanDyDocです。CanDyDocはツールというより、標準の方法をいい感じに使う方法といった方が適切かもしません。かなり昔に作られたpublic domainなプロジェクトで、昔D言語のパッケージをtracで管理していた際の代物です。
非常にシンプルなドキュメントを生成することができます。

## CanDyDocのインストール方法
ドキュメント生成先のフォルダにCanDyDocのファイルを配置します。

```sh
git clone https://github.com/eldar/candydoc.git
```

## CanDyDocの使用方法
標準のドキュメント生成方法に加えて、モジュール一覧用のddocファイルと、テンプレ用のcandy.ddocを指定します。
モジュール一覧用のファイルは自分自身で以下のように定義します。

```d
MODULES =
	$(MODULE_FULL main)
	$(MODULE_FULL test)
```

HTMLの生成は以下のようにdmdにより行います。

```sh
dmd -D -o- -c src/main.d doc/candydoc/modules.ddoc doc/candydoc/candy.ddoc -Dfdoc/main.html
dmd -D -o- -c src/test.d doc/candydoc/modules.ddoc doc/candydoc/candy.ddoc -Dfdoc/test.html
```

もちろん、一つずつHTMLを生成するのは大変なので、makeなどを使用するといいでしょう。また、`modules.ddoc`もシェル芸とか使ってファイル一覧から機械的に生成するようにするといいでしょう。

dubでCanDyDocの生成を行うのは結構難しいです。postBuildCommandsなどでmake走らせるとか言う強引な方法が一番楽そうです。

## candydocの適用例
- [msgpack-d](http://msgpack.github.io/msgpack-d/)
- [GtkD](https://api.gtkd.org/gtkd/gtk/AboutDialog.html)

# ddox
- [公式](https://github.com/rejectedsoftware/ddox)
- [リポジトリ](https://github.com/rejectedsoftware/ddox)
- [dubパッケージ](https://code.dlang.org/packages/ddox)

D言語のパッケージツールdubでデフォルト対応していて、vibe.dで使われているドキュメント生成ツールです。


## ddoxのインストール方法
dubが利用できる状態であれば、特にインストールを必要とせずに使用することができます。(ただし、その場合細かな設定はできません)

自分でビルドする方法もあります。dubでそこそこ簡単にビルドできます。
ただし、Windows(dmd)だとライブラリのOMFがいい感じにできていないせいか、うまくいかないことが多く、LDCや64bit版や、mscoff形式でビルドするとうまいこと行くことが多いです(というか、そのせいでdubから直接使用する方法が使えないことがあります)。

```sh
dub build -a=x86_64 -b=release -c=application --compiler=ldc2
```

## ddoxの使用方法
### dubから使う方法
dubを使って、以下のようにビルドすることで、実行ファイルやライブラリではなく、ドキュメントを生成することができます。

```sh
dub build --build=ddox
```

### ddoxを直接使う方法
まず、dmdのJSON生成機能を用いてddocs.jsonを生成します。

```sh
dmd -Xfdocs.json -o- -c src/a.d src/b.d src/c.d src/e.d
```

`ddox filter`により、ドキュメント生成に使用する定義を抽出して、`ddox generate-html`によってHTMLを生成します。

```sh
ddox filter docs.json --min-protection Protected
ddox generate-html docs.json doc --navigation-type=DeclarationTree
```

上記のように、多少レイアウトを弄ることができます。(上記では`--navigation-type=DeclarationTree`でナビゲーションバーの表示を切り替えています)

### カスタマイズ
ddoxの出力するHTMLはdietテンプレートを用いて作成されており、これを編集することで細かくカスタマイズすることが可能です。
さらに、カスタマイズしたddoxをdubパッケージで公開することで、dubから直接使用することができます。
以下のリストは実際にdubパッケージに登録されているddoxをカスタマイズしたテーマで、カスタマイズされたドキュメントを生成するためのツールです。

- [scod](https://github.com/MartinNowak/scod)
- [WhammyDoc](https://github.com/Azbukagh/WhammyDoc)

これらはdubパッケージで公開済みなので、以下のようにすることでカスタムテーマに対応することができます。(この例はscodを使用する例です)

```json:dub.json
{
    :
    :
    "-ddoxTool": "scod"
    :
    :
}
```

ドキュメント生成はdubを使った方法と同じです。

```sh
dub build --build=ddox
```

これ、公開必須とかいささか気軽さに欠けると思います。もっと気軽にできればいいのに。` "-ddoxTool": {"path": "custom_ddox"} `ってな感じに。

### 自分でカスタマイズしたddoxテーマをローカルで使用するdub設定

パッケージで公開するのもちょっと…っていうような場合は、以下のようにすることで、自前改造のddoxを使ってドキュメント生成することができます。

例えばこんな感じに以下の3つのファイルをいじくって…

<details><summary>ddox.inc.composite.dt</summary><div>

```d:ddox.inc.composite.dt
- import ddox.api;
- import ddox.highlight;
- import std.algorithm;
- import std.string : toLower;
- import std.typetuple;

- void outputCompositePrototype(CompositeTypeDeclaration item)
	- auto cls_item = cast(ClassDeclaration)item;
	- auto intf_item = cast(InterfaceDeclaration)item;

	| <span class="kwd">#{item.kind.to!string.toLower()}</span> <span class="typ">#{item.name}</span>
	- info.renderTemplateArgs(&_diet_output, item);

	- bool first = true;
	- void outputBase(CachedType tp)
		- if (tp.typeName.among("Object", "object.Object"))
			- return;
		| !{first ? "<br>&nbsp;&nbsp;: " : "<br>&nbsp;&nbsp;, "}!{info.formatType(tp, false)}
		- first = false;

	- if (cls_item && (cls_item.baseClass || cls_item.derivedInterfaces.length))
		- if (cls_item.baseClass)
			- outputBase(cls_item.baseClass);
		- foreach (intf; cls_item.derivedInterfaces)
			- outputBase(intf);

	- if (intf_item && intf_item.derivedInterfaces.length)
		- foreach (intf; intf_item.derivedInterfaces)
			- outputBase(intf);

	- if (item.templateConstraint.length)
		| #[br]&nbsp;&nbsp;
		- if (item.templateConstraint.length)
			br
			| <span class="kwd">if</span> <span class="pun">(</span>!{highlightDCode(item.templateConstraint)}<span class="pun">);</span>
	- else
		span.pun ;

- void outputCompositeMembers(CompositeTypeDeclaration item, int hlevel)
	- alias TypeTuple!(InterfaceDeclaration, ClassDeclaration, StructDeclaration, UnionDeclaration, EnumDeclaration, AliasDeclaration, TemplateDeclaration) kinds;
	- static const kindnames =      ["Inner interfaces", "Inner classes", "Inner structs", "Unions", "Enums", "Aliases", "Templates"];
	- static const kindnames_sing = ["Inner interface",  "Inner class",   "Inner struct",  "Union",  "Enum",  "Alias",   "Template"];

	- FunctionDeclaration[] properties, methods, constructors;
	- foreach( itm; getDocGroups!FunctionDeclaration(item) )
		- if( itm.hasAttribute("@property") )
			- properties ~= itm;
		- else if( itm.name != "this" )
			- methods ~= itm;
		- else
			- constructors ~= itm;

	- if( constructors.length )
		section
			- heading(hlevel, "Constructors");
			table
				col.caption
				tr
					th Name
					th Description
				- foreach( p; constructors )
					tr
						td
							a(href="#{info.linkTo(p)}", class=declStyleClasses(p))
								code= p.name
							span.tableEntryAnnotation (#{p.parameters.map!(param => param.name[]).joiner(", ")})
						td!= info.formatDoc(p.docGroup, 3, sec => sec == "$Short")

	- if( hasChild!VariableDeclaration(item) )
		section
			- heading(hlevel, "Fields");
			table
				col.caption
				tr
					th Name
					th Type
					th Description
				- foreach( f; getChildren!VariableDeclaration(item) )
					tr
						td
							a(href="#{info.linkTo(f)}", class=declStyleClasses(f)) <code>#{f.name}</code>
						td.typecol!= info.formatType(f.type)
						td!= info.formatDoc(f.docGroup, 3, sec => sec == "$Short")

	- if( properties.length )
		section
			- heading(hlevel, "Properties");
			table
				col.caption
				tr
					th Name
					th Type
					th Description
				- foreach( p; properties )
					- auto mems = p.docGroup ? p.docGroup.members : [cast(Entity)p];
					tr
						td
							a(href="#{info.linkTo(p)}", class=declStyleClasses(p)) <code>#{p.name}</code>
							span.tableEntryAnnotation= anyPropertyGetter(mems) ? anyPropertySetter(mems) ? "[get, set]" : "[get]" : "[set]"
						td.typecol!= info.formatType(getPropertyType(mems))
						td!= info.formatDoc(p.docGroup, 3, sec => sec == "$Short")

	- if( methods.length )
		section
			- heading(hlevel, "Methods");
			table
				col.caption
				tr
					th Name
					th Description
				- foreach( p; methods )
					tr
						td
							a(href="#{info.linkTo(p)}", class=declStyleClasses(p))
								code= p.name
							span.tableEntryAnnotation (#{p.parameters.map!(param => param.name[]).joiner(", ")})
						td!= info.formatDoc(p.docGroup, 3, sec => sec == "$Short")
					tr
						td(colspan=2)
							include ddox.inc.function
							- auto fdecl = cast(FunctionDeclaration)p;
							- assert(fdecl !is null, "Invalid node of function kind: " ~ p.qualifiedName.to!string);
							- outputFunctionPrototypeList(fdecl);

	- foreach( i, kind; kinds )
		- if( hasChild!kind(item) )
			section
				- heading(hlevel, kindnames[i]);
				table
					col.caption
					tr
						th Name
						th Description
					- foreach( grp; getDocGroups!kind(item) )
						tr
							td
								a(href="#{info.linkTo(grp)}", class=declStyleClasses(grp))
									code= grp.name
							td!= info.formatDoc(grp.docGroup, 3, sec => sec == "$Short")

```

</div></details>


<details><summary>ddox.inc.function.dt</summary><div>

```d:ddox.inc.function.dt
- import ddox.api;
- import ddox.highlight;
- import std.algorithm;

- void outputFunctionPrototype(FunctionDeclaration item)
	- auto docgroup = item.docGroup;
	- auto mems = docgroup.members;
	- foreach (size_t pi, pd; mems)
		- auto proto = cast(FunctionDeclaration)pd;
		- if (!proto) continue;
		- auto attribs = proto.attributes.dup;
		- if (pi > 0)
			br
			br
		- auto rettype = proto.name == "this" ? "" : info.formatType(proto.returnType, false) ~ " ";
		- if (rettype.length == 1 || rettype == "{null} ")
			- foreach (i, attr; attribs)
				- if (attr == "auto")
					- rettype = highlightDCode(attr) ~ " ";
					- break;
		- attribs = attribs.remove!(a => a.str == "auto");
		- auto attribute_prefix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionPrefix));
		- auto attribute_suffix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionSuffix));
		- auto variadic_suffix = highlightDCode(getVariadicSuffix(proto.type));
		- if (!proto.templateConstraint.length) attribute_suffix ~= "<span class=\"pun\">;</span>";

		- if (proto.parameters.length)
			| !{attribute_prefix}!{rettype}#[span.pln= proto.name]
			- info.renderTemplateArgs(&_diet_output, proto);
			span.pun (
			br
			- foreach (size_t i, p; proto.parameters)
				- auto pattribs = highlightDCode(getAttributeString(p.attributes, AttributeStringKind.normal));
				- auto suffix = i+1 < proto.parameters.length ? "<span class=\"pun\">,</span>" : variadic_suffix;
				- if (p.initializer)
					| &nbsp;&nbsp;!{pattribs}!{info.formatType(p.type, false)} #[span.pln= p.name] #[span.pun =] !{highlightDCode(p.initializer.valueString)}!{suffix}
				- else
					| &nbsp;&nbsp;!{pattribs}!{info.formatType(p.type, false)} #[span.pln= p.name]!{suffix}
				br
			|#[span.pun )]!{attribute_suffix}
		- else
			| !{attribute_prefix}!{rettype}#[span.pln= proto.name]
			- info.renderTemplateArgs(&_diet_output, proto);
			| #[span.pun<> (]!{variadic_suffix}#[span.pun )]!{attribute_suffix}

		- if (proto.templateConstraint.length)
			br
			|#[span.kwd if] #[span.pun (]!{highlightDCode(proto.templateConstraint)}#[span.pun );]


- void outputFunctionPrototypeList(FunctionDeclaration item)
	ul
		- auto docgroup = item.docGroup;
		- auto mems = docgroup.members;
		- foreach (size_t pi, pd; mems)
			li
				- auto proto = cast(FunctionDeclaration)pd;
				- if (!proto) continue;
				- auto attribs = proto.attributes.dup;
				- auto rettype = proto.name == "this" ? "" : info.formatType(proto.returnType, false) ~ " ";
				- if (rettype.length == 1 || rettype == "{null} ")
					- foreach (i, attr; attribs)
						- if (attr == "auto")
							- rettype = highlightDCode(attr) ~ " ";
							- break;
				- attribs = attribs.remove!(a => a.str == "auto");
				- auto attribute_prefix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionPrefix));
				- auto attribute_suffix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionSuffix));
				- auto variadic_suffix = highlightDCode(getVariadicSuffix(proto.type));
				- if (!proto.templateConstraint.length) attribute_suffix ~= "<span class=\"pun\">;</span>";

				- if (proto.parameters.length)
					| !{attribute_prefix}!{rettype}#[span.pln= proto.name]
					- info.renderTemplateArgs(&_diet_output, proto);
					span.pun (
					- foreach (size_t i, p; proto.parameters)
						- auto pattribs = highlightDCode(getAttributeString(p.attributes, AttributeStringKind.normal));
						- auto suffix = i+1 < proto.parameters.length ? "<span class=\"pun\">,</span>" : variadic_suffix;
						- if (p.initializer)
							| &nbsp;&nbsp;!{pattribs}!{info.formatType(p.type, false)} #[span.pln= p.name] #[span.pun =] !{highlightDCode(p.initializer.valueString)}!{suffix}
						- else
							| &nbsp;&nbsp;!{pattribs}!{info.formatType(p.type, false)} #[span.pln= p.name]!{suffix}
					|#[span.pun )]!{attribute_suffix}
				- else
					| !{attribute_prefix}!{rettype}#[span.pln= proto.name]
					- info.renderTemplateArgs(&_diet_output, proto);
					| #[span.pun<> (]!{variadic_suffix}#[span.pun )]!{attribute_suffix}

				- if (proto.templateConstraint.length)
					|#[span.kwd if] #[span.pun (]!{highlightDCode(proto.templateConstraint)}#[span.pun );]

```
</div></details>


<details><summary>ddox.module.dt</summary><div>

```d:ddox.module.dt
extends ddox.layout

block ddox.defs
	- import ddox.api;
	- import std.algorithm : canFind, map, joiner;
	- import std.typetuple;

block ddox.title
	- title = "Module " ~ info.mod.qualifiedName.to!string;

block ddox.description
	p!= info.formatDoc(info.mod.docGroup, 2, sec => sec == "$Short")

	|!= info.formatDoc(info.mod.docGroup, 2, sec => sec == "$Long")

block ddox.sections
	section!= info.formatDoc(info.mod.docGroup, 2, sec => !canFind(["License", "Copyright", "Authors", "$Short", "$Long", "Source"], sec))

block ddox.members
	include ddox.inc.function
	- alias TypeTuple!(FunctionDeclaration, InterfaceDeclaration, ClassDeclaration, StructDeclaration, UnionDeclaration, EnumDeclaration, TemplateDeclaration) kinds;
	- static const kindnames =      ["Functions", "Interfaces", "Classes", "Structs", "Unions", "Enums", "Templates"];
	- static const kindnames_sing = ["Function",  "Interface",  "Class",   "Struct",  "Union",  "Enum",  "Template"];

	- foreach( i, kind; kinds )
		- if( hasChild!kind(info.mod) )
			section
				h2= kindnames[i]
				table
					col.caption
					tr
						th Name
						th Description
					- foreach( grp; getDocGroups!kind(info.mod) )
						tr
							td
								code
									a(id=grp.name[], class=declStyleClasses(grp), href=info.linkTo(grp))= grp.name
									- if (auto fd = cast(FunctionDeclaration)grp)
										span.tableEntryAnnotation (#{fd.parameters.map!(p => p.name[]).joiner(", ")})
							td!= info.formatDoc(grp.docGroup, 3, sec => sec == "$Short")
						- if (kindnames[i] == "Functions")
							tr
								td(colspan=2)
									- auto fdecl = cast(FunctionDeclaration)grp;
									- assert(fdecl !is null, "Invalid node of function kind: " ~ grp.qualifiedName.to!string);
									- outputFunctionPrototypeList(fdecl);

	- alias TypeTuple!(EnumMemberDeclaration, VariableDeclaration, AliasDeclaration) tkinds;
	- static const tkindnames =      ["Manifest constants", "Global variables", "Aliases"];
	- static const tkindnames_sing = ["Manifest constant",  "Variable",  "Alias"];

	- foreach( i, kind; tkinds )
		- if( hasChild!kind(info.mod) )
			section
				h2 #{tkindnames[i]}
				table
					col.caption
					tr
						th Name
						th Type
						th Description
					- foreach( f; getDocGroups!kind(info.mod)  )
						tr
							td
								a(id=f.name[], class=declStyleClasses(f), href=info.linkTo(f))
									code= f.name
							td
								- if( f.type )
									|!= info.formatType(f.type)
							td!= info.formatDoc(f.docGroup, 3, sec => sec == "$Short")

block ddox.authors
	|!= info.formatDoc(info.mod.docGroup, 0, sec => sec == "Authors")
block ddox.license
	|!= info.formatDoc(info.mod.docGroup, 0, sec => sec == "License")
block ddox.copyright
	|!= info.formatDoc(info.mod.docGroup, 0, sec => sec == "Copyright")

```

</div></details>


```sh
dub build -a=x86_64 -b=release -c=applicataion
```

ってな感じでビルドして…

ドキュメントを生成したいプロジェクトのdub.jsonにはサブパッケージを定義して…

<details><summary>dub.json</summary><div>

```json:dub.json
{
    :
    :
    "subPackages": [
        "doc"
    ],
    :
    :
}
```
</div></details>

docフォルダの中にこんな感じにサブパッケージを作って…

<details><summary>doc/dub.json</summary><div>

```json:doc/dub.json
{
	"name": "doc",
	"description": "document.",
	"copyright": "Copyright © 2018, SHOO",
	"targetType": "library",
	"versions": ["Test"],
	"buildOptions": ["syntaxOnly"],
	"importPaths": [
		".."
	],
	"sourcePath": "../src",
	"dflags": ["-Xfdocs.json"],
	"dependencies": {
		"ddox": "~>0.16.0"
	},
	"postBuildCommands-windows": [
		"robocopy $DDOX_PACKAGE_DIR\\public\\ $PACKAGE_DIR\\ /E & time /T>nul",
		"ddox filter docs.json --min-protection Protected",
		"ddox generate-html docs.json doc --navigation-type=DeclarationTree",
		"if exist __dummy.html del __dummy.html"
	]
}
```

</div></details>

こうじゃ

```sh
dub build :doc
```

## ddoxの適用例
- [vibe.d](http://vibed.org/api/)

## 関連記事

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">多分Windowsでddox出す人しか困らないんですけど、雑にdub build --build=ddoxしてOPTLINKにエラー云々言われて困る場合のWorkaroundがこちらになります。<a href="https://twitter.com/hashtag/dlang?src=hash&amp;ref_src=twsrc%5Etfw">#dlang</a><a href="https://t.co/yInVNlEgDF">https://t.co/yInVNlEgDF</a></p>&mdash; lempiji@思秋期 (@lempiji) <a href="https://twitter.com/lempiji/status/1094500207746736129?ref_src=twsrc%5Etfw">2019年2月10日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# adrdox
- [公式](https://github.com/adamdruppe/adrdox)
- [リポジトリ](https://github.com/adamdruppe/adrdox)

最近、dubのパッケージに登録されているものについては、自動的にドキュメントが生成されるようになっています。その生成ツールがこの**adrdox**です。  
Adam D. Ruppeさんが作成しているドキュメント生成ツールで、バイナリを配布している公式ページはないもよう。

## adrdoxのインストール
インストールというか、ビルド方法は以下の通り。普通にdubでビルドできます。

```sh
git clone https://github.com/adamdruppe/adrdox.git .
dub build -a=x86_64 -b=release
```

`build`以下に作成されるファイルが必要なファイルです。

- adrdox.exe
- script.js
- skeleton-default.html
- style.css
- search-docs.html (たぶんcopyFilesに指定し忘れている)
- search-docs.js (たぶんcopyFilesに指定し忘れている)

<!-- 中身見ると、プログラム自体はさておき、プロジェクトの構成がプアな感は否めません… -->

## adrdoxの使用方法
1. ビルドにより生成された各ファイルを、ドキュメントを生成するフォルダにいれます。
2. 以下のコマンドでドキュメントを生成

```sh
./adrdox -i ../src
```


## adrdoxの適用例
- [dub](https://dub.dpldocs.info)
- [vibe.d](https://vibe-d.dpldocs.info)
- [dxml](https://dxml.dpldocs.info)
- [msgpack-d](https://msgpack-d.dpldocs.info)



# harbored-mod
- [公式](https://github.com/dlang-community/harbored-mod)
- [code.dlang.org](https://code.dlang.org/packages/harbored-mod)

adrdox同様、DDocとMarkdownを使ったドキュメント化コメントを取り扱ってHTMLを吐き出すツールです。
dubパッケージとして登録されているアプリケーションなので、dubで比較的簡単に取り扱うことができます。

## インストール方法
dubに登録されているアプリケーションですので、インストールは不要です。

```sh
dub fetch harbored-mod
dub run harbored-mod -- src
```

もちろん、ビルドしてもいいですね。binフォルダが作られて、その中にhmodというバイナリが生成されます。
(以下はldc2でx86_64向けにリリースビルドしてみる例です)

```sh
git clone https://github.com/dlang-community/harbored-mod.git
cd harbored-mod
dub build -a=x86_64 -b=release --compiler=ldc2
```


## 使用方法

基本的には以下でOKです。以下のようにすると、srcフォルダ以下の.dファイルが検索され、ドキュメントを生成してくれます。

```sh:srcフォルダ以下のソースをドキュメント化
dub run harbored-mod -- src
```

```sh:ヘルプ
dub run harbored-mod -- -h
```

```sh:設定ファイル生成(hmod.cfg)
dub run harbored-mod -- -g
```

## 適用例
- [iz](https://basile-z.github.io/new-hmod-preview/iz.html)


# doxygen

- [公式](http://www.doxygen.nl/)
- [日本語](http://www.doxygen.jp/)

この有名なドキュメント生成ツールも、D言語をサポートしています。
たぶんJavadoc方式でコードにコメントを付けることでHTMLを生成してくれると思います。

## doxygenのインストール方法
- [公式](http://www.doxygen.nl/download.html)
- [日本語](http://www.doxygen.jp/install.html)

公式ページ参照。(あまり深く説明する気がない)
場合によってはGraphvizもインストールするといいでしょう。

[Qiita解説記事](https://qiita.com/t-kashima/items/a0ae4929ca8b5728d5bc)

## doxygenの使用方法

まず、以下のようなコマンドでDoxyfileを作成します。

```sh
doxygen -g
```

doxyfileを編集します。D言語専用の設定は特にありません。

ドキュメント生成は以下。

```sh
doxygen
```

## 適用例
- (すみません、D言語での例は見たことありません)



# まとめ
各種ツール(標準, candydoc, ddox, adrdox, harbored-mod, doxygen)の概要、インストール方法、使用方法、適用例についてご紹介いたしました。
現時点におけるD言語の「最強のドキュメント生成ツール！これで万事解決！！！」みたいな決定打は今のところない感じです。
最近はadrdoxみたいな選択肢も増えているので、今後に期待ですね。