前々回の記事ではChromebookでTyporaを使えるようにしました。でも、それだけじゃ物足りないなと感じています。やっぱりChromebookでも普段やっているゲームやアプリの開発ができるようにしたいのです。そこで、今回は環境の導入からOpenSiv3Dライブラリのビルド、そしてサンプルプログラムのビルドと実行まで実践してみます。

目次

  1. 実験環境
  2. 方策
  3. Crostiniの導入
  4. 前準備
    1. OpenCV4の導入
    2. Boostの導入
    3. gcc 9.3.0の導入
  5. OpenSiv3Dライブラリのビルド
  6. Siv3Dアプリのビルド
  7. まとめ
  8. 参考文献

実験環境

  • 型番: HP ChromeBook x360
  • OS: Google Chrome OS (64ビット)
    • バージョン: 94.0.4606.104
  • CPU: Intel Pentium(詳細な型番は不明)
  • 画面解像度: 1920×1280ピクセル
  • RAM: 4GB
  • SSD: 64GB
  • Linux環境のディスクサイズ: 20GB

普段触れてるWindowsやMacのPCに比べれば低スペックの部類に入ります。しかしこれはChromebookですので、Chromebookとしては標準的なスペックと言えると思います。日常的に開発に使うには厳しそうだけど。

インストールするものは以下の通り。

  • Linux開発環境(Crostini)
  • OpenSiv3D v0.6.3
  • OpenCV 4.5.1
  • Boost 1.71.0
  • gcc 9.3.0
  • その他、必要なライブラリなど
  • (エディタ:Emacs)

今日(2021年11月15日)時点で最新のOpenSiv3D v0.6.3を導入します。バージョンが更新されると要求されるライブラリのバージョンなども変わってきますので、必ずOpenSiv3DのリポジトリのREADMEをご確認ください。

方策

さあ、早速ターミナルを起動して、OpenSiv3Dをビルドして…といきたいところですが、残念ながらそう簡単にはいきません。Ubuntuのような一般的なLinuxディストリビューションとは異なり、Chrome OSはライトユーザー層に向けて作られたブラウザが主役の軽量OSですので、わざわざこんなOSでC++のコードをバリバリ書いてゲーム開発しようなんて考え出すような変態向けには作られておりません。
しかし近年、寛大なるGoogle先生はCrostiniと呼ばれるLinux仮想環境をChrome OSに与えてくださりました。CrostiniはDebian10が動くコンテナ環境です。スペックの関係上、開発環境としては非力ながらも、一応Chrome OSでもLinux開発が可能になりました。

全体的な流れとしては以下のように行います。

  1. Crostiniの導入

  2. 前準備

    1. OpenCV4の導入

    2. Boost 1.71.0の導入

    3. gcc 9.3.0の導入

  3. OpenSiv3Dライブラリのビルド

    1. 依存パッケージのインストール

    2. cmake

    3. ビルド

  4. Siv3Dアプリのビルド

前準備ではOpenCV、Boost、gccをソースコードからビルドしてインストールするのでかなり時間がかかります。後半の「OpenSiv3Dライブラリのビルド」と「Siv3Dアプリのビルド」では、ほぼSiv3Dリファレンス通りに進めればOKです。

Crostiniの導入

※導入済みの場合は飛ばしてください。

Chrome OSにLinux仮想環境Crostiniを導入します。導入は簡単で、設定画面から「Linux開発環境」をオンにするだけです。

Crostini導入についての詳細は↓の記事の冒頭に書いてあります。
ChromebookでもTyporaが使いたい! | 為せばnull

前準備

Crostiniでは、OpenSiv3Dを導入する前に前準備が必要になります。なぜ前準備が必要かというと、OpenSiv3Dのリファレンス通りに進めてもOpenCV、Boost、gccの必要なバージョンがCrostiniに導入できないからです。Crostiniの中身はDebianなのでapt installでパッケージを導入できますが、aptで提供されているバージョンが古いのです。

ではなぜUbuntuなら前準備無しでapt installで最新版が手に入るのかというと、ubuntu-toolchainが利用できるからです。Ubuntuであれば、最初に

$ sudo add-apt-repository ppa:ubuntu-toolchain-r/test

