Siv3D製ゲームを、LinuxにWindowsから移植する

Windowsで書いていたSiv3DのコードをLinuxに移植して
ビルド・実行するところまで試してみました。

この記事では、実際に構築した流れと、詰まったポイントをまとめます。

環境

  • Windows 11
  • VMware Workstation Pro
  • Ubuntu 22.04.5
  • Siv3D v0.6.16

参考にした公式情報

基本的には以下の公式手順をベースに進めました

VMware Workstation Pro に Ubuntu をインストール

導入方法は割愛します。

公式で言われている「Ubuntu 22.04.5」をインストールしましょう。

執筆時点での最新版は「Ubuntu 26.4」ですが、サポート対象外です(v0.8で対応予定とのこと)

Ubuntuのセットアップ

Minimal installationを選びました。

必要パッケージをインストール

公式マニュアルでは、以下のパッケージをインストールするようあります。

sudo apt update
sudo 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

これに加えてコンパイラ系も必要だったので、

build-essentialtとcmakeもインストールします

sudo apt install build-essential
sudo apt install cmake

また、マニュアルではzipでダウンロード…とありましたが、git入れてcloneしたほうが楽なので、こちらも入れておきます

sudo apt-get install git

Siv3Dのビルドとインストール

devフォルダ作成

作業を始める前に、home下に「dev」というフォルダを作っておきます。

Siv3Dのビルドや、自作プロジェクトはここに置いていきます。

Siv3Dライブラリをビルドする

devフォルダに入ったら、以下のcloneコマンドでコードを入手します。

(マニュアル通り、ブラウザからzipでダウンロードして展開でも可)

git clone https://github.com/Siv3D/OpenSiv3D.git

OpenSiv3D/Linux フォルダにbuildフォルダを作って、その中に入ります。

以下のコマンドで、cmakeして

cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

Linuxフォルダに戻ってビルドします

cd ../
cmake --build build

時間かかるので待ちましょう

Siv3Dをインストールする

ビルドが完了したらインストールします。

sudo cmake --install build

これでSiv3Dが使えるようになります。

Siv3Dのサンプルを動かしてみる(動作確認)

OpenSiv3D/Linux/App フォルダに、buildフォルダを作って、その中に入ります。

さっきと同じく、以下のコマンドでcmakeして

cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

Appフォルダに戻ってビルドします

cd ../
cmake --build build

Appフォルダの中に「Siv3DTest」ができればOKです。

LinuxのMainはほぼ空のプログラムなので、クリックしても動きません。

Main.cppを、サンプルプログラムに書き換えます。

# include <Siv3D.hpp>

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);
	}
}

もう一度「cmake –build build」して、出来上がった「Siv3DTest」を実行して動いたら成功です。

Windowsのプロジェクトを移植する

ソースコードを取り込みます。

直接取り込んでもいいですし、gitのリモートリポジトリにあるならcloneしてもいいです。

(今回はPrivateリポジトリからsshでクローンしました)

Windows のVisual Studio で組んでるのであれば、概ね以下のようなフォルダ構成になっていると思います。


  • 📁MyGame
    • MyGame.sln
    • 📁MyGame
      • Main.cpp(その他ヘッダーやソース)
      • MyGame.vcxproj
      • MyGame.vcxproj.filters
      • 📁App
        • 📁dll とか 📁engine とか

ここに、Linuxでのコンパイルに必要なものを入れていきます。

「resources」の用意

Siv3Dのサンプルから「resources」フォルダをコピーして、「App」に入れてください。

これがないと動きません

「CmakeLists.txt」の用意

「MyGame/MyGame/App」の中に、先ほどSiv3Dのサンプルビルドに使用した「OpenSiv3D/Linux/App/CmakeLists.txt」をコピーします。

※「OpenSiv3D/Linux/CmakeLists.txt」ではありません(こっちはOpenSiv3Dそのもののビルドに使うもの)

CmakeLists.txt を開いて、

