Describe the bug
Not a bug. I am just wondering what prevents building filament using the native Microsoft compiler in Visual Studio? Is it just a matter of C++ code not building?
I saw a reference about assembly code in another issue. Is this still a problem or is there equivalent c code?
msvc encounters a lot of errors and warnings when attempting to build our codebase. We are not willing to implement some of the fixes required to make our code compile with msvc. That said we haven't tried with VS2019 which might behave better (unfortunately our CI is limited to VS2015 at the moment.
Note that you can use a prebuilt version of Filament with msvc; our public headers should work just fine, if they don't please let us know.
Thanks a lot for the quick answer. I just need to say that filament is awesome, and the doc too!
Unfortunately, The public headers don't quite work with msvc.
vs2015 was having lots of issues with constexpr, so I switched to vs2019, but even then the headers have issues.
For example in utils/compilers.h we hit the #error Compiler does not support the packed attribute.. This #error can be commented out as the macro UTILS_PACKED doesn't seem to be referenced by the other headers.
Another issue which shows up when building a sample (however this may not be required for using filament) is the following on vec2, vec3, vec4:
error C2976: 'filament::math::vec2': too few template arguments on:
using half2 = vec2
Although half is defined as is_floating_point in half.h, it is not defined as is_arithmetic which is what is tested in:
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value >::type>
using vec2 = details::TVec2<T>;
Possibly libc++ automatically does that, but not msvc. In any case I'm not sure how useful the std::enable_if in the vec2, vec3 and vec4 definitions is (besides giving a shrter error is someone tries to define a vec2 of a non-arithmetic type).
I'll keep trying to build the material_sandbox sample using native vs2019.
Thanks for the info, we should fix the headers.
@bejado Ben, do you mind fixing those issue? The problem in half.h should be easy to fix.
Yes, just adding in half.h:
#if defined(_MSC_VER)
template<> struct is_arithmetic< filament::math::half> : public std::true_type {};
#endif
is enough. But if you guys want, give me a couple days and I'll send you a PR.
We don't need to make is msvc specific right? I don't see any reason why we couldn't do this with clang.
I was just concerned that if there is the same definition in libc++ it might cause an error, but I just tried rebuilding with clang on my pc with the non-msvc specific change and it built fine.
Another issue is this:
1>C:\greg\filament\samples - Copy\app\CameraManipulator.cpp(74,29): error C2666: 'filament::math::details::TQuatProductOperators<filament::math::details::TQuaternion,T>::operator *': 13 overloads have similar conversions
1>C:\greg\filament\samples - Copy\app\CameraManipulator.cpp(74,29): error C2666: with
1>C:\greg\filament\samples - Copy\app\CameraManipulator.cpp(74,29): error C2666: [
1>C:\greg\filament\samples - Copy\app\CameraManipulator.cpp(74,29): error C2666: T=double
1>C:\greg\filament\samples - Copy\app\CameraManipulator.cpp(74,29): error C2666: ]
1>C:\greg\filament\include\math\TQuatHelpers.h(130,39): message : could be 'filament::math::details::TQuaternion<double> filament::math::details::TQuatProductOperators<filament::math::details::TQuaternion,T>::operator *(filament::math::details::TQuaternion<T>,T)' [found using argument-dependent lookup]
1>C:\greg\filament\include\math\TQuatHelpers.h(130,39): message : with
1>C:\greg\filament\include\math\TQuatHelpers.h(130,39): message : [
1>C:\greg\filament\include\math\TQuatHelpers.h(130,39): message : T=double
1>C:\greg\filament\include\math\TQuatHelpers.h(130,39): message : ]
1>C:\greg\filament\include\math\TQuatHelpers.h(135,39): message : or 'filament::math::details::TQuaternion<double> filament::math::details::TQuatProductOperators<filament::math::details::TQuaternion,T>::operator *(T,filament::math::details::TQuaternion<T>)' [found using argument-dependent lookup]
1>C:\greg\filament\include\math\TQuatHelpers.h(135,39): message : with
1>C:\greg\filament\include\math\TQuatHelpers.h(135,39): message : [
1>C:\greg\filament\include\math\TQuatHelpers.h(135,39): message : T=double
1>C:\greg\filament\include\math\TQuatHelpers.h(135,39): message : ]
1>C:\greg\filament\include\math\TVecHelpers.h(204,49): message : or 'filament::math::details::TVec4<double> filament::math::details::TVecProductOperators<filament::math::details::TVec4,T>::operator *(filament::math::details::TVec4<T>,const filament::math::details::TVec4<T> &)' [found using argument-dependent lookup]
1>C:\greg\filament\include\math\TVecHelpers.h(204,49): message : with
1>C:\greg\filament\include\math\TVecHelpers.h(204,49): message : [
1>C:\greg\filament\include\math\TVecHelpers.h(204,49): message : T=double
1>C:\greg\filament\include\math\TVecHelpers.h(204,49): message : ]
...
I guess this is because the quaternions and vec4 and vec3 ... can all be implicitely constructed with a float or a double, because the following are not explicit. I wonder how this is not an issue with clang:
// handles implicit conversion to a tvec4. must not be explicit.
template<typename A>
constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {
static_assert(std::is_arithmetic<A>::value, "requires arithmetic type");
}
and
// handles implicit conversion to a tvec4. must not be explicit.
template<typename A>
constexpr TVec4(A v) : x(v), y(v), z(v), w(v) { }
The same issue happens with vec2/3/4. myVec2 + 0.5 yields an error with MSVC (at least with VS2015). And it's one of ergonomics we don't want to compromise.
Well, we really should figure out which compiler is correct, because if clang is not standard conformant by allowing this, it could change in a future release.
I wonder how it is possible to feel confident in what the code actually compiles to with all these implicit conversions?
gcc was fine with that code too, but yeah I agree.
@pixelflinger who owns this code.
Some hints can probably be found here: https://en.cppreference.com/w/cpp/language/implicit_conversion
Yes. I'll try reproducing the issue in a small program so it is easier to figure out which compiler is correct.
Confirmed as still an issue on vs2019.
Also confirmed adding is_arithmentic fixes it,
template<> struct is_arithmetic< filament::math::half> : public std::true_type {};
C:\projects\XXX\filament-20190426-windows\include\math\vec2.h(102): error C2976: 'filament::math::vec2': too few template arguments
C:\projects\XXX\filament-20190426-windows\include\math/vec2.h(98): note: see declaration of 'filament::math::vec2'
C:\projects\XXX\filament-20190426-windows\include\math\vec3.h(121): error C2976: 'filament::math::vec3': too few template arguments
C:\projects\XXX\filament-20190426-windows\include\math/vec3.h(117): note: see declaration of 'filament::math::vec3'
C:\projects\XXX\filament-20190426-windows\include\math\vec4.h(113): error C2976: 'filament::math::vec4': too few template arguments
C:\projects\XXX\filament-20190426-windows\include\math/vec4.h(109): note: see declaration of 'filament::math::vec4'
It may be more involved than I originally thought to reproduce the error C2666: 'filament::math::details::TQuatProductOperators<filament::math::details::TQuaternion,T>::operator *': 13 overloads have similar conversions issue. I tried the code below, but it does build fine with msvc as well as gcc.
#include <cstdio>
#include <cassert>
#if __has_attribute(pure)
# define MATH_PURE __attribute__((pure))
#else
# define MATH_PURE
#endif
#ifdef _MSC_VER
#define MATH_EMPTY_BASES __declspec(empty_bases)
#define MATH_NOUNROLL
#else // _MSC_VER
#define MATH_EMPTY_BASES
#define MATH_NOUNROLL _Pragma("nounroll")
#endif // _MSC_VER
template <template<typename T> class QUATERNION, typename T>
class TQuatProductOperators {
public:
constexpr QUATERNION<T>& operator *= (T v) {
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
lhs[i] *= v;
}
return lhs;
}
friend inline
constexpr QUATERNION<T> MATH_PURE operator *(QUATERNION<T> q, T scalar) {
// don't pass q by reference because we need a copy anyways
return q *= scalar;
}
friend inline
constexpr QUATERNION<T> MATH_PURE operator *(T scalar, QUATERNION<T> q) {
// don't pass q by reference because we need a copy anyways
return q *= scalar;
}
friend inline
constexpr QUATERNION<T> MATH_PURE operator /(QUATERNION<T> q, T scalar) {
// don't pass q by reference because we need a copy anyways
return q /= scalar;
}
};
template <typename T>
class MATH_EMPTY_BASES TQuaternion : public TQuatProductOperators<TQuaternion, T>
{
public:
enum { SIZE = 4 };
inline constexpr static size_t size() { return SIZE; }
inline constexpr T& operator[](size_t i) {
assert(i < SIZE);
return (&x)[i];
}
template<typename A>
constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {
}
union {
struct { T x, y, z, w; };
};
};
template<template<typename T> class VECTOR, typename T>
class TVecProductOperators {
public:
/* compound assignment from a another vector of the same size but different
* element type.
*/
template<typename OTHER>
constexpr VECTOR<T>& operator *=(const VECTOR<OTHER>& v) {
VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
for (size_t i = 0; i < lhs.size(); i++) {
lhs[i] *= v[i];
}
return lhs;
}
/*
* NOTE: the functions below ARE NOT member methods. They are friend functions
* with they definition inlined with their declaration. This makes these
* template functions available to the compiler when (and only when) this class
* is instantiated, at which point they're only templated on the 2nd parameter
* (the first one, BASE<T> being known).
*/
/* The operators below handle operation between vectors of the same size
* but of a different element type.
*/
template<typename RT>
friend inline constexpr VECTOR<T> MATH_PURE operator *(VECTOR<T> lv, const VECTOR<RT>& rv) {
// don't pass lv by reference because we need a copy anyways
return lv *= rv;
}
/* The operators below (which are not templates once this class is instanced,
* i.e.: BASE<T> is known) can be used for implicit conversion on both sides.
* These handle operations like "vector * scalar" and "scalar * vector" by
* letting the compiler implicitly convert a scalar to a vector (assuming
* the BASE<T> allows it).
*/
friend inline constexpr VECTOR<T> MATH_PURE operator *(VECTOR<T> lv, const VECTOR<T>& rv) {
// don't pass lv by reference because we need a copy anyways
return lv *= rv;
}
};
template <typename T>
class MATH_EMPTY_BASES TVec3 : public TVecProductOperators<TVec3, T> {
public:
static constexpr size_t SIZE = 3;
union {
T v[SIZE];
struct { T x, y, z; };
};
inline constexpr size_t size() const { return SIZE; }
// array access
inline constexpr T const& operator[](size_t i) const {
// only possible in C++0x14 with constexpr
assert(i < SIZE);
return v[i];
}
inline constexpr T& operator[](size_t i) {
assert(i < SIZE);
return v[i];
}
// constructors
// default constructor
constexpr TVec3() = default;
// handles implicit conversion to a tvec4. must not be explicit.
template<typename A>
constexpr TVec3(A v) : x(v), y(v), z(v) { }
template<typename A, typename B, typename C>
constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { }
};
template <typename T> using vec3 = TVec3<T>;
template <typename T>
class MATH_EMPTY_BASES TVec4 : public TVecProductOperators<TVec4, T>{
public:
typedef T value_type;
typedef T& reference;
typedef T const& const_reference;
typedef size_t size_type;
static constexpr size_t SIZE = 4;
union {
T v[SIZE];
struct { T x, y, z, w; };
};
inline constexpr size_t size() const { return SIZE; }
// array access
inline constexpr T const& operator[](size_t i) const {
// only possible in C++0x14 with constexpr
assert(i < SIZE);
return v[i];
}
inline constexpr T& operator[](size_t i) {
assert(i < SIZE);
return v[i];
}
// constructors
// default constructor
constexpr TVec4() = default;
// handles implicit conversion to a tvec4. must not be explicit.
template<typename A>
constexpr TVec4(A v) : x(v), y(v), z(v), w(v) { }
template<typename A, typename B, typename C, typename D>
constexpr TVec4(A x, B y, C z, D w) : x(x), y(y), z(z), w(w) { }
template<typename A, typename B>
constexpr TVec4(const TVec3<A>& v, B w) : x(v.x), y(v.y), z(v.z), w(w) { }
template<typename A>
constexpr TVec4(const TVec4<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) { }
};
using double3 = vec3<double>;
int main()
{
double3 d_s = { 1.0, 0.0, 0.0};
double3 d_t = { 0.0, 1.0, 0.0};
double s = 1;
double t = 2;
double3 mTranslation = (s * d_s);
double3 tTranslation = (t * d_t);
return (int)mTranslation[0];
}
@meshula Thanks for the update!
@gpyalt I think we'll need to wait for @pixelflinger to chime in :/
Thanks @romainguy and @meshula!
One more note, I'm attempting to use msvc to link, but running into issues vs opengl32.lib. I added some notes on this related issue: https://github.com/google/filament/issues/652#issuecomment-500646203
@bejado To solve our CI problem maybe we could setup a CircleCI or similar for the Windows build? Releases will be a bit more annoying but we'd have access to more recent compilers I think.
And VS Community is available for Open Source projects so that could work for us.
I think that is_arithmetic should be true for any type that is_floating_point. This is not technically the C++ spec, but this is what it says on cppreference.com:
If T is an arithmetic type (that is, an integral type or a floating-point type) or a cv-qualified version thereof, provides the member constant value equal true. For any other type, value is false.
So this looks like an MSVC issue. I'll have a workaround in filament.
Clang 8.0.1 on Windows has the same problem with is_arithmetic. clang-cl unable to compile the code with original headers:
is_arithmetic logs
In file included from ..\source\filament.cpp:2:
In file included from ..\source/filament.h:52:
In file included from ..\include\filament/Engine.h:20:
In file included from ..\include\filament/Camera.h:22:
In file included from ..\include\filament/Frustum.h:22:
In file included from ..\include\filament/Box.h:26:
In file included from ..\include\math/mat4.h:20:
In file included from ..\include\math/mat3.h:20:
In file included from ..\include\math/quat.h:21:
In file included from ..\include\math/TQuatHelpers.h:28:
In file included from ..\include\math/vec3.h:20:
..\include\math/vec2.h(97,58): error: failed requirement 'std::is_arithmetic<filament::math::half>::value'; 'enable_if'
cannot be used to disable this declaration
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value >::type>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
..\include\math/vec2.h(102,15): note: in instantiation of default argument for 'vec2<filament::math::half>' required
here
using half2 = vec2<half>;
^~~~~~~~~~
In file included from ..\source\filament.cpp:2:
In file included from ..\source/filament.h:52:
In file included from ..\include\filament/Engine.h:20:
In file included from ..\include\filament/Camera.h:22:
In file included from ..\include\filament/Frustum.h:22:
In file included from ..\include\filament/Box.h:26:
In file included from ..\include\math/mat4.h:20:
In file included from ..\include\math/mat3.h:20:
In file included from ..\include\math/quat.h:21:
In file included from ..\include\math/TQuatHelpers.h:28:
..\include\math/vec3.h(116,58): error: failed requirement 'std::is_arithmetic<filament::math::half>::value'; 'enable_if'
cannot be used to disable this declaration
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value >::type>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
..\include\math/vec3.h(121,15): note: in instantiation of default argument for 'vec3<filament::math::half>' required
here
using half3 = vec3<half>;
^~~~~~~~~~
In file included from ..\source\filament.cpp:2:
In file included from ..\source/filament.h:52:
In file included from ..\include\filament/Engine.h:20:
In file included from ..\include\filament/Camera.h:22:
In file included from ..\include\filament/Frustum.h:22:
In file included from ..\include\filament/Box.h:26:
In file included from ..\include\math/mat4.h:20:
In file included from ..\include\math/mat3.h:20:
In file included from ..\include\math/quat.h:23:
..\include\math/vec4.h(108,58): error: failed requirement 'std::is_arithmetic<filament::math::half>::value'; 'enable_if'
cannot be used to disable this declaration
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value >::type>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
..\include\math/vec4.h(113,15): note: in instantiation of default argument for 'vec4<filament::math::half>' required
here
using half4 = vec4<half>;
There's also a few other errors:
M_PI logs
In file included from ..\source\filament.cpp:2:
In file included from ..\source/filament.h:52:
In file included from ..\include\filament/Engine.h:20:
In file included from ..\include\filament/Camera.h:22:
In file included from ..\include\filament/Frustum.h:22:
In file included from ..\include\filament/Box.h:26:
..\include\math/mat4.h(495,28): error: use of undeclared identifier 'M_PI'; unqualified lookup into dependent bases of
class template 'TMat44' is a Microsoft extension [-Werror,-Wmicrosoft-template]
h = std::tan(fov * M_PI / 360.0f) * near;
^
..\include\math/mat4.h(498,28): error: use of undeclared identifier 'M_PI'; unqualified lookup into dependent bases of
class template 'TMat44' is a Microsoft extension [-Werror,-Wmicrosoft-template]
w = std::tan(fov * M_PI / 360.0f) * near;
^
(Can be solved by adding #define _USE_MATH_DEFINES to the helpers before #include <math.h>).
Unsafe floating-point comparison:
In file included from ..\source\filament.cpp:2:
In file included from ..\source/filament.h:52:
In file included from ..\include\filament/Engine.h:20:
In file included from ..\include\filament/Camera.h:22:
In file included from ..\include\filament/Frustum.h:22:
..\include\filament/Box.h(47,36): error: comparing floating point with == or != is unsafe [-Werror,-Wfloat-equal]
return length2(halfExtent) == 0;
~~~~~~~~~~~~~~~~~~~ ^ ~
MSVC 19.22.27905 throws a small warning:
filament.cpp
..\include\utils/algorithm.h(49): warning C4293: '>>': shift count negative or too big, undefined behavior
..\include\utils/algorithm.h(77): note: see reference to function template instantiation 'T utils::details::clz<unsigned int>(T) noexcept' being compiled
with
[
T=unsigned int
]
Hi @nxrighthere, I am still working on building all filament with vs2019. At this point I am not concerned with the warnings, just trying to get it all to build. The main issue I have is with aggregate initializers, where filament code uses some non-standard features (that clang supports). Sometimes the fix is easy, like use the struct order even when .designators are used. I'm making good progress, and hopefully I'll be done in a few days and have a PR to submit to the filament team.
@gpyalt Do you have examples of non-standard features Filament relies on? It's definitely not our intent to use features that are not part of the C++ standard.
@romainguy, sure, I am glad to hear that! (ps: this is my personal github acct - same as @gpyalt)
As I said, I plan to send a PR with a bunch of diffs. Or I can send them piecemeal so there are easier to digest. Just for info, whatever you prefer, I also have changes in the CMakeLists.txt so that the visual studio config works.
Here is some things I found
examples:
struct B b = {.a.x = 0}; // valid C, invalid C++ (nested)nested: multiple instances. For example in PostProcessManager.cpp, FrameGraph.cpp
{ .attachments.color = { data.ssao, FrameGraphRenderTarget::Attachments::WRITE },
.attachments.depth = { data.depth, FrameGraphRenderTarget::Attachments::READ }
example of change:


out of order: multiple instances (Renderer.cpp, ...)
data.depth = builder.createTexture("Depth Buffer", {
.width = svp.width, .height = svp.height,
.samples = msaa,
.format = TextureFormat::DEPTH24
});
example of change:





Thanks, that's useful.
Please don't make any change yet... I'll be submitting pull requests soon.
I basically have everything building with vs2019/msvc, last issue is some undefined symbols when linking suzanne (related to backend/bluegl):
1>------ Build started: Project: suzanne, Configuration: Debug x64 ------
1>LINK : warning LNK4044: unrecognized option '/Wl,--gc-sections'; ignored
1>backend.lib(OpenGLDriver.obj) : error LNK2019: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64,unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::beginFrame(__int64,unsigned int)>::log(void)" (?log@?$Command@$1?beginFrame@Driver@backend@filament@@QEAAX_JI@Z@?$CommandType@P8Driver@backend@filament@@EAAX_JI@Z@backend@filament@@AEAAXXZ) referenced in function "public: static void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64,unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::beginFrame(__int64,unsigned int)>::execute<void (__cdecl filament::OpenGLDriver::*)(__int64,unsigned int),class filament::OpenGLDriver &>(void (__cdecl filament::OpenGLDriver::*&&)(__int64,unsigned int),class filament::OpenGLDriver &,class filament::backend::CommandBase *,__int64 *)" (??$execute@P8OpenGLDriver@filament@@EAAX_JI@ZAEAV12@@?$Command@$1?beginFrame@Driver@backend@filament@@QEAAX_JI@Z@?$CommandType@P8Driver@backend@filament@@EAAX_JI@Z@backend@filament@@SAX$$QEAP8OpenGLDriver@3@EAAX_JI@ZAEAV43@PEAVCommandBase@23@PEA_J@Z)
1>backend.lib(NoopDriver.obj) : error LNK2001: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64,unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::beginFrame(__int64,unsigned int)>::log(void)" (?log@?$Command@$1?beginFrame@Driver@backend@filament@@QEAAX_JI@Z@?$CommandType@P8Driver@backend@filament@@EAAX_JI@Z@backend@filament@@AEAAXXZ)
1>backend.lib(OpenGLDriver.obj) : error LNK2019: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64)>::Command<&public: void __cdecl filament::backend::Driver::setPresentationTime(__int64)>::log(void)" (?log@?$Command@$1?setPresentationTime@Driver@backend@filament@@QEAAX_J@Z@?$CommandType@P8Driver@backend@filament@@EAAX_J@Z@backend@filament@@AEAAXXZ) referenced in function "public: static void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64)>::Command<&public: void __cdecl filament::backend::Driver::setPresentationTime(__int64)>::execute<void (__cdecl filament::OpenGLDriver::*)(__int64),class filament::OpenGLDriver &>(void (__cdecl filament::OpenGLDriver::*&&)(__int64),class filament::OpenGLDriver &,class filament::backend::CommandBase *,__int64 *)" (??$execute@P8OpenGLDriver@filament@@EAAX_J@ZAEAV12@@?$Command@$1?setPresentationTime@Driver@backend@filament@@QEAAX_J@Z@?$CommandType@P8Driver@backend@filament@@EAAX_J@Z@backend@filament@@SAX$$QEAP8OpenGLDriver@3@EAAX_J@ZAEAV43@PEAVCommandBase@23@PEA_J@Z)
1>backend.lib(NoopDriver.obj) : error LNK2001: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64)>::Command<&public: void __cdecl filament::backend::Driver::setPresentationTime(__int64)>::log(void)" (?log@?$Command@$1?setPresentationTime@Driver@backend@filament@@QEAAX_J@Z@?$CommandType@P8Driver@backend@filament@@EAAX_J@Z@backend@filament@@AEAAXXZ)
1>backend.lib(OpenGLDriver.obj) : error LNK2019: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::endFrame(unsigned int)>::log(void)" (?log@?$Command@$1?endFrame@Driver@backend@filament@@QEAAXI@Z@?$CommandType@P8Driver@backend@filament@@EAAXI@Z@backend@filament@@AEAAXXZ) referenced in function "public: static void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::endFrame(unsigned int)>::execute<void (__cdecl filament::OpenGLDriver::*)(unsigned int),class filament::OpenGLDriver &>(void (__cdecl filament::OpenGLDriver::*&&)(unsigned int),class filament::OpenGLDriver &,class filament::backend::CommandBase *,__int64 *)" (??$execute@P8OpenGLDriver@filament@@EAAXI@ZAEAV12@@?$Command@$1?endFrame@Driver@backend@filament@@QEAAXI@Z@?$CommandType@P8Driver@backend@filament@@EAAXI@Z@backend@filament@@SAX$$QEAP8OpenGLDriver@3@EAAXI@ZAEAV43@PEAVCommandBase@23@PEA_J@Z)
1>backend.lib(NoopDriver.obj) : error LNK2001: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(unsigned int)>::Command<&public: void __cdecl filament::backend::Driver::endFrame(unsigned int)>::log(void)" (?log@?$Command@$1?endFrame@Driver@backend@filament@@QEAAXI@Z@?$CommandType@P8Driver@backend@filament@@EAAXI@Z@backend@filament@@AEAAXXZ)
...
1>backend.lib(OpenGLDriver.obj) : error LNK2019: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::Command<&public: void __cdecl filament::backend::Driver::draw(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::log(void)" (?log@?$Command@$1?draw@Driver@backend@filament@@QEAAXUPipelineState@34@U?$Handle@UHwRenderPrimitive@backend@filament@@@34@@Z@?$CommandType@P8Driver@backend@filament@@EAAXUPipelineState@23@U?$Handle@UHwRenderPrimitive@backend@filament@@@23@@Z@backend@filament@@AEAAXXZ) referenced in function "public: static void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::Command<&public: void __cdecl filament::backend::Driver::draw(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::execute<void (__cdecl filament::OpenGLDriver::*)(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>),class filament::OpenGLDriver &>(void (__cdecl filament::OpenGLDriver::*&&)(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>),class filament::OpenGLDriver &,class filament::backend::CommandBase *,__int64 *)" (??$execute@P8OpenGLDriver@filament@@EAAXUPipelineState@backend@2@U?$Handle@UHwRenderPrimitive@backend@filament@@@42@@ZAEAV12@@?$Command@$1?draw@Driver@backend@filament@@QEAAXUPipelineState@34@U?$Handle@UHwRenderPrimitive@backend@filament@@@34@@Z@?$CommandType@P8Driver@backend@filament@@EAAXUPipelineState@23@U?$Handle@UHwRenderPrimitive@backend@filament@@@23@@Z@backend@filament@@SAX$$QEAP8OpenGLDriver@3@EAAXUPipelineState@23@U?$Handle@UHwRenderPrimitive@backend@filament@@@23@@ZAEAV43@PEAVCommandBase@23@PEA_J@Z)
1>backend.lib(NoopDriver.obj) : error LNK2001: unresolved external symbol "private: void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::Command<&public: void __cdecl filament::backend::Driver::draw(struct filament::backend::PipelineState,struct filament::backend::Handle<struct filament::backend::HwRenderPrimitive>)>::log(void)" (?log@?$Command@$1?draw@Driver@backend@filament@@QEAAXUPipelineState@34@U?$Handle@UHwRenderPrimitive@backend@filament@@@34@@Z@?$CommandType@P8Driver@backend@filament@@EAAXUPipelineState@23@U?$Handle@UHwRenderPrimitive@backend@filament@@@23@@Z@backend@filament@@AEAAXXZ)
1>C:\greg\github\filament\out2\samples\Debug\suzanne.exe : fatal error LNK1120: 53 unresolved externals
Any idea?
bluegl doesn't seem to be involved here. It looks like this method wasn't compiled/exported properly?
template<typename... ARGS>
template<void (Driver::*METHOD)(ARGS...)>
void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log() noexcept {
log(std::make_index_sequence<std::tuple_size<SavedParameters>::value>{});
}
It is inside CommandStream.cpp, I wonder if it needs to move somewhere else.
Thanks for the pointer, @romainguy , I'll look into it further.
@romainguy I see the CommandType template definition, but I don't understand where all the specializations are defined. It seems that it should be with the #include "private/backend/DriverAPI.inc", but this is included only when #if DEBUG_COMMAND_STREAM
@pixelflinger
Undefined symbol (more legible):
void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64,unsigned int)>::
Command<&public: void __cdecl filament::backend::Driver::beginFrame(__int64,unsigned int)>::
log(void)"
referenced in function
void __cdecl filament::backend::CommandType<void (__cdecl filament::backend::Driver::*)(__int64,unsigned int)>::
Command<&public: void __cdecl filament::backend::Driver::beginFrame(__int64,unsigned int)>::
execute<void (__cdecl filament::OpenGLDriver::*)(__int64,unsigned int),class filament::OpenGLDriver &>(void (__cdecl filament::OpenGLDriver::*&&)(__int64,unsigned int),class filament::OpenGLDriver &,class filament::backend::CommandBase *,__int64 *)"
OK, I got it to link. Indeed the issue was that the CommandType::Command::log() template functions were defined in CommandStream,cpp, but not called from that file. It is called from other cpp files, however none of which had access to the function definition) so MSVC did not instantiate this function in any .o file.
Moving the definition of the two log() functions inline in the CommandType::Command definition fixed the issue.
Finally, I got the material_sandbox to run on windows, all built with vs2019. I'll keep sending PRs for the changes.


it builds with msvc now, closing the issue :-)
Most helpful comment
Finally, I got the material_sandbox to run on windows, all built with vs2019. I'll keep sending PRs for the changes.
