bug in boost::date_time::time_facet?
Hi all I've run into a problem with *_facet from boost::date_time when compiling for windows and I'm pretty convinced it is a bug in boost (tested 1.49 and 1.54). However, since gcc makes a successful attempt not to trigger it, and I'm not exactly an expert on windows formats/linkers/etc I'd like to have second opinion before I fill a ticket. So, here we go: Consider following code: ------------- setFacet.h -------------------------- #include <iostream> __declspec(dllexport) void setFacet(std::ostream &); -------------- setFacet.cpp ----------------------- #include <boost/date_time/posix_time/posix_time.hpp> #include <locale> #include "setFacet.h" __declspec(dllexport) void setFacet(std::ostream & os) { boost::posix_time::time_facet * dateFormat =new boost::posix_time::time_facet("%Y-%m"); os.imbue(std::locale(os.getloc(), dateFormat)); } ------------------- test.cpp -------------------------- #include <boost/date_time/posix_time/posix_time.hpp> #include <iostream> #include "setFacet.h" using namespace std; int main() { std::string ts("20020131T235959"); boost::posix_time::ptime t(boost::posix_time::from_iso_string(ts)); cerr << t << endl; setFacet(cerr); cerr << t << endl; return 0; } ------------------------------------------------------- The expected result is that facet with "%Y-%m" format is imbued to cerr after calling "setFacet" function and that second print uses specified format. Now, suppose we built it so that we have setFacet.dll exporting function setFacet, and test.exe is linked against this dll. In such setting the code works under linux (gcc 4.1, 4.7), but it doesn't work under mingw-w64 4.6.4 or msvc10 - default format is used both times: linux: 2002-Jan-31 23:59:59 2002-01 windows: 2002-Jan-31 23:59:59 2002-Jan-31 23:59:59 Why? Well, lets look at operator<< for ptime. It does one interesting comparison: if (std::has_facet<custom_ptime_facet>(os.getloc())) this comparison gives different results under linux and windows. The key is static member "id" of a facet class. It is declared in boost/date_time/time_facet.hpp and it is used by has_facet to give answer whether locale has facet for the given class. Since this header is included twice - once in dll and once in exe there are two storages for id of the same facet class. In gcc 4.1 appropriate symbols are weak objects. Apparently only one is selected as the proper one by the linker and used universally. In gcc 4.7 it is even better. Appropriate symbols are "unique global symbol" which explicitly means there should be only one instance in whole process. In mingw both these storages are used independently and the same class (boost::posix_time::time_facet) has different id in dll (in setFacet function) and different in exe file (in operator<<). This is why operator<< believes locale has no facet for posix_time. At this point I was suspecting some incompatibility between windows' linker and mingw's libstdc++ implementation (regarding std::locale::id initialization) However, under msvc10 it doesn't work either, with msvc library. I believe it is a bug in boost, even if some deficiency in mingw/msvc/windows is involved. Also, let me confess I'm far from having learned boost docs by heart. If there is some big red sign somewhere telling I must link statically if using facets from boost::date_time have mercy on me. command lines used to build example: gcc (just get rid of these dllspecs): g++ -fPIC -shared -o libsetFacet.so setFacet.cpp g++ -L. -lsetFacet -Wl,--rpath=. -o test test.cpp mingw: x86_64-w64-mingw32-g++ -isystem pathToBoostIncludes -shared -o libsetFacet.dll -m32 -Wl,--enable-runtime-pseudo-reloc-v2 -Wl,--out-implib,libsetFacet.lib setFacet.cpp x86_64-w64-mingw32-g++ pathToBoostIncludes -o test.exe -m32 -Wl,--enable-runtime-pseudo-reloc-v2 -L. -lsetFacet test.cpp msvc10: cl.exe /I"pathToBoostIncludes" /LD set.cpp /EHsc /link /out:setFacet.dll /LIBPATH:"pathToBoostLibs" cl.exe /I"pathToBoostIncludes" /EHsc setFacet.lib test.cpp /link /LIBPATH:"pathToBoostLibs" regards, Jakub Zytka
participants (1)
-
Jakub Zytka