プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

Wordを捨ててTeXでドキュメントを自動生成しようじゃないか

 やーやーやー

  •  シミュレータや合成ツールに金出したら、もう金がないので、チップの検証環境を自作
  •  金がないので、RTL自動生成を自作
    •  気がつけば10モジュールぐらい担当してた
  •  金がないので、RedmineとGitbuket、Rocket.Chat、TestLinkを導入して、開発環境と検証環境と連携するシステムを自作

 

 と、命令された訳でも無いのに、ひたすら文句を言い続けてたら、いつの間にかこんな状況になってしまった。ついでの過去の罪状として、プログラムの開発環境が貧弱と文句を言っていたら、いつの間にか統合開発環境(IDE)を自作していた。器用貧乏を地で行っている気がしてならない。

 

 現状を現状のままに受け入れる力が、社会人に最も重要な能力。みんなは黙って働こう。

 

 

ドキュメントを自動生成したい

 プロダクトに関わると、どうしても設計資料とは別に、利用者の為のドキュメント(データシート)を、どこかの時点で用意する必要に迫られる。

 数ページ済む様なデータシートならどうとでもなるが、1000pにもなりそうなデータシートなんて、手で書いていられない。そもそも、プロトタイプではAだったが、具合を見て変わる予定という情報は匂いすぎる。予言者でなくとも、ドキュメントがバグる未来が見える。

 仕様書やデータがあるなら、ドキュメントは自動生成してしまった方が、安心安全だ。しかし、金はない。仕方がない、またしても余計な仕事を勝手に抱えようじゃないか

 

 では、どうやってドキュメントを自動生成するか。

 途中工程によっても違うだろうが、極論をしてしまえば、ドキュメントは最後にPDFになりさえすれば良い。自動生成プログラムから直にPDFを吐き出すことも不可能ではないが、手段はおおよそ以下の二つだろう。

  • Wordを生成し、WordからPDFにする
  • PDFに変換出来る言語(TeXなど)を生成する

 

Wordを使う選択肢

 私は、最初は諸々の政治的な理由からWordの自動生成を試した。

 しかし、Wordの自動生成は無理と言わんが、片手間に出来るレベルじゃないと言って良い。理由を語ろう。

 それぞれの場面において、ドキュメントを作成する為のフォーマットガイドはあるだろう。例えばフッターだったり、ヘッダーだったり、フォント、表の配置、行間等など、それを従ってなくては怒られる。 書籍を出す訳でもないのに、フォーマットを確認する費用で、何円の価値が生まれるのか、私には甚だ疑問だが。

 一般的に、処理とデータ(文章)と、フォーマット(文章の見た目)は別個に管理することが、見通しも、プログラマの精神衛生的にもとてもよろしい。しかし、Wordを自動生成をする場合、これらをゴッチャにして、ガイドを満たす様にプログラムを組まなくてはならない。反吐が出る。

 仮にスタイルのテンプレートファイルを使うとしても、細かいルールが全てスタイルの設定で解決する訳ではない。細かい計算をする必要はある。例えば、表は画面幅いっぱいとかいうルールは、スタイルで解決しない。だいたい、そもそものスタイルテンプレートファイルが変更されたら、どうするというのだ。

  

 更にまだ問題はある。

 ドキュメントの全てを自動生成出来るはずもない。かならず、手作業でドキュメントを作る部分は存在する。

 巨大な自動生成したドキュメントなら、別冊で良いだろう。では、2、3文の程度の、断片的な自動生成可能な情報は?1つ程度の表は?数値は?単語は?手作業で作るドキュメントに追加したい、小さな自動生成情報はどうするというのだ?

