UE4: クラスファイルにたいてい仕込むログマクロの糖衣マクロ
UE4 に C++ コードファイルを追加する場合、特に UCLASS
では規模がよほど小さくない限りたいてい定義するログマクロの定義と糖衣を紹介。
// MyHoge.h // コンパイラーオプションで MYHOGE_ENABLE_LOG=1 など明示的に渡されない場合でも // デバッグビルドの場合にはログマクロを ON にする #if defined( UE_BUILD_DEBUG ) && ! defined( MYHOGE_ENABLE_LOG) #define MYHOGE_ENABLE_LOG 1 #endif // ログマクロを有効にする場合 #if MYHOGE_ENABLE_LOG > 0 /// ログONの場合のログマクロラッパー定義 DECLARE_LOG_CATEGORY_EXTERN( MYHOGE, Log, All ); #endif
// .cpp // ログマクロを有効にする場合 #if MYHOGE_ENABLE_LOG > 0 // ログカテゴリー定義 DEFINE_LOG_CATEGORY( MYHOGE ); // このソース内でのみ有効なログマクロ書き糖衣マクロ #ifndef LOG #define LOG( LEVEL, BODY, ... ) \ { UE_LOG( MYHOGE, LEVEL, TEXT( BODY ), __VA_ARGS__ ) } #endif // ログOFFの場合のログマクロラッパー定義 #else #ifndef LOG #define LOG( ... ) #endif #endif
この仕込みを施したならば、 .cpp でログを仕込む際には LOG( "hoge %s %f", *something_string, something_float )
と書くだけでよい。UE_LOG
を {
}
でブロックスコープにしてあるので、 if ( x ) LOG( "hoge" )
のように使っても翻訳に支障もない。MYHOGE_ENABLE_LOG
を明示的に制御したい場合は "{your-project-name}.Build.cs に Definitions
で Add
すればよい。
UE4: UnrealWebServer-1.4 の GetData に文字列末尾が汚染されるバグを見つけたので応急対処法
1. UnrealWebServer
2. 問題
- UnrealWebServer-1.4 の
GetData
API の返り値の文字列の末尾がランダムな文字群で汚染されるバグに遭遇した。高頻度で汚染される。
3. 原因
GetData
の実装詳細を確認したところ、内部バッファーとして使用する固定長の char
配列が未初期のため発生する問題の可能性が高い事がわかった。
4. 修正
UnrealWebServer-1.4 を使用して GetData
するニーズのある方が応急処置可能な必要最小限の diff を示します。
Private/Connection.cpp:
43c43 < char post_data[4096]; --- > char post_data[4096] = { 0 };
- Note: UnrealWebServer は Marketplace で販売されている有料のエンジンプラグインのため、応急処置として必要最小限の diff 露出に留めます。
5. おまけ: 自家修正版エンジンプラグインのビルド&エンジンへの配置の仕方
- diff に基いてパッチする。
cmd
でも何でもいいので"C:\Program Files\Epic Games\UE_4.18\Engine\Build\BatchFiles\RunUAT.bat" BuildPlugin -plugin="C:\Program Files\Epic Games\UE_4.18\Engine\Plugins\Marketplace\UnrealWebServerPlugin\UnrealWebServer.uplugin" -package="C:\Users\<your-account>\tmp\UnrealWebServerPlugin"
などと唱える。- 念の為、元のエンジンプラグイン一式 "C:\Program Files\Epic Games\UE_4.18\Engine\Plugins\Marketplace\UnrealWebServerPlugin\" をバックアップする。
- 自家ビルドの修正版エンジンプラグイン "C:\Users\<your-account>\tmp\UnrealWebServerPlugin" を元のエンジンプラグインがあった場所へ入れる。
6. 問題の報告と公式の更新について
この記事を書く前に開発元の Isara tech. にもバグ報告、原因、修正 diff を送ってあるのでそう遠くなくアップデートしてくれる、はず。
UE4: 4.17.2 -> 4.18.1 プロジェクトのアップデートで発生した Warning と Error と対処メモ
若干の調査は必要なものの何れも些細な単純な置き換えで済む問題だけで済んだ。
Warning
1. AddTorque
は AddTorqueInRadians
に置き換えよ
warning C4996: 'UPrimitiveComponent::AddTorque': Use AddTorqueInRadians instead. Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.
- UPrimitiveComponent::AddTorque | Unreal Engine
- UPrimitiveComponent::AddTorqueInRadians | Unreal Engine
void AddTorque ( FVector Torque // Torque to apply. Direction is axis of rotation and magnitude is strength of torque. , FName BoneName = NAME_None // If a SkeletalMeshComponent, name of body to apply torque to. 'None' indicates root body. , bool bAccelChange = false // If true, Torque is taken as a change in angular acceleration instead of a physical torque (i.e. mass will have no effect). );
void AddTorqueInRadians ( FVector Torque // Torque to apply. Direction is axis of rotation and magnitude is strength of torque. , FName BoneName = NAME_None // If a SkeletalMeshComponent, name of body to apply torque to. 'None' indicates root body. , bool bAccelChange = false // If true, Torque is taken as a change in angular acceleration instead of a physical torque (i.e. mass will have no effect). );
API Reference だけ見ても違いがわからない。違いについては予感としては「たぶんない」のだけど、「ない」と知る必要がある。単位や補助単位の変換が必要だとか何かとあり得ない事もない。
source: Runtime/Engine/Classes/Components/PrimitiveComponent.h
void AddTorque(FVector Torque, FName BoneName = NAME_None, bool bAccelChange = false) { AddTorqueInRadians(Torque, BoneName, bAccelChange); }
安心して単に置き換えるとしよう。
2. FPaths::GameDir
は FPath::ProjectDir
に置き換えよ
warning C4996: 'FPaths::GameDir': FPaths::GameDir() has been superseded by FPaths::ProjectDir(). Please update your code to the new API before upgrading to the next release, otherwise your project will no longer compile.
source: Runtime/Core/Public/Misc/Paths.h
DEPRECATED(4.18, "FPaths::GameDir() has been superseded by FPaths::ProjectDir().") static FORCEINLINE FString GameDir() { return ProjectDir(); }
これも単純な置き換えで構わない。
Error
FFileHelper::LoadFileToString
の第3引数の型FFileHelper::EHashOptions
はuint32
から暗黙的に変換不能となった
error C2664: 'bool FFileHelper::LoadFileToString(FString &,const TCHAR *,FFileHelper::EHashOptions)': cannot convert argument 3 from 'const uint32' to 'FFileHelper::EHashOptions'
4.18 に取り込まれた以下のコミットで Runtime/Core/Public/Misc/FileHelper.h の struct EHashOptions { enum Type {
が enum class EHashOptions {
に変更されたので整数の値は直接設定不能になった。
素直に FFileHelper::EHashOptions::None
など enum class
値に置き換えればよい。
UE4: Free Voxel Plugin の作者が Marketpalce にて $99.99 で売り出された Voxel Plugin に痛烈なコメントを付けている件
Marketplace に出品された問題のプラグインは↓の "Voxel Plugin"
知らずに一見すると素晴らしいボクセル地形のプラグインと錯覚してしまい、 $99.99 の価格にも "これくらいなら" とポチってしまうかもしれない。
ところが、ポチる前によくコメントを見ると非常に有用で、愉快かつ痛烈なコメントを見つけられる。
Hethger: What about the Free Voxel Plugin the community is working on? https://forums.unrealengine.com/community/released-projects/125045-free-voxel-plugin What are the improvements worth paying this price for?
Phyronnaz: I've tried the demo, and it seems to perform a lot worse than the free voxel plugin (edit is slow, low render distance). If you consider buying this, you should first check out the free voxel plugin, as it offers many additional features (materials, mesh/landscape/spline import, tesselation, load/save, LOD with infinite render distance ...). Disclaimer: Free Voxel Plugin creator
翻訳:
ヘザー「コミュニティー版の Free Voxel Plugin に比べてどう違うんだい? https://forums.unrealengine.com/community/released-projects/125045-free-voxel-plugin に対して $99.99 を払う付加価値がどこにあるのさ。」
フィロナズ「私がデモを試した限りでは Free Voxel Plugin より酷いシロモノに感じられたよ(編集が遅いし、レンダリング距離も短いし)。これを購入する気なら、それよりも先に Free Voxel Plugin を試してほしいね、それにはもっとたくさんの付加機能もあるし(マテリアル、メッシュ/ランドスケープ、スプラインのインポート、テッセレーション、ロードとセーブ、無限遠のLODレンダリング、ほかたくさん)。注:Free Voxel Plugin の作者より」
面白い、あるいはこのコメントのやりとりは有用だと思った UE4er はとりえあえず UP VOTE して来よう・x・
ちなみに、 Phyronnaz (フィロナズ)は本当に Free Voxel Plugin の開発者です。
ちょうど、ボクセル地形を扱う用事が発生していたところでこのやり取りを見かけて少し面白い気持ちがしたので紹介でした。
参考:
MSVC++ BUG: C Preprocessor is not capable empty argument
MSVC++(2017; cl.exe-19.11.25547) で C プリプロセッサーのマクロが空の引数を受け付けない C++11/14/17, C99/11 に対する規格違反を報告しました。
概要
#define X( X0 ) something ## X0 ()
が定義される時、引数が空の呼び出し X()
は「空のトークンの引数」を受け付ける事になった C++11 (C99) 以降の言語規格に従えば something()
に展開されるべきだが、該当バージョンの現行最新 MSVC++ ではマクロの展開が期待通り行われるエラーとされる。
再現
// compile this code in the MSVC++-19.11.25547 // Expected: compilable // Actual: not compilable; see the comment below #include <cstdio> #define Y( Y0, Y1 ) something ## Y0 ## Y1 () #define X( X0 ) something ## X0 () void something() { puts( "(n/a)" ); } void somethingFoo() { puts( "Foo" ); } void somethingBar() { puts( "Bar" ); } void somethingFooBar() { puts( "FooBar" ); } int main() { Y( Foo, Bar ); Y( Foo, ); // <-- C99 capable, MSVC++ is compilable Y( , Bar ); // <-- C99 capable, MSVC++ is compilable Y( , ); // <-- C99 capable, MSVC++ is compilable X( FooBar ); X( ); // <-- C99 capable, MSVC++ is NOT compilable }
- clang-5.0.0
-std=c++11 -pedantic-errors
: https://wandbox.org/permlink/7KxTfjQ4X52GmH2g
この問題の影響
- 言語規格違反
Y(,)
パターンのような回避策を強いられる。- Microsoft プラットフォームのため『だけ』に追加のコーディングコストを強いられる。
だるい・x・
C++: C プリプロセッサーで定義されるマクロに空のパラメーターを渡す合法性
背景
ソースコード中に大量の少し複雑なアクセサー大量に定義する必要があり、久しぶりに C プリプロセッサーのマクロでアートする機会がありました。マクロを組み上げる上で1つ気になる事が生じました。「マクロに空のパラメーターを渡すのは合法か?」と。
例
#include <cstdio> #define X(X0,X1,X2) X0 ## _ ## X1 ## X2 () void Hoge_FugaPiyo() { puts( "A" ); } void Hoge_Piyo() { puts( "B" ); } int main() { X( Hoge, Fuga, Piyo ); X( Hoge, , Piyo ); }
- GCC-7.2.0
-std=c++1z -pedantic_errors
https://wandbox.org/permlink/lKAR7hpIiCHwjM6w - GCC-7.2.0
-std=c++03 -pedantic_errors
https://wandbox.org/permlink/potzF17rOIEBtkCW
結論
- C++03 (C89) --> 「未定義」(もし意図通り動作するとすればそれはコンパイラーの独自拡張)
- C++11 (C99) --> 「合法」(次節の「論拠」を参照)
- C++14 (C99) --> 「合法」( C++11 を踏襲 )
- C++17 (C11) --> 「合法」( C99 -> C11 で関連仕様は引っくり返っていない)
(Note: C++17 が C11 か C99 かで2回記事を修正しました。詳しくは記事末尾の「修正にあたり頂いた情報源」をどうぞ😃)
論拠
(2.1.) WG14/N1256 Committee Draft - September 7, 2007 ISO/IEC 9899:TC3 §6.10.3/4:
A new feature of C99: Function-like macro invocations may also now have empty arguments, that is, an argument may consist of no preprocessing tokens."
「C99における新機能: 関数様のマクロの実行において空の引数は有り得る、つまり、引数にはプリプロセッサーのトークンが無い事は有り得る。」
(2.2.) Rationale for International Standard - Programming Languages - C Revision 5.10 April-2003 §6.10.3
If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition.
「マクロ定義の識別子リストが省略記号 ( ...
) で終わっていない場合、関数様のマクロ実行の引数群(プリプロセッシングトークンが無い引数も含め)はマクロ定義と同数でなければならない。」
(3.1.) ISO/IEC 9899:201x Committee Draft - April 12, 2011/N1570 §6.10.3/4
C99 と同じ。
と、いうわけで「C++11以降のCプリプロセッサーマクロでは、プリプロセッサーのトークンとしては空っぽの引数もあっていい」と書いてありました😃
参考
- Rationale for International Standard - Programming Languages - C Revision 5.10 April-2003
- WG14/N1256 Committee Draft - September 7, 2007 ISO/IEC 9899:TC3
- ISO/IEC 9899:201x Committee Draft - April 12, 2011/N1570
- c++ - Are empty macro arguments legal in C++11? - Stack Overflow
修正にあたり頂いた情報源
参照情報についてご意見頂き記事を再々修正しました(1回目:C++17がC11ではなくC99ままになったかと誤解して一旦断言を保留。2回目:以下のご意見からC++17はC11を参照と確認できたため記事を初稿同様C++17をC11参照として断言へ)。ありがとうございます😃
C++17 から C11 参照、で合ってますよ。
— Kazutoshi SATODA (@k_satoda) 2017年11月12日
[intro.refs] (1.3) "ISO/IEC 9899:2011, Programming languages — C"https://t.co/8MkQs7kEp5
UE4 の EULA と GPL 、プラグインが内包するソースで確認が必要だったはなし
UE4 EULA と GPL
UE4/EULA では UE4 と一緒に使ってはダメなソースコードのライセンスを明記しています。一部抜粋。
Other Restrictions Non-Compatible Licenses You may not combine, Distribute, or otherwise use the Licensed Technology with any code or other content which is covered by a license that would directly or indirectly require that all or part of the Licensed Technology be governed under any terms other than those of this Agreement (“Non-Compatible License”). Code or content under the following licenses, for example, are prohibited: GNU General Public License (GPL), Lesser GPL (LGPL) (unless you are merely dynamically linking a shared library), or Creative Commons Attribution-ShareAlike License. Code or content under the following licenses, for example, are allowed: BSD License, MIT License, Microsoft Public License, or Apache License. You may not sublicense the Licensed Technology under a Non-Compatible License.
ざっくり要訳としては、
- 「UE4と相容れないライセンス」の「ソースコードなどのあらゆる技術的要素をUE4と組み合わせて使用、配布はできませんよ」
- 「例えば GPL 、動的リンクではない LGPL 、 CC-SA などのライセンスが UE3と相容れないライセンスの技術要素に該当します」
- 「ちなみに、 BSD License 、 Microsoft Public License 、 Apache License などは許容されますよ」
と書いてあります。不自由な GPL にラインセンスされた少なくとも UE4 使いにとっては不遇なライブラリー群に特に外部ライブラリーを必要に応じて導入する機会も少なくない UE4/C++er はよく注意する必要があります。
Note: EULAのより広範についての公式な日本語のFAQは UE4/日本語版FAQ をどうぞ。
Mongoose と GPLv2
先日、 UE4 の Marketplace にも登録されている "あるエンジン向けのソースコードプラグイン" の内部で Github Mongoose を使用している事に気付きました。ライセンシングにある程度の注意を払っている一般的な C++er としては脳が警戒モードの動作に切り替わり確認作業が始まります。
- Github Mongoose LICENSE latest <-- 明らかに GPLv2
しかし、"あるプラグイン" については、結論としては「UE4での使用、製品のリリースに問題なし。GPLv2の影響は受けないので最終的な製品のソースコード開示義務も負わない」となりました。 "あるプラグイン" では確かに内部的に "Mongoose" ライブラリーを使用していましたが、"最新版の GPLv2 の Mongoose" のコードは使っていないと調査されたためです。そして、 "Mongoose" はある時点でライセンスを "AS IS" タイプの自由なライセンスから不自由な "GPLv2" へ切り替えています。
- Github Mongoose LICENSE diff <-- 2013年8月16日、自由な "AS IS" ライセンスから不自由な "GPLv2" へ切り替え
"あるプラグイン"のソースコードが添付の LICENSE ファイルだけでなく、本当にライセンス変更以前のバージョンのものか調査するコストは若干の手間はかかりますが、結果、 UE4 で使用しても問題のない自由なライセンス時代のソースをベースにしている事がわかり、無事にこの "ライセンス違反の恐れ" は問題無い事がわかったのでした。
Marketplace で手に入る"いわば公認"のプラグイン群については心配するだけ過剰な気もしますが、コミュニティーベースのフリーのプラグインや公式から遠いところで公開されているプラグイン、また自作のプラグインなどでうっかりライセンス違反が起こらないように気を付けたいですね。