きっかけ
Siv3Dを使って通信対戦ゲームを作りたい。
Siv3Dに実装されているTCPServerをサーバー上で稼働する必要がありました。
そこで、Linux版Siv3Dをインストールしたdocker imageを作成することにしました。
Linux版Siv3Dについて
Linux版Siv3Dは@wynd2608さんが有志でLinuxに移植しているものです。
さっそく作ってみる!
Linux版Siv3Dにはコンパイル済みバイナリの配布がありません。そのため、自前でビルドする必要があります。
今回はDockerfileを記述し、ビルドすることでdocker imageを作成します。
Siv3Dのホームページ(?)にLinux版のインストール手順が記載されてましたので参考にしました。
(Ubuntu で Siv3D プログラミングを始める)
Dockerfileの記述
まずは任意のディレクトリにdockerfile
という名前のファイルを作り、以下のように記述しました。
結論から言うと、このDockerfileではうまくいきませんでした。
FROM ubuntu:22.04
RUN apt update && apt upgrade -y
RUN apt install -y \
ninja-build \
libasound2-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libboost-dev \
libcurl4-openssl-dev \
libgtk-3-dev \
libgif-dev \
libglu1-mesa-dev \
libharfbuzz-dev \
libmpg123-dev \
libopencv-dev \
libopus-dev \
libopusfile-dev \
libsoundtouch-dev \
libswresample-dev \
libtiff-dev \
libturbojpeg0-dev \
libvorbis-dev \
libwebp-dev \
libxft-dev \
uuid-dev \
xorg-dev
RUN mkdir /root/download
RUN mkdir /root/download/OpenSiv3D
RUN git clone https://github.com/Siv3D/OpenSiv3D.git /root/download/OpenSiv3D
RUN mkdir /root/download/OpenSiv3D/Linux/build
WORKDIR /root/download/OpenSiv3D/Linux/build
RUN cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
WORKDIR /root/download/OpenSiv3D/Linux
RUN cmake --build build
WORKDIR /root/download/OpenSiv3D/Linux
RUN cmake --install build
RUN mkdir /root/download/OpenSiv3D/Linux/App/build
WORKDIR /root/download/OpenSiv3D/Linux/App/build
RUN cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
WORKDIR /root/download/OpenSiv3D/Linux/App
RUN cmake --build build
このDockerfile
があるディレクトリに移動し、以下のコマンドを実行してビルドします。
$ sudo docker build -t siv3d .
今回は試験的に作成しているのでイメージのタグは付けていないので自動的にlatestになりますが、基本的には付けた方が良いらしいです。
タグをつける場合には以下のコマンドを利用してください。
$ sudo docker build -t siv3d:1 .
siv3d:1
の1
の部分がタグになります。
一度目の失敗
RUN apt update && apt upgrade
で止まってしまいました。
エラーログは申し訳ないけれども控えてないですが、原因を調べたところWSL2上のubuntuの時刻のずれが原因でした。
Topic
WSL2ではPCをスリープすると時刻がずれるバグが存在します!
時刻のずれを修正するには以下のコマンドを実行すればいいです。
$ sudo hwclock --hctosys
これでも治らない場合はwslを再起動してみたり、タイムゾーンが正しいかどうか確認しましょう。
二度目の失敗
改めてビルドします。
……おや、今度は以下のようなログの状態でapt install
が途中で止まってしまいましたね……。
=> => # Please select the geographic area in which you live. Subsequent configuration
=> => # questions will narrow this down by presenting a list of cities, representing
=> => # the time zones in which they are located.
=> => # 1. Africa 3. Antarctica 5. Arctic 7. Atlantic 9. Indian 11. US
=> => # 2. America 4. Australia 6. Asia 8. Europe 10. Pacific 12. Etc
=> => # Geographic area:
これはタイムゾーンが指定されていないため起こります。
数字を入力すれば続きに行けそうな雰囲気はありますが、ここで数字を入力しても受け付けてくれません。
一旦Ctrl+C
でビルドをキャンセルし、Dockerfileの2行目に以下の文言を追加します。
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ln
コマンドはシンボリックリンクを作成するコマンドです。
おそらくinstall時に参照するディレクトリに対してタイムゾーンを示すシンボリックリンクを作成しているようですが、私もよくわかっておりません……。
しかしこれを記述すると上のログの場所で止まることはありませんでした。
三度目の失敗
三度目の正直……はもちろんうまくいかず、以下のエラーが出てビルドが終了しました。
dockerfile:34
--------------------
32 | RUN mkdir /root/download
33 | RUN mkdir /root/download/OpenSiv3D
34 | >>> RUN git clone https://github.com/Siv3D/OpenSiv3D.git /root/download/OpenSiv3D
35 |
36 | RUN mkdir /root/download/OpenSiv3D/Linux/build
--------------------
ERROR: failed to solve: process "/bin/sh -c git clone https://github.com/Siv3D/OpenSiv3D.git /root/download/OpenSiv3D" did not complete successfully: exit code: 127
git clone
がうまくいってませんね。
う~ん理由は明白!!! gitパッケージ入ってないやんけ!!!
ということで追加しましょう。
よく考えたら今後使うコマンドであるcmakeや、なんとなく必要そうなg++なども入ってませんね。
ということで完全に独断と偏見で必要そうなパッケージを追加します。
追加したパッケージは以下の通りです。
- git
- cmake
- gcc
- g++
ついに成功!
これらを追加してビルドすると成功しました!!
最終的はDockerfileは以下の通りです。
FROM ubuntu:22.04
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN apt update && apt upgrade -y
RUN apt install -y \
git \
cmake \
gcc \
g++ \
ninja-build \
libasound2-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libboost-dev \
libcurl4-openssl-dev \
libgtk-3-dev \
libgif-dev \
libglu1-mesa-dev \
libharfbuzz-dev \
libmpg123-dev \
libopencv-dev \
libopus-dev \
libopusfile-dev \
libsoundtouch-dev \
libswresample-dev \
libtiff-dev \
libturbojpeg0-dev \
libvorbis-dev \
libwebp-dev \
libxft-dev \
uuid-dev \
xorg-dev
RUN mkdir /root/OpenSiv3D
RUN git clone https://github.com/Siv3D/OpenSiv3D.git /root/OpenSiv3D
RUN mkdir /root/OpenSiv3D/Linux/build
WORKDIR /root/OpenSiv3D/Linux/build
RUN cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
WORKDIR /root/OpenSiv3D/Linux
RUN cmake --build build
WORKDIR /root/OpenSiv3D/Linux
RUN cmake --install build
最初のDockerfileからサイレント修正した点がありますので紹介します。
-
RUN cmake --install build
以降の記述
途中から気づいたのですが、この部分以降はSiv3Dアプリのビルドであるため、イメージをビルドする段階では必要ない処理でしたので削除しました。 - downloadディレクトリの削除
最初はダウンロードしたあと別の場所にインストールするのかと思っていたためdownloadディレクトリにOpenSiv3Dをクローンし、ビルドしていましたがそうではないことがわかったのでdownloadディレクトリは削除しました。
これにて、今回やりたいことは達成されました! わーい!!
おまけ
せっかくなので、作成したイメージでコンテナを作成し、Siv3Dを動かしてみたいなと思いました。
GUIなし
まずはGUIが無いSiv3Dアプリを動かしてみます。
まずはdocker imageを基にしてコンテナを起動します。
$ docker run -it siv3d
root@192f3ae3ecac:~/OpenSiv3D/Linux#
docker run
を実行するとコンテナが立ち上がりました。
Siv3DのサンプルコードにはGUIを必要としないプログラムがありますので、そちらを利用します。
サンプルコード
/////////////////
//
// Example non-graphical program
//
# include <Siv3D.hpp> // OpenSiv3D v0.6.11
SIV3D_SET(EngineOption::Renderer::Headless) // Force non-graphical mode
void Main()
{
Console << U"\n----------------";
Console << U"Hello, Siv3D!";
Console << U"You are running a non-graphical program.";
Console << U"You can code a graphical program in Linux/App/Main.cpp";
Console << U"----------------\n";
}
//
/////////////////
/*
/////////////////
//
// Example graphical program
//
# include <Siv3D.hpp> // OpenSiv3D v0.6.11
void Main()
{
// 背景の色を設定する | Set the background color
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// 画像ファイルからテクスチャを作成する | 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 };
// 太文字のフォントを作成する | Create a bold font with MSDF method
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
// テキストに含まれる絵文字のためのフォントを作成し、font に追加する | Create a font for emojis in text and add it to font as a fallback
const Font emojiFont{ 48, Typeface::ColorEmoji };
font.addFallback(emojiFont);
// ボタンを押した回数 | Number of button presses
int32 count = 0;
// チェックボックスの状態 | Checkbox state
bool checked = false;
// プレイヤーの移動スピード | Player's movement speed
double speed = 200.0;
// プレイヤーの X 座標 | Player's X position
double playerPosX = 400;
// プレイヤーが右を向いているか | Whether player is facing right
bool isPlayerFacingRight = true;
while (System::Update())
{
// テクスチャを描く | Draw the texture
texture.draw(20, 20);
// テキストを描く | Draw text
font(U"Hello, Siv3D!🎮").draw(64, Vec2{ 20, 340 }, ColorF{ 0.2, 0.4, 0.8 });
// 指定した範囲内にテキストを描く | Draw text within a specified area
font(U"Siv3D (シブスリーディー) は、ゲームやアプリを楽しく簡単な C++ コードで開発できるフレ ームワークです。")
.draw(18, Rect{ 20, 430, 480, 200 }, Palette::Black);
// 長方形を描く | Draw a rectangle
Rect{ 540, 20, 80, 80 }.draw();
// 角丸長方形を描く | Draw a rounded rectangle
RoundRect{ 680, 20, 80, 200, 20 }.draw(ColorF{ 0.0, 0.4, 0.6 });
// 円を描く | Draw a circle
Circle{ 580, 180, 40 }.draw(Palette::Seagreen);
// 矢印を描く | Draw an arrow
Line{ 540, 330, 760, 260 }.drawArrow(8, SizeF{ 20, 20 }, ColorF{ 0.4 });
// 半透明の円を描く | Draw a semi-transparent circle
Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1.0, 0.0, 0.0, 0.5 });
// ボタン | Button
if (SimpleGUI::Button(U"count: {}"_fmt(count), Vec2{ 520, 370 }, 120, (checked == false)))
{
// カウントを増やす | Increase the count
++count;
}
// チェックボックス | Checkbox
SimpleGUI::CheckBox(checked, U"Lock \U000F033E", Vec2{ 660, 370 }, 120);
// スライダー | Slider
SimpleGUI::Slider(U"speed: {:.1f}"_fmt(speed), speed, 100, 400, Vec2{ 520, 420 }, 140, 120);
// 左キーが押されていたら | If left key is pressed
if (KeyLeft.pressed())
{
// プレイヤーが左に移動する | Player moves left
playerPosX = Max((playerPosX - speed * Scene::DeltaTime()), 60.0);
isPlayerFacingRight = false;
}
// 右キーが押されていたら | If right key is pressed
if (KeyRight.pressed())
{
// プレイヤーが右に移動する | Player moves right
playerPosX = Min((playerPosX + speed * Scene::DeltaTime()), 740.0);
isPlayerFacingRight = true;
}
// プレイヤーを描く | Draw the player
emoji.scaled(0.75).mirrored(isPlayerFacingRight).drawAt(playerPosX, 540);
}
}
//
/////////////////
*/
ではこのサンプルコードからSiv3Dアプリをビルドします。
docker内ではroot権限のため、ドルマークではなくシャープマークの方が正しいですが、コメントアウトと見分けがつかないためここではドルマークで記述致します。
$ pwd
/root/OpenSiv3D/Linux
$ mkdir App/build
$ cd App/build
$ cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
$ cd ..
$ cmake --build build
ここまででSiv3Dアプリのビルドは完了です。
最後に実行してみます。
$ ./Siv3dTest
# 省略
----------------
Hello, Siv3D!
You are running a non-graphical program.
You can code a graphical program in Linux/App/Main.cpp
----------------
これにてGUIを必要としないSiv3Dアプリの実行はできました! やったね!!
GUIあり
さて、最後にGUIを必要とするSiv3Dアプリをコンテナ上で動かしてみようと思います。
今回のTCPServerとして稼働させるという目的には関係ないですが、ここまで来たらせっかくなのでやってみたい!!ということでやってみました。
コンテナにはGUI出力する機能はありません。(正確にはコンテナ内のubuntuがGUI出力するための設定を知らない)
そのため、起動時にそれらを教えてあげる必要があります。
compose.yml
の記述
dockerコンテナを起動する方法として先程はdocker run
を使用しましたが、GUI出力を設定するために様々な設定をするので今回はcompose.yml
に設定を記述し、docker compose up
コマンドで起動することにします。
こちらのサイトを参考にし、私は以下のように記述しました。
version: "3.9"
services:
app:
image: siv3d
command: /bin/bash -c "/root/src/build.sh"
volumes:
- ./src:/root/src
- /tmp/.X11-unix:/tmp/.X11-unix
- /mnt/wslg:/mnt/wslg
environment:
- DISPLAY=$DISPLAY
- WAYLAND_DISPLAY=$WAYLAND_DISPLAY
- XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR
- PULSE_SERVER=$PULSE_SERVER
./src
にはGUIを出力するようにしたMain.cpp
と、ビルドの手順が書いてあるシェルスクリプトを置いています。
その後、このcompose.ymlが置いてあるディレクトリに移動し、以下のコマンドを実行しました。
$ docker compose up
実行するとコンテナが起動し……。
無事コンテナ内からGUI出力ができました!!
終わりに
Linux版Siv3Dをインストールしたdocker imageの作成は意外と難しいものではありませんでしたが、docker初心者であるが故に色々詰まってしまいました。
今回の記事の内容がどなたかの役に立てばうれしいです。