从共享库中使用时忽略imbue/facet,具体取决于Android下的动态加载顺序
我正在 Android 上部署一个 C++ 应用程序,它使用boost::date_time. 它有很多库,有些是在编译时链接的(共享库),有些是插件,在运行时通过dlopen. 在某些库中,将 a 设置boost::posix_time::time_facet为 a std::ostream(使用imbue)以自定义boost::posix_time::ptime显示无效(被忽略)。我可以在以下 MCVE 中隔离问题:
bug_datetime_base是一个共享库,它使用boost::date_time但只编译将 a 重定向boost::posix_time::ptime到 a 的代码std::ostream(未boost::posix_time::time_facet使用):
MyClass::MyClass( const boost::posix_time::ptime& timeInfo )
{
std::cout << timeInfo;
}
bug_datetime_lib是一个共享库,它使用boost::date_time和导出一个函数,该函数将使用 a 将 aboost::posix_time::time_facet重定向boost::posix_time::ptime到std::ostream具有特定格式的 a:
#include <sstream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <QDebug>
void TestBoost()
{
boost::posix_time::ptime t1(boost::gregorian::date(2002,boost::gregorian::Jan,10),
boost::posix_time::time_duration(1,2,4));
std::stringstream temp;
temp << "FROM TestBoost:" << std::endl << "Unformatted:" << t1 << std::endl;
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%Y$%b$%d %H:%M:%S.TestBoost.%f");
const std::locale loc = std::locale(std::locale::classic(), facet);
temp.imbue(loc);
temp << "Formatted:" << t1;
qDebug() << temp.str().c_str();
}
bug_datetime_wrapper是一个只链接到bug_datetime_baseand的共享库,bug_datetime_lib什么都不做:
MyWrapperClass::MyWrapperClass()
{
}
bug_datetime是主程序,它使用boost::date_time、链接到bug_datetime_base并bug_datetime_wrapper通过dlopen以下方式动态加载:
#include <sstream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <QDebug>
#include <QApplication>
#include <dlfcn.h>
typedef void* dllHandle;
int main( int argc, char* argv[] )
{
QApplication app( argc, argv );
void* wrapperPtr = NULL;
// Workaround2:
// if commenting line below, bug_datetime_wrapper is not loaded, using imbue from any places works perfectly
wrapperPtr = dlopen( "libbug_datetime_wrapper_armeabi-v7a.so", 0);
if ( wrapperPtr )
qDebug() << "Loaded bug_datetime_wrapper, then formatting will fail";
else
qDebug() << "Failed to load bug_datetime_wrapper, then formatting will work";
{
boost::posix_time::ptime t1(boost::gregorian::date(2002,boost::gregorian::Jan,10),
boost::posix_time::time_duration(1,2,4));
std::stringstream temp;
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%Y$%b$%d %H:%M:%S.main.%f");
const std::locale loc = std::locale(std::locale::classic(), facet);
temp.imbue(loc);
temp << t1;
qDebug() << "FROM MAIN: " << temp.str().c_str();
}
auto libPtr = dlopen( "libbug_datetime_lib_armeabi-v7a.so", 0);
if ( libPtr )
{
typedef void (*TestBoostFunc)();
auto func = (TestBoostFunc) dlsym( libPtr, "TestBoost" );
if ( func )
(*func)();
else
qDebug() << "Failed to load TestBoost function";
}
else
{
qDebug() << "Failed to load library function";
}
return app.exec();
}
在主程序中:
- 使用 a
boost::posix_time::time_facet自定义 aboost::posix_time::ptime到 a 的重定向std::ostream工作正常 - 但是,通过
bug_datetime_lib执行相同的操作调用代码不起作用(忽略方面)
所以程序输出是:
D libbug_datetime_armeabi-v7a.so: Loaded bug_datetime_wrapper, then formatting will fail
D libbug_datetime_armeabi-v7a.so: FROM MAIN: 2002$Jan$10 01:02:04.main.000000
D libbug_datetime_armeabi-v7a.so: FROM TestBoost:
D libbug_datetime_armeabi-v7a.so: Unformatted:2002-Jan-10 01:02:04
D libbug_datetime_armeabi-v7a.so: Formatted:2002-Jan-10 01:02:04
在期待时:
D libbug_datetime_armeabi-v7a.so: Loaded bug_datetime_wrapper, then formatting will fail
D libbug_datetime_armeabi-v7a.so: FROM MAIN: 2002$Jan$10 01:02:04.main.000000
D libbug_datetime_armeabi-v7a.so: FROM TestBoost:
D libbug_datetime_armeabi-v7a.so: Unformatted:2002-Jan-10 01:02:04
D libbug_datetime_armeabi-v7a.so: Formatted:2002$Jan$10 01:02:04.TestBoost.000000
整个代码在这里可用:https : //github.com/jporcher/bug_datetime
请注意,我使用 QtCreator 轻松编译和部署应用程序,但我很确定可以使用常规 ndk-build 重现该问题。
库架构没有意义,因为我删除了大量代码来隔离 MCVE。如果我删除bug_datetime_wrapper或bug_datetime_base从项目中,问题将不再重现。
请注意,我发现了许多可以解决该问题的解决方法,它们都非常令人惊讶:
- 解决方法 1:在 中
bug_datetime_base,评论std::cout << timeInfo;修复了问题 - 解决方法 2:评论
wrapperPtr = dlopen( "libbug_datetime_wrapper_armeabi-v7a.so", 0);(因此不加载bug_datetime_wrapper)修复了问题 - 解决方法 3:删除下面的链接可解决问题
- Workaround3.1未将
bug_datetime程序链接到bug_datetime_base(正在删除link1) - Workaround3.2未链接
bug_datetime_wrapper到bug_datetime_base(正在删除link2) - Workaround3.3未链接
bug_datetime_wrapper到bug_datetime_lib(正在删除link3)
- Workaround3.1未将
- 解决方法 4:更改中的链接顺序
bug_datetime_wrapper,bug_datetime_lib在bug_datetime_base修复问题之前进行链接 - 解决方法 5:在编译时将
bug_datetime程序链接到bug_datetime_wrapper修复了该问题
当前代码没有未定义的行为并且完全有效,所以我正在寻找对出了什么问题的合理解释以及应该如何干净地修复它(保留现有链接,因为它们在我创建这个 MCVE 的原始项目中是需要的) .
6 月 7 日编辑:尝试将 boost 编译为共享库而不是静态库。我仍然观察到同样的问题。