LoginSignup
4
2

Linux版Siv3DをDockerで動かしたい

Posted at

きっかけ

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:11の部分がタグになります。

一度目の失敗

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

実行するとコンテナが起動し……。
image.png
無事コンテナ内からGUI出力ができました!!

終わりに

Linux版Siv3Dをインストールしたdocker imageの作成は意外と難しいものではありませんでしたが、docker初心者であるが故に色々詰まってしまいました。
今回の記事の内容がどなたかの役に立てばうれしいです。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2