FBX SDKの"シンボルがあいまいです"エラーを駆逐する
結論
.vscode/c_cpp_properties.json
のdefinesにFBXSDK_DEFINE_NAMESPACE=0
とFBXSDK_NAMESPACE_USING=0
を追加する。
{
"configurations": [
{
"name": "Win32",
"defines": [
"FBXSDK_DEFINE_NAMESPACE=0",
"FBXSDK_NAMESPACE_USING=0"
],
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
.vscode/settings.json
に以下の項目を追加する。
{
"C_Cpp.default.mergeConfigurations": true
}
以上。
はじめに
VSCodeでFBX SDKを使ってコードを書いているとよくこうなる。
(Visual Studio使えとか言わないで)
ウザすぎる
何があいまいなんだ。3秒前までちゃんと補完してくれていたじゃないか。
CMakeを使っている場合は再度Configureすれば直るがあまりにも頻繁になるので鬱陶しすぎる。
これをとにかく何とかしたい。
FBX SDKにnamespaceってないの?
あいまいです系のエラーといえば大体namespace被りとかその辺りである。
そもそもFbxManager
とかFbxNode
とかは特にnamespaceをつけなくても使用することができるが、別にnamespaceが定義されていないわけではない。
fbxsdk.h
を覗いてみると末尾に以下の記述がある
...
#if defined(FBXSDK_NAMESPACE) && (FBXSDK_NAMESPACE_USING == 1)
using namespace FBXSDK_NAMESPACE;
#endif
...
つまり、FBXSDK_NAMESPACE
という名前のマクロで定義されたnamespaceがあり、それをusing namespaceすることでスコープ外からそのまま使えるようにしている。
namespaceはどこで定義されているか
当たり前だがFBXSDK_NAMESPACE
の定義がどこかに存在する。これはfbxsdk.h
でincludeされるfbxsdk/fbxsdk_def.h
でincludeされているfbxsdk/fbxsdk_version.h
の中にある。
...
//FBX SDK namespace definition
#ifndef FBXSDK_DEFINE_NAMESPACE
#define FBXSDK_DEFINE_NAMESPACE 1
#endif
#if FBXSDK_DEFINE_NAMESPACE == 1
#define FBXSDK_NAMESPACE fbxsdk
#else
#define FBXSDK_NAMESPACE
#endif
...
FBXSDK_DEFINE_NAMESPACE
が定義されていなければ1と定義し、この場合FBXSDK_NAME
が"fbxsdk"になる。
つまり、
#define FBXSDK_NAMESPACE_USING 0
#include <fbxsdk.h>
などとしてやれば
int main() {
fbxsdk::FbxManager* manager = fbxsdk::FbxManager::Create();
}
のようなかたちで書くことになる。
namespaceブロックはどうなっているか
namespaceがどこで定義されているのかは分かったが、実際に各クラスはどのようにしてnamespaceの中に収まっているのか。たとえばfbxsdk/core/fbxobject.h
の中身を覗いてみると何やら怪しげな記述がある
//! \file fbxobject.h
#ifndef _FBXSDK_CORE_OBJECT_H_
#define _FBXSDK_CORE_OBJECT_H_
/* ~色々なinclude~ */
#include <fbxsdk/fbxsdk_nsbegin.h>
/* ~さまざまな定義~ */
#include <fbxsdk/fbxsdk_nsend.h>
#endif /* _FBXSDK_CORE_OBJECT_H_ */
このfbxsdk_nsbegin.h
とfbxsdk_nsend.h
の中身は
//! \file fbxsdk_nsbegin.h
#include <fbxsdk/fbxsdk_version.h>
#if FBXSDK_DEFINE_NAMESPACE == 1
namespace FBXSDK_NAMESPACE {
#endif
//! \file fbxsdk_nsend.h
#if FBXSDK_DEFINE_NAMESPACE == 1
}
#endif
という短いもの。これを各ファイルでincludeすることで全部のクラスをnamespace内に収めている。
なぜエラーは起こるか
ところでこのfbxsdk_nsbegin.h
をIntelliSenseが効いた状態で覗いてみよう
なんかエラー出てる~
これは推測に過ぎないが、これこそがあいまいですエラーを出している元凶である。C++のIntelliSenseはnamespaceが別ファイルに記述されてincludeされるという状態を想定していないと思われる。
ということはnamespaceを消せば…!
ここまでくれば解決策は簡単に思いつく。
FBX SDKではnamespaceを定義されたうえで全体でusingされている。つまりnamespace定義を抹消してもコード記述は変わらない。じゃあ消せばいいんや!
#define FBXSDK_DEFINE_NAMESPACE 0
#define FBXSDK_NAMESPACE_USING 0
#include <fbxsdk.h>
これで全部解決!計算通り、完璧〜♪
そうは問屋が卸さなかった
😱😱😱
何が起こったか。そう、リンカエラーである。
namespaceを消した状態でビルドするとシンボル名が変わってしまうためdllで定義された名前と変わってしまい、ビルドに失敗してしまう。
ならこんな回りくどいnamespaceのつけ方するな
本当の解決策
要するに「IntelliSenseにはnamespaceがないかのように見せかけ、ビルドするときは存在していればいい」のである。ので、冒頭の結論通りに.vscode/c_cpp_properties.json
のdefinesにFBXSDK_DEFINE_NAMESPACE=0
とFBXSDK_NAMESPACE_USING=0
を追加する。
{
"configurations": [
{
"name": "Win32",
"defines": [
"FBXSDK_DEFINE_NAMESPACE=0",
"FBXSDK_NAMESPACE_USING=0"
],
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
ビルドはVisual StudioでやっててIntelliSenseだけ別に設定するならここまででよい。しかしCMake Toolsを使っている場合、configurationProviderから提供される設定でc_cpp_properties.json
の設定のほとんどが上書きされてしまう。そこで下記を追加する。
{
"C_Cpp.default.mergeConfigurations": true
}
この設定をするとconfigurationProviderから来た設定とc_cpp_properties.json
の設定を混ぜることができる。つまり、IntelliSenseだけ騙すことができ、無事"あいまいです"エラーは出なくなるし、ビルドも通るようになる。
これにて本当に、一件落着。
Discussion