はじめに
頑張れば、何かがあるって、信じてる。nikkieです。
技術同人誌執筆以来使っているドキュメンテーションツールSphinxで、include
するファイルはrst
以外の拡張子にするべきということを知りました。
Tips: you should use other extensions for included documents (cf .txt).
目次
要するに
Sphinxにはref
やnumref
を使ったクロスリファレンスの仕組み1があります。
セクションの直前にラベルを付けて、それを参照できます(ドキュメントにある例)。
.. _my-reference-label: Section to cross-reference -------------------------- This is the text of the section. It refers to the section itself, see :ref:`my-reference-label`.
これを使ったところ、PDFのビルドに限っては、includeしたファイルの中のラベルを参照することができませんでした。
HTMLでは参照できる2のですが、PDFになると参照できません(probref
とラベルそのものが出てしまっています)。
出力先によって動きが違う理由に見当が付かず、「悔しくって死にそう」でした。
Issueを漁っていたところ、冒頭で紹介したものに出会い、解消できました。
include
するファイルはrst以外の拡張子にする必要がありました。
サンプルドキュメント
上記Issueに添付されたファイルを例にします。
. ├── Makefile ├── _build ├── conf.py ├── index.rst ├── make.bat ├── section1.rst ├── subsec1.rst └── subsec2.rst
index.rst
sections1.rstからなるtoctreeです。
.. toctree:: :maxdepth: 2 :caption: Contents: section1
section1.rst
subsec1.rst と subsec2.rst をinclude
しています。
参照しているラベル probref
は subsec1.rst にあります。
Section 1 ========= Labels in included files cannot be referenced. .. include:: subsec1.rst .. include:: subsec2.rst Subsection 3 ------------ References also do not work from parent document: :ref:`probref`
subsec1.rst
「Subsection 1」に probref
ラベルを付けています。
.. _probref:
Subsection 1
------------
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
ut labore et dolore magna aliquyam erat, sed diam voluptua.
subsec2.rst
subsec1.rst にあるラベル probref
を参照しています。
Subsection 2
------------
References do not work from other included document: :ref:`probref`
環境
PDFビルドには sphinxdoc/sphinx-latexpdf:3.3.1
(DockerHub)を使いました。4
PDFビルドコマンド
docker run --rm -v $PWD:/docs sphinxdoc/sphinx-latexpdf:3.3.1
作られたPDFではラベルが参照できず、probref
というラベル名が表示されています(図を再掲します)
解決策
probref
ラベルを定義したファイル subsec1.rst を subsec1.rst.txt のように拡張子をrst以外に変更すると解決します。
合わせて、section1.rst の include
も更新します。
.. 変更がないので省略 .. include:: subsec1.rst.txt .. include:: subsec2.rst .. 変更がないので省略
「Subsection 1」とラベルが指すセクションの名前が表示されていますね🙌
解決する理由
前掲のIssueでは、includeされたドキュメントが二度処理されたためと説明されていました。
- section1.rst の処理で、subsec1.rst と subsec2.rst を
include
したドキュメントとなる(probref
ラベルが section1に定義される) - Sphinx が
*.rst
という名前のファイルを検索することで、 subsec1.rst もドキュメントとして処理される。これによりprobref
ラベルが subsec1にも定義される5
同じラベルが2回現れるため、Sphinxは混乱し、最初の画像のようにリファレンスが壊れるとのことでした。
裏付けるように以下のwarningも出ています。
/docs/subsec1.rst:4: WARNING: duplicate label probref, other instance in /docs/section1.rst
include
するファイルを subsec1.rst.txt
とリネームすると、上記の2で処理されなくなります。
これにより、同じラベルが2回出てこなくなるということですね!
Sphinxのドキュメント6には include
ディレクティブについて
単純に一つのファイルを別のファイルに"挿入"する場合、 include ディレクティブを使えます。
という注釈があるのですが、この「一つのファイル」がrst以外のファイルという前提があったことが分かりました。
拡張子を変えたあとの色分け設定(VSCode)
nikkieはVSCodeを使っていますが、subsec1.rst.txtを開くと、rstファイルで見られた色分けがされません(文字は白一色です)。
これは、Select Language Mode から reStructuredText を選択することで解決しました。
(追記)選択を頻繁に繰り返していたので .vscode/settings.json
に files.associations
を設定しました。
"files.associations": { "*.rst.txt": "restructuredtext" }
終わりに
rstファイルを分割して include
して使っていましたが、これはプラクティスに反していたことを身をもって体験しました。
拡張子を変えたことで、ref
やnumref
でラベルが参照されるようになり、心の平穏を取り戻しました。
Sphinxの動きはまだまだブラックボックスですが、昨年のPyCon JPの以下はチェックしようと思います。
- https://www.sphinx-doc.org/ja/master/usage/restructuredtext/roles.html#role-ref↩
- ↩
-
make html
の実行に使いました。PDFビルドに使うDockerイメージとSphinxのバージョンを合わせる意図でバージョン指定しています。↩ - リポジトリは https://github.com/sphinx-doc/docker 。DockerでLaTeXビルド環境が立ち上がってとても助かっています!↩
- 元のコメントでは subsec2.rst ですが、ラベルがある subsec1.rst のことを言っているのだと理解しました↩
- https://www.sphinx-doc.org/ja/master/usage/restructuredtext/directives.html#table-of-contents↩