tags:

views:

253

answers:

2

I am working on a C++ project that uses Qt (gui lib), VTK (graphics lib) and another library which is so obscure I won't mention its name and will instead call it LIB_X. The project uses Qt for the gui components and VTK (more precisely the QVTKWidget extension provided by VTK that supports Qt) for rendering geometry.. and it uses LIB_X to gather and manipulate geometry.

The problem is that it turns out that LIB_X actually uses VTK (where and how, I don't know, it's closed source). At first there was no problem, compiling with both libs linked was going fine, but at some point I called a certain (and highly needed) LIB_X function and compiling led to a bunch of 'blah blah something about a VTK lib/obj already defined in LIB_X dll' errors.

e.g. (and note this is with /FORCE:MULTIPLE so it's a warning here, let me know if you want the error without /FORCE:MULTIPLE and I'll post it):

1>LIB_X.lib(LIB_X.dll) : warning LNK4006: "public: __thiscall std::vector<double,class std::allocator<double> >::~vector<double,class std::allocator<double> >(void)" (??1?$vector@NV?$allocator@N@std@@@std@@QAE@XZ) already defined in vtkCommon.lib(vtkInformationDoubleVectorKey.obj);

I tried using /FORCE:MULTIPLE and it seemed to be a miracle at first, but I am getting random errors in code that would mostly give heap errors. I decided to remove all references to LIB_X from the main project and created a static lib that would handle all LIB_X stuff. I'm not a C++ expert, so I'm not certain how it handles lib clashing when you're using a pre-compiled lib, but I still received lib clashing errors when linking my static lib into my main project, so I still have to use /FORCE:MULTIPLE.

Once I had the static lib it seemed like the random errors had gone away, I was able to do a lot with LIB_X methods in the main project via the static lib, BUT out of nowhere, I added a new data member to my main project's class (a std::vector of doubles) and suddenly I was getting a heap error in one of my static library's methods. If I commented out the new data member, the static library's method would run fine. I hate to give the current error, because honestly I'm not sure if examining it will be worthwhile, but here it is anyway in case it can help:

note: it crashes to xutility on about line 151, pops up assertion: "file: dbgheap.c line: 1279 expression: _CrtIsValidHeapPointer(pUserData)"

The error comes after adding a vector vector double to a vector vector vector double, crashing on the push_back line:

std::vector<std::vector<double>> tmpVec;
for(srvl_iter = srvl.begin(); srvl_iter != srvl.end(); ++srvl_iter)
{
 tmpVec.push_back((*srvl_iter).getControlPoints());
}
this->_splines.push_back(tmpVec); //CRASH

It only started crashing here when I added a new data member to my main project (separate from the static lib!) Commenting out the new data member takes the error away.

std::vector<std::vector<std::vector<double>>> _geometry; 

So, /FORCE:MULTIPLE seems bad, I get random errors that just don't make sense to me. Are there other solutions? Am I screwed? Is there something I can do with LIB_X's linking of VTK?

A: 

The commenting out is probably just random luck - if you are corrupting the heap you don't always see it right away but an stl vector will allocate and deallocate things left and right so it's no wonder it's finding the error.

Some libs require you include things in a certain order. I am not sure why exactly because to me it seems like giving up and saying you can't design a library properly, but it's the sad fact. So long as you don't include this lib_x anywhere that you include vtk it should be fine, though.

However, they might be fighting over some resource or using something improperly that makes it impossible for them to work together. If you are able to get the compile to work ok by segregating them and it still fails then yes you are just out of luck because it's just a failing in the way that this lib_x was designed and since it's so obscure it's not likely to have been thoroughly debugged against all uses. When something's not widely used it usually ends up being something that works on the developer's machine and project but not necessarily anyone else's.

