C++ ときどき ごはん、わりとてぃーぶれいく☆

Wonder Rabbit Projectのなかのひとのブログ。主にC++。

UE4/C++ FORCEINLINE にしたいけど Debug ビルドの時は inline 最適化されたくない関数を定義する方法、あるいは UE_BUILD_xxxx シリーズのマクロについて。

UE4/C++ FORCEINLINE にしたいけど Debug ビルドの時は inline 最適化されたくない関数を定義する方法

#ifndef UE_BUILD_DEBUG
  FORCEINLINE
#endif
  void hogehoge()
  { /* fugafuga */ }

と、いうわけで #ifdef でOK。 Debug ビルドで定義される UE_BUILD_DEBUG の他に Development ビルドで定義される UE_BUILD_DEVELOPMENT もあるので用途に応じて使う。

あるいは UE_BUILD_xxxx シリーズのマクロについて

これらのマクロのシリーズは公式ドキュメント的にはたぶんアンドキュメント。ソースを見るとこのプリフィックスのシリーズは Engine/Source/Runtime/Core/Public/Misc/Build.h に、

  1. UE_BUILD_DEBUG
  2. UE_BUILD_DEVELOPMENT
  3. UE_BUILD_TEST
  4. UE_BUILD_SHIPPING
  5. UE_BUILD_SHIPPIING_WITH_EDITOR
  6. UE_BUILD_DOCS
  7. UE_BUILD_FINAL_RELEASE
  8. UE_BUILD_MINIMAL

の存在を UE-4.16 現在、確認できる。

追記: FORCEINLINE_DEBUGGABLE について

↑までの内容でブログを書いた後もしばらくソースを眺めていると、 FORCEINLINE_DEBUGGABLE マクロの定義もあることに気付いた。これを使うと、

FORCEINLINE_DEBUGGABLE void hogehoge()
{ /* fugafuga */ }

こんな具合で簡単化できて嬉しいのかなー・・・と思ったものの、ちょっと違った。冒頭で紹介した #ifdef の代わりに使ってしまうと FORCEINLINE ほどではないもののデバッグ実行は実際問題としては難しくなってしまう。

UE_BUILD_xxxx シリーズや FORCEINLINE_DEBUGGABLEEngine/Source/Runtime/Core/Public/Misc/Build.h で定義されていて、 FORCEINLINE_DEBUGGABLEFORCEINLINE_DEBUGGABLE_ACTUAL へ置換される。それから Engine/Source/Runtime/Core/Public/HAL/Platform.hFORCEINLINE_DEBUGGABLE_ACTUAL が"未定義"の場合には FORCEINLINE_DEBUGGABLE_ACTUALinline と定義される。

つまり、そんなこんなで少し入り組んでいるものの、ともかく FORCEINLINE_DEBUGGABLE を使うと C++ キーワードの inline と同様の挙動で inline 最適化が指示された関数を定義した事になる。

ちなみに、 FORCEINLINEC++ キーワードの inline ではなくて、コンパイラーの独自拡張によるより強制力の高い inline 関数を指示するキーワードへ置換される UE4 定義のマクロで、例えば cl.exe(MSVC++) なら __forceinline に置換されたりする。UE4 が対応する FORCEINLINE のプラットフォームごとの対応は Engine/Source/Runtime/Core/Public/<PLATFORM>/<PLATFORM>Platform.h でそれぞれに定義されていて、

置換先
Android __attribute__ ((always_inline))
iOS __attribute__ ((always_inline))
Linux __attribute__ ((always_inline))
Mac __attribute__ ((always_inline))
Windows __forceinline

こんな感じに定義されている。

参考

  1. https://github.com/EpicGames/UnrealEngine/blob/4.16/Engine/Source/Runtime/Core/Public/Misc/Build.h
  2. How can I differentiate between Macros for DebugGame Editor vs Development Editor? - UE4 AnswerHub

追記参考

  1. https://github.com/EpicGames/UnrealEngine/blob/4.16/Engine/Source/Runtime/Core/Public/Misc/Build.h

続・ VSCode で UE4 デバッグの launch.json: DebugGame と Development の切り替え追加と違いについて

概要

