CPLString makes gdal.dll export symbols for std::string on MSVS 2010-2017
|Reported by:||opals||Owned by:||warmerdam|
|Severity:||normal||Keywords:||CPLString multiply defined symbols STL|
Because CPLString derives from std::string, gdal.dll created with MSVC (tested on MSVS 2010 and MSVS 2017) exports symbols not only for CPLString, but also for std::string. This becomes a problem when linking both GDAL and a static library that (implicitly) instantiates std::string (many will do that!). The work-around to force the linker to still generate its output is a generally unsafe option. Much better is to make CPLString not export symbols for std::string. This relates to the same problem as defect #4099 However, in #4099, we suggested to either
- not export symbols for CPLString at all, which forces binaries that need to use CPLString (like the GDAL utility programs) to link GDAL statically, or
- not derive CPLString from std::string, but make std::string a member variable hidden in a D-Pointer (pimpl-idiom).
Contrary to the 2 options suggested in #4099, we now use a much less intrusive solution: For MSVC, turn the declaration of CPLString into the declaration of the template class CPLStringT, and make CPLString itself a typedef of that template class. Do not export symbols for the template class as a whole, but only for its few non-inline member functions. Hence, no symbols for std::string are exported, and no symbols for the inline member functions of CPLString. Still, all methods of CPLString and its base class std::string remain available, since they are implicitly instantiated (instead of explicitly, like currently), thereby avoiding duplicate symbols. Resolution attached, based on GDAL 2.2.3. Possibly, also port/cpl_port.h needs to be extended slightly, such that CPL_DLL is defined as declspec(dllimport) when symbols are to be imported by MSVC:
#ifndef CPL_DLL #if defined(_MSC_VER) && !defined(CPL_DISABLE_DLL) # ifdef GDAL_EXPORTS # define CPL_DLL declspec(dllexport) # else # define CPL_DLL declspec(dllimport) # endif #else ... #endif