Charles Eli Cheese
I thought that keeping vtk and lib_x as separate as possible would fix it as well. But I did create a static lib for my lib_x stuff. I only link in lib_x libraries in this static lib and of course there is no vtk linking within my static lib. My main project does not link in any lib_x libs, but linking to the static lib exposes vtk and lib_x clashing.Is there some other way to make them even more separate?Last resort is I make a separate app for lib_x that writes out all output to a text file. It will be much slower, but it might work as a temp solution.
ferr
I have been looking further into it, and I think that it might be obvious now that both LIB_X and VTK may both be fighting over a resource.If you look at the linker error, it specifies that the problem is with std::vector being defined multiple times. I went through the call stack for the crash, and it crashes after attempting to deallocate an std::vector.. the method of crashing is apparently about trying to deallocate something that has already been deallocated. So my guess is two things are trying to deallocate a vector.
ferr
Well, what you can do is compile and run them both as entirely separate processes and send the data to it with IPC or a memory mapping or something. unfortunately you can't just make it all extern and load it separately as it won't initialize the static stuff. In dlls I think all the versions get their own static variables so if you can compile them in separate dlls? I am not sure, usually I avoid them like the plague, maybe someone else will know.
Charles Eli Cheese
A: 

I encountered a bunch of LNK4006 errors when linking my app to a library (call it library LIB_Y) that made heavy use of std::vector<std::string>, which I also did in my app. After a bit of experimenting I found one solution that worked -- wrap LIB_Y in a separate DLL that calls LIB_Y (LIB_Y_WRAPPER, say), and then link the main app against LIB_Y_WRAPPER.

To try out my suggestion you will need to:

  1. Change your "static lib that handles all LIB_X stuff" from a static LIB project into a DLL project (which I will call LIB_X_WRAPPER).
  2. Make sure the header files of LIB_X_WRAPPER don't include any of the LIB_X header files. This is really important because the wrapper needs to completely isolate your app from the data types declared in the LIB_X header files (such as std::vector<double>). Only refer to LIB_X's header files from within the source files of LIB_X_WRAPPER.
  3. Change the declaration of all classes and functions in your static lib to ensure they are exported from the DLL (see this answer if you need details about exporting from a DLL).

This solution worked for me because it kept the instantiation (compiler generated functions) of the std::vector<std::string> class used by LIBY completely separate from the instantiation of std::vector<std::string> in my app.

As an aside, I suspect the cause of the crash you are seeing (you comment it is in the destructor of std::vector<double>) is because the instantiation of std::vector<double> in your app is different to that in LIB_X.

mcdave
I was wondering if something like this would work, I'll try testing it out.My problem with this so far is #2, removing libx headers from the wrapper. I need data members from libx in my class, and they need the libx namespace for declaration. The variable might look like Libx::DataStructA _dataStructA; I can't create a class prototype because it requires the namespace, and I can't use the namespace because I don't have header access, but maybe there's something I don't know about when it comes to namespaces that can solve this?
ferr
More on my above comment, I'm not sure if it's about the namespace, it's just a forward declaration problem entirely on a number of levels. The libx class I'm trying to forward declare isn't declared as a pointer in my class, so it throws a fit about that for one thing. Declaring it as a pointer doesn't seem to help much.
ferr
OK, after doing much screwing around and googling it looks like you can forward declare a class within a namespace like this: namespace LibX { class libxClass; } within the header so that I can later declare a LibX::libxClass. The problem I'm having now is that I'm getting redefinition errors. I have the libxClass.h file included in my .cpp file, and it complains about having a definition within my header and the libxClass.h files. On top of that, the 'class' I am trying to forward declare is actually a typedef of a class.. not sure what impact that has on the situation.
ferr
You can forward declare the LIBX classes or you can forward declare your own internal class and have them use the LIBX classes as data members. I sometimes use Header: struct my_class_data_t; class MY_LIB_EXPORTS MyClass { private: my_class_data_t *m_me; } Source: struct my_class_data_t { LibX::libxClass *libx_data; }
mcdave
Also, when forward declaring a class the declaration line needs to match the exact actual definition. You might need to forward declare as: namespace LibX { class __declspec(dllimport) libxClass; }. Watch for macros in the LibX header files and track them back to see what they are expanded to. The __declspec(dllimport) is probably the most common class decoration.
mcdave
Given you need to forward declare a typedef, the cleanest solution is, I think, to forward declare your own internal data struct.
mcdave
Alright, that took care of step 2. I forward declared a new struct in the header, then defined that struct in the source with LibX classes. Next up is getting it all into a DLL.
ferr