std::mutex incompatible with C++/CLI

I’m upgrading a C++/CLI .NET application from VTK 8.1 to 9.2.6.

I’m now getting many compile errors:

fatal error C1189: #error: <mutex> is not supported when compiling with /clr or /clr:pure.

…which I’ve tracked down to a change in vtkAbstractTransform.h to move from vtkSimpleCriticalSection to std::mutex (in version 9.1 I think).

It seems like there is no possibility to compile code including vtkTransform.h using the /clr option because it indirectly #includes <mutex>.

The advice is to refactor my code to isolate any VTK code to files built without /clr, but honestly I don’t see how to do that yet - to say the least it will be a major refactoring if it’s possible at all.

Has anyone else hit up against this? It seems like it would be pretty commonplace for anyone using C++/CLI. Can anyone suggest a straightforward workaround?

It looks like it comes from vtkAbstractTransform.h. Luckily, they are private, so moving them to an implementation class to hide the header include would suffice. But that’s unlikely to land until 9.3.

I can see the same with in version 9.2.6

<thread> is not supported when compiling with /clr or /clr:pure.

Is it also fixed ?

I found :
https://gitlab.kitware.com/vtk/vtk/-/merge_requests/10106

  • Changes merged into master with [5e6ab676]

Actually I tested the fix, there is still error because

#include <mutex> 

Is still exist in vtkAbstractTransform.h :face_with_open_eyes_and_hand_over_mouth:

FWIW…

I added a temporary wrapper class to my C++/CLI project to avoid #including vtkTransform.h directly. The code is below. I set the compiler option for that wrapper class to be non-managed (“No Common Language RunTime Support”). Then all my managed code uses this wrapper class. YMMV on the methods you have to expose through the wrapper… I exposed just the ones I needed. In the end, when this is fixed in VTK 9.3 (or whatever), I’ll just revert back from using vtkTransformWrapper instances to vtkTransform instances.

vtkTransformWrapper.h:

#pragma once

class vtkTransform;
class vtkProp3D;
class vtkCamera;

class vtkTransformWrapper
{
public:

    vtkTransformWrapper();
    ~vtkTransformWrapper();

    void Delete();

    static vtkTransformWrapper* New();

    void Translate(double x, double y, double z);
    void Scale(double x, double y, double z);
    void PostMultiply();
    void RotateWXYZ(double angle, double x, double y, double z);

    vtkTransform* GetTransform();

    void SetPropUserTransform(vtkProp3D* prop);
    void ApplyCameraTransform(vtkCamera* cam);

protected:

    vtkTransform* _theTransform = nullptr;
};

vtkTransformWrapper.cpp

#include "stdafx.h"
#include "vtkTransformWrapper.h"
#include "vtkTransform.h"
#include "vtkProp3D.h"
#include "vtkCamera.h"

vtkTransformWrapper::vtkTransformWrapper()
{
    _theTransform = vtkTransform::New();
}

vtkTransformWrapper::~vtkTransformWrapper()
{
    if (_theTransform != nullptr) 
    { 
        _theTransform->Delete();
        _theTransform = nullptr;
    }
}

void vtkTransformWrapper::Delete()
{
    delete this;
}

vtkTransformWrapper* vtkTransformWrapper::New()
{
    return new vtkTransformWrapper();
}

void vtkTransformWrapper::Translate(double x, double y, double z)
{
    if (_theTransform != nullptr)
    {
        _theTransform->Translate(x, y, z);
    }
}

void vtkTransformWrapper::Scale(double x, double y, double z)
{
    if (_theTransform != nullptr)
    {
        _theTransform->Scale(x, y, z);
    }
}

void vtkTransformWrapper::PostMultiply()
{
    if (_theTransform != nullptr)
    {
        _theTransform->PostMultiply();
    }
}

void vtkTransformWrapper::RotateWXYZ(double angle, double x, double y, double z)
{
    if (_theTransform != nullptr)
    {
        _theTransform->RotateWXYZ(angle, x, y, z);
    }
}

vtkTransform* vtkTransformWrapper::GetTransform()
{
    return _theTransform;
}

void vtkTransformWrapper::SetPropUserTransform(vtkProp3D* prop)
{
    prop->SetUserTransform(_theTransform);
}

void vtkTransformWrapper::ApplyCameraTransform(vtkCamera* cam)
{
    cam->ApplyTransform(_theTransform);
}