Use qmake to build a framework to load static and shared libraries

table of Contents

1. Establish a large-scale project

1.1 Build a static library

1.2 Create a shared library

Two, call the generated library file

Three, load shared libraries at runtime

About the plugin

About packaging


 

For the syntax of qmake, please refer to: http://doc.qt.io/qt-5/qmake-manual.html . This is qt5, and qt4 and qt5 are written slightly differently.

Generally speaking, the projects we build using qt creator end with .pro, in fact, what is involved here is the qmake syntax.

In addition to .pro files, there are .pri, .prf, and .prl files.

  • Not much to say about the pro file.
  • The i in pri is the first letter of i nclude. It is similar to the header files in C and C++. Anyway, we can put a part of the *.pro file into a *.pri file, and then include it.
  • The prf f is the characteristic ( f similar eature) of the first character, and pri file is to be included into the pro file as CONFIG + = QT.

  • ls link prl of ( L Ink) of the first character. It is mainly related to generating and using static libraries (dynamic libraries can also have this file, just go to the lib directory under the Qt installation directory to have a look).

For details, please refer to the blog post " On the pro, pri, prf, and prl files of qmake ".

Therefore, qmake is particularly important for building a large-scale project.

This article refers to blog posts: " Qt to create and use shared libraries ", " Qt to load shared libraries at runtime " and " Qt to create and use static link libraries ".

 

1. Establish a large-scale project

First choose to create a new project, click on other projects, select the subdirectory project, and then select the path and name it.

The .pro file generated at this time should be as follows:

TEMPLATE = subdirs
CONFIG += ordered

Then create different sub-projects under the project, which can be executable programs or library files. Right-click to create a new "new subproject".

For example, create a new library project here, and enter the next step after selection:

Here you can choose to build a shared library, a static library or a Qt plugin (Qt Plugin).

1.1 Build a static library

Choose to build a static library. At this time, the sub-project .pro file should contain the following:

TARGET = staticLib
TEMPLATE = lib
CONFIG += staticlib

Indicates that a static library named staticLib will be generated.

Add a few more lines below:

CONFIG += debug_and_release
CONFIG(debug, debug|release): TARGET = $$join(TARGET,,,d)
DESTDIR = ../../externlib/

Indicates that the generated library file will be placed under externlib, and if it is debug compiled, d will be added to the generated suffix.

For .h and .cpp files, you can write various functions freely.

1.2 Create a shared library

The process of creating a shared library is the same as creating a static library, but the selection is different. At this time, the .pro file should be as follows:

TARGET = sharedLib
TEMPLATE = lib
DEFINES += SHAREDLIB_LIBRARY

Indicates that a shared library named sharedLib will be generated.

Since the shared library needs to be placed in the same directory as the executable program, the following lines need to be added:

CONFIG += debug_and_release
CONFIG(debug, debug|release): TARGET = $$join(TARGET,,,d)
CONFIG(debug, release|debug): DESTDIR = ../../debug/
CONFIG(release, release|debug): DESTDIR = ../../release/

Similarly, here d is added to the compiled suffix under the debug version.

For .h and .cpp files, you can freely write function interfaces.

In addition to the two files of general C++ classes, Qt Creator will also help us create a header file named {projectName}_global.h to ensure that the correct macro can be called.

In addition, if it is written in C language, you also need to add extern "C" in the exported header file.

 

Two, call the generated library file

First create a new sub-project, select Application to generate executable files.

Similarly, for the final file generated, we assign it to the feature directory. Generally speaking, the software will have a debug version and a release version for distinction, and also add the following code.

CONFIG(debug, release|debug): DESTDIR = ../../debug/
CONFIG(release, release|debug): DESTDIR = ../../release/

Writing in this way is a good habit to effectively separate the rel generated by debug.

Then in the subproject, right click to add the library. Since the static library shared library projects created before are all under the same project, you can select the internal library.

The name of the library to be selected can be automatically recognized, the platform can be checked, and the debug version is added with'd' as a suffix.

After adding, the following lines will be automatically added to the .pro file:

win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../externlib/ -lstaticLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../externlib/ -lstaticLibd
else:unix: LIBS += -L$$OUT_PWD/../../externlib/ -lstaticLib

INCLUDEPATH += $$PWD/../staticLib
DEPENDPATH += $$PWD/../staticLib

win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../externlib/libstaticLib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../externlib/libstaticLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../externlib/staticLib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../externlib/staticLibd.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../externlib/libstaticLib.a

