pandoc の使い方メモ — 相互参照について

やりたいことは「元の文章を markdown で複数のファイルに分割して書き、それをウェブで公開するために個々に HTML に変換したい。もう一方では印刷できるような一括した PDF を LaTeX 経由で作りたい。ついでに EPUB も作りたい」です。割とありがちなケースだと思うので、もっとすっきりした方法があるように思うのですが、うまく見つけられませんでした。

相互参照とは、HTML では id 属性と a タグで実現されるもの、LaTeX では \label{}\ref{} で表現されるものです。

索引は、LaTeX では後で処理するために \index{} で印を付けておくものです。HTML と EPUB では使いません。

例を挙げます。

a.md

はじめに {#hajimeni}
========

...

用意するもの
============

...

道具 {#dougu}
----

* 包丁
* まな板
* ...

これらは[「下ごしらえ」](b.html#shita)で使います。

* 大きな鍋\index{おおきななべ@大きな鍋}
* ...

これらは[「調理」](b.html#chouri)で使います。

材料 {#zairyo}
----

...

b.md

手順
====

下ごしらえ {#shita}
----------

ここで使う材料は[「材料」](a.html#zairyo)にまとめてあります。
...

調理 {#chouri}
----

...
大きな鍋\index{おおきななべ@大きな鍋}([「道具」](a.html#dougu)を参照のこと)を使います。
...

盛り付け {#moritsuke}
--------

おわりに
========

...


という文書が元になります。

HTML

a.md → a.html, b.md → b.html のように個々のページを独立して生成することにします。それを見越して、md ではリンクの書式のところにこれらのファイル名を入れておきます。

md を pandoc

pandoc -o a.html a.md
pandoc -o b.html b.md

と処理すると

a.html
<h1 id="hajimeni">はじめに</h1>
<p>...</p>
<h1 id="用意するもの">用意するもの</h1>
<p>...</p>
<h2 id="dougu">道具</h2>
<ul>
<li>包丁</li>
<li>まな板</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#shita">「下ごしらえ」</a>で使います。</p>
<ul>
<li>大きな鍋</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#chouri">「調理」</a>で使います。</p>
<h2 id="zairyo">材料</h2>
<p>...</p>
b.html
<h1 id="手順">手順</h1>
<h2 id="shita">下ごしらえ</h2>
<p>ここで使う材料は<a href="a.html#zairyo">「材料」</a>にまとめてあります。 ...</p>
<h2 id="chouri">調理</h2>
<p>... 大きな鍋(<a href="a.html#dougu">「道具」</a>を参照のこと)を使います。 ...</p>
<h2 id="moritsuke">盛り付け</h2>
<h1 id="おわりに">おわりに</h1>
<p>...</p>

ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

LaTeX 経由 PDF

ソースは複数ファイルに分割されていても最終的な成果物はひとつであってほしいため、main.tex を用意しておき、

main.tex
\documentclass[a5paper]{jarticle}
\usepackage[dvipdfmx]{hyperref}
\usepackage{makeidx}
\makeindex
\begin{document}
\tableofcontents
%
\input{a}
\input{b}
%
\printindex
\end{document}

これから dvi を作り、さらにそれから pdf を作ることにします(pandoc から PDF を出力させることもできるようですが、日本語のとおる環境を設定したり次に述べる処理を挟んだりするのがやりにくいので、こういうやり方にします)。

さて、ここで読み込まれる a.tex, b.tex を md から pandoc で生成するのですが、単純にやるだけでは、HTML 向けに書いていたリンクのところが

これらは\href{b.html\#shita}{「下ごしらえ」}で使います。

のようになってしまいます。これではよろしくないので、

sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' a.md \
| pandoc -t latex \
| sed 's/\(\\hyperref\[\([^\]*\)\]\)[\{][^\}]*[\}]/\1\{\\ref\{\2\}\}/g' \
> a.tex

のようにします。バックスラッシュと括弧だらけでわかりにくいですが、前段の sed

[「下ごしらえ」](b.html#shita)

[「下ごしらえ」](#shita)

のように、丸カッコ内のファイル名相当の部分を削除します。これで生成物の当該部分は

\hyperref[shita]{「下ごしらえ」}

となるので、後段の sed でこれを

\hyperref[shita]{\ref{shita}}

のように書き換えます。

これにより、生成物は

a.tex
\section{はじめに}\label{hajimeni}

\ldots{}

\section{用意するもの}\label{ux7528ux610fux3059ux308bux3082ux306e}

\ldots{}

\subsection{道具}\label{dougu}

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  包丁
\item
  まな板
\item
  \ldots{}
\end{itemize}

これらは\hyperref[shita]{\ref{shita}}で使います。

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  大きな鍋\index{おおきななべ@大きな鍋}
\item
  \ldots{}
\end{itemize}

これらは\hyperref[chouri]{\ref{chouri}}で使います。

\subsection{材料}\label{zairyo}

\ldots{}
b.tex
\section{手順}\label{ux624bux9806}

\subsection{下ごしらえ}\label{shita}

ここで使う材料は\hyperref[zairyo]{\ref{zairyo}}にまとめてあります。 \ldots{}

\subsection{調理}\label{chouri}

\ldots{}
大きな鍋\index{おおきななべ@大きな鍋}(\hyperref[dougu]{\ref{dougu}}を参照のこと)を使います。
\ldots{}

\subsection{盛り付け}\label{moritsuke}

\section{おわりに}\label{ux304aux308fux308aux306b}

\ldots{}

となります。

これで相互参照が正しくなった中間ソース a.tex, b.tex ができましたので、main.tex を

platex main
platex main
mendex main
platex main
dvipdfmx main

と処理して、最終的に main.pdf を得ることができます。

EPUB

pandoc は EPUB 形式を出力することもできます。

ソースは複数ファイルに分割されていても成果物はひとつにまとまっていたほうがいいので cat でつなぎます。また、HTML 向けに付けていたリンクの書き方を変更して(LaTeX の場合の前処理と同じです)、pandoc にかけます。

cat a.md b.md \
| sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' \
| pandoc --self-contained -o main.epub

これで最終成果物の main.epub ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

HTML や LaTeX、EPUB を出力する際には、もっと適切な pandoc のオプションを付けたり、テンプレートを用意したほうがいいのですが、ここでは相互参照に絞って説明するため、これらを割愛しました。

KVM に Kernel Samepage Merging (KSM)

いわゆる自宅サーバーの機器を更新し、これを機にソフトも KVM の上に載せてみることにしました。

用途と向きによって仮想サーバーを切り分けます。ホストも複数のゲストも、ぜんぶ Debian で同じバージョンです。ネットの検索によって得た知識でも何とかなります。

当初気づかずに、後から「こういうのがあるのか」と気づいたのが、KSM (Kernel Samepage Merging) でした(解説はたとえば Linux カーネル共有メモリーの徹底調査)。

KVM on Debian Squeeze – My Notes を参考に設定しました。

ホストとゲストの両方で /etc/rc.local を編集し、次を追加します。

echo 1 > /sys/kernel/mm/ksm/run
echo 300 > /sys/kernel/mm/ksm/sleep_millisecs

再起動後、/sys/kernel/mm/KSM/pages_sharing がゼロより大きな値になっていれば、有効になっています。

KSM は使わないほうがいい?

さて、はじめ気づかなかった KSM についての情報に行き当たったのは、とりあえずしばらく動かしていると、ゲストOSが徐々にメモリを食いつぶしていくという現象をどうにかしたいと思って調べてみたからです。 そこで上記のように KSM を有効にしてみたのですが、引き続き検索していると、「KVMで複数VMを起動してVM間の相互作用を減らしたいときに考えること 」という記事を見つけました。
  • メモリはオーバーコミットしない
    • メモリをオーバーコミットするとろくなことがありません。なので要るだけ積みあげます。安いし。
      • 特にゲストOSがlinuxの場合、メモリはあるだけ使おうとする。本来だとキャッシュとしての有効活用になるキャッシュを積極的に使う戦略が、メモリオーバーコミット環境下ではswapを多発させる原因になってしまう

うーむ。これが原因かもしれません。個々のゲストはさほど深刻な負荷があるわけではなし、一方が急に働くことになっても他方はそれほどでもないことがほとんどなので、個々のゲストのメモリ割り当てを、ほぼ実メモリと同じくらい、としていました。すなわち、ゲストに割り当てたメモリを合計すると実メモリの数倍になっていました。しかし、この記述によると

    • メモリは足りてるはずなのでKSMは停止する

確かに KSM はホストに負荷がかかるので、動かさずに済むならそのほうがいいかもしれません。

もうしばらく様子を見ながら(まだ理解できていないことも多いし)、考えたいと思います。