を実行してやれば、その後はOpenCV4もBoost 1.71.0もgcc 9.3.0も普通にaptコマンドで導入できます。ところがこのubuntu-toolchain、Ubuntu向けであるため(おそらく)Crostiniでは利用できません。いろいろ試行錯誤してみましたが、自分の環境では無理でした。

ではどうするのかというと、これらのソースをダウンロードし、自前でビルドしてインストールします。面倒くさそうに思えるかもしれませんが、既に各パッケージをビルドからインストールまで自動で行ってくれるシェルスクリプトが用意されておりますので、今回はそれを利用します。必要なのはビルドにかかる時間のみです。

ここからはターミナル上で作業を進めます。

OpenCV4の導入

まずはOpenCV4を導入します。前述の通り、CrostiniではaptコマンドではOpenCV4は手に入りません。sudo apt install libopencv-devではOpenCV 3.2.0がインストールされます。古すぎ!

最初にaptをupdate & upgrade

$ sudo apt update
$ sudo apt upgrade

次に、OpenCVをインストールしてくれるシェルスクリプトをダウンロードします。

$ cd ~
$ wget https://raw.githubusercontent.com/milq/milq/5b7c3332c78b3a2dd952321f247a72b13a3026db/scripts/bash/install-opencv.sh
$ chmod +x install-opencv.sh
$ ./install-opencv.sh

最後の$ ./install-opencv.shで2~3時間くらいかかりました。何をしているかというと、必要なパッケージを集め、OpenCVのソースをダウンロードし、ビルドして配置するという一連のインストール作業をこれ一つで進めてくれます。
何も変更せずに進めるとOpenCV 4.5.1がインストールされます。別のバージョンをインストールしたい場合は、install-opencv.shの中にバージョンを指定する部分がありますので、実行前に書き換えてみてください。OpenSiv3Dを動かしたいのであれば4.5.1で問題ありません。

完了したらバージョン確認。

$ opencv_version
4.5.1

4.x.xが表示されたら成功です。

次に、cmake実行時にpkg_check_modulesopencv4を見つけてくれるように、pkg-config用のファイルを作成します。
まずはエディタをインストール。

$ sudo apt install emacs

pkgconfigのディレクトリに移動し(なければディレクトリを新規作成)、

$ cd /usr/lib/pkgconfig

新たにopencv4.pcを作成します。

sudo emacs opencv4.pc

opencv4.pcの中身は以下のように書き込みます。

prefix=/usr/local
exec_prefix=${prefix}
includedir_old=${prefix}/include/opencv4/opencv2
includedir_new=${prefix}/include/opencv4
libdir=${exec_prefix}/lib

Name: opencv4
Description: The opencv library
Version: 4.5.1
Libs: -L${exec_prefix}/lib -lopencv_dnn -lopencv_gapi -lopencv_highgui -lopencv_ml -lopencv_objdetect -lope\
ncv_photo -lopencv_stitching -lopencv_video -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_vi\
deoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core
Libs.private: -ldl -lm -lpthread -lrt
Cflags: -I${includedir_old} -I${includedir_new}

opencvの場所は多分どの環境でも同じだと思いますが、もし違う場所に配置されていたら環境に合わせて適宜prefixの値を変更してください。Versionはインストールされたバージョンをここに書き入れます。今回はOpenCV 4.5.1がインストールされたのでVersion: 4.5.1としました。
完了したらopencv4.pcを保存して閉じ、以下のコマンドを実行。

$ pkg-config –cflags opencv4
$ pkg-config –libs opencv4

これでcmakeがopencv4を見つけてくれるようになったはずです。以上でOpenCV4の導入は完了です。

Boostの導入

Boostもaptでは古いバージョン(1.67.0)しか手に入りません。OpenSiv3DのリポジトリのREADME.mdを見て、最新のLinux版が要求しているBoostのバージョンを確認すると、v0.6.3ではBoost 1.71.0 - 1.73.0が必須になっています。今回はBoost 1.71.0を導入しました。
ここで注意点ですが、必ずREADME.mdに記載されたバージョンを導入してください。現在はもっと新しいバージョンのBoostが出ていますが、最新の1.78.0ではOpenSiv3Dのビルド途中でビルドエラーが発生しビルドを完了できませんでした。

まずはホームディレクトリにBoost 1.71.0のソースをダウンロードし解凍。

$ wget https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2
$ tar -jxvf boost_1_71_0.tar.bz2

