OSC2021 Nagoya 「ゼロからのOS自作入門」の執筆を支える技術

128 Views

May 31, 21

スライド概要

「ゼロからのOS自作入門」を執筆する際に活用したOSSツールを紹介します。また、執筆中によく使ったGit Rebaseのテクニックも説明します。

profile-image

サイボウズ・ラボ株式会社で教育向けのOSやCPU、コンパイラなどの研究開発をしています。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

「ゼロからのOS自作入門」 の執筆を支える技術 2021年5月29日 OSC2021 Online/Nagoya @uchan_nos

2.

自己紹介 内田公太 @uchan_nos サイボウズ・ラボ株式会社でOSと言語処理系の研究開発 自作OSもくもく会コアメンバー 校正協力 執筆 執筆

3.

「ゼロからのOS自作入門」の紹介 「OS」を自分で作る過程を解説する書籍 他のOSに頼らず「Hello, world」を出力するアプリから始め、 30章で本格的なOSを作成  64ビット動作、メモリ管理、マルチタスク、ファイルシステム…… 本書で作成する「MikanOS」上で様々なアプリが動く様子

4.

執筆に使ったツール Re:VIEW  太字指定などの各種マークアップ、索引指定、PDF化 review-text-imager  アスキーアートで書いた図をPNGに変換する Git  MikanOSの開発にも使用 git-extract-tags  引用するソースコードをGitリポジトリから取得する もちろん、全部OSSです!

5.

Re:VIEW 書籍用マークアップ言語

6.

書籍用マークアップ 書籍原稿には様々な指定が必要  太字、等幅フォント  図、表、リスト、コマンドラインの スタイル  図、表、リストの参照  章構成 執筆途中で紙面を確認したい  手軽にPDFを生成したい 書籍にはRe:VIEWがおすすめ!  書籍執筆用だけあり、必要な機能が 揃っている リストの例 ハローワールドプログラムの本体は@<tt> {Main.c}ファイルです。@<list>{day02 a_Main.c}にその全体を示します。ぱっと 見て@<chapref>{day01}で作った@<tt> {hello.c}よりすっきりしていることが分 かると思います。 Re:VIEWソースコードの例

7.

Re:VIEW https://github.com/kmuto/review 書籍用のマークアップ言語+ビルドシステム  Re:VIEW記法の原稿から、PDF、EPUB、HTML等に変換できる  日本人が開発の主体なので、日本語サポートがばっちり 2015年頃から開発され、最新が5.1.1  「ゼロからのOS自作入門」の原稿を書いていたころはバージョン3系  1年でメジャーバージョンが1上がるほど、開発が活発  技術書典で回を経る毎に使う人が増加していった(肌感)

8.
[beta]
Re:VIEW記法
「ゼロからのOS自作入門」で使った記法を一部紹介

等幅フォント
@<tt>{Main.c}
画像参照 @<img>{event-propagation}
画像埋め込み

//image[event-propagation][イベントの伝搬][scale=0.8]{
//}
索引登録 @<idx>{タイマ}
脚注参照 @<fn>{heavy-task}
脚注
//footnote[heavy-task][脚注本文]
ユーザ定義タグも作れる
 等幅フォント化+索引登録

@<codeidx>{SendMouseMessage()}

9.

ラフ図案を手軽に描く

10.

ラフ図案 本文を執筆中に図を入れたくなることがある その場で本格的な作図をしたくない  本格的な作図により、本文用の脳内メモリが奪われる ASCIIアートで本文中に描いて、それを図の代用としたい //image[layering][レイヤによる画面描画][scale=0.9]{ マウスのレイヤ --> -------------------\ ---\ デスクトップの --> - \ \ ↑ \ <---\--- マウスのウィンドウ レイヤ \ \ ---\ \ -------------------\ \ -------------------//}

11.

コメントを抽出してPNG化する Re:VIEWの「//image{…}」は、コメントが埋め込める →コメントを抽出してPNG化して埋め込めばいいかも? 専用ツールpngnize-image-bodyを作りました  https://github.com/uchan-nos/review-text-imager 先ほどのコメントをPNG化した結果 ImageMagick + IPAゴシック でPNG生成

12.

本文でMikanOSのソースコー ドを引用する

13.

「ゼロからのOS自作入門」の特性 MikanOS自体の開発の歴史と、本文の執筆の歴史がある 本文でMikanOSのソースコードを引用する MikanOSの過去のバージョンを直したくなることがある  本文の説明をストレートにするため day01 day02 MikanOSの Gitリポジトリ コードの引用 本文の Gitリポジトリ day03

14.

2つの歴史 MikanOSは大規模なソフトウェア →専用のリポジトリが欲しい  https://github.com/uchan-nos/mikanos 本文も大規模になるので、バージョン管理したい  https://github.com/uchan-nos/legacy-free-os-book MikanOSの実装を進めつつ本文を執筆 2つのGitリポジトリが、並行に進展

15.

MikanOSのソースコードを引用する MikanOSのソースコードを解説するために、本文に引用したい 手動でコピペするとミスが出る Re:VIEWのファイル埋め込み機能が使えそう!  #@mapfile(ファイル名)~#@end と書くと、そのファイルの内容を展開してくれる プリプロセッサが ソースコード を展開する //list[list_tag][リストタイトル]{ #@mapfile(foo.c) #@end //}