前回のポスト「VSCode で UE4/C++: デバッグ実行に必要な launch.json の設定の仕方 - C++ ときどき ごはん、わりとてぃーぶれいく☆」で VSCode の launch.json を設定して UE4 のデバッグ実行を VSCode から"えせ"スタンドアローン風に実行する方法を紹介した。

今回のポストでは UE4/C++ プロジェクトで標準的に用意される DebugGame と Development を切り替える方法と何が違うのかについて追加的に解説したい。

DebugGame と Development の切り替え

前回は launch.json の初手の作成方法の解説として AttachLaunch で2つのデバッグ実行モードを VSCode へ設定する方法を示した。今回はこのうちの LaunchDebugDevelopment の2つに分けて、 Attach Debug Development の3つに分けた launch.json を示す。

{ "version": "0.2.0"
, "configurations":
  [ { "name": "Attach"
    , "type": "cppvsdbg"
    , "request": "attach"
    , "processId": "${command:pickProcess}"
    }
  , { "name":"Debug"
    , "type": "cppvsdbg"
    , "request": "launch"
    , "program": "C:/Program Files/Epic Games/UE_4.16/Engine/Binaries/Win64/UE4Editor.exe"
    , "args": [ "C:/<YOUR-UE4-PROJECT-PATH>/<YOUR-PROJECT-NAME>.uproject", "-debug", "-game" ]
    , "cwd": "${workspaceRoot}"
    }
  , { "name":"Development"
    , "type": "cppvsdbg"
    , "request": "launch"
    , "program": "C:/Program Files/Epic Games/UE_4.16/Engine/Binaries/Win64/UE4Editor.exe"
    , "args": [ "C:/<YOUR-UE4-PROJECT-PATH>/<YOUR-PROJECT-NAME>.uproject", "-game" ]
    , "cwd": "${workspaceRoot}"
    }
  ]
}

DebugDevelopment に対して args で指示する引数が1つ多く -debug が追加されている。

DebugGame と Development の違い

-debug を追加で渡して実行する Debug モードでは、実行時に <YOUR-UE4-PROJECT-PATH>/Binaries/Win64/<YOUR-PROJECT-NAME>.exe と一連の .dll の代わりに、 <YOUR-UE4-PROJECT-PATH>/Binaries/Win64/<YOUR-PROJECT-NAME>-Win64-DebugGame.exe と一連の .dll を用いた実行を試みるようになる。

DebugGame と Development 、2つのコンフィグレーションで実際にどのようにデバッグ性が変化するのか図を交えて紹介する。

DebugGame:

f:id:USAGI-WRP:20170614095428p:plain

Development:

f:id:USAGI-WRP:20170614101525p:plain

適当なブレイクポイントで止めてみると、 Debug 版では全ての VARIABLES が丸見えでまさにデバッグ実行と言った風だが、 Development 版では VARIABLES の表示に幾つか Variable is optimized away and not available. となり扱えない状態で実行されている事がわかる。 Development 版は Debug 版に比べ、デバッガーがまるで役に立たないほどではないものの、あここちでちらほらと最適化によってソースコードと対応の取れない変数や制御が発生している。

通常、 UE4Editor が起動時に読み出す C++ コードの産物は Development コンフィグレーション版だが、 C++er が特に VSCode 等の外部のエディターや開発環境を用いて UE4 開発を行う際には Debug と Development (必要に応じて他に Shipping も)を切り替えながら便利に開発を進捗させる事になる。

参考

  1. VSCode で UE4/C++: デバッグ実行に必要な launch.json の設定の仕方 - C++ ときどき ごはん、わりとてぃーぶれいく☆

VSCode で UE4/C++: デバッグ実行に必要な launch.json の設定の仕方

概要

VSCode で UE4/C++ を開発する際にデバッグ実行に必要な launch.json の設定方法を紹介。

f:id:USAGI-WRP:20170613205409p:plain

↑こんな感じで VSCode しか起動していない状態から"えせ"スタンドアローン風の実行もできる。もちろん、起動中の UE4Editor へのアタッチもできる。

VSCode の設定の仕方

