Visual studio 2012 portability...
#1
Photo 
Hi !

I have tried to compile mcserver using vs2012 (simply because I don't have free disk space for vs2013), and it gives compilation errors like:

1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\ratio(216): error C2027: use of undefined type 'std::_Ratio_divide2<_R1,_R2>'
1> with
1> [
1> _R1=std::ratio_multiply<std::ratio<0x01,0x03e8>,std::ratio<0x032>>,
1> _R2=std::milli
1> ]
1> c:\projects_new\server\mcserver\src\entities\../World.h(173) : see reference to class template instantiation 'std::ratio_divide<_R1,_R2>' being compiled
1> with
1> [
1> _R1=std::ratio_multiply<std::ratio<0x01,0x03e8>,std::ratio<0x032>>,
1> _R2=std::milli
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\ratio(216): error C2146: syntax error : missing ';' before identifier 'type'
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\ratio(216): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\ratio(216): error C2602: 'std::ratio_divide<_R1,_R2>::type' is not a member of a base class of 'std::ratio_divide<_R1,_R2>'


I suspect that C++11 & chrono header files are not fully supported by vs2012 ?

There was other errors as well, but lets start from smaller ones. :-)

You can get unbelievably cryptic errors using templates. chrono is something new to me, wondering why to use it.
Reply
Thanks given by:
#2
Yeah I think VS 2013 is the minimum required version, since it's also used in the compiling tutorial: https://github.com/mc-server/MCServer/bl...md#windows
Reply
Thanks given by:
#3
std::chrono is used because it has cross platform support. Previously we had to maintain our own abstraction layer to handle the different time APIs on windows and POSIX. With std::chrono we just let the standard ibrary handle it.

Also visual studio is particularly bad at template error messages. Clang is much better at templates generally.
Reply
Thanks given by:
#4
This is bit odd that chrono template is included in vs2012 includes but still it's not fully functional.
May be some basic usage is working, but more advanced template parameters don't !?

Can you pin point me to older git points where you've used your own timers (and where).
It's easier for me to port to older visual studio than to install new visual studio.

I'm getting new laptop within one month, then I will have vs2013 preinstalled.
Reply
Thanks given by:
#5
It should be possible to compile MCS with VS2012, but you need the CTP compiler/toolset installed - that is the one that brings C++11 capabilities to VS2012.
Reply
Thanks given by:
#6
Indeed this could work out, but I'm waiting my laptop to arrive, and just of curiosity I have tried to drag mcserver compatibility back to vs2012.

Apparently I've managed to compile the code, however I have made quit serious cracks in code, so I suspect I've managed to brake it down - because it now claims about stack overflow exception, meanwhile according to call stack it did not reach deeply enough. I probably need to debug bit deeper what is happening.

Unhandled exception at 0x000007F6C6DE91E7 in MCServer_debug.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000A4538B3000).


Most complex was to add support of variable number of arguments - e.g. in cLuaState / Call. Defines looks so afwul, may be better would be to wait for laptop to arrive and actually install vs2013.

But this kind of trick is achievable with vs2012:
MacroArg.h:
#pragma once

//
// Retrieve the type
//
// TYPEOF( (ArgType) argName ) => ArgType
//
// http://stackoverflow.com/questions/41453...pplication
//
#define TYPEOF(x) TYPEOF_PASS2(TYPEOF_PASS1 x,)
//
// => TYPEOF_PASS2(TYPEOF_PASS1 (ArgType) argName,)
//
#define TYPEOF_PASS1(...) (__VA_ARGS__),
//
// => TYPEOF_PASS2( (ArgType), argName,)
//
#define TYPEOF_PASS2(...) TYPEOF_PASS3((__VA_ARGS__))
//
// => TYPEOF_PASS2(( (ArgType), argName,))
//
#define TYPEOF_PASS3(x) TYPEOF_PASS4 x
//
// => TYPEOF_PASS4 ( (ArgType), argName,)
//
#define TYPEOF_PASS4(x, ...) REM x
//
// => REM (ArgType)
//
#define REM(...) __VA_ARGS__
//
// => ArgType
//

//
// This counts the number of args:
//
// NARGS( (ArgType1) argName1, (ArgType2) argName2 ) => 2
//
#define NARGS(...) NARGS_PASS1((__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
//
// => NARGS_PASS1(( (ArgType1) argName1, (ArgType2) argName2, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
//
#define NARGS_PASS1(x) NARGS_PASS2 x
//
// => NARGS_PASS2( (ArgType1) argName1, (ArgType2) argName2, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
//
#define NARGS_PASS2(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,N,...) N
//
// => 2

//
// Show the type without parenthesis
//
// PAIR( (ArgType1) argName1 ) => ArgType1 argName1
//
#define PAIR(x) REM x
//
// => REM (ArgType1) argName1
//
// => ArgType1 argName1
//

//
// Strip off the type
//
// ARGNAME( (ArgType1) argName1 ) => argName1
//
#define ARGNAME(x) EAT x
//
// => EAT (ArgType1) argName1
//
#define EAT(...)
//
// => argName1
//