It looks very complicated and is actually similar to adding dependencies in a VS project, including the directory where the header files are located. Note that the static library file needs to be assigned to the externlib folder , corresponding to the previous build.

Similarly, the process of adding shared libraries is the same. After adding, the following will be added to the .pro file:

win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../release/ -lsharedLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../debug/ -lsharedLibd
else:unix: LIBS += -L$$OUT_PWD/../sharedLib/ -lsharedLib

INCLUDEPATH += $$PWD/../sharedLib
DEPENDPATH += $$PWD/../sharedLib

It's basically the same as adding a static library.

 

Regarding static libraries and shared libraries, both .lib files are required during compilation. After compilation, the dll or so files of the shared library must be placed in a location where the executable file can be found, otherwise the runtime will prompt that the dependency is missing, and the static library It is required at compile time. The specific advantages and disadvantages are as follows:

  • When creating a shared library, it needs to be deployed to an application. The applications and libraries associated with the shared library are very small.
  • Static linking will generate an independent executable file. The advantage of this is that only a few files need to be deployed. The disadvantage is that the executable file will become very large.

After the above deployment, we can call the function interface in the static library or shared library.

 

Three, load shared libraries at runtime

The first and second above all talk about how to deploy in a complete project while relying on library files. In fact, another advantage of the shared library file is to choose whether to load or not to load when the program starts, that is to say the plug-in mode we often call.

Qt suggests QLibrary library or QPluginLoader two ways to load shared libraries.

If you use the QLibrary class, the resolve function is generally used. For details, see " Qt: Loading Shared Libraries at Runtime ".

If you use QtPlugin, you need to add the following lines:

#define PluginID   "org.qt-project.Qt.Examples.plugin.IPluginUi"
Q_DECLARE_INTERFACE(IPluginUi, PluginID)

Q_PLUGIN_METADATA(IID PluginID FILE "pluginForm.json")
Q_INTERFACES(IPluginUi)

The json file is used to describe some properties of the plug-in.

The key code of QtPlugin's specific calling method is as follows:

QStringList filters;
filters << "*.dll" << "*.so";      //在插件所在的文件夹下筛选后缀为dll或so结尾的文件
pluginDir.setNameFilters(filters);
foreach (QString filename, pluginDir.entryList(QDir::Files))
{
	QPluginLoader *pluginload = new QPluginLoader(pluginDir.absoluteFilePath(filename));
	pluginload->setLoadHints(QLibrary::ExportExternalSymbolsHint | QLibrary::ResolveAllSymbolsHint);
	if(pluginload->load())
	{
		QObject *obj = pluginload->instance();
		if(obj)
		{
			IPluginUi *plugin = qobject_cast<IPluginUi*>(obj);
			if(plugin)
			{
				QWidget *widget = plugin->PluginUi();
				QString str_sn = plugin->getSerialNumber();

				QString class_name = pluginload->metaData().value("className").toString();
				ui->textEdit->append("export class: " + class_name);
				QJsonObject json = pluginload->metaData().value("MetaData").toObject();
				QString str_author = json.value("author").toString();
				QString str_date = json.value("date").toString();
				QString str_license = json.value("license").toString();
				QString str_version = json.value("version").toString();
				QJsonArray array = json.value("changelog").toArray();
			}
		}
	}
}

Since then, the plug-in has been loaded.

The demo effect for a demonstration is as follows:

The loaded plug-in interface will be displayed in Tab2.

The complete code of the project can be found in https://github.com/WelinLee/qt_pattern , and it can be compiled under both windows and linux platforms.

 

About the plugin

Through the above, we can design a small plug-in program. When designing such a modular program, the following points must be considered:

  • How to register the plugin;
  • How to call the plug-in;
  • How to test the plug-in;
  • Plug-in life cycle management;
  • Provide information such as the name, version, and status of the plug-in, get the plug-in list, record the processing log of the plug-in, etc.;
  • Plug-in error handling.

For details, see "In- depth understanding of the plug-in system " and " Building your own Qt plug-in system ".

 

About packaging

For the generation of the software, if it is windows platform can be used windeploy qt .exe packaged.

In linux, you can use the ldd command (deplist=$(ldd $exe | awk'{if (match($3,"/")){printf("%s ",$3)}}')) to find what the program needs Dependencies and then package them.

 

Guess you like

Origin blog.csdn.net/u014610460/article/details/84928321
Recommended