未定义符号:_ZN7QString13toUtf8_helperERKS_ 在运行时
Posted
技术标签:
【中文标题】未定义符号:_ZN7QString13toUtf8_helperERKS_ 在运行时【英文标题】:Undefined symbol: _ZN7QString13toUtf8_helperERKS_ at runtime 【发布时间】:2014-12-31 00:11:25 【问题描述】:我有两个使用 Qt 的项目。一个是用 QtCreator 开发的,另一个是用 eclipse 开发的。两者都使用相同的 Qt 5.3.1 库,都使用 GCC 编译。但是,当我运行 Eclipse 中的程序时,它会崩溃并显示消息 Undefined symbol: _ZN7QString13toUtf8_helperERKS_
。
查找显示产生此错误的代码是
path.toStdString().c_str() // path is a QString
qstring.h 中的确切位置是
#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
QByteArray toLatin1() const & Q_REQUIRED_RESULT
return toLatin1_helper(*this);
QByteArray toLatin1() && Q_REQUIRED_RESULT
return toLatin1_helper_inplace(*this);
QByteArray toUtf8() const & Q_REQUIRED_RESULT
return toUtf8_helper(*this); // <- here
QByteArray toUtf8() && Q_REQUIRED_RESULT
return toUtf8_helper(*this);
QByteArray toLocal8Bit() const & Q_REQUIRED_RESULT
return toLocal8Bit_helper(constData(), size());
QByteArray toLocal8Bit() && Q_REQUIRED_RESULT
return toLocal8Bit_helper(constData(), size());
在另一个项目(QtCreator 中的那个)中将QString
转换为std::string
效果很好。可能是什么问题? eclipse中是否缺少任何编译器选项?
编辑: 两个项目的示例文件的编译器输出是(我添加了换行符以提高可读性):
日食
Building file: ../src/mysource1.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/username/myfolder/myproject1/src"
-I"/home/username/myfolder/myproject1/src/dialogs"
-I"/home/username/myfolder/myproject1/src/ignore"
-I/usr/local/Qt-5.3.1/include -I/usr/local/Qt-5.3.1/include/QtCore
-I/usr/local/Qt-5.3.1/include/QtGui -I/usr/local/Qt-5.3.1/include/QtWidgets
-O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -fPIE -MMD -MP
-MF"src/mysource1.d" -MT"src/mysource1.d" -o "src/mysource1.o"
"../src/mysource1.cpp"
QtCreator
g++ -c -pipe -g -Wall -W -D_REENTRANT -fPIE -DQT_WIDGETS_LIB -DQT_GUI_LIB
-DQT_CORE_LIB -I/usr/local/Qt-5.3.1/mkspecs/linux-g++ -I../myproject2
-I../myproject2/src -I../myproject2/src/data -I../myproject2/src/dialogs
-I../myproject2/src/widgets -I../myproject2/src/widgets/overlays
-I../myproject2/src/widgets/tools -I/usr/local/Qt-5.3.1/include
-I/usr/local/Qt-5.3.1/include/QtWidgets -I/usr/local/Qt-5.3.1/include/QtGui
-I/usr/local/Qt-5.3.1/include/QtCore -I. -I. -o mainwind.o
../myproject2/src/mainwind.cpp
编辑2: 链接器输出如下:
日食
Invoking: GCC C++ Linker
g++ -L/usr/local/Qt-5.3.1/lib -o "myproject1" /*list of .o files*/
-lQt5Core -lQt5Gui -lQt5Widgets -lgit2
QtCreator
g++ -Wl,-rpath,/usr/local/Qt-5.3.1/lib -o myproject2 /*list of .o files*/
-L/usr/local/Qt-5.3.1/lib -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
【问题讨论】:
我不确定,所以我会写评论而不是回答。当带有这些符号的源文件不包含在编译的源文件中时,会引发未定义符号错误。 @fnc12 我不确定我是否理解正确:QString::toUtfHelper
的符号出现在源头文件中,但不在编译库中?但我使用的是由make install
复制到/usr/local/Qt-5.3.1
的源文件,以及位于同一文件夹中的库(我使用ldd
进行了检查)。这里怎么会出现矛盾?此外,另一个项目使用相同的文件没有错误。
使用 Qt 静态库还是动态库?
只是随机尝试 - Qt 是使用一组预处理器定义构建的(无论您构建还是预构建)。如果在 QtCreator/Eclipse 中没有使用相同的预处理器定义集,那么这将意味着 Eclipse 中包含的 Qt 头文件略有不同(假设任何函数声明都被预处理器保护)。这会影响 vtables 指针。您能否确保在 Eclipse 和 QtCreator 中使用相同的预处理器定义。希望您可以从构建消息中确认。
@Kiran 如何在 QtCreator 中查看预处理器定义?我没有在eclipse中列出。但是,QtCreator 使用 qmake,也许 qmake 有某种内置的预处理器设置?
【参考方案1】:
qmake/cmake
是要走的路。但有趣的是,看看链接器是如何成功的,然后在运行期间,我们得到一个未定义的引用(不是一个不匹配的 dll 案例)。特别是因为在 QT github repo 中没有针对 toUtf8_helper
的预处理器保护。再试一次。您能否添加-DQT_COMPILING_QSTRING_COMPAT_CPP
,以便我们在#else 部分采用与toUtf8()
略有不同的路径,并且不调用缺少的toUtf8_helper
方法。
原因:我认为这是因为 QtCore dll 是使用一组在项目构建期间不匹配的预处理器标志构建的。然后像qstring.h
这样的头文件包含在你的代码中,它具有内联函数,由预处理器定义保护,如在toStdString()
期间调用的toUtf8()
将采用不同的路径。
另请注意,不建议尝试在没有qmake/cmake
文件的情况下构建 QT 项目,如本问题/答案所示,这必然会导致项目出现更多问题。
【讨论】:
在我的例子中,它是-DQT_COMPILING_QSTRING_COMPAT_CPP
- 以防万一其他人偶然发现这个。
使用 -DQT_COMPILING_QSTRING_COMPAT_CPP 也解决了我的问题。非常感谢您分享这些信息,好心的先生!【参考方案2】:
Undefined symbol: _ZN7QString13toUtf8_helperERKS_
可能是由以下原因引起的:
由于缺少-Wl,-rpath,/usr/local/Qt-5.3.1/lib
或LD_LIBRARY_PATH
,Eclipse 中的链接错误(过时的Qt 库)。 Eclipse 构建环境未设置为 QtCreator 构建环境。
您写道,您已经使用 ldd
检查了应用程序的动态链接,但您也应该在 eclipse 中添加缺少的链接器选项 -Wl,-rpath,/usr/local/Qt-5.3.1/lib
。
(另一种选择是使用 LD_LIBRARY_PATH,但保持两个构建环境相同是合理的。ldd 和应用程序一样受 LD_LIBRARY_PATH 影响。LD_LIBRARY_PATH 可能无法正确导出?)
同时添加编译器标志-D_REENTRANT -fPIE -DQT_WIDGETS_LIB -DQT_GUI_LIB
-DQT_CORE_LIB -I/usr/local/Qt-5.3.1/mkspecs/linux-g++
【讨论】:
【参考方案3】:我假设您想使用 QString.toStdString().c_str() 函数将QString
转换为const char *
。这不是一种可靠的方法。我不知道文件说什么,但我尝试使用这个函数获取文件位置,它给了我一些奇怪的东西。请检查 const char* 是否与 QString 中的值相同。如果是这种情况,那么您有两种选择。
-
要么分两步完成。即
QString().toStdString()
和
在下一步中将其转换为const char*
。虽然不是
干净,但它的工作原理。 (主要问题是有“深拷贝”。当你
将QString转换为std::string,Qt创建一个临时对象并直接
尝试读取此临时对象。使用此方法,您将创建两个
单独的对象。
使用QString().toAscii.constData()
或QString():toUtf8().constData()
(首选)
【讨论】:
虽然您认为QString::toUtf8().constData()
是将QString
转换为const char *
的更优雅的方式是正确的,但它仍然会产生此错误以及您的其他建议。似乎是从 QString 到 Utf8 的转换有问题,它也用于到 std::string
的转换。顺便说一句,从 Qt5 开始,QString::toAscii() 不再存在。
您是否分两个不同的步骤来实现它?像 qstring 到 stdstring 以及从 stdstring 到 const char*?如果是这样,它什么时候崩溃?
是的,std::string spath = path.toStdString();
转换为 std::string
时崩溃。
你要转换的字符串,是英文的吗??
这是文件系统中的一个路径。我刚刚检查了它,它没有非ASCII字符。【参考方案4】:
从外观上看,您没有编译错误,而是链接错误。您还没有向我们展示正在使用的 linking 命令,您应该检查它们是否不同。要正确使用 QString
方法,您必须链接到 QtCore。
您使用的是哪个构建系统?想从命令行尝试吗?如果你自己编译呢?我看了你的一些cmets,你好像用ldd
检查了可执行文件,它们的输出是一样的吗?
此外,这些标志:-DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB
,它们可能会有所不同,您应该尝试在 Eclipse 项目中也定义这些标志。
Qt 的库可能很复杂,如果没有适当的构建系统(例如,您在 Eclipse 项目中缺少正确的定义),单独使用 Qt 库可能会很复杂,特别是如果您打算使用 QtQuick 或如果您打算在 android 中构建未来。我会选择 qmake 或 CMake。如果您的计划是支持不同的 IDE,CMake 是值得的,因为它可以为大多数 IDE 生成项目。
【讨论】:
我在问题中添加了链接器输出。在 Eclipse 中,我使用带有 Gnu Make Builder 的 Linux GCC 工具链。ldd
的输出与 Qt 相同,可执行文件链接到完全相同的文件 /usr/local/Qt-5.3.1/lib/libQt5Core.so.5
、/usr/local/Qt-5.3.1/lib/libQt5Gui.so.5
和 /usr/local/Qt-5.3.1/lib/libQt5Widgets.so.5
。但是,在 QtCreator 项目的输出中,这些是按相反的顺序列出的,不确定这是否可以发挥作用。从命令行尝试并自己编译、手动运行 gcc 而不是从 IDE 运行是什么意思?以上是关于未定义符号:_ZN7QString13toUtf8_helperERKS_ 在运行时的主要内容,如果未能解决你的问题,请参考以下文章
未定义符号:导入 pybind11 绑定时的 _ZN3a13A
内联程序集返回:在创建共享对象时,不能使用针对未定义符号的重定位R_X86_64_32S [重复]