from qmake to cmake

缘起

一直使用Qt进行开发,Qt是一个非常好用的开发工具。Qt中默认是使用qmake进行编译的,一个项目配置好*.pro文件即可。

在集成编译的时候需要使用cmake编译,项目中平时也会遇到cmake配置的项目,GitHub中也都是cmake为主。

所以需要进行从qmake到cmake的转变。

cmake学习

两个教程的内容是一样的,英文教程没有demo,可读性不怎么好

更推荐后面这个中文教程,所有的代码GitHub上都有,算是网上找到的最好的cmake教程了。

cmake实践

qmake到cmake的转换

就拿我编写的IPC_Serial举例。 qmake的pro文件如下

#-------------------------------------------------
#
# Project created by QtCreator 2017-10-23T15:39:48
#
#-------------------------------------------------

QT       += core dbus
QT       -= gui

TARGET    = IPC_Serial
CONFIG   += console
CONFIG   -= app_bundle
CONFIG   += 0x11
TEMPLATE  = app

SOURCES += \
    src/demo.cpp \
    src/taskManager.cpp \
    src/TLVtools.cpp \
    src/DataLinkLayer.cpp \
    src/TransportLayer.cpp \
    src/COBSTool.cpp \
    src/MsgQueue.cpp \
    src/common.cpp \
    src/serial.cpp \
    src/timeout.cpp \
    src/Msg2MCUhandler.cpp \
    src/SerialServer.cpp

HEADERS += \
    src/common.h \
    src/taskManager.h \
    src/TLVtools.h \
    src/DataLinkLayer.h \
    src/TransportLayer.h \
    src/COBSTool.h \
    src/MsgQueue.h \
    src/serial.h \
    src/timeout.h \
    src/Msg2MCUhandler.h \
    src/SerialServer.h

简析下这个pro: 1. 需要使用到core、dbus库,需要使用用c++11 2. 包含了一些source和head

转成cmake

cmake_minimum_required(VERSION 2.6)
project( IPC_Serial )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -std=c++0x -O2 -g3 -fPIC")

set(SYSROOT_DIR /home/fan/Qt5.10.0/5.10.0/gcc_64)#your sysroot path
INCLUDE_DIRECTORIES(${SYSROOT_DIR}/include/)
INCLUDE_DIRECTORIES(${SYSROOT_DIR}/include/QtCore)
INCLUDE_DIRECTORIES(${SYSROOT_DIR}/include/QtDBus)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/)
link_directories(${SYSROOT_DIR}/lib/ /usr/lib/)
AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/ SRC_LIST_1)


ADD_EXECUTABLE(IPC_Serial  ${SRC_LIST_1} )

TARGET_LINK_LIBRARIES(IPC_Serial Qt5Core Qt5DBus pthread )

简单说明:

  • SYSROOT_DIR:本地qt路径
  • INCLUDE_DIRECTORIES:需要包含的库的头文件路径
  • link_directories:需要包含的库的lib文件路径 AUX_SOURCE_DIRECTORY:代码路径
  • ADD_EXECUTABLE:编译代码
  • TARGET_LINK_LIBRARIES:链接工作,第一个参数是目标文件,后面是需要的链接库名称

问题回顾

1、Qt也可以管理cmake项目

电脑上安装cmake后,使用qt打开CMakeList.txt文件即可。Qt会根据CMakeList.txt的内容打开相应文件

2、DSO missing from command line

