Skip to content

Commit

Permalink
Correct possible ODR violations in the AutoInit generated code
Browse files Browse the repository at this point in the history
The previous `AutoInit` approach generated a class in each TU
for a VTK-module. That class would have the same name and
the same contents for the constructor. This was fine as long
as the VTK-module was built dynamically.

This constructor would look like:

```cxx
AuotInit()
{
  InitFactory1();
  InitFactory2();
}
```

The problem arised when VTK-module's are built statically. In
that case we would get multiple differing implementations
of the same class. This happens as VTK-module deeper in the
hierarchy would would need initialize more factories than
VTK-modules they depended on.

```cxx
AuotInit() //from VTK-module A
{
  InitFactory1();
  InitFactory2();
}

AuotInit() //from VTK-module B
{
  InitFactory1();
  InitFactory2();
  InitFactory3();
  InitFactory4();
}
```

These ODR violations are problematic because it meant that the linker
would select a single implementation for `AutoInit` which could
be one that would only initialized 2 modules instead of one that
initialized 4 modules.

To solve this problem we have gone with an approach where each
AuotInit is placed into an anonymous namespace making them all
unique and not an ODR violation.
  • Loading branch information
Robert Maynard committed Jul 2, 2019
1 parent 545c682 commit 5a148ce
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 15 deletions.
2 changes: 1 addition & 1 deletion CMake/vtkObjectFactory.cxx.in
Expand Up @@ -40,7 +40,7 @@ void @_vtk_object_factory_library_name@ObjectFactory::PrintSelf(ostream &os, vtk
}

// Registration of object factories.
static unsigned int @_vtk_object_factory_library_name@Count;
static unsigned int @_vtk_object_factory_library_name@Count = 0;

@_vtk_object_factory_configure_EXPORT_MACRO@ void @_vtk_object_factory_library_name@_AutoInit_Construct()
{
Expand Down
28 changes: 14 additions & 14 deletions Common/Core/vtkAutoInit.h
Expand Up @@ -23,13 +23,13 @@
#define VTK_AUTOINIT(M) VTK_AUTOINIT0(M,M##_AUTOINIT)
#define VTK_AUTOINIT0(M,T) VTK_AUTOINIT1(M,T)
#define VTK_AUTOINIT1(M, T) \
/* Declare every <mod>_AutoInit_Construct function. */ \
VTK_AUTOINIT_DECLARE_##T static struct M##_AutoInit { \
/* Call every <mod>_AutoInit_Construct during initialization. */ \
M##_AutoInit() { \
VTK_AUTOINIT_CONSTRUCT_##T \
} \
} M##_AutoInit_Instance;
/* Declare every <mod>_AutoInit_Construct function. */ \
VTK_AUTOINIT_DECLARE_##T namespace { \
static struct M##_AutoInit { \
/* Call every <mod>_AutoInit_Construct during initialization. */ \
M##_AutoInit() { VTK_AUTOINIT_CONSTRUCT_##T } \
} M##_AutoInit_Instance; \
}

#define VTK_AUTOINIT_DECLARE_0()
#define VTK_AUTOINIT_DECLARE_1(t1) VTK_AUTOINIT_DECLARE_0() VTK_AUTOINIT_DECLARE(t1)
Expand Down Expand Up @@ -70,13 +70,13 @@
//
// The above snippet if included in the global scope will ensure the object
// factories for vtkRenderingOpenGL2 are correctly registered and unregistered.
#define VTK_MODULE_INIT(M) \
VTK_AUTOINIT_DECLARE(M) \
static struct M##_ModuleInit { \
/* Call <mod>_AutoInit_Construct during initialization. */ \
M##_ModuleInit() { VTK_AUTOINIT_CONSTRUCT(M) } \
} M##_ModuleInit_Instance;

#define VTK_MODULE_INIT(M) \
VTK_AUTOINIT_DECLARE(M) namespace { \
static struct M##_ModuleInit { \
/* Call <mod>_AutoInit_Construct during initialization. */ \
M##_ModuleInit() { VTK_AUTOINIT_CONSTRUCT(M) } \
} M##_ModuleInit_Instance; \
}

#endif
// VTK-HeaderTest-Exclude: vtkAutoInit.h

0 comments on commit 5a148ce

Please sign in to comment.