未定义符号:_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/libLD_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 中构建未来。我会选择 qmakeCMake。如果您的计划是支持不同的 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_ 在运行时的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 13 更新后出现未定义符号错误

未定义符号:导入 pybind11 绑定时的 _ZN3a13A

内联程序集返回:在创建共享对象时,不能使用针对未定义符号的重定位R_X86_64_32S [重复]

GoogleMapsSDK:架构 x86_64 的未定义符号

奇怪的 Swift XCode '未定义符号' 错误

架构 x86_64 的未定义符号,颤振 ios