解凍が完了したらBoostのインストールに移ります。

$ cd boost_1_71_0
$ ./bootstrap.sh
$ ./b2 toolset=gcc-8 --prefix=/usr/local -j5
$ sudo ./b2 install toolset=gcc-8 --prefix=/usr/local -j5

最後の2つでかなり時間がかかります。これでBoostの導入は完了です。

gcc 9.3.0の導入

実はC/C++コンパイラであるgcc(とg++)も自分でコンパイルして導入し直さなければなりません。
OpenSiv3DのリポジトリのREADME.mdによれば、v0.6.3のLinux版ではgcc 9.3.0が要求されていますが、例によってaptでは古いバージョンであるgcc 8.3.0までしか手に入りません。
OpenSiv3DではC++20の機能が多く活用されていますのでgcc8では対応していない部分が多いです。例えば、gcc8ではchar8_tなどといったOpenSiv3Dで多用されている型が定義されていません。

既にgccは自動でインストールされていましたが、やはりgcc 8.3.0でした。

$ gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

この古いgccはまだ残したまま、新しいgccである9.3.0のソースをダウンロードしてビルドします。何故残しておくかというと、新しいgccをビルドするために古いgccが必要だからです。

まずはgccのソースをダウンロードして解凍。

$ cd ~
$ wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-9.3.0/gcc-9.3.0.tar.gz
$ tar xvf gcc-9.3.0.tar.gz

ビルド用の場所を用意。

$ cd gcc-9.3.0
$ ./contrib/download_prerequisites
$ cd ..
$ mkdir build
$ cd build

今回はCとC++のコンパイラだけあれば十分なので、enable-languages=c,c++とします。

$ ../gcc-9.3.0/configure --prefix=/usr/local/gcc-9.3.0 --enable-languages=c,c++ --disable-multilib --disable-bootstrap
$ make
$ sudo make install

自前の環境ではmakeに1時間ほど要しました。

ビルドが完了したら、古いgccを削除します。

$ sudo apt remove gcc

そして新しいgccへのシンボリックリンクを作成します。

$ sudo ln -s /usr/local/gcc-9.3.0/bin/gcc /usr/bin/gcc
$ sudo ln -s /usr/local/gcc-9.3.0/bin/g++ /usr/bin/g++
$ sudo ln -s /usr/local/gcc-9.3.0/bin/c++ /usr/bin/c++

最後に動作確認。

