Vagrantを利用してMikanOSをビルドする

# Vagrantとは

簡単な設定ファイルを書いて簡単なコマンドを実行することで、
簡単に仮想マシンを立ち上げることができるソフトウェア。
単に仮想マシンを立ち上げるだけでなく、
設定ファイルに開発環境などの構築(プロビジョン)の手順を記述し、実行させることができる。

[Vagrant by HashiCorp](https://www.vagrantup.com/)

※簡単かどうかの感じ方には個人差があります

仮想マシンの立ち上げには、別途仮想マシンのソフトウェアが必要である。
今回はVirtualBoxを用いる。

[Oracle VM VirtualBox](https://www.virtualbox.org/)

# MikanOSとは

[uchan様](https://twitter.com/uchan_nos)が開発している教育用オペレーティングシステム。
64bit UEFIを用い、USBメモリなどから起動が可能である。

[GitHub - uchan-nos/mikanos: Educational Operating System](https://github.com/uchan-nos/mikanos)

# Vagrantを利用してMikanOSをビルドする

## 環境を構築する

MikanOSのビルドの手順は
[GitHub - uchan-nos/mikanos-build: Build and run scripts for MikanOS](https://github.com/uchan-nos/mikanos-build)
にかかれているので、これに基づいてMikanOSのビルド用にVagrantの設定ファイルを記述していく。

まず、「Ubuntu 18.04 で動作を確認しています。」とのことなので、
Vagrantの公式サイトにある[Find Boxes](https://app.vagrantup.com/boxes/search)で `ubuntu 18.04` を検索する。
色々出てくるが、今回は

> Official Ubuntu 18.04 LTS (Bionic Beaver) builds

となっている `ubuntu/bionic64` を用いる。Officialらしいので。 (適当)

次に、前述のビルドの手順に基づいて、コマンド群をVagrantの設定ファイルに記述していく。
今回は、「設定ファイルに埋め込まれたシェルスクリプトを実行する」というプロビジョンの方法を用いる。
ビルドの手順のうち、

* リポジトリのダウンロード
* 開発ツールの導入
* MikanOS のソースコードの入手
* ブートローダーのビルド (ディレクトリのリンクのみ)

を行うようにする。

プロビジョンの実行時にはユーザーによる操作はできないので、
`apt-get` のオプションに `-y` を加えて確認無しでインストールを実行するようにする。

MikanOSのリポジトリにはシンボリックリンクが使われており、
このリポジトリをVagrantの共有ディレクトリにcloneしようとしてしまうと、
シンボリックリンクがただのファイル名が書かれたテキストファイルになってしまい、ビルドに失敗する原因になるので、
リポジトリは仮想マシン内のファイルシステムにcloneするようにする。

また、シェルスクリプトはrootとして実行されるようなので、
後で使いやすいように環境変数 `HOME` を設定してユーザーのホームディレクトリに各種データを出力するようにし、
さらに `chown` を用いてファイル群の所有者をユーザーに切り替える。

さらに、プロビジョニングはプロビジョニング済の環境でもう一回実行しても大丈夫なようにしておくべきである。
このために、ファイル (ディレクトリ) の有無を判定し、存在するかどうかで処理を切り替えるようにした。
(参考：[【シェルスクリプト】ファイルやディレクトリの有無を確認する方法色々 | server-memo.net](https://www.server-memo.net/shellscript/file_check.html))

以下が今回の設定ファイルである。
設定ファイルは、 `Vagrantfile` という名前で保存する。

```:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

script = <<-SHELL
sudo apt-get update
sudo apt-get -y upgrade

sudo apt-get install -y git ansible python3-distutils

export HOME=/home/vagrant
cd $HOME
if [ -e osbook ]; then
  cd osbook
  git pull
else
  git clone https://github.com/uchan-nos/mikanos-build.git osbook
fi
cd $HOME/osbook/devenv
ansible-playbook -K -i ansible_inventory ansible_provision.yml

cd $HOME
if [ -e mikanos ]; then
  cd mikanos
  git pull
else
  git clone https://github.com/uchan-nos/mikanos.git mikanos
fi

cd $HOME/edk2
if [ ! -e MikanLoaderPkg ]; then
  ln -s $HOME/mikanos/MikanLoaderPkg ./
fi
chown -R vagrant:vagrant $HOME/edk2 $HOME/mikanos $HOME/osbook
SHELL

Vagrant.configure(2) do |config|
  # config.vm.box_download_insecure = true

  config.vm.box = "ubuntu/bionic64"
  config.vm.provision "shell", inline: script
end
```

ウイルス対策ソフトの影響などでboxのダウンロードに失敗する時は、
`config.vm.box_download_insecure = true` のコメントアウトを解除すると改善する場合がある。
(参考：[vagrant up 時にSSLエラー が出た時の対策 - リジェクト東京](https://reject.tokyo/vagrant-error-ssl/))

## MikanOSをビルドする

設定ファイル(`Vagrantfile`)を置いたディレクトリで

```
vagrant up
```

というコマンドを実行することで、仮想マシンを起動する。
この時、

* 利用するbox(仮想マシンのテンプレート)をまだダウンロードしていない場合は、ダウンロードする
* 仮想マシンをまだ作成していない場合は、作成する
* プロビジョニングをまだしていない場合は、する

という操作が自動で行われる。

次に、

```
vagrant ssh
```

というコマンドを実行することで、仮想マシンに接続し、操作ができるようになる。
(環境によっては接続するための情報が出力されるだけかもしれない)

その後、仮想マシン上で以下のコマンドを実行することで、MikanOSのビルドを行う。

```
cd ~/edk2
source edksetup.sh
(Conf/target.txt を指示通りに修正する)
build
cd ~/mikanos/
source ~/osbook/devenv/buildenv.sh
APPS_DIR=apps RESOURCE_DIR=resource ./build.sh
```

成功すると `~/mikanos` ディレクトリに `disk.img` ファイルができるので、
これをVagrantが作成した共有ディレクトリにコピーし、取り出す。

```
cp disk.img  /vagrant/
```

このコマンドにより、 `disk.img` が `Vagrantfile` のあるディレクトリにコピーされる。
得られた `disk.img` は例えば[7-Zip](https://sevenzip.osdn.jp/)で展開(解凍)することができ、
USBメモリのルートディレクトリに展開することで実機での起動実験に用いることができる。
USBメモリの先頭セクタに特殊なデータを書き込む、などの操作は不要である。

仮想マシンの作成完了後、プロビジョニングをもう一度行う(MikanOSのアップデートを反映させるなど)のは、

```
vagrant up --provision
```

というコマンドでできる。

仮想マシンを停止(シャットダウン)するには、

```
vagrant halt
```

というコマンドを実行する。

仮想マシンの破棄(削除)は、

```
vagrant destroy
```

というコマンドでできる。

# ん

よく見たら、[MikanOS公式のVagrantfile](https://github.com/uchan-nos/mikanos-build/blob/master/devenv/Vagrantfile)があるっぽいぞ。
でも、READMEにはこれについて何も書かれてなさそうだし、使い方がよくわからないなあ。
やっぱり公式の説明に基づいておまじないを唱えるのが確実だよね。