zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt编译和链接错误

2023-06-13 09:11:59 时间
为了演示 Qt Creator 的报错信息,我们刻意制造一个小 Bug。依然使用《Qt Creator使用教程(简明版)》一节中创建的项目和代码,双击 HelloWorld.pro,或者在 Qt Creator 主菜单中选择 文件 打开文件或项目 ,或者按下 Ctrl+O 快捷键都可以打开 HelloWorld 项目。

修改 widget.cpp,添加一行新代码和一个新头文件,如下所示:


#include widget.h 

#include ui_widget.h 

#include QtTest/QTest //new header file

Widget::Widget(QWidget *parent) :

 QWidget(parent),

 ui(new Ui::Widget)

 ui- setupUi(this);

 qsleep(1000); //new code

Widget::~Widget()

 delete ui;

}

QtTest/QTest 是 Qt 单元测试模块的头文件,它里面有一个睡眠函数 void QTest::​qSleep(int ms),让当前程序睡眠参数指定的 ms 毫秒。上面示范故意写错了函数名,S 大写变成了小写 s 。

点击运行按钮,或者按下 Ctrl+R 快捷键,就可以看到如下图所示的编译错误:

Qt Creator报错信息

下面的输出面板自动显示了编译时的错误, qsleep 没有在当前作用域中声明;在源代码编辑器 qsleep(1000) 这一行的行首有红色背景的感叹号,标出了这行有错误发生。

接着我们把睡眠函数改成正确的 qSleep,再次点击运行按钮,或者按下 Ctrl+F5 快捷键,发现还有错误:

Qt Creator报错信息

还是提示 qSleep 没有声明,但这回给出的错误描述不一样,在问题面板的 note 字样一行可以看到提示 QTest::qSleep ,这次出错是因为 qSleep 函数在名字空间 QTest 里面声明的,如果要用这个函数得加名字空间前缀,或者用 using 语句引入名字空间。我们这里直接给出错的行加名字空间前缀,变成:

QTest::qSleep(1000);

对于编译时错误,常见的就是写错函数名或变量名、类名,没有包含正确的头文件,没有使用正确的名字空间或类前缀等。如果是 Qt 自己的模块或类,直接包含相应的头文件就可以了。

如果是非 Qt 库的头文件,可以在 pro 文件里添加 INCLUDEPATH 变量,比如:

INCLUDEPATH += E:/mylibs/extra headers
INCLUDEPATH += /home/username/extra headers

上面第一个是 Windows 路径包含,第二个是 Linux/Unix 路径包含。添加包含路径之后,可以在项目源代码里直接包含头文件名:

#include extra.h

QtCreator 编辑器支持包含的文件名补全,可自动搜索 Qt 库标准路径和额外包含路径里的头文件。

按照上面的说明修改好代码之后,我们就来验证一下吧。再次点击运行按钮,或者按下 Ctrl+R 快捷键,竟然还会有报错信息:
Qt Creator链接错误

这回也是撞见鬼了,就改了一行代码,还是往正确了改,怎么蹦出十几条错误?最后一条错误描述说明链接器 ld 返回错误了,这是链接目标文件和库文件时出了错误,无法生成最终的可执行程序。问题面板列的十几条错误,就最后倒数第二个是指向 widget.cpp 里的睡眠函数的,报的错误是error: undefined reference to `_imp___ZN5QTest6qSleepEi ,这是未找到真实的函数引用(定义)的意思,`_imp___ZN5QTest6qSleepEi 是函数 QTest::qSleep 在编译之后的库文件里的引用名字,链接时找不到引用,通常是没有链接正确的 *.a 库声明文件(Linux 上直接链接到 *.so )。

之前提到 qSleep 是 Qt 单元测试模块里的函数,需要为当前项目添加对应的 Qt 模块,编译链接时 qmake 才会为项目添加正确的头文件目录和链接库文件。上面源代码实际没有问题,出问题的是 HelloWorld.pro 文件。在左边项目视图打开 HelloWorld.pro 文件,编辑如下(注释部分已去掉):

QT  += core gui testlib

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = HelloWorld
TEMPLATE = app

SOURCES += /
  main.cpp /
  widget.cpp

HEADERS += /
  widget.h

FORMS += /
  widget.ui

上面就是为项目添加了 Qt 模块 testlib ,使用单元测试模块,就应该在 pro 文件里的QT +=一行里添加 testlib ,然后保存项目文件。

QtCreator 会稍微花些时间重新解析 pro 文件,然后我们点击主菜单菜单 构建 重新构建项目 HelloWorld ,对项目进行重新构建。一般如果修改了 pro 文件,需要手动重新构建项目,避免一些莫名其妙的构建错误(如找不到 WinMain 函数引用)。另外,删除构建目录如 build-HelloWorld-Desktop_Qt_5_9_0_MinGW_32bit-Debug ,然后点击构建或运行按钮,也能实现重新构建项目。如果遇到莫名其妙的构建问题,可以尝试这两种方法。

运行正确编译链接的目标程序,主界面弹出之前会明显感觉到有 1 秒多的迟钝,这是因为我们在主界面构造函数里睡眠了 1000 毫秒,也就是 1 秒。

为 Qt 添加库文件

对于链接时错误,最常遇到的就是本小节里的 undefined reference to **** 链接错误,通常是没有链接到正确的库文件,对于 Qt 自己的库模块,只需要在 pro 文件里QT += 一行末尾加上对应的模块名字,qmake 就会在编译链接时为项目添加正确的包含路径和链接库文件。

对于非 Qt 模块的库文件,通常是在项目文件 pro 里添加 LIBS 变量行,一般添加规则是:

LIBS += 库文件路径全名
LIBS += -L库文件路径  -l库文件短名

这两种写法都可行。库文件短名是指去掉打头的 lib 和扩展名,只留下中间的,比如 libextra.a 或 libextra.so 都写成 -lextra (Linux 里优先链接动态库 .so,Windows 里不用管这些)。

下面是一些例子:

LIBS += C:/mylibs/extra libs/extra.lib
LIBS += C:/mylibs/extra libs/libextra.a
LIBS += -L/home/user/extra libs   -lextra

上面示范的是有空格的路径,必须加双引号才能找到正确位置,如果没空格可以省去双引号。因此不要在库的全路径里出现空格或特殊字符,那纯粹是找麻烦。

示例的第一个 是 VC 库文件用法,第二个是 MinGW 动态链接库引用库 .a 文件或静态库 .a 文件用法,第三个是 Linux/Unix 里的链接库用法,MinGW 也可以采用这种写法。

这些东西在以后的章节里会有些涉及,对于纯 Qt 程序目前不用操心的,这里只是提点一下,等到用的时候再查文档就行了。

22445.html

htmllinuxQtSTL链接库