[omniORB] OmniOrb 4.2: Broken definition of _init_in_cldef_ and _init_in_cldecl_ for VS 2012 an older

Daniel Krügler daniel.kruegler at gmail.com
Wed Nov 19 07:37:46 GMT 2014


The header file

include/omniORB4/CORBA_sysdep.h

contains two macro definitions (_init_in_cldef_ and _init_in_cldecl_)
that are used to generate proper declarations and definitions of
static class data members of integral or enumeration type during code
generation of the CORBA C++ mapping files.

Between OmniOrb 4.1* and 4.2 the definitions have changed in the sense
that a Visual Studio 2012 compiler is now assumed to be completely
standard-conforming compiler in regard to usage of static data members
that are initialized in the class definition context.

In parts the new preprocessor logic is now:

#  elif defined (_MSC_VER) && (_MSC_VER < 1500)
#    define _init_in_cldecl_(x)
#    define _init_in_cldef_(x) x
#  else
#    define _init_in_cldecl_(x) x
#    define _init_in_cldef_(x)
#  endif

while in previous versions the logic was:

#ifndef _init_in_cldecl_
#  if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
#    define _init_in_cldecl_(x) x
#  else
#    define _init_in_cldecl_(x)
#  endif
#else
#error "Name conflict: _init_in_cldecl_ is already defined."
#endif

#ifndef _init_in_cldef_
#  if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
#    define _init_in_cldef_(x)
#  else
#    define _init_in_cldef_(x) x
#  endif
#else
#error "Name conflict: _init_in_cldef_ is already defined."
#endif

The new definition assumes that a Visual Studio compiler beyond VS
2008 (corresponding to _MSC_VER == 1500) can declare and define static
data members in a way conforming with the C++ standard. This means
that given a class A and a constant N I can write the following:

// A.h:

class A {
public:
  static const int N = 42; // OK: In-class initializer
};

// A.cpp:

#include "A.h"

const int A::N; // No initializer

Unfortunately this assumption doesn't hold, and we recently stumbled
across this when trying to generate code from our existing IDL file
that has the following content (abbreviated):

module parser {
interface ParserFlags {
    const long long MSRES_NOFLAG = 0x00000000;
    //...
};
};

When including the generated header into another file and compiling
the whole program this leads to linker errors of the form:

corba-idl.lib([..]) : error LNK2005: "public: static __int64 const
parser::ParserFlags::MSRES_NOFLAG"
(?MSRES_NOFLAG at ParserFlags@parser[...]) already defined in [..]

This linkage error is related to the fact that the Visual Studio
compiler incorrectly generates code that has the effect to two
definitions of the same static data member. See

http://blogs.msdn.com/b/xiangfan/archive/2010/03/03/vc-s-evil-extension-implicit-definition-of-static-constant-member.aspx

http://stackoverflow.com/questions/16404173/does-visual-studio-2010-c-fully-support-in-class-const-variables/16405288#16405288

for more details about this misbehavior.

A possible workaround would be to remove the out-of-class-definition
for Visual Studio compilers, when an in-class-initializer is present,
but this rule could *only* be applied for Visual Studio compilers,
because it is not conforming to omit the out-of-class definition
(without initializer) for such members, when they are ODR-used in the
program (What usually happens).

Instead I suggest to change the new definition (again in parts) as
follows (In the following I'm using the xml markers <del> and </del>
to denote ranges of deletion):

#  elif defined (_MSC_VER) <del>&& (_MSC_VER < 1500)</del>
#    define _init_in_cldecl_(x)
#    define _init_in_cldef_(x) x
<del>#  else
#    define _init_in_cldecl_(x) x
#    define _init_in_cldef_(x) </del>
#  endif

This has the effect that user code still cannot use these constants in
constant expressions (as before) but at least the code is well-defined
and does not cause linkage errors.

The problem is really severe, because we have no alternative than to
patch the current header file manually, because our IDL files are part
of a larger code-generation framework (shared with Java and C++ code)
where we cannot simply replace the interface containing constants by a
module containing constants.

Thanks,

- Daniel Krügler



More information about the omniORB-list mailing list