Vcpkg+CMakeでのSDL2ビルド
C++用パッケージマネージャVcpkgと C系言語用ビルドソフトCMakeと組み合わせてSDL2をビルドした。
環境
- Windows 10
- ビルドジェネレータ: Visual Studio 2019 (x64)
この記事の内容はWIndows10でなくてもおおむね問題なく使えるはず。 なお、CMakeは既に導入済みとして話を進める。
Vcpkgの導入
READMEに従い導入を進める。
Vcpkgのレポジトリをcloneし、中にあるbootstrap-vcpkg.bat
(Linux等ではbootstrap-vcpkg.sh
)を実行する。
> git clone https://github.com/Microsoft/vcpkg.git > cd vcpkg > .\bootstrap-vcpkg.bat
Vcpkgとビルドシステムを連携するために、integrate install
コマンドを実行する(管理者権限が必要)。
> .\vcpkg integrate install
尚、必要に応じてPATHを通してもよい(自分は面倒で通してない :P)。
SDL2の導入
vcpkg install
を使用する。
> .\vcpkg install sdl2 --triplet x64-windows
--triplet
オプションの引数は環境によって変える。
有効な引数は.\vcpkg help triplet
から見れる(後々変わるかもしれないので、一応自分で実行したほうがいいかもしれない)。
> .\vcpkg help triplet Available architecture triplets: arm-uwp arm-windows arm64-uwp arm64-windows x64-linux x64-osx x64-uwp x64-windows x64-windows-static x86-uwp x86-windows x86-windows-static
ビルド
最初に、CMakeLists.txt
を書く。
vcpkg install
完了時に表示されるスニペットを参考にする。
project(main) find_package(sdl2 CONFIG REQUIRED) add_executable(main main.cpp) target_link_libraries(main PRIVATE SDL2::SDL2 SDL2::SDL2main)
次にcmake
を実行し、ビルドスクリプトを作成する。
今回はCMakeLists.txt
を同じディレクトリで実行したとして書く。
実際にはbuild
とかそういうビルド用のディレクトリを作ってそこでやった方がいいと思う。
> cmake . "-DCMAKE_TOOLCHAIN_FILE=<vcpkg_root>\scripts\buildsystems\vcpkg.cmake" -A x64
<vcpkg_root>
にはVcpkgがあるディレクトリを指定する。
-A x64
は使用するビルドジェネレータやビルド対象とするアーキテクチャによって変えること。
例えば、Ninjaで64ビットのWindowsを対象にビルドする場合は
> cmake . "-DCMAKE_TOOLCHAIN_FILE=<vcpkg_root>\scripts\buildsystems\vcpkg.cmake" -G Ninja -DVCPKG_TARGET_TRIPLET=x64-windows
となる。
最後に、cmake --build
でビルドする。
> cmake --build .
ここで指定するディレクトリは先程ビルドスクリプトを作成したディレクトリであることに注意しよう。
メインのCMakeLists.txt
がある場所とは限らない。
リンクエラーが出たら
私の場合、リンクエラー(LNK2019)が出てしまいビルドが成功しなかった。
理由はSDL2はmain
にマクロを入れており、
コマンドライン引数を明示しないとそのマクロが動作せずリンクエラーとなる(参考)。
int main() // ダメ! int main(int argc, char* argv[]) // よし!
OmegaTで既存の翻訳文章を参考訳文として再利用する方法
某アプリの日本語訳が微妙だったので直そうと思ったのだが、OmegaTでその訳を入力する方法が分からなかったのでメモ
- OmegaT4.xをインストールする
- [ツール]→[ファイルの整列]を選択
- 訳文に取り込みたい訳のファイルを指定し確定
- ちゃんと対応が取れているか確認して次へ
- 同様に確認してTMX(翻訳メモリファイル)を保存
この機能は3.xにも存在するようだが、GUIのサポートが無いので4.xがおすすめ。
3.xでやる方法はこちら
必要に応じて比較モードやアルゴリズムを調整する。 私の場合は翻訳対象がAndroidのリソースファイルだったのでIDで比較するだけで完璧になった。
必要に応じて調整する。
保存後は再読み込み(F5)すれば参考訳文に元の訳が表示される。 参考訳文または選択範囲に置換(Ctrl+R)を使えばそのまま利用できる。
参考
8時間でゲームを作れなかった話
Ludum Dareというゲームジャムがあります。ゲームジャムというのは一定の時間でゲームを作る(要するにゲーム版ハッカソン)というもので、Ludum Dareはその中でも世界最大規模のものです。
自分は次回のLudum Dareに参加しようと思っているのですが、ゲームジャムに参加したことがありませんでした。というわけで、昨日(2019/6/8)試しに8時間で一人ゲームジャムをやってみました。
ルール
- 時間は8時間。ただし、ごはん休憩とお風呂休憩中は時間をすすめない
- テーマはランダム単語ジェネレータで開始時に決める
- 用意してよいのは開発環境とコードのテンプレートのみ。絵などが必要であれば時間中に作成する。素材の使用は認めない。
- 泣かない
ゲームジャム中の風景
警告: 無編集、約9時間
シークバーの真ん中あたりをクリックして「へー」と思ってくれたら十分です。
できたものの説明
テーマ「まつぼっくり、戦艦、ボーダーライン」にそって考えた結果、まつぼっくりを広い範囲に届けて生存範囲を広げるゲームになりました。
ゲームが始まると、松の木からまつぼっくりが落ちてきます。右クリックを押している間まつぼっくりの傘が開いて(画像1枚しかないから見た目は開いてないけど)右方向に進むことができます。 地面に着地するまでに進めば進むほど、生存範囲を広げたということで高得点がもらえます。 ただし、着地したまつぼっくりを何故か狙う鳥がいます。この鳥にまつぼっくりをとられてしまうと、その分の点数が減ります。
まつぼっくりは何故か謎の弾丸を発射することができるので、この鳥を打ち落とすことで点数の減少を防ぐとともに、鳥が持って行った分だけ点数アップを狙うことができます。
なお、弾丸の発射と傘を開くことを同時に行うことはできません。バランスが重要。
反省点
完成しなかった
結局、8時間以内に完成させることができませんでした(レポジトリのコードは時間が終わった後に調整したもの。ゲームジャム終了時点のコードが見たい場合はgame-jam-end
タグを参照)。
おそらく、ペース配分をするときに休憩を計算に入れなかったことが原因の一つだと思います。例えば、1時間ごとに5分休憩をとるなどを決めていれば、途中で必要以上に休憩したりすることがなかったと思います。 また、ここで私が言う「完成」は「ゲームが開始し、プレイ結果が出て、終了する」、この一連の流れができることを言っています。今回の場合、ゲーム終了の実装が間に合いませんでした(つまり、ゲームが永遠に終わらない)。 個人的に、そもそも先にゲームの終了部分を作るべきでだったと思います。 ゲーム本体がまだまだ未熟でも、とりあえず結果が出て終了すればゲームと言い張れると思うからです。
使ったテンプレートやライブラリの把握が足りなかった
今回、開発にはRust+ggezを選択し、ggezの開発者の方が作ったテンプレートを基にゲームを作りました(ggezは結構低レベルなライブラリで一からやると結構めんどい)。Rustはともかくとして、ggezに関しては何か月か前に少し触って以来だったので、APIの把握があまりできていませんでした。 また、テンプレートの方も前日に読んで動かしただけで、ちょっとコードを書いてみて弱点等の把握をしていなかったため(実はマウスの対応が不完全だった等)、それらに若干振り回されてしまった時もありました。
感想
完走した感想ですが、意外と楽しかったです。自分はかなり飽きっぽいのぶっちゃけ30分くらいで飽きると思っていましたが、なんだかんだで完走できました。
今回は個人的嗜好によりRustで作りましたが、今度はUnityとかデカいゲームエンジンで作ってみたいです。C#言語4.0以来使ったことないけど。それともまさかのF#? 次回やるとした、多分9月くらいだと思います。次は時間内に完成させたいところ。
ggezをバージョンアップしたらnix-shell上でプログラムが起動しなくなった話
タイトルはggez
だけど、エラーメッセージはglutin
とwinit
から出ているからそれ関係なら使えるはず。
解決策
shell.nix
に以下のような設定を加える。
LD_LIBRARY_PATH = lib.makeLibraryPath [ "/run/opengl-driver" xorg.libX11 xorg.libXcursor xorg.libXrandr xorg.libXi libGL ];
Rustなどその他もろもろも入れるとこうなる。
let moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz); nixpkgs = import <nixpkgs> { overlays = [ moz_overlay ]; }; rust = nixpkgs.rustChannels.stable.rust; in with nixpkgs; mkShell { buildInputs = [ rust alsaLib pkgconfig SDL2 libudev ]; LD_LIBRARY_PATH = lib.makeLibraryPath [ "/run/opengl-driver" xorg.libX11 xorg.libXcursor xorg.libXrandr xorg.libXi libGL ]; }
事の顛末
ggez
を0.5.0-rc0にバージョンアップしたら、1
以下のエラーが出て自分のプログラムが動かなくなってしまった。
thread 'main' panicked at 'Failed to initialize any backend! Wayland status: NoCompositorListening X11 status: LibraryOpenError(OpenError { kind: Library, detail: "opening library failed (libXcursor.so.1: cannot open shared object file: No such file or directory); opening library failed (libXcursor.so: cannot open shared object file: No such file or directory)" })', /home/ix/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.18.0/src/platform/linux/mod.rs:437:9 note: Run with `RUST_BACKTRACE=1` for a backtrace.
最初は依存関係にlibXcursor
が足りないのかと思ったから、buildInputs
に
xorg.libXcursor
を追加してみたが改善しなかった。
ここでメッセージをちゃんと読むと動的ライブラリのlibXcursor
がないと出ている。
ということはLD_LIBRARY_PATH
が通っていないと思い、試しにecho $LD_LIBRARY_PATH
をしたところ案の定だった。2
$ echo $LD_LIBRARY_PATH /run/opengl-driver/lib
そこでlibXcursor
をLD_LIBRARY_PATH
へ追加した。
LD_LIBRARY_PATH = "${xorg.libXcursor}/lib";
上の「動的ライブラリがない」エラーがlibXrandr
とlibXi
で出たから同様のことを繰り返す。
LD_LIBRARY_PATH = "${xorg.libXcursor}/lib:${xorg.libXrandr}/lib:${xorg.libXi}/lib";
これで直ったかと思いきや、次は以下のようなエラーが出た。
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NotSupported("both libglx and libEGL not present")', libcore/result.rs:1009:5 note: Run with `RUST_BACKTRACE=1` for a backtra
libEGL
は字面から見て関係なさそうだから、3あとのlibglx
が問題なはず。
libglx
はGLXの実装でOpenGLをX Window System上で使うためのものっぽい。
何も考えずnix search libglx
をしたところ何も見つからなかった。でもlibGL
なるものはあったからこれを前のようにLD_LIBRARY_PATH
に入れてみる。
LD_LIBRARY_PATH = "${xorg.libXcursor}/lib:${xorg.libXrandr}/lib:${xorg.libXi}/lib:${xorg.libGL}/lib";
そうすると次は以下のようなエラーが出た。
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: OsError("`glXQueryExtensionsString` found no glX extensions")', libcore/result.rs:1009:5 note: Run with `RUST_BACKTRACE=1` for a backtrace.
こんどはglX extensions
なるものがないらしい。
GLX extensionはグラフィックドライバによってサポートされるものらしいから試しにパソコンを変えてみたけれど変わらなかった。つまり、ドライバの問題ではないはず。
ここで、試しにglxgears
を起動してみることにした。glxgears
はmesa
のデモプログラムで、その名の通りGLXで歯車が描画される。
やってみたところ、エラーが出て起動しなかった。ただ、nix-shell
を使っていない状態では問題なく起動できた。
ならばnix-shell
を使っていない状態に何か手がかりがあるかもしれない。nix-shell
抜きでLD_LIBRARY_PATH
を確認してみる。
$ echo $LD_LIBRARY_PATH /run/opengl-driver/lib
あ、なんかopengl
とか書いてあるしそれっぽい……。
というわけで上で出てきたものをshell.nix
に追加したらめでたく動いた。
LD_LIBRARY_PATH = "${xorg.libXcursor}/lib:${xorg.libXrandr}/lib:${xorg.libXi}/lib:${xorg.libGL}/lib:/run/opengl-driver/lib";
ただ、なんだか記述が野暮ったくて気に入らないので既存のパッケージを色々見てみたところ、lib.makeLibraryPath
というそのまんまな関数があったので早速使う。4
LD_LIBRARY_PATH = lib.makeLibraryPath [ "/run/opengl-driver" xorg.libXcursor xorg.libXrandr xorg.libXi libGL ];
冒頭のコードにはこれに加えてxorg.libX11
がある。これはこの記事を書く前にもう一度動作確認してみたところ何故か足りないと言われてしまったので追加したから。理由は謎。