最近在研究qt 的mqtt,看到官方demo的pro文件有些生疏,研究了下 是qtmodule的写法;
搬运过来如下:(大概有个概念即可,凑乎看看~)
制作Qt Module 的总结
注意:本文档中代码用蓝色标识,以csystem代码库为例讲述。
1、代码结构
根目录:stem
一级目录:stem rpmupstream
stem:是存放源码的目录,名字可以随意;
rpm:是放置spec文件和patch文件的目录;
upsteam:是用于放置随着QT版本升级所需的东西。
二级目录:.qmake.conf stem.prosrc sync.profile 〔examples testsconfig.tests〕
.qmake.conf:定义模块开始制作的标志,及加载qt_build_config和当前的QT版本号,内容如下:
MODULE_VERSION =$$QT_VERSION
load(configure)
# FIXME: This causes tests to be installed (if examplesare installed as well),
# which is needed to run some tests because they arebroken.
CONFIG += ordered
load(qt_parts)
src:放置源码
sync.profile:定义生成模块的源码和模块路径和生成模块时用到的qt模块等,内容如下:
%modules = ( # path to module namemap
"QtStem" => "$basedir/src/stem",//生成的QT模块的名字,后面的路径是生成模块的源码路径
);
%moduleheaders = ( # restrict the module headers to thosefound in relative path
);
# Module dependencies.
# Every module that is required to build this moduleshould have one entry.
# Each of the module version specifiers can take one ofthe following values:
# - A specific Gitrevision.
# - any git symbolic ref resolvable from the module'srepository (e.g. "refs/heads/master" to track masterbranch)
# - an empty string to use the same branch under test(dependencies will become "refs/heads/master" if we are in themaster branch)
#
�pendencies = (
"qtbase" => "",
"qtxmlpatterns" => "",
);
〔config.tests:〕这个目录可有可无,主要目的是在编译之前进行一些编译链接的测试。如在pro中,有 CONFIG += link_pkgconfig PKGCONFIG +=bluez 这样的编译链接存在,可以在制作模块之前,进行一些链接验证,这种情况下,可以将bluez的链接测试放在这里,具体的做法如下:
1)在config.tests里面创建bluez文件夹,里面包含两个文件:bluez.promain.cpp ;
bluez.pro的代码如下:
TEMPLATE = app
CONFIG += link_pkgconfig
PKGCONFIG += bluez
TARGET = bluez
SOURCES += main.cpp
main.cpp的代码如下:
#include
int main()
{
return 0;
}
2)在pro中添加编译,这时的pro文件代码如下:
load(configure)
qtCompileTest(bluez)
# FIXME: This causes tests to be installed (if examplesare installed as well),
# which is needed to run some tests because they arebroken.
CONFIG += ordered
load(qt_parts)
三级目录:src.prostem
src.pro:代码如下:
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += stem
stem:这是在pro中QT +=名字,这个名字和stem是相对应的。
四级目录:公有.h文件.cpp文件和私有.h文件.cpp文件,以及pro文件
pro文件的大致结构是:
QT += core dbus networkgui
TARGET = QtSystem //生成的模块名字
SOURCES += \
PUBLIC_HEADERS +=
PRIVATE_HEADERS +=
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS\
load(qt_module) //这个必须存在
2、编译过程
1)exportQTDIR=/usr/share/qt5
导入qt,因为在后续的过程中,可能用到qt的一些pri或是其他模块文件
2)touch.git
这个必须做,只有执行了这步,才可以在/include/QtSystem里面生成相应的模块库以及headers.pri,否则只能生成QtSystemDepends一个文件。
3)qmake 〔CONFIG+=ofono CONFIG+=nox11optionCONFIG+=upower〕
4)make
3、编译后的正确生成文件
在一级目录里面会多三个文件夹:include libmkspecs
include:只包含了生成的模块名的文件夹:QtStem
QtStem中包含了:QtStem、QtStemDepends、QtStemVersion、headers.pri、qtstemversion.h、5.3.0
QtSystem包含了所有的头文件的名字,如下面所示:
#ifndefQT_QTSTEM_MODULE_H
#defineQT_QTSTEM_MODULE_H
#include
#include "cbatteryinfo.h"
#include "mainpage.h"
#include"qtstemversion.h"
#endif
QtStemDepends这个文件是根据stem.pro中QT+= 生成的,内容如下所示:
#include
#include
#include
#include
QtStemVersion包含了记录版本号的头文件的名字,内容如下所示:
#include"qtstemversion.h"
headers.pri记录了这个文件夹中包含的所有文件信息,内容如下所示:
SYNCQT.HEADER_FILES = 所有头文件的名称和../../include/QtStem/qtstemversion.h../../include/QtStem/QtStem
SYNCQT.HEADER_CLASSES =../../include/QtStem/QtStemVersion
SYNCQT.PRIVATE_HEADER_FILES = 所有私有头文件的名称
SYNCQT.QPA_HEADER_FILES =
SYNCQT.INJECTIONS =
qtstemversion.h记录版本信息,内容如下所示:
#ifndefQT_QTSTEM_VERSION_H
#defineQT_QTSTEM_VERSION_H
#define QTSTEM_VERSION_STR"5.3.0"
#define QTSTEM_VERSION0x050300
#endif //QT_QTSTEM_VERSION_H
5.3.0这个以版本号命名的文件夹,里面包含了所有的私有头文件
lib目录下面存在三种文件:
cmake目录下面存放着一些制作模块过程中用到的.cmake文件,如:Qt5StemConfig.cmake和Qt5StemConfigVersion.cmake
pkgconfig目录下存放着生成的pc文件,内容大致如下所示:
prefix=/usr
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include/qt5
Name: Qt5 Stem
Description: Qt Stemmodule
Version: 5.3.0
Libs: -L${libdir}-lQt5Stem
Libs.private: -lfontconfig -L/usr/lib -lQt5Network-lQt5DBus -lQt5Gui -lQt5Core -lpthread-lGLESv2
Cflags: -I${includedir}/QtStem-I${includedir}
Requires: Qt5Core Qt5Gui Qt5DBusQt5Network
剩下的就是生成的一些libQt5Stem.la、libQt5Stem.prl和libQt5Stem.so文件
mkspec中存在两个文件夹:modulesmodules-inst
modules中存在一个qt_lib_stem.pri文件,内容如下所示:
QT_MODULE_BIN_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/bin
QT_MODULE_INCLUDE_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/include
QT_MODULE_IMPORT_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.skyt21/stem/imports
QT_MODULE_QML_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/qml
QT_MODULE_LIB_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/lib
QT_MODULE_HOST_LIB_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/lib
QT_MODULE_LIBEXEC_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/libexec
QT_MODULE_PLUGIN_BASE = /home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/plugins
include(/home/xx/rpmbuild/SOURCES/stem-5.3.0.sky21/stem/mkspecs/modules-inst/qt_lib_stem.pri)
modules-inst中包含两个文件:qt_lib_stem.priqt_lib_stem_private.pri
QT.stem.libs =$$QT_MODULE_LIB_BASE
QT.stem.rpath = /usr/lib
QT.stem.includes = $$QT_MODULE_INCLUDE_BASE$$QT_MODULE_INCLUDE_BASE/QtStem
QT.stem.bins =$$QT_MODULE_BIN_BASE
QT.stem.libexecs =$$QT_MODULE_LIBEXEC_BASE
QT.stem.plugins =$$QT_MODULE_PLUGIN_BASE
QT.stem.imports =$$QT_MODULE_IMPORT_BASE
QT.stem.qml =$$QT_MODULE_QML_BASE
QT.stem.depends = core gui dbusnetwork
QT.stem.DEFINES =QT_SYSTEM_LIB
qt_lib_stem_private.pri的内容如下所示:
QT.stem_private.VERSION =5.3.0
QT.stem_private.MAJOR_VERSION =5
QT.stem_private.MINOR_VERSION =3
QT.stem_private.PATCH_VERSION =0
QT.stem_private.libs =$$QT_MODULE_LIB_BASE
QT.stem_private.includes =$$QT_MODULE_INCLUDE_BASE/QtStem/5.3.0$$QT_MODULE_INCLUDE_BASE/QtStem/5.3.0/QtStem
QT.stem_private.depends =stem
QT.stem_private.module_config = internal_moduleno_link
4、spec文件
下面提供一个现成的spec文件,一起分析一下。和上面设置中相对应的stem.spec,具体内容如下所示:
Name: stem//文件名字,需要修改
Summary: Qt Stemmodules
Version: 5.3.0.sky21//以本地QT版本相对应,设置版本号
Release:1%{?dist}.14.3
Group:System/Libraries
License: LGPLv2.1 with exception orGPLv3
URL: //....
Source0:%{name}-%{version}.tar.bz2
BuildRequires: qt5-qtcore-devel//编译依赖需要修改
BuildRequires:qt5-qtgui-devel
BuildRequires:qt5-qtnetwork-devel
BuildRequires:qt5-qtsql-devel
BuildRequires:qt5-qtdbus-devel
BuildRequires:qt5-qtxml-devel
BuildRequires:qt5-qttest-devel
BuildRequires:qt5-qtopengl-devel
BuildRequires:qt5-qtdeclarative-devel
BuildRequires:qt5-qtdeclarative-qtquick-devel
BuildRequires:qt5-qmake
BuildRequires:fdupes
BuildRequires:pkgconfig(libudev)
BuildRequires:pkgconfig(bluez)
�scription//模块描述
Qt is a cross-platform application and UIframework. Using Qt, you can
write web-enabled applications once anddeploy them across desktop,
mobile and embedded systems without rewritingthe source code.
.
This package contains the Qt stemmodules
%package -n qt5-qtstem//最后生成的rpm包
Summary: Qt steminfo
Group:Stem/Libraries
Requires(post):/sbin/ldconfig
Requires(postun):/sbin/ldconfig
�scription -nqt5-qtstem
Qt is a cross-platform application and UIframework. Using Qt, you can
write web-enabled applications once anddeploy them across desktop,
mobile and embedded systems without rewritingthe source code.
.
This package contains the Qt StemInfomodule
%package -nqt5-qtstem-devel
Summary: Qt stem info - developmentfiles
Group:Development/Libraries
Requires: qt5-qtstem =%{version}-%{release}
�scription -nqt5-qtstem-devel
Qt is a cross-platform application and UIframework. Using Qt, you can
write web-enabled applications once anddeploy them across desktop,
mobile and embedded systems without rewritingthe source code.
.
This package contains the Qt StemInfodevelopment files
%prep//解压,打patch的过程
%setup -q -n%{name}-%{version}/stem
%build//编译的过程,做对应的修改
exportQTDIR=/usr/share/qt5
touch.git
qmake -qt=5 CONFIG+=ofono CONFIG+=nox11optionCONFIG+=upower
make%{?_smp_mflags}
%install//安装的过程,如果按上面生成的结构,一般不需要特别修改
rm -rf%{buildroot}
%qmake5_install
#Remove unneeded .la files
rm -f %{buildroot}/%{_libdir}\1/" {}\;
�upes%{buildroot}/%{_includedir}
#### Pre/Postsection
%post -nqt5-qtstem
/sbin/ldconfig
%postun -nqt5-qtstem
/sbin/ldconfig
#### Filesection
%files -n qt5-qtstem// 打包的过程
�fattr(-,root,root,-)
%{_libdir}/libQt5Stem.so.5
%{_libdir}/libQt5Stem.so.5.*
%files -nqt5-qtstem-devel
�fattr(-,root,root,-)
%{_libdir}/libQt5Stem.so
%{_libdir}/libQt5Stem.prl
%{_libdir}/pkgconfig/Qt5Stem.pc
%{_includedir}/qt5/QtStem/
%{_datadir}/qt5/mkspecs/modules/qt_lib_stem.pri
%{_datadir}/qt5/mkspecs/modules/qt_lib_stem_private.pri
%{_libdir}/cmake/Qt5Stem/
5、总结
按照上面给出的代码结构,构建自己的qt模块生成代码库。严格按照编译过程给出的步骤,验证一下自己生成的模块的正确性。如果验证完成,修改spec文件,生成相应的rpm包。
可能存在的问题:
1)编译没问题,可是生成的include/模块名/里面之包含了一个文件,里面的头文件都没有。可能的原因是在编译的过程中,没有运行touch.git这个步骤;
2)生成的模块没问题,安装后,导入使用的时候,如:在测试pro中QT+= 模块名字,可是在具体使用到某个函数的时候,提示:
qflashtest.o: In function`QFlashTest::QFlashTest(QObject*)':
qflashtest.cpp:(.text+0x3c):undefined reference to `QFlash::QFlash(QObject*)'
qflashtest.o: In function`QFlashTest::turnOn()':
qflashtest.cpp:(.text+0x21c):undefined reference to `QFlash::turnOn()'
qflashtest.o: In function`QFlashTest::turnOff()':
qflashtest.cpp:(.text+0x44c):undefined reference to `Qflash::turnOff()'这样的错误,原因是:在你的源码中,头文件没有按规范的格式书写。
3)关于qt模块生成中源码的规范:
必须有一个*global.h的文件,下面以stem中的为例:stemglobal.h,内容如下:
#ifndefCSTEMGLOBAL_H
#defineCSTEMGLOBAL_H
#include
#ifndefQT_STATIC
#ifdefined(QT_BUILD_SYSTEMINFO_LIB)
#define Q_EXPORTQ_DECL_EXPORT
#else
#define Q_EXPORTQ_DECL_IMPORT
#endif
#else
#define Q_EXPORT
#endif
#endif //CSTEMGLOBAL_H
具体到某一个头文件的时候,如qflash.h,内容如下所示:
#ifndef QFLASH_H
#define QFLASH_H
#include"cstemglobal.h"
#include
QT_BEGIN_NAMESPACE
class Q_EXPORTQFlash : publicQObject
{
Q_OBJECT
public:
explicit QFlash(QObject *parent =0);
~QFlash();
Q_INVOKABLE voidturnOn();
Q_INVOKABLE voidturnOff();
};
QT_END_NAMESPACE
#endif // QFLASH_H
对应的cpp文件
#include
#include
#include
#include "qflash.h"
QT_BEGIN_NAMESPACE
QFlash::QFlash(QObject *parent):QObject(parent)
{
}
QFlash::~QFlash()
{
}
void QFlash::turnOn()
{
}
void QFlash::turnOff()
{
}
QT_END_NAMESPACE