432 Views
May 31, 21
スライド概要
「ゼロからのOS自作入門」を執筆する際に活用したOSSツールを紹介します。また、執筆中によく使ったGit Rebaseのテクニックも説明します。
サイボウズ・ラボ株式会社で教育向けのOSやCPU、コンパイラなどの研究開発をしています。
「ゼロからのOS自作入門」 の執筆を支える技術 2021年5月29日 OSC2021 Online/Nagoya @uchan_nos
自己紹介 内田公太 @uchan_nos サイボウズ・ラボ株式会社でOSと言語処理系の研究開発 自作OSもくもく会コアメンバー 校正協力 執筆 執筆
「ゼロからのOS自作入門」の紹介 「OS」を自分で作る過程を解説する書籍 他のOSに頼らず「Hello, world」を出力するアプリから始め、 30章で本格的なOSを作成 64ビット動作、メモリ管理、マルチタスク、ファイルシステム…… 本書で作成する「MikanOS」上で様々なアプリが動く様子
執筆に使ったツール Re:VIEW 太字指定などの各種マークアップ、索引指定、PDF化 review-text-imager アスキーアートで書いた図をPNGに変換する Git MikanOSの開発にも使用 git-extract-tags 引用するソースコードをGitリポジトリから取得する もちろん、全部OSSです!
Re:VIEW 書籍用マークアップ言語
書籍用マークアップ 書籍原稿には様々な指定が必要 太字、等幅フォント 図、表、リスト、コマンドラインの スタイル 図、表、リストの参照 章構成 執筆途中で紙面を確認したい 手軽にPDFを生成したい 書籍にはRe:VIEWがおすすめ! 書籍執筆用だけあり、必要な機能が 揃っている リストの例 ハローワールドプログラムの本体は@<tt> {Main.c}ファイルです。@<list>{day02 a_Main.c}にその全体を示します。ぱっと 見て@<chapref>{day01}で作った@<tt> {hello.c}よりすっきりしていることが分 かると思います。 Re:VIEWソースコードの例
Re:VIEW https://github.com/kmuto/review 書籍用のマークアップ言語+ビルドシステム Re:VIEW記法の原稿から、PDF、EPUB、HTML等に変換できる 日本人が開発の主体なので、日本語サポートがばっちり 2015年頃から開発され、最新が5.1.1 「ゼロからのOS自作入門」の原稿を書いていたころはバージョン3系 1年でメジャーバージョンが1上がるほど、開発が活発 技術書典で回を経る毎に使う人が増加していった(肌感)
Re:VIEW記法
「ゼロからのOS自作入門」で使った記法を一部紹介
等幅フォント
@<tt>{Main.c}
画像参照 @<img>{event-propagation}
画像埋め込み
//image[event-propagation][イベントの伝搬][scale=0.8]{
//}
索引登録 @<idx>{タイマ}
脚注参照 @<fn>{heavy-task}
脚注
//footnote[heavy-task][脚注本文]
ユーザ定義タグも作れる
等幅フォント化+索引登録
@<codeidx>{SendMouseMessage()}
ラフ図案を手軽に描く
ラフ図案 本文を執筆中に図を入れたくなることがある その場で本格的な作図をしたくない 本格的な作図により、本文用の脳内メモリが奪われる ASCIIアートで本文中に描いて、それを図の代用としたい //image[layering][レイヤによる画面描画][scale=0.9]{ マウスのレイヤ --> -------------------\ ---\ デスクトップの --> - \ \ ↑ \ <---\--- マウスのウィンドウ レイヤ \ \ ---\ \ -------------------\ \ -------------------//}
コメントを抽出してPNG化する Re:VIEWの「//image{…}」は、コメントが埋め込める →コメントを抽出してPNG化して埋め込めばいいかも? 専用ツールpngnize-image-bodyを作りました https://github.com/uchan-nos/review-text-imager 先ほどのコメントをPNG化した結果 ImageMagick + IPAゴシック でPNG生成
本文でMikanOSのソースコー ドを引用する
「ゼロからのOS自作入門」の特性 MikanOS自体の開発の歴史と、本文の執筆の歴史がある 本文でMikanOSのソースコードを引用する MikanOSの過去のバージョンを直したくなることがある 本文の説明をストレートにするため day01 day02 MikanOSの Gitリポジトリ コードの引用 本文の Gitリポジトリ day03
2つの歴史 MikanOSは大規模なソフトウェア →専用のリポジトリが欲しい https://github.com/uchan-nos/mikanos 本文も大規模になるので、バージョン管理したい https://github.com/uchan-nos/legacy-free-os-book MikanOSの実装を進めつつ本文を執筆 2つのGitリポジトリが、並行に進展
MikanOSのソースコードを引用する MikanOSのソースコードを解説するために、本文に引用したい 手動でコピペするとミスが出る Re:VIEWのファイル埋め込み機能が使えそう! #@mapfile(ファイル名)~#@end と書くと、そのファイルの内容を展開してくれる プリプロセッサが ソースコード を展開する //list[list_tag][リストタイトル]{ #@mapfile(foo.c) #@end //}
masterブランチから引用する? //list[main][MikanOSのメイン関数]{ #@mapfile(../mikanos/kernel/main.cpp) #@end //} 問題:最新版のソースコードを引用するので大丈夫? 答え:ダメ。章ごとに機能を追加していくから。 特定のバージョンを引用したい day03 day04 master MikanOSの Gitリポジトリ タグ 引用するバージョンを固定したい ブランチ
main.cppの内容の変遷
osbook_day03aのmain.cpp
extern "C" void KernelMain() {
while (1) __asm__("hlt");
}
main.cppを引用する
タグXのmain.cppを引用する
osbook_day03cのmain.cpp
#include <cstdint>
extern "C" void KernelMain(uint64_t frame_buffer_base,
uint64_t frame_buffer_size) {
uint8_t* frame_buffer = reinterpret_cast<uint8_t*>(frame_buffer_base);
for (uint64_t i = 0; i < frame_buffer_size; ++i) {
frame_buffer[i] = i % 256;
}
while (1) __asm__("hlt");
}
タグを指定して引用したい タグ毎にファイルを配置したディレクトリを用意すればできる 実際に、こんなディレクトリ構成にしてみた text/ images/ dayN.re … distrib/ dayN/ MikanLoaderPkg/Main.c kernel/main.cpp … …
タグを指定して引用する タグ毎にファイルを配置したディレクトリを用意すればできる 実際に、こんなディレクトリ構成にしてみた text/ images/ dayN.re … distrib/ dayN/ osbook_dayN MikanLoaderPkg/Main.c タグに対応 kernel/main.cpp … … 希望のタグから ソースコードを引用する
タグを指定して引用する
Re:VIEWを使った本文の例
//list[day02a_Main.c][EDK IIを使ったハローワールドアプリ(Main.c)][c]{
#@mapfile(../distrib/day02a/MikanLoaderPkg/Main.c)
#include <Uefi.h>
#include <Library/UefiLib.h>
EFI_STATUS EFIAPI UefiMain(
EFI_HANDLE image_handle,
EFI_SYSTEM_TABLE *system_table) {
Print(L"Hello, Mikan World!\n");
while (1);
return EFI_SUCCESS;
}
#@end
//}
ハローワールドプログラムの本体は@<tt>{Main.c}ファイルです。
@<list>{day02a_Main.c}にその全体を示します。
タグ内容を抽出するツール osbook_dayNというタグに対応するソースコードを取得し distrib/dayNディレクトリに展開したい 専用ツールgit-extract-tagsを作りました https://github.com/uchan-nos/git-extract-tags 使い方 $ git extract-tags -s distrib \ osbook_ ../mikanos プレフィクスが「osbook_」であるタグから ファイルを抽出してdistribに書き出す legacy-free-os-book/ text/ images/ dayN.re … distrib/ dayN/ … mikanos/ MikanLoaderPkg/ kernel/ … 想定するディレクトリ構成
MikanOSの過去のバージョン を直したくなることがある
ソフトウェアにはバグがある 執筆中にOSのバグを見つけることがよくある 解説文を書いていると、コードの動作を深く考えるから、余計に。 osbook_day06cでバグを入れてしまったことに 第20章を執筆中に気付くと、大変辛い。 6c、20という数字はただの例。後で見つかれば見つかるほど辛い 選択肢1:第20章に「osbook_day06cの実装にバグがあったので、 直します」みたいな解説文を書き、osbook_day20xを修正する 選択肢2:osbook_day06cに修正を加え、何事も無かったかのよう に執筆を進める
MikanOSの歴史を綺麗に保つ day06b day06c master MikanOSの Gitリポジトリ 本文の Gitリポジトリ … master … やはり「選択肢2」を取りたい 選択肢1の方がリアルな開発姿勢だが、解説がごちゃごちゃする ただでさえ大変なOS自作なので、解説くらいは綺麗にしたい Gitで過去のバージョンを修正するには? →リベース!
リベース 1. バグ修正を コミットする day06c day06b A … D C B master X a バグ修正コミット day06c day06b 2. リベースする A a … D C B C’ D’ X … master X’ リベース:Cのベースをaに付け替える
リベースの問題点 MikanOSの利用者が困惑する 公開されたブランチをリベースするのは混乱の元 MikanOSでは、しばらくはリベースがたくさん発生するよ、とREADME に書いた タグが付け変わらない day06cがCを指したまま C’を指して欲しい day06c a … D C B C’ タグを手動で付け替えるのは大変 BからXまでの、全タグを付け替える必要あり リベース作業はバグ発見のたびに何度も発生 D’ master X … X’
タグを付け替えるツール 元のブランチからリベース先のブランチへ各タグを移動したい 専用ツールgit-retagを作りました https://github.com/uchan-nos/git-extract-tags 使い方 $ git retag osbook_ old new プレフィクスが「osbook_」であるタグを、oldからnewへ付け替える tag2 tag1 C B A a B’ new E D C’ old D’ E’
タグ付け替えの例 「handle close button」と「exit task on window close」の間に修 正を挿入する例 挿入した修正「hoge-fix」 「osbook_dayX」というタグす べてを、「new-day30f」ブラン チに移動したい
git-retag使用例 git retag --dry-run osbook_ osbook_day30f new-day30f 指定した2つのブラン チの共通の祖先を見つ け、 プレフィクスが 「osbook_」であるタ グを移動する
Git rebase入門
コミットグラフを理解しよう リベース操作は複雑で分かりにくい? コミットグラフの変化が想像できるようになれば、怖くない! コミット:ワークツリー全体のスナップショット Diffではない ブランチ:コミットを指すラベル コミットの列、ではない ブランチ コミット A master B C D
コミットはDiffではない A B C コミットは、親に対する差分、ではない コミットは、ワークツリー全体のスナップショットである 1つのコミットは、管理対象の全ファイルの完全な内容を持つ もちろん、無変更のファイルの内容は持たない、などの最適化はある Diffではないので、自由に組み替え可能
リベース $ git checkout -b fix-bug B 《ワークツリーを修正》 $ git commit -a A B D C master fix-bug a $ git rebase fix-bug master A B fix-bug a C’ D’ master
リベース(interactiveモード) 非常に多用途な git rebase -i コミットの順番を入れ替える、 不要なコミットを捨てる、 コミットメッセージを修正する、など ここを入れ替えたいなあ…… $ git checkout master $ git rebase -i A 行を入れ替えて保存 A B C D master
git rebase -iのその他の機能
「pick」を希望のコマンドに書き換える
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#
# These lines can be re-ordered; they are executed from top to bottom.
コミットグラフを理解する便利なコマンド $ git log --graph --all ここでマージされた ここで枝分かれして
間違ったリベースを無かったことにする Git reflog 「ブランチやタグ等が、過去何を指していたか」が コミットやリベース等、Gitの操作をするたびに記録される リベースなどでミスしてもデータが失われるわけではないので、 安心して実験しましょう ブランチを任意のコミットに付け直すには $ git checkout <branch> $ git reset --hard <commit>
まとめ 「ゼロからのOS自作入門」の執筆に様々なOSSを使った Re:VIEW、review-text-imager、Git、git-extract-tags ラフ図案をASCIIアートで→pngnize-image-body 「ゼロからのOS自作入門」は2本のGitリポジトリで構成される タグを指定したソースコード引用を行いたい→git-extract-tags 引用プログラムのバグを直したい→git-retag リベースを使いこなそう