f:id:nodamushi:20190323205333p:plain:w320

 こういうものも、出来れば自動生成しておきたい。しかし、これをWordで上手く解決する手段を、私は思いつかなかった。何か良い手段があれば、是非教えて頂きたい。

 どうしてもWordファイルに拘り、手作業で書くドキュメントと、自動生成の融合を図り、Wordの様なバカ向け……WYSIWYGに拘るなら、Blogの様なWYSIWYGなシステムを提供し(なお、この記事はMarkdownで書かれてる)、Wordファイルを出力するシステムを作るしかないだろう。

 お金があるなら、それはとても良いことだ。ベンダーにお金を払えば良い。それらのシステムが出来ないことは、絶対にありえない。Office365はブラウザで動くのだから。

 しかし、お金がないからこういう問題に頭を悩ます訳で。

 むろん、私が死ぬまで働いて解決出来るなら、私一人で死ねば良い。歯車一つ壊れる程度は、コラテラル・ダメージでしかない。だが、私一人死んだからと言って、システムが完成する未来は見えない。完成するにしても、間に合うことは絶対にない。そのぐらい大きな規模のシステムになる。

 

 

ドキュメントにTeXを使う選択肢

 

 Wordで自動生成と手作業ドキュメントの統合は諦めた。ならば、残る選択肢は以下の三つだ。

  • 自動生成を諦める
  • 統合だけを諦める(Wordを自動生成するという選択肢は残る)
  • もう、Wordを使わない

 もちろん、自動生成を諦めるという選択肢は論外だが、どれにせよ、全員で痛みを共有することになる。

 ところで、なぜ、Wordファイルでなくてはならないのかというのは、大抵、査読等の理由だ。しかし、そもそも、自動生成されたWordを修正をしたところで、意味が無い。真に修正すべきはデータベースと自動生成プログラムであり、Wordファイルではない。更に言えば、毎回自動生成されるのだから、Wordファイルに履歴は残らない。そうなると、WordでPDFを編集出来るのだから、もはやWordに拘る理由がない。後は政治的な理由のみだ。

 どの手段を選ぶにせよ、自動生成するプログラムがWordを吐き出す正義はなくなった。

 ではWord以外の、何を生成すべきか、何でPDFを生成すべきか、だ。

  • TeX
  • Re:VIEW
  • troff

 まだあるかも知れないが、私が知っているのはこの程度だ。

 新しい物好きな私は、Re:VIEWにしようかなとも思ったのだが、よく読むと、結局の所LaTeXを作成してPDFにするらしい。レイアウトの細かい調整をするには結局TeXを弄る必要がある。だったら、学生の頃よく使ってたし、しょぼい処理系を作ったこともあるTeXでいっかということで、TeXを生成することにした。

 そして、TeXの場合、マクロを提供するという形で、自動生成ドキュメントと、手作業によるドキュメントの統合が可能になる。「初期のモードは\initmode です」と書いておけば、コンパイル時に\initmode が適切な文字列に変わるのだ。

 ならば、もう選ぶべき手段は、Wordを使わない、である。容易な手段が転がっているのに、それを使わないというのか。

 WYSIWYGなんて、もういいじゃないか。マイクロソフトに保護に抱かれて気持ちよかっただろう?コンピュータを、人間の直感の為に改良してくれて、とても安心出来ただろう?コンピュータという気味が悪いナニカに、親しむことが出来ただろう?でも、それは必ずしも、コンピュータをコンピュータとして、効率よく使っているとは限らない。いい加減、コンピュータをコンピュータとして使おうじゃないか。

  f:id:nodamushi:20190323215020p:plain

 と、いうわけで、上司に昼飯時にぼやいてみたら、ノリに乗ってくれて、そのまま公式に認められてしまった。素晴らしい上司である。

 

 

TeXを何処まで自動生成するか

 さぁ、TeXを使うと決まった。

 TeXならテキストファイルを書き出すだけなので、ライブラリも特に何もなくても作れる。とても楽である。 と言って、何も考えずに「\section{ほげ} \begin{table}[h] ~~~」などと吐き出すのは、やめた方がいい。

 文章やドキュメント構成を全てプログラムで行うと、校正でダメ出しされるときが面倒くさい。プログラムを修正し、再生成しなくてはならない。運用次第ではあるが、それぞれのメンバーごとに、ファイルを自動生成する様な仕組みなら、ちょっとやっていられない。

 そもそも、TeXはほぼ何でも出来るのだ。言ってしまえば、データさえあれば、ドキュメント構成は全てTeXで処理することだって可能だ。

 ドキュメントの構成を全てTeXに任せてしまうのなら、自動生成するプログラムはデータをシリアライズして、書き出すだけである。TLCのリストみたいな感じに書き出しておくと、扱いやすい。