16.

masterブランチから引用する? //list[main][MikanOSのメイン関数]{ #@mapfile(../mikanos/kernel/main.cpp) #@end //} 問題:最新版のソースコードを引用するので大丈夫? 答え:ダメ。章ごとに機能を追加していくから。 特定のバージョンを引用したい day03 day04 master MikanOSの Gitリポジトリ タグ 引用するバージョンを固定したい ブランチ

17.
[beta]
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");
}

18.

タグを指定して引用したい タグ毎にファイルを配置したディレクトリを用意すればできる 実際に、こんなディレクトリ構成にしてみた text/ images/ dayN.re … distrib/ dayN/ MikanLoaderPkg/Main.c kernel/main.cpp … …

19.

タグを指定して引用する タグ毎にファイルを配置したディレクトリを用意すればできる 実際に、こんなディレクトリ構成にしてみた text/ images/ dayN.re … distrib/ dayN/ osbook_dayN MikanLoaderPkg/Main.c タグに対応 kernel/main.cpp … … 希望のタグから ソースコードを引用する

20.
[beta]
タグを指定して引用する
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}にその全体を示します。

21.

タグ内容を抽出するツール 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/ … 想定するディレクトリ構成

22.

MikanOSの過去のバージョン を直したくなることがある

23.

ソフトウェアにはバグがある 執筆中にOSのバグを見つけることがよくある  解説文を書いていると、コードの動作を深く考えるから、余計に。 osbook_day06cでバグを入れてしまったことに 第20章を執筆中に気付くと、大変辛い。  6c、20という数字はただの例。後で見つかれば見つかるほど辛い 選択肢1:第20章に「osbook_day06cの実装にバグがあったので、 直します」みたいな解説文を書き、osbook_day20xを修正する 選択肢2:osbook_day06cに修正を加え、何事も無かったかのよう に執筆を進める

24.

MikanOSの歴史を綺麗に保つ day06b day06c master MikanOSの Gitリポジトリ 本文の Gitリポジトリ … master … やはり「選択肢2」を取りたい  選択肢1の方がリアルな開発姿勢だが、解説がごちゃごちゃする  ただでさえ大変なOS自作なので、解説くらいは綺麗にしたい Gitで過去のバージョンを修正するには? →リベース!

25.

リベース 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に付け替える

26.

リベースの問題点 MikanOSの利用者が困惑する  公開されたブランチをリベースするのは混乱の元  MikanOSでは、しばらくはリベースがたくさん発生するよ、とREADME に書いた タグが付け変わらない  day06cがCを指したまま  C’を指して欲しい day06c a … D C B C’ タグを手動で付け替えるのは大変  BからXまでの、全タグを付け替える必要あり  リベース作業はバグ発見のたびに何度も発生 D’ master X … X’

27.

タグを付け替えるツール 元のブランチからリベース先のブランチへ各タグを移動したい 専用ツール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’

28.

タグ付け替えの例  「handle close button」と「exit task on window close」の間に修 正を挿入する例  挿入した修正「hoge-fix」  「osbook_dayX」というタグす べてを、「new-day30f」ブラン チに移動したい

29.

git-retag使用例  git retag --dry-run osbook_ osbook_day30f new-day30f  指定した2つのブラン チの共通の祖先を見つ け、  プレフィクスが 「osbook_」であるタ グを移動する

30.

Git rebase入門

31.

コミットグラフを理解しよう リベース操作は複雑で分かりにくい? コミットグラフの変化が想像できるようになれば、怖くない! コミット:ワークツリー全体のスナップショット  Diffではない ブランチ:コミットを指すラベル  コミットの列、ではない ブランチ コミット A master B C D

32.

コミットはDiffではない A B C コミットは、親に対する差分、ではない コミットは、ワークツリー全体のスナップショットである 1つのコミットは、管理対象の全ファイルの完全な内容を持つ  もちろん、無変更のファイルの内容は持たない、などの最適化はある Diffではないので、自由に組み替え可能

33.

リベース $ 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

34.

リベース(interactiveモード) 非常に多用途な git rebase -i  コミットの順番を入れ替える、  不要なコミットを捨てる、  コミットメッセージを修正する、など ここを入れ替えたいなあ…… $ git checkout master $ git rebase -i A 行を入れ替えて保存 A B C D master

35.
[beta]
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.

36.

コミットグラフを理解する便利なコマンド $ git log --graph --all ここでマージされた ここで枝分かれして

37.

間違ったリベースを無かったことにする Git reflog  「ブランチやタグ等が、過去何を指していたか」が  コミットやリベース等、Gitの操作をするたびに記録される リベースなどでミスしてもデータが失われるわけではないので、 安心して実験しましょう ブランチを任意のコミットに付け直すには $ git checkout <branch> $ git reset --hard <commit>

38.

まとめ 「ゼロからのOS自作入門」の執筆に様々なOSSを使った  Re:VIEW、review-text-imager、Git、git-extract-tags ラフ図案をASCIIアートで→pngnize-image-body 「ゼロからのOS自作入門」は2本のGitリポジトリで構成される タグを指定したソースコード引用を行いたい→git-extract-tags 引用プログラムのバグを直したい→git-retag リベースを使いこなそう