Scanning dependencies of target IPC_Serial
[  7%] Building CXX object CMakeFiles/IPC_Serial.dir/src/MsgQueue.cpp.o
[ 15%] Building CXX object CMakeFiles/IPC_Serial.dir/src/TransportLayer.cpp.o
[ 23%] Building CXX object CMakeFiles/IPC_Serial.dir/src/COBSTool.cpp.o
[ 30%] Building CXX object CMakeFiles/IPC_Serial.dir/src/timeout.cpp.o
[ 38%] Building CXX object CMakeFiles/IPC_Serial.dir/src/Msg2MCUhandler.cpp.o
[ 46%] Building CXX object CMakeFiles/IPC_Serial.dir/src/common.cpp.o
[ 53%] Building CXX object CMakeFiles/IPC_Serial.dir/src/SerialServer.cpp.o
[ 61%] Building CXX object CMakeFiles/IPC_Serial.dir/src/TLVtools.cpp.o
[ 69%] Building CXX object CMakeFiles/IPC_Serial.dir/src/serial.cpp.o
[ 76%] Building CXX object CMakeFiles/IPC_Serial.dir/src/demo.cpp.o
[ 84%] Building CXX object CMakeFiles/IPC_Serial.dir/src/DataLinkLayer.cpp.o
[ 92%] Building CXX object CMakeFiles/IPC_Serial.dir/src/taskManager.cpp.o
[100%] Linking CXX executable IPC_Serial
/usr/bin/ld: CMakeFiles/IPC_Serial.dir/src/demo.cpp.o: undefined reference to symbol '_ZN16QCoreApplication4execEv'
/home/fan/Qt5.4.0/5.4/gcc/lib/libQt5Core.so.5: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
CMakeFiles/IPC_Serial.dir/build.make:380: recipe for target 'IPC_Serial' failed
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/IPC_Serial.dir/all' failed
Makefile:83: recipe for target 'all' failed
make[2]: *** [IPC_Serial] Error 1
make[1]: *** [CMakeFiles/IPC_Serial.dir/all] Error 2
make: *** [all] Error 2

我根据错误提示

error adding symbols: DSO missing from command line

搜了很多资料,资料说库包含错误,我再三确认后肯定Qt5DBus是正确包含的。后来才发现是少包含了Qt5Core库