\def\data{%
  {peripherals}{%
    {%
      {name}{DMA}%
      {address}{{4981504}{4C0300}}%
      {registers}{%
        {%
          {name}{CTRL}%
          {address}{{4981504}{4C0300}}%
          {fields}{%
            .............以下略............
}

 これだと、自動生成する側のやることはほとんど無くて、管理が楽である。やることと言えば、_&^等の文字をエスケープするのと、10進数、16進数、2進数の数値データを用意してあげる位だ。 (n進数変換はTeXでやろうとしたのだけど、TeXのカウンターは32bit符号付き整数なので、大きな数字はやりにくい。出来ないことは無いけど。)

 ドキュメントにダメ出しが入っても、プログラムを修正する必要も、再生成する必要もなく、TeXを再コンパイルするだけで良い。実に楽だ。

 じゃぁ、これで万事解決かというと、そうでもない。

 

 話は突然変わるが、皆さんは約千行のプログラム、と聞いてどんな印象を持つだろうか?

 無論、プログラムというのはその機能や、管理のしやすさと言った面から評価すべきであり、行数は大した価値を持つべきではない。それは千も承知の上で、ただただ、千行のプログラム、で考えてみて欲しい。

 まぁ、半日~1日ぐらいで書き殴ったプロトタイプかな、という印象ではなかろうか。

 で、今回、私はTeXのマクロを1000~2000行程書いたが、気がつけば2週間過ぎている。マジか。

 慣れていないから、というのもその通りなのだが、ひじょーにデバッグしにくい。いや、マジで。高々if文で躓くし、expandafterで、noexpandで、relaxで、table環境の\hlineで、tabularxで、ありとあらゆるところでゲロを吐く羽目になった。

 一度躓くと、エラーが何処で起こってるのか分からない。プログラミングなら、エラーが起こった場所はブレークポイントなりで解析出来るが、TeXの場合はどういう展開になるのか見てくしかない。

 

 というわけで、素人に毛が生えた程度で何でもTeXでやってやるぜ、というのはやめた方がいい。いたぶられ続けて、段々トランスして、気持ちよくなってくる快感を味わいたいなら止めはしないが。アンッ♡

 どの程度をTeXで処理し、どの程度をプログラムでやるのか、その辺は技量と運用方法と性癖をよく考えながら作る必要がある。

 

 

TeXの環境を整備しよう

 TeXを使います!TeXを自動生成しました!はい、後はみんな頑張って!よっしゃ、お終い!というほど話は簡単ではない。TeXを使わせるなら、TeXを使うなりのシステムを用意する必要がある。

 少なくとも、みながTeX素人なら、以下の内容について言い出しっぺが準備する必要がある。(私も正直TeXの素人に毛が生えた程度だが)

 

  • どのTeXエンジンを使うかの選定と、インストール方法の定義
  • TeXの使い方の講習
  • ドキュメントガイドに沿ったクラスファイルの作成
  • 表、画像などを統一する為のマクロ(スタイル)の提供
  • その他、チーム特有の問題を解決する為のスタイルの提供
  • チームでファイルを分割してコンパイルする環境整備
  • Git管理の手法
  • Lintツールの導入

 

 

LuaLaTeXを使おう

 TeXかLaTeXか新規に選択しろ、というなら普通にLaTeXを選べば良い。ConTeXtは安定してないのでどうなんだろうね。わからん。

 LaTeXが提供するマクロを捨てて、TeXだけで闘う理由は特に思い当たらない。別に原理主義に陥る必要は全くない。

 次にどのTeXエンジンを使うか、である。単にTeXといっても、幾つかの処理系があり、処理系ごとに特色が微妙に異なる。同じOSで、だいたい同じような機能は提供してても、Windows、Mac、Linuxで操作が微妙に異なる様な物だ。

 これは作成するドキュメントガイド次第ではあるが、細かくフォントの指定がされているなら、LuaTeXを使うことをお勧めする。

 10年ま………ゲフン、ゲフン、学生だった頃に使ってたpLaTeXを最初弄っていたのだが、クッソメンドイ。やってられん。XeTeXも試してみたのだが、どうも日本語のフォントを切り替えるのが、上手くいかなかった。

 で、LuaTeXなのだが、これがクッソ楽だった。とりあえず、\newjfontfamilyでフォント定義しておいて、必要な場面で使えばいいだけなのだ。

 過去の資産も何もない状態なら、LuaTeXはとても良い選択肢だろう。

 

 

 ただ、幾つかの致命的注意点が存在する。

 まず、致命的にクソ遅い。pTeXなら、ペペペっと終わる処理が、LuaTeXだとぺーーーぺーーー(固まる)ぺーーーーって感じだ。たぶん、4,5倍は遅い。気分的には10倍以上遅い。精神衛生を侵し、SAN値を削ってくる。命に関わるといってよい

 最終的なドキュメントはLuaLaTeXで処理して、普段はフォント設定無視して、pLaTeXで結果を見るのが良いと思う。むろん、時々ちゃんとLuaLaTeXで処理して、確認しないと後で痛い目を見そうだが。普段からずっとLuaTeXを使う場合でも、フォント設定は切っておいた方がいい。少しは速くなる。

 そのため、提供するマクロにLuaを使わない方がいい。Luaを使うと、デバッグがしんどいマクロ作成が非常に楽になるのだが、私はSAN値が削れることに耐えられない。チマチマLaTeXに修正中である。

 

 次に、致命的にメモリを食う。とりあえず、500pぐらいのドキュメントを自動生成したのだが、余裕で2Gbのメモリを消費した。1000pぐらいになったら、そもそも32bitでメモリ足りるのか疑問である。

 最後に、仕様が安定していない。私はTeXLive2018を使っているが、TeXLive2019ではLuaのバージョンが5.2から5.3になるらしい。このとき、Luaの後方互換は破壊的であるそうだ。事故る未来が見える。

 さらに、同じTeXLive2018でも、ISO版(2018年4月版)と、常に最新版が入るインターネットインストーラ版で挙動が異なる。特に、何故かフォントに游明朝の太字(YuMincho Demibold)を使うと、インターネットインストーラ版ではメモリエラーが発生する。これはW32TeXでもだった。年間を通して、エンジンは同じらしいので、パッケージのバグだとは思う。

 従って、LuaTeXを使う場合、私から言えるアドバイスは以下である。

  • インストール日付に依存せず、全員同じ環境になるインストールの仕組みを定義せよ。TeXLive2018ならISO版を使うことを推奨する。(2019以上の場合は知らない)
  • アップデートは検証を行った後で、許可をせよ
  • TeXLiveは32bitしかインストールされないので、64bitエンジンのインストール手段を定義せよ。メモリ足りなくなってから泣いても知らん
  • PCのメモリは8Gbじゃ足りない
  • 提供するマクロはLuaに依存しない方がいい

 

 

クラスファイルを定義しよう

 ドキュメントの見た目を定義するのがクラスファイルである。\documentclass{jsarticle}とか書いてる所のjsarticleの部分だ。

 余白やフォント、ヘッダーフッター、行間、chapter、sectionの文字などを設定するのだが、全て0から定義するのは大変すぎる。無理せず\LoadClassで提供されている既存のクラスファイルを読み込み、必要に応じてハックしたり、設定を書き換えるのが良い。

 なお、間違ってもjsarticle.clsなどの実際のファイルを書き換えるべきではない。ライセンス的にどうなんだという話と、個人の環境に依存してしまうのが怖い。必ず、\LoadClassで読み込んでから必要な関数を上書きしたりしよう。

 大体次の内容を作れば十分だろう。

  • 表紙
  • 目次ページのカスタマイズ
  • ヘッダー、フッター
  • Confidentialのオプション
  • フォント
  • chapterやsectioの表現
  • 表、図、式のcaptionでの表現(図:1-1とか)
  • 表、図、式と文字の行間
  • item環境の●や■の文字
  • enumerate環境の連番表示の仕方
  • easylistの調整
  • listingsの設定(フレームやフォントなど)

 

 

ところで、Windowsフォントについて

 ガイドにWindowsのフォントが指定されていて、私は驚愕した。PDFにする以上、普通はフォントを埋め込む。それにWindowsフォントを使うのか!?と。ライセンスは大丈夫なのかと。

 しかし、それは私が学生だった10ね………数年前の話であり、今は状況が違っている。2017年にWindows標準フォントについて、ついにMicrosoftが沈黙を破り、その指標を公開していた

 読んでみた限り、PDFを暗号化し、編集不可能にしておけば、Windows標準フォントに関しては、Windows上でPDFを作成する限り、PDFに埋め込んで良いと思われる。(必ず原文を当たり自分で確認すること)

 ※Wordに付属して付いてくるフォントは標準フォントではない。HG●●フォントとか。

 

スタイルファイルを定義しよう

 クラスファイルを作ったら、次はスタイルファイルの定義だ。

 どんなマクロが必要かはチームによって違うだろうが、少なくとも以下は用意したい。

 

  • 図を読み込むマクロ(コマンド一つで表示できるように)
  • 複数の図を読み込むマクロ(図1(a)みたいに参照できるように)
  • キャプションを引数として受け取る表環境(上にキャプションを付けるのか、下に付けるのか固定)
  • 表、図、式へのref(図1、表1、式(1)みたいに接頭辞が必要ならそれも強制的に付けてしまえ)
  • inputやsubfile、includegraphicsなどのファイル読み込みを、現在のファイルからの相対パスで読めるコマンドで出来るコマンドの用意。

 

 特に、複数人でファイルを分割して作業する場合、input系のマクロは事故る未来しか見えないので、必ず現在のファイルからの相対パス化したい。\currfiledirを引数の前に付加するだけで良い。

 これらを準備した上で、各チームごとに必要なマクロを定義しよう。例えば、ペリフェラルのレジスタを参照するマクロとかを私は用意した。

 個人的には、PAD図をTikzで簡単にかける様にしたい。けど、Tikz全然分からない。  

 

ファイルの分割について

 inputを使うよりもsubfileを使った方がいい。subfileで分割すると、個別にコンパイルが出来るので、全部をコンパイルすると死ぬ程遅いLuaTeXでも、致命傷程度の速度でコンパイル出来る。

 そのために、プリアンブルだけ定義したtexファイルは一番最初に用意しておこう。

 

 

RedPen

 今時、Lintもなしにドキュメントを書くなんて考えられない。なお、このブログは特にLintは使っていない。(オイ

 Wordなら、Wordが色々とウザいお節介を焼いてくれるが、TeXだと、色々お膳立てしなければならない。

 Markdownで使ってるTextLintLaTeX拡張があるが、どうも使いにくかった。調べてみたら、RedPenがデフォルトでLaTeXに対応しているので、これを導入することにした。

 ただ、このRedPenは実行にJavaが必要なのが悩み所。一般人はジャバってなーにと言うレベルだ。特に今は無償で公式のJREのみのインストーラが無くなったのだから、余計に説明が面倒だ。まぁ、TextLintだってnode.jsという謎の危険が危ないナニカが必要なので、大差はない気もするが…

 RedPenにはサーバー機能があるので、社内サーバーを用意するか、ファイルサイズがでかくても、exe化した方がいい。通信して外に出しても良いというなら、公式のRedPenサーバーReadmeに従って、Herokuを使ってみてもいいだろう。どうするかは、運用次第だが、とにかく、Javaは一般人にとって、百害あって一利無しである。

 また、サーバーにする場合は、コマンド一つでサーバーに対してリクエストを発行し、返ってくるJSONを解析してエラー箇所を表示する仕組みを作る必要がある。 全員がEmacsかAtomを使ってくれるなら、プラグインで解決出来るが、TeXWorksだと、どうしてもそういう準備は必要だ。

 

終わりに

 うーわ、久しぶりのブログ長っ。1万文字だとよ。

 というわけで、いつもの発作でまた余計な仕事を抱えた私が、やってみたことをまとめてみた。ドキュメントを自動生成したいけど金がない、システムに金かけるのは無駄、という人々の手掛かりになれば幸いである。そして、いずれはドキュメントの自動化に金を払ってもらう足がかりにしよう。

 作ったんだから、死ぬまでオメーが管理しろ、というのであれば…………辞めるしかないかな。