VSCode で .uproject のあるディレクトリーを開くなどしている状態で:

  1. 画面左 Debug アイコンをぽち –> 左側に展開する DEBUG カラムの上部の歯車アイコンをぽち
    • or メニュー > Debug > Open Configurations
  2. VSCode .vscode/launch.json を次のように編集
{ "version": "0.2.0"
, "configurations":
  [ { "name": "Attach"
    , "type": "cppvsdbg"
    , "request": "attach"
    , "processId": "${command:pickProcess}"
    }
  , { "name":"Launch"
    , "type": "cppvsdbg"
    , "request": "launch"
    , "program": "C:/Program Files/Epic Games/UE_4.16/Engine/Binaries/Win64/UE4Editor.exe"
    , "args": [ "C:/<YOUR UE4 PROJECT PATH>/<YOUR PROJECT NAME>.uproject", "-game" ]
    , "cwd": "${workspaceRoot}"
    }
  ]
}

Note: <YOUR UE4 PROJECT PATH>/<YOUR PROJECT NAME> は各自のUE4プロジェクトの配置パスとプロジェクト名に置き換える。

launch.json を保存した直後から DEBUG の緑のプレイ的なボタンの右側のコンボボックスに AttachLaunch が出現。Launch で緑のプレイ的なボタンをぽちると"えせ"スタンドアローン風の実行( UE4Editorから Launch した場合と同様の独立したウィンドウでの起動)が可能。既に起動中の UE4Editor へアタッチしたい場合は VSCode の DEBUG で Attach を選択した状態で緑のプレイ的なボタンをぽちり、プロセス選択で ue4 くらいまで入力するとインクリメンタルに UE4Editor を選択でき、 ENTER してアタッチできる。

デバッグ中は行番号の左側にブレイクポイントを仕込んで止めたり、ステップ実行したり、ローカル変数、ウォッチ、コールスタック、スレッドの監視、デバッグコンソールなどを活用してバグの原因を確認するなど、よくある便利なGUIデバッガーの必要十分な機能を使える。