//
// This will call a macro on each argument passed in
//
// APPLY(typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 )
//
#define APPLY(macro, ...) APPLY_PASS1(CAT(APPLY_, NARGS(__VA_ARGS__)), (macro, __VA_ARGS__))
//
// => APPLY_PASS1(CAT(APPLY_, NARGS( (ArgType1) argName1, (ArgType1) argName2 ) ), (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) ))
// => APPLY_PASS1(CAT(APPLY_, 2), (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) ))
//
#define CAT(x, y) CAT_PASS1((x, y))
//
// => APPLY_PASS1(CAT_PASS1((APPLY_, 2)), (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) ))
//
#define CAT_PASS1(x) PRIMITIVE_CAT x
//
// => APPLY_PASS1(PRIMITIVE_CAT (APPLY_, 2), (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) ))
//
#define PRIMITIVE_CAT(x, y) x ## y
//
// => APPLY_PASS1( APPLY_2 ), (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) ))
//
#define APPLY_PASS1(m, x) m x
//
// => APPLY_2 (typename TYPEOF, (ArgType1) argName1, (ArgType1) argName2 ) )
//
#define APPLY_1(m, x1) m(x1)
#define APPLY_2(m, x1, x2) m(x1), m(x2)
//
// => typename TYPEOF( (ArgType1) argName1 ), typename TYPEOF( (ArgType1) argName2 ) )
// => typename ArgType1, typename ArgType1
//
#define APPLY_3(m, x1, x2, x3) m(x1), m(x2), m(x3)
#define APPLY_4(m, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4)
#define APPLY_5(m, x1, x2, x3, x4, x5) m(x1), m(x2), m(x3), m(x4), m(x5)
#define APPLY_6(m, x1, x2, x3, x4, x5, x6) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6)
#define APPLY_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7)
#define APPLY_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8)
#define APPLY_9(m, x1, x2, x3, x4, x5, x6, x7, x8, x9) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9)
#define APPLY_10(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10)
#define APPLY_11(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11)
#define APPLY_12(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12)
#define APPLY_13(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13)
#define APPLY_14(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14)
#define APPLY_15(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14), m(x15)

//
// ARGX(1) => (Arg1) arg1
//
#define ARGX(index) (Arg##index) arg##index

//
// Defines same function with different amount of arguments.
//
#define DEFINE_MULTIARG_FUNC(macro) \
macro ( ARGX(1) ); \
macro ( ARGX(1), ARGX(2) ); \
macro ( ARGX(1), ARGX(2), ARGX(3) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14) ); \
macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14), ARGX(15) ); \


Test code could look like this:

#define DEFINE_DoTestFunc(...) \
template < APPLY(typename TYPEOF, __VA_ARGS__ ) > \
void DoTest( APPLY(PAIR, __VA_ARGS__ ) ) \
{ \
APPLY(printf, \
APPLY( ARGNAME, __VA_ARGS__ ) \
); \
printf("\r\n"); \
}

//
// In theory generates code like:
// printf(arg1), printf(arg2), ;
// Works well with commas ',' as well as with semicolon ';'
//
DEFINE_MULTIARG_FUNC(DEFINE_DoTestFunc)

and actual function call like this:
DoTest("arg 1", "arg2");
DoTest("arg 1", "arg2", "arg3x");


But in similar technique it's possible to replace function like this:

template <typename FnT, typename... Args>
bool Call(const FnT & a_Function, Args &&... args)
{
if (!PushFunction(a_Function))
{
// Pushing the function failed
return false;
}
return PushCallPop(args...);
}


With two part implementation:
template <typename FnT >
bool Call(const FnT & a_Function)
{
if (!PushFunction(a_Function))
return false;
return PushCallPop();
}

#define DEFINE_CallFunc(...) \
template <typename FnT, APPLY(typename TYPEOF, __VA_ARGS__ ) > \
bool Call(const FnT & a_Function, APPLY(PAIR, __VA_ARGS__ ) ) \
{ \
if (!PushFunction(a_Function)) \
return false; \
return PushCallPop( APPLY(ARGNAME, __VA_ARGS__ ) ); \
}

DEFINE_MULTIARG_FUNC(DEFINE_CallFunc)


Does anyone here have skype - e.g. in case if I want to ask some questions related to mcserver code ?
Reply
Thanks given by:
#7
Those horrible workarounds are the reason we dropped support VS 2012 is about 8 years behind clang and gcc in terms of support. If you ahve any questions please post them. Its useful to have a public repository of questions for when other people have issues.
Reply
Thanks given by:
#8
They do look quite scary until you understand machinery behind it. Actually I was bit surprised that macros which I have found can be used for C++ "reflection" - this thing I was looking for quite long. However, I suspect that "double field" versus "double field[3]" - arrays might bring much more complexity into story.

Managed to make mcserver fully functional on vs2012. make_unique and some lua call functions were missing double reference pointer usage, also I have compiled under 64 bit windows - switched back to 32-bit.

Posted whole header file to stack overflow: http://stackoverflow.com/questions/41453...pplication

Release build of mcserver hangs vs2012 linker, so I suspect that some of optimizations might be to heavy for vs2012 to eat them. It's not first time I come across such problems.

Anyway - vs2012 port is just for my learning experience, won't push it to git.

Now I can dig up deeper into code.
Reply
Thanks given by:




Users browsing this thread: 1 Guest(s)