Linux カーネルでの Sphinx 利用法を見てみよう

年末カウントダウン Sphinx 連載、第3弾です。
一切下準備をせずに連載を始めたので、早くも息切れをしています。
だれかと約束をしたわけでもないのに急にアドベントカレンダー的なものを始めるのは、なんだか死に急いでいる気がしてきました。

今回は、今年から Sphinx の利用者に加わったある大型プロジェクトについて紹介しましょう。
そのプロジェクトとは、世界最大級の OSS のひとつである Linux カーネルです。

現在の Linux カーネルドキュメント

今年開催された LinuxCon Japan 2016 で Linux カーネルのドキュメントに Sphinx を使うという発表がありました。
Linus Torvalds氏が登壇、「約10週間のリリースサイクルは続く」 - クラウド Watch

それから約 5ヶ月。現在はどうなっているのか見てみましょう。
Linux カーネルのドキュメントは https://www.kernel.org/doc/ で公開されています。

f:id:tk0miya:20161226223215p:plain

最初に目に入るのは (new sphinx format) という記述が目に入ります。
そして docbook format の方には (deprecated) の文字が。

というわけで、いまでは Linux カーネルのメインのドキュメントには Sphinx が使われています。
リンクをたどると見慣れた readthedocs テーマで生成されたドキュメントが現れます。

f:id:tk0miya:20161226223231p:plain

カーネルドキュメントに Sphinx が採用された経緯

LinuxCon 2016 のプレゼンを聞いていた @senopen 氏は当時こんな風にツイートしています。
(当時、仕事中にこれが流れてきてかなりびっくりした覚えがあります)





DocBook から移行をするのは理解できるものの、なぜ asciidoc ではダメだったのか、
Ruby 依存とはどういうことかと疑問に思っていたのですが、
その答えは LWN.net への投稿 で説明されていました。

asciidoc と Sphinx のどちらを採用するかの判断理由として、次のように説明されています。

But it seemed that neither tool would work as-is, or at least we wouldn't be able to get their full potential without extending the tools ourselves. In the kernel tree, there are no tools written in Ruby, but there are plenty of tools written in Python. It was fairly easy to lean towards Sphinx in this regard.

超訳

Grant Likely summed it up this way: "Honestly, in the end I think we could make either tool do what is needed of it. However, my impression after trying to do a document that needs to have nice publishable output with both tools is that Sphinx is easier to work with, simpler to extend, better supported.”

超訳

  • どちらのツールでも要求は満たせた
  • 両方試した結果、Sphinx の方が使いやすく、簡単に拡張できて、サポートがよかった


どうやら、既にカーネルの構成管理ツールとして Python が使われていたので、どちらかといえば Python を使ったほうが楽だろうという判断のようですね。また、Sphinx の方を気に入ってくれたようです。
(サポートが良かった、というのはどういうことなんでしょうかね。特に何かをした覚えはないのですが)


ちなみに Part.2 では移行や、あたらしいドキュメントの書き方について説明しています。
個人的にツボった所だけ抜粋しておきます。

grepping and reading reStructuredText is much easier than the angle-bracketed mess that is DocBook.

reST を grep したり読んだりするのは、DocBook のタグよりはるかにかんたんです。

It's a nice vision, I hear angels singing when I think about it and so on, it's where I want to go.

(数年後、包括的で読みやすいドキュメントができることについて)
そう考えると天使の歌声が聞こえます。

カーネルドキュメントはどのような設定になっているのか

カーネルドキュメントの設定は ここ から参照できます。
読み進めていくと、極めて一般的な、Sphinx の基本設定だけで構築されていることがわかります。

primary_domain が C になっているのは、やはり Linux カーネルですね。

primary_domain = 'C'
highlight_language = 'none'	

LaTeX のプリアンブル部には、いくつかの設定が指定されています。

  • 色やスタイルなどの指定
  • landscape 出力の準備
  • XeLaTeX 用のフォント設定

また、巨大なドキュメントであるため、PDF もいくつかに分冊して出力するようになっています。
このあたりは Python のドキュメントでも培われた、ドキュメントを小分けにするテクニックをうまく使っているようですね。

latex_documents = [
    ('doc-guide/index', 'kernel-doc-guide.tex', 'Linux Kernel Documentation Guide',
     'The kernel development community', 'manual'),
    ('admin-guide/index', 'linux-user.tex', 'Linux Kernel User Documentation',
     'The kernel development community', 'manual'),
    ('core-api/index', 'core-api.tex', 'The kernel core API manual',
     'The kernel development community', 'manual'),
    ('driver-api/index', 'driver-api.tex', 'The kernel driver API manual',
     'The kernel development community', 'manual'),
    ('kernel-documentation', 'kernel-documentation.tex', 'The Linux Kernel Documentation',
     'The kernel development community', 'manual'),
    ('process/index', 'development-process.tex', 'Linux Kernel Development Documentation',
     'The kernel development community', 'manual'),
    ('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide',
     'The kernel development community', 'manual'),
    ('media/index', 'media.tex', 'Linux Media Subsystem Documentation',
     'The kernel development community', 'manual'),
    ('security/index', 'security.tex', 'The kernel security subsystem manual',
     'The kernel development community', 'manual'),
]

また、カーネル特有の設定として、いくつかの拡張を利用するようになっています。

extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain']

ここで指定されている kerneldoc, rstFlatTable, kernel_include, cdomain という4つの拡張はドキュメントと一緒にコミットされている
カーネル専用の Sphinx 拡張です。
それぞれどういう効果のある拡張なのか、ひとつずつ見ていってみます。

カーネルドキュメント専用の拡張

kerneldoc

外部スクリプトである kernel-doc コマンドを呼び出して、カーネルソースコードからコメントを抽出するディレクティブ kernel-doc を提供します。
抽出したコメントは reST として解釈され、ドキュメントに埋め込まれるようです。

rstFlatTable

list-table のようなリストベースの記法で、なおかつセル結合に対応したテーブル系ディレクティブです。

このページ のサンプルでわかるように :rspan: と :cspan: というふたつのロールを使ってセル結合を行います。
また、セルが足りない場合は自動的に補ってくれる autospan 機能もついています。

やや ad-hoc なマークアップではあるものの、複雑な表を作りたい場合は便利そうです。

kernel_include

環境変数などを含んだパスに対応した include ディレクティブである、kernel-include ディレクティブを提供しています。

cdomain

Sphinx の C ドメインを拡張したものです。
基本的な機能はそのままに、

  • 細かい warning を nitpicky オプションで黙らせるように
  • c:function ディレクティブに :name: オプションを追加

などをカスタマイズしています。

まとめ

ということで、

  • 既に Sphinx を使った Linux カーネルのドキュメントは運用に載っていて、
  • いくつかの拡張を使いながら、Sphinx っぽくドキュメントが書かれている

ことがわかりました。
自分が関わってるソフトウェアが、カーネルを支えてるってすごいことですね。

おまけ

Linus が reStructuredText を書いているのか気になって調べてみたら、
過去半年で彼が Documentation/ ディレクトリ以下にコミットしたの、これだけだった。
https://github.com/torvalds/linux/commit/852d21ae1fcdf0e4de6b5bfa730d29cb013c7ff3
(その他はすべてマージコミット)

.rst ファイルに symlink を貼ったのも、Sphinx を使ったの一部、ですよね? (弱気)