VSCode の非常に軽快ながらパワフルな動作はプログラマーにとって憂鬱なムダに浪費されてしまう MOTTAINAI 的なコストを小さく抑えながら快適にソフトウェアの開発やドキュメントの記述が可能で、今回招待したように UE4/C++ 開発についても少しの設定で快適にGUIデバッガーとしても機能。嬉しいですねヽ(´ー`)ノ

参考

曰く「Project.uproject を右クリックして Generate Visual Studio project files」・・・そんなのダルい!今すぐ端末でコマンドを撃たせろ!!って思ったらどうすれば良いか・w・

問題

UE4 C++er は .cpp を追加したりリネームするたびに「Project.uproject を右クリックして Generate Visual Studio project files」しなければならない、事になっている(目につくドキュメントや AnswerHub 的なスタンダードな回答によれば)。

f:id:USAGI-WRP:20170612233457p:plain

だるい・w・

どうしたいのか?

  • いつもの zsh などのお気に入りのシェルからぱぱっとコマンドを打ちたい
  • Vim や VSCode などのお気に入りのテキストエディターのカスタムコマンドとしてさくっと使いたい

Windows の「右クリックメニュー」の中身の定義を見る

  1. Win + R –> regedit –> Enter
  2. CTRL + F –> Generate Visual Studio project files –> Enter
  3. しばらく検索を待つ –> Computer\HKEY_CLASSES_ROOT\Unreal.ProjectFile\shell\rungenproj がヒット
  4. 付近の構造を確認 –> rungenproj の下に command があるので値を選択して Modify
  5. Value data がテキストボックスなので値をコピーして後はお好みで使う

f:id:USAGI-WRP:20170612232623p:plain

f:id:USAGI-WRP:20170612234026p:plain

f:id:USAGI-WRP:20170612234115p:plain

手っ取り早い方法としては %1 を実際の Project.uproject のフルパスに置換して1行コマンドを書いただけの generate.bat をプロジェクトルートにでも入れておき、お好みのシェルなりテキストエディターなりから必要な時にそれを叩けばOK。

その他、そもそもシェル関数にするとか alias 張るとか .lnk ショートカットを作ってタスクバーにピン留めしたりグローバルキーボードショートカットを設定したりなどお好みの応用でどうぞ。

何れにしても↓のGUIが動作して .uproject を右クリックして云々と同様の動作となります。

f:id:USAGI-WRP:20170612235007p:plain

これでまたストレスが1つ減りました・w・

Visual Studio 2017 を日本語でインストールした後で English に変更する方法(UE4の文字化け嫌だしー)

状況

Visual Studio 2017 の cl.exe のメッセージを English にしたい。

“googlability” や “stackoverflowability” や “ue4-answerhubability” 的な都合でも合理的だし、 UE4 の UE4Editor から C++ コードをビルドした際に問題が生じた場合に UE4Editor のログ表示で文字化けが起こり、具体的にどんな問題が起きてしまったのか読めず、適当な端末なり Visual Studio なりを起動して"よっこらせ"と再度ビルドして確認する事になるのを避けたいのがいちばんの理由。

方法

  1. Visual Studio Installer” を起動する
  2. “Modify” –> “Language Packs” タブ
  3. “English” –> checked –> Modify (右下のボタン)
  4. Visual Studio 2017” を起動する
  5. “ツール” –> “オプション” –> 「言語」などで絞り込み –> “環境/国際対応の設定” –> 言語: EnglishWindowsの言語設定を English にしている場合は「Microsoft Windows と同じ」でもOK)
  6. Visual Studio 2017” を終了する

これで以降は Visual StudioIDE や UE4Editor や端末で cl.exe を叩いた場合などの表示挙動が English になり無駄な事でいらいらする可能性がそれなり減ります♥

図解

Visual Studio Installer、インストール済みの Visual Studio 2017 の Modify を押すところ。これは Community の例だけど、たぶん Enterprise や Professional でも同じでしょう(執筆現在まだ仕事用の Professional とかで実際に試してないので断言はできませんが)。

f:id:USAGI-WRP:20170612140445p:plain

Visual Studio Installer、 Language Packs を追加するところ。日本語を入れたまま English を追加しても問題は起きない。

f:id:USAGI-WRP:20170612140306p:plain

Visual Studio 2017 の IDE から言語設定を買えるまでははじめにインストールした言語が規定になったままになっているので切り替えるまでは相変わらず CP932 が吐かれてこころが壊れるまま。

f:id:USAGI-WRP:20170612141356p:plain

cl.exe のエラーメッセージの変化の様子

日本語動作のエラー表示:

f:id:USAGI-WRP:20170612135347p:plain

English 動作のエラー表示:

f:id:USAGI-WRP:20170612135947p:plain

UE4Editor で C++ コードにエラーがある状態で Compile しても cl.exe が English なエラーメッセージを吐く状態ならえんじにあの心が壊れずに快適に問題を解決して進捗できるようになる:

f:id:USAGI-WRP:20170612141735p:plain

C++ 標準の promise / future / thread に対応する UE4 標準の TPromise / TFuture / FRunnableThread の使い方

C++ 標準の std::promise / std::future / std::thread

C++erにとっては基礎的なおさらい。

#include <iostream>
#include <future>

int main()
{
  using namespace std;
  
  promise< int > p;
  auto f = p.get_future();
  auto t = thread( [ =, p = move(p) ] () mutable { p.set_value( 123 ); } );
  cout << f.get();
  t.join();
}

C++ 標準では lambda-expression を std:thread へ放り投げるのが簡単なところが嬉しいポイント。

対応する UE4 標準の TPromise / TFuture / FRunnableThread

UE4 標準でコード上で同様の事を記述しようとすると少しめんどくさい。

#include "Runtime/Core/Public/Async/Future.h"

void your_something_function()
{
  // std::promise と同様
  TPromise< int > p;
  // std::future の std::promise からの取得と同様
  auto f = p.GetFuture();
  // ここがちょっとめんどくさい: std::thread( ... ) に相当するコード
  struct r_type: public FRunnable
  { TPromise<int> p;
    r_type( TPromise<int>&& p_ ) : p( std::move( p_ ) ) { }
    bool Init() override { return true; }
    uint32 Run() override { p.SetValue( 123 ); return 0; }
    void Stop() override { }
  } r( std::move( p ) );
  // ↓この2つのフラグは今回のミニマルコード例を応用する人がいた場合に間違えるととても危険なため目立つようにこのように書いておきました。
  constexpr auto bAutoDeleteSelf      = false;
  constexpr auto bAutoDeleteRunnable  = true;
  // ↓これに↑をやる lambda-expression をそのまま放り込めないので FRunnable の派生クラスを定義してもにょもにょ。
  FRunnableThread::Create( &r, TEXT( "promise-future tester"), bAutoDeleteSelf, bAutoDeleteRunnable, 0 );
  // std の例では cout していた部分を今回コード例では UE_LOG で代用しました。
  UE_LOG( LogTemp, Log, TEXT( "promise-future: %d" ), f.Get() );
}

ミニマルコード例として C++ 標準の promise / future / thread ( / lambda-expression ) に対応する事を優先して UE4 標準のコードを書くとこうなります。( FRunnableThread::Create には引数が少し簡単なオーバーロードもあり、 r_typenew して bAutoDeleteSelf 相当のフラグを true として構わない状況ではそちらを使った方が楽な事もあるかもしれません。 )

実用上はこのような例では PROMISE-FUTURE-THREAD 系の低レベルの記述をせず、 C++ 標準なら std::async 、 UE4 標準なら Async へそれぞれ lambda-expression を放り投げた方がよい場合が多いと思いますが、ときおり諸事情により PROMISE-FUTURE 系の低レベルのコード記述が欲しい事があります。例えば既存のライブラリーが非同期処理のコールバックパターンの API を提供しているところで、外で PROMISE と FUTURE を作って非同期処理を呼びつつコールバックに PROMISE を std::move で投げておいてコールバック内で PROMISE に値をセットさせ API の呼び出し元では FUTURE から値の取得を行ったり FUTURE の状態を監視するなどしたい場合とか。

参考

UE4 プロジェクトを git で管理する際の remote origin の選択について

あちこちのサービスを試す事はあっても、結果的には git リポジトリーの remote origin は基本的にはなんでも GitHub を使っていました。しかし、 GitHub だと 100 MB を超えるファイルを少なくともそのままでは放り投げられないのでちょっと工夫とか面倒がありました。

それで、久しぶりに VSTS ( MicrosoftVisual Studio Team Services ) を使ってみる事にしました。きっかけは TwitterFacebook のタイムラインの観測範囲で VSTS がいい感じに進化しているらしいという話がちらほら見えたので。

VSTSの日本語の入り口ページ

www.visualstudio.com

↑を UE4 プロジェクトの git の remote origin にしてしばらくお試ししてみた感想を整理します。

  • 良いと感じた事
    1. 遠慮なく Content/ も git の通常の管理に含められるようになった。らく。
    2. プロジェクトの管理単位が team/project となっていて整理しやすいと感じた。
      • 例えば Hoge プロジェクトがあるとき、メインの hoge リポジトリーの他に prototype-x とか fuga-tool とか補助的な単位があると便利なこともままあるので、事務的な意味でのプロジェクトの管理単位を VSTS の team として、そのシリーズの中でのソース管理単位を VSTS の project として整理して使えて便利が良いです。
    3. push/pull がはやい。(通信の経路にも寄ると思いますが、わがやの場合は github より応答性が良いと感じました。)
    4. モダンな開発プロセスを考慮したリポジトリー運用ルールやレビュープロセスを標準でしれっと使える状態になっている。(一人でやる分にはあんまり関係ないけど)
  • 改善して欲しいと感じた事
    1. ssh 接続に ECDSA 公開鍵を使えなかった事( RSA は使えるけど)
    2. GitHub における public リポジトリー相当の使い方もできるようになると嬉しい(UE4プロジェクトではあんまり必要ない事だけど)

これまで Content/ だけ別管理していたので、それが必要なくなるだけでも嬉しい変更でした。ちなみに、 BitBucket はモッサリ感が開発者のストレス要因になる気配の漂うレベルなので選択肢にふだんはあがりません。総合的に使い倒せれば BitBucket, Atlassian, JIRA 関連のサービス群はもちろん強力だけど、それ相応のちょっとお高い維持費も必要になっちゃうしね・w・

おまけ // git remote の tips

既に GitHub を origin にしているローカルリポジトリーを新たに vsts をデフォルトに変更したい場合はこんな感じ。

git remote add vsts ssh://<YOUR-TEAM>@<YOUR-TEAM>.visualstudio.com:22/_git/<YOUR-PROJECT>
git push -u vsts master