3、undefined reference to `vtable for SerialServer’

修改上面Qt5Core库少包含的问题后,又出现如下错误

[  7%] Building CXX object CMakeFiles/IPC_Serial.dir/src/MsgQueue.cpp.o
[ 15%] Building CXX object CMakeFiles/IPC_Serial.dir/src/TransportLayer.cpp.o
[ 23%] Building CXX object CMakeFiles/IPC_Serial.dir/src/COBSTool.cpp.o
[ 30%] Building CXX object CMakeFiles/IPC_Serial.dir/src/timeout.cpp.o
[ 38%] Building CXX object CMakeFiles/IPC_Serial.dir/src/Msg2MCUhandler.cpp.o
[ 46%] Building CXX object CMakeFiles/IPC_Serial.dir/src/common.cpp.o
[ 53%] Building CXX object CMakeFiles/IPC_Serial.dir/src/SerialServer.cpp.o
[ 61%] Building CXX object CMakeFiles/IPC_Serial.dir/src/TLVtools.cpp.o
[ 69%] Building CXX object CMakeFiles/IPC_Serial.dir/src/serial.cpp.o
[ 76%] Building CXX object CMakeFiles/IPC_Serial.dir/src/demo.cpp.o
[ 84%] Building CXX object CMakeFiles/IPC_Serial.dir/src/DataLinkLayer.cpp.o
[ 92%] Building CXX object CMakeFiles/IPC_Serial.dir/src/taskManager.cpp.o
[100%] Linking CXX executable IPC_Serial
CMakeFiles/IPC_Serial.dir/src/SerialServer.cpp.o: In function `SerialServer::SerialServer()':
/media/fan/DiskA/Github/IPC_Serial/src/SerialServer.cpp:3: undefined reference to `vtable for SerialServer'
CMakeFiles/IPC_Serial.dir/src/SerialServer.cpp.o: In function `SerialServer::~SerialServer()':
/media/fan/DiskA/Github/IPC_Serial/src/SerialServer.cpp:8: undefined reference to `vtable for SerialServer'
CMakeFiles/IPC_Serial.dir/src/TLVtools.cpp.o: In function `TLVtools::TLVTable(unsigned short, unsigned short, unsigned short, unsigned char, unsigned char*)':
/media/fan/DiskA/Github/IPC_Serial/src/TLVtools.cpp:123: undefined reference to `SerialServer::broadcastCANInfo(QByteArray, unsigned char)'
CMakeFiles/IPC_Serial.dir/build.make:380: recipe for target 'IPC_Serial' failed
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/IPC_Serial.dir/all' failed
Makefile:83: recipe for target 'all' failed
collect2: error: ld returned 1 exit status
make[2]: *** [IPC_Serial] Error 1
make[1]: *** [CMakeFiles/IPC_Serial.dir/all] Error 2
make: *** [all] Error 2

https://www.cnblogs.com/qianyuming/archive/2011/03/09/1978910.html

在Qt中,undefined reference to ‘vtable for 通常出现在打开了宏 Q_OBJECT的程式当中。我遇到的情况是:

将类体及类体实现直接写到main.cpp里,没有包含 moc文件。这是一种常见的C++错误,通常就是类体中声明的虚函数没有找到实体。有时候你会说,我没有声明虚函数啊,怎么出来的? 那么建议你 Ctrl+左键追踪一下Q_OBJECT这个宏,这个宏其实默认给你的类加入了一些虚函数的声明(关于signal-slot实现的关键设施),而其实现实在moc_xx.cpp中自动生成的,如果你的编译过程没有产生这个文件,或者产生的这个文件没有参与到编译链接中去,那么就会发生这个错误。

undefined reference to ‘vtable for 常见情况:

一:预编译器打开宏Q_OBJECT,声明若干个由moc处理(implement)的成员函数。如果得到类似于“undefined reference to vtable for LcdNumber”的编译错误(if you get compiler errors along the lines of “undefined reference to vtable for LcdNumber”),你可能是忘记了执行moc,或者忘记了将moc输出加入到link命令里。  某一个类中如果加入Q_OBJECT后,则link时提示:undefined reference to vtable for “xxx::xxx”.删掉它则没有任何问题.  解决:尝试(1):把所有的obj文件和uic文件删除,重新编译.仍然失败.  去trolltech的mail lists找到原因: 因为qmake生成Makefile的时候,这个类的头文件中并没有Q_OBJECT,所以在相应的Makefile里面并没有用moc xxx.h命令,最终导致链接失败.重新运行qmake,问题解决.  在查找解决方法的时候,附带发现一点:   qmake 不会处理.cpp文件里的Q_OBJECT,所以,如果在.cpp文件中有它的话,也会产生undefined reference to vtable for “xxx::xxx”. 这时,需要先用moc xxxx.cpp生成相应的moc文件,再包含到.cpp里面去,才能解决这个问题.  这里可以发现问题的出现是因为没有moc生成相应的moc文件,之后连接就出问题。  我找了好多源码之类的问题,就是没有找pro的错误,后来想到qt中moc我们是有make做的  qt的make编译是根据Makefile来的,而Makefile是由pro文件来的。这才想到了找pro文件的错误。  

二:undefined reference to vtable for “xxx::xxx”  今天碰到了这个问题。  原因:qmake不会处理.cpp文件里的Q_OBJECT,所以,如果在.cpp文件中有它的话,也会产生undefined reference to vtable for “xxx::xxx”. 这时,需要先用moc xxxx.cpp生成相应的moc文件,再包含到.cpp里面去,才能解决这个问题. 

https://stackoverflow.com/questions/31205877/qt-undefined-reference-to-vtable

Absence of a vtable is usually a symptom of failing to include the output of moc in the linker arguments. Make sure that you ran moc on your header, and that you linked the result.

Note that if you’re using qmake, you may need to re-run qmake to generate new makefiles if you change a class that was not Q_OBJECT so that is now Q_OBJECT – it will not otherwise know that moc should be run.

In passing, it’s a good idea to add a constructor that takes an optional parent QObject, to get some of the benefits of Qt’s memory management (freeing of child objects) where the user wants it.

简而言之是SerialServer类继承了QObject,使用了Q_OBJECT。应该有个moc的步骤,生成moc_xxx.cpp文件。

在src目录下运行如下命令,生成moc文件

moc SerialServer.h > moc_SerialServer.cpp

https://stackoverflow.com/questions/1552069/undefined-reference-to-vtable-trying-to-compile-a-qt-project

In order to automatically ensure that all moc cpp files are generated, you can get qmake to automatically generate a .pro file for you instead of writing one yourself.

in the project directory, and qmake will scan your directory for all C++ headers and source files to generate moc cpp files for.

或者可以使用qmake生成moc文件,这样的好处是不会漏

4、error: “This file was generated using the moc from 4.8.7.

moc版本不对,项目期望的是5.XX的版本,而使用的moc是4.8.7的版本,因为moc改动大,所以不兼容

https://sourceforge.net/p/guvcview/tickets/36/

if you are using 5.6.2 then you should use moc from that version. It looks like you have both qt4 and qt5 installed and moc is defaulting to qt4 version.

在terminal使用moc -version可以看到moc的版本,我电脑里面目前默认的moc版本是4.8.7

➜   moc -version
Qt Meta Object Compiler version 63 (Qt 4.8.7)

使用export QT_SELECT=5可以切换默认Qt到Qt5,看看Qt5里面的moc的版本。也可以到Qt5的安装目录下找到moc,直接使用。

至此,成功完成从cmake到qmake的转换

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.