$ gcc --version
gcc (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

gcc 9.3.0がgccコマンドで呼び出されるようになりました。

これでコンパイラはgcc 9.3.0に置き換わりましたが、libstdc++が古いままです。OpenSiv3Dアプリでは実行する際にGLIBCXX_3.4.26が要求されますが、現時点ではGLIBCXX_3.4.26が含まれたlibstdc++.so.6が正しい位置に配置されていません。

$ cd /usr/lib/x86_64-linux-gnu/
$ ls
...
libssl.so.1.1                           libxcb-shm.so.0
libstdc++.so.6                          libxcb-shm.so.0.0.0
libstdc++.so.6.0.25                     libxcb.so
libstemmer.so.0d                        libxcb.so.1
...

stringsコマンドでlibstdc++.so.6のバイナリの可読部分を表示してみます。

$ strings libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_DEBUG_MESSAGE_LENGTH

ご覧の通り、従来(gcc 8.3.0)のlibstdc++.so.6にはGLIBCXX_3.4.25までしか含まれていません。gcc 9.3.0のlibstdc++.so.6にはGLIBCXX_3.4.26が同梱されますので、先程gccビルド時に生成されたlibstdc++.so.6に置き換えます。

$ cd /usr/lib/x86_64-linux-gnu/
$ sudo rm libstdc++.so.6
$ sudo cp /usr/local/gcc-9.3.0/lib64/libstdc++.so.6 /usr/lib/x86_64-linux-gnu/

置き換え後にもう一度確認してみると、

$ strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBCXX_3.4.21
GLIBCXX_3.4.22
GLIBCXX_3.4.23
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_3.4.26
GLIBCXX_3.4.27
GLIBCXX_3.4.28
GLIBCXX_DEBUG_MESSAGE_LENGTH
(以下略)

GLIBCXX_3.4.26が追加されていました。これでgcc 9.3.0の導入は完了です。

OpenSiv3Dライブラリのビルド

これでようやくOpenSiv3Dライブラリのビルド環境が整いました。ここからはOpenSiv3Dをビルドし、libSiv3D.aを生成します。ここからはほぼリファレンス通りです。
まずはOpenSiv3Dの最新コードをダウンロード。

$ cd ~
$ git clone https://github.com/Siv3D/OpenSiv3D.git

次に依存パッケージを導入。リファレンスではOpenCVとBoostのインストールも含まれていますが、これらは既に導入済みのため除いてあります。

$ sudo apt install ninja-build
$ sudo apt install libasound2-dev
$ sudo apt install libavcodec-dev
$ sudo apt install libavformat-dev
$ sudo apt install libavutil-dev
$ sudo apt install libcurl4-openssl-dev
$ sudo apt install libgtk-3-dev
$ sudo apt install libgif-dev
$ sudo apt install libglu1-mesa-dev
$ sudo apt install libharfbuzz-dev
$ sudo apt install libmpg123-dev
$ sudo apt install libopus-dev
$ sudo apt install libopusfile-dev
$ sudo apt install libsoundtouch-dev
$ sudo apt install libswresample-dev
$ sudo apt install libtiff-dev
$ sudo apt install libturbojpeg0-dev
$ sudo apt install libvorbis-dev
$ sudo apt install libwebp-dev
$ sudo apt install libxft-dev
$ sudo apt install uuid-dev
$ sudo apt install xorg-dev

これを一つ一つ実行するのは面倒だったので、パッケージを一括インストールするシェルスクリプトを用意しました。以下を実行して導入できます。

$ wget https://yotiosoft.github.io/datacenter/sh/opensiv3d_packages_install.sh
$ chmod +x ./opensiv3d_packages_install.sh && ./opensiv3d_packages_install.sh

ここからビルド作業に入っていきます。 まずはcmakeでCMakeListsを作成。

$ cd ~/OpenSiv3D/Linux
$ mkdir build && cd build
$ cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

そして最後にOpenSiv3Dライブラリをビルド。
Chromebookで並列コンパイルをやらせるとすぐにメモリ不足になってしまいますので、cmake-j 1オプションを付け加えておきました。自分の環境ではこれがないとSivGeometory2D.cpp.oをビルドするときにメモリ不足で強制終了されてしまいます。

$ cd ../
$ cmake --build build -j 1

ここでも数時間ほどかかりますので気長に待ちます。buildディレクトリ内にlivSiv3D.aが生成されたらビルド成功です。

Siv3Dアプリのビルド

OpenSiv3Dライブラリのビルドが完了したので、サンプルプログラム(Hello Siv3D)をビルドしてみましょう。とその前に、サンプルプログラムのOpenSiv3D/Linux/App/Main.cppを少し修正します。
Linux版のサンプルプログラムは、CIの動作確認のため初期状態ではMain.cppは空のMain関数が記述されており、このままビルドして実行するとウィンドウが表示されることなくすぐに実行終了します。

/////////////////
//
//	Test code for CI
//	- 通常のアプリケーション開発時には除去してください
//
# include <Siv3D.hpp> // OpenSiv3D v0.6.3
SIV3D_SET(EngineOption::Renderer::Headless) // Non-graphical mode
void Main() { }
//
/////////////////

/*
# include <Siv3D.hpp> // OpenSiv3D v0.6.3
void Main()
{
	// 背景の色を設定 | Set background color
	Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
	// 通常のフォントを作成 | Create a new font
	const Font font{ 60 };
	// 絵文字用フォントを作成 | Create a new emoji font
	const Font emojiFont{ 60, Typeface::ColorEmoji };
	// `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback
	font.addFallback(emojiFont);
	// 画像ファイルからテクスチャを作成 | Create a texture from an image file
	const Texture texture{ U"example/windmill.png" };
	// 絵文字からテクスチャを作成 | Create a texture from an emoji
	const Texture emoji{ U"🐈"_emoji };
	// 絵文字を描画する座標 | Coordinates of the emoji
	Vec2 emojiPos{ 300, 150 };
	// テキストを画面にデバッグ出力 | Print a text
	Print << U"Push [A] key";
	while (System::Update())
	{
		// テクスチャを描く | Draw a texture
		texture.draw(200, 200);
		// テキストを画面の中心に描く | Put a text in the middle of the screen
		font(U"Hello, Siv3D!🚀").drawAt(Scene::Center(), Palette::Black);
		// サイズをアニメーションさせて絵文字を描く | Draw a texture with animated size
		emoji.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(emojiPos);
		// マウスカーソルに追随する半透明な円を描く | Draw a red transparent circle that follows the mouse cursor
		Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1, 0, 0, 0.5 });
		// もし [A] キーが押されたら | When [A] key is down
		if (KeyA.down())
		{
			// 選択肢からランダムに選ばれたメッセージをデバッグ表示 | Print a randomly selected text
			Print << Sample({ U"Hello!", U"こんにちは", U"你好", U"안녕하세요?" });
		}
		// もし [Button] が押されたら | When [Button] is pushed
		if (SimpleGUI::Button(U"Button", Vec2{ 640, 40 }))
		{
			// 画面内のランダムな場所に座標を移動
			// Move the coordinates to a random position in the screen
			emojiPos = RandomVec2(Scene::Rect());
		}
	}
}
(以下略)
*/

冒頭部分(Test code for CIの部分)を消去し、下のMain関数のコメントアウトを外して保存します。

# include <Siv3D.hpp> // OpenSiv3D v0.6.3
void Main()
{
	// 背景の色を設定 | Set background color
	Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
	// 通常のフォントを作成 | Create a new font
	const Font font{ 60 };
	// 絵文字用フォントを作成 | Create a new emoji font
	const Font emojiFont{ 60, Typeface::ColorEmoji };
	// `font` が絵文字用フォントも使えるようにする | Set emojiFont as a fallback
	font.addFallback(emojiFont);
	// 画像ファイルからテクスチャを作成 | Create a texture from an image file
	const Texture texture{ U"example/windmill.png" };
	// 絵文字からテクスチャを作成 | Create a texture from an emoji
	const Texture emoji{ U"🐈"_emoji };
	// 絵文字を描画する座標 | Coordinates of the emoji
	Vec2 emojiPos{ 300, 150 };
	// テキストを画面にデバッグ出力 | Print a text
	Print << U"Push [A] key";
	while (System::Update())
	{
		// テクスチャを描く | Draw a texture
		texture.draw(200, 200);
		// テキストを画面の中心に描く | Put a text in the middle of the screen
		font(U"Hello, Siv3D!🚀").drawAt(Scene::Center(), Palette::Black);
		// サイズをアニメーションさせて絵文字を描く | Draw a texture with animated size
		emoji.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(emojiPos);
		// マウスカーソルに追随する半透明な円を描く | Draw a red transparent circle that follows the mouse cursor
		Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1, 0, 0, 0.5 });
		// もし [A] キーが押されたら | When [A] key is down
		if (KeyA.down())
		{
			// 選択肢からランダムに選ばれたメッセージをデバッグ表示 | Print a randomly selected text
			Print << Sample({ U"Hello!", U"こんにちは", U"你好", U"안녕하세요?" });
		}
		// もし [Button] が押されたら | When [Button] is pushed
		if (SimpleGUI::Button(U"Button", Vec2{ 640, 40 }))
		{
			// 画面内のランダムな場所に座標を移動
			// Move the coordinates to a random position in the screen
			emojiPos = RandomVec2(Scene::Rect());
		}
	}
}

これでOKです。サンプルプログラムをビルドしてみます。

$ ./App
$ mkdir build && cd build
$ cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cd ../
$ cmake --build build

しばらく待つとSiv3DTestが生成されます。これが実行ファイルです。実行してみます。

$ ./Siv3DTest 

すると…

おお!おなじみのサンプルプログラムが、ついにChrome OS上で動き始めました。マウス操作やキー操作もできるし、SimpleGUIのボタンも使えます。

v0.6から実装された3Dも問題なく動きます。

画面録画しながら実行しているので動画はカクカクしていますが、実際はもっとヌルヌル動いてくれます。思ってたより快適です。

まとめ

Chrome OSでもLinux仮想環境であるCrostiniを用いてOpenSiv3Dの導入からSiv3Dアプリのビルドまで実現できました。これでCities Boxやその他もろもろの開発がChromebookでもできます。前述の通りCrostiniの中身はDebianですので、Debianでも同様の手順で導入できるかと思います。
次は開発用のエディタとしてChrome OSにVS Codeでも入れてみようかなと思います。

参考文献