add_executable(Siv3DTest
  Main.cpp
  #../../Test/Siv3DTest.cpp
  #../../Test/Siv3DTest_Array.cpp
  #../../Test/Siv3DTest_BinaryReader.cpp
  #../../Test/Siv3DTest_BinaryWriter.cpp
  #../../Test/Siv3DTest_FileSystem.cpp
  #../../Test/Siv3DTest_Image.cpp
  #../../Test/Siv3DTest_Resource.cpp
  #../../Test/Siv3DTest_Stopwatch.cpp
  #../../Test/Siv3DTest_TextEncoding.cpp
  #../../Test/Siv3DTest_TextReader.cpp
  #../../Test/Siv3DTest_TextWriter.cpp
  #../../Test/Siv3DTest_Timer.cpp
  )

find_package(Siv3D)
target_link_libraries(Siv3DTest PUBLIC Siv3D::Siv3D)

target_compile_features(Siv3DTest PRIVATE cxx_std_20)

if(BUILD_TESTING)
enable_testing()
add_test(
  NAME Test
  COMMAND Siv3DTest
  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  )
endif()

file(GLOB SRC_FILES
    "../*.cpp"
)
add_executable(MyGame
    ${SRC_FILES}
)

find_package(Siv3D)
target_link_libraries(MyGame PUBLIC Siv3D::Siv3D)

target_compile_features(MyGame PRIVATE cxx_std_20)

if(BUILD_TESTING)
enable_testing()
add_test(
  NAME Test
  COMMAND MyGame
  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  )
endif()

に書き換えます。

ビルドする

buildフォルダ(MyGame/MyGame/App/build)を作成して、そこで

cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

MyGame/MyGame/Appに戻ってビルド

cd ../
cmake --build build

…すればできるはずなのですが、私の場合はエラーが出まくりました。

inclideエラーを直す

原因はコンパイラの違いです

Visual Studioでは問題なくコンパイルできていたコードが、GCC / Clang ではコンパイルエラーになるケースがありました。

特に多かったのが

#include <queue>
#include <memory>

などの標準ライブラリのincludeが不足しているケースです。

以下のようなエラーメッセージがたくさん出てきます。

/home/username/dev/MyGame/MyGame/Hoge.cpp:4:1: note: ‘std::priority_queue’ is defined in header ‘<queue>’; did you forget to ‘#include <queue>’?
    3 | #include "○○.h"
  +++ |+#include <queue>
    4 | #include "△△.h"

もう一つは、Siv3D独自の型がないといわれるもの。

Vec2やArrayが、無い、宣言されてないとエラーを吐きます。

/home/username/dev/MyGame/MyGame/FugaA.h:13:9: error: ‘Vec2’ does not name a type
   13 |         Vec2 scale = Vec2::One();
/home/username/dev/MyGame/MyGame/FugaB.h:19:25: error: ‘Vec2’ has not been declared
   19 |        scale = Vec2::One();

原因

Windows側では、別ヘッダ経由で偶然 include されていて通っていたコードでも、Linux側では厳密にチェックされるためです。

Visual Studioは、本来は直接 includeすべきヘッダーが間接的に読み込まれていることがあります。

たとえば

std::queue

を使用している場合、本来必要なのは

#include <queue>

です。

しかし、includeしている別のヘッダー(または、そこでさらに読み込んでいるヘッダー)が <queue> を includeしていると、自身でincludeしていなくても読み込まれる間接ヘッダーという仕様がVisual Studioにはるようです。

Clean up C/C++ includes in Visual Studio

GCC / Clangにはそのような仕様はないため、該当のクラスを使用しているファイルには1つずつincludeしていく必要があります。

対策

標準ライブラリに入っているものに関しては、

#include <queue>
#include <memory>

とヘッダーに書いていきます。

Vec2やArrayなどSiv3D独自に定義されているものは

#include <Siv3D.hpp>

と書いていきます

完成

というわけで修正し、起動することができました

移植終わり!!

メインの開発はWindows側で、Linuxはビルド専用になると思いますが、include等気を付けてすぐにコンパイルできる状態にしておきたいものです。