Article Directory
Write in front
surroundings
- Ubuntu 18.04
- Qt 5.9.3
Classification of Qt libraries
Create a new project in QtCreator , select Library - C++ library
It can be found that it provides three types, namely:
-
Shared library (DLL)
selection of the type, will generate dynamic link library,linux
the is*.so
, inWindows
case of*.dll
. -
Static link library
Select this type to generate a static link library, and the final generated library is*.a
. -
This type of Qt Plugin is related to plug-ins, here for the time beingPASS
.
ps : The static library will be linked to the target code when the program is compiled, and the static library will no longer be needed when the program is running. After compilation, the program file is large, but the loading is fast and the isolation is good. The dynamic library is not linked to the target code when the program is compiled, but is loaded when the program is running, so the dynamic library needs to be in the program when the program is running. Multiple applications can use the same dynamic library, time launch multiple applications, just load the dynamic library into memory once 1 .
How to generate library files
Shared library
New Project, select the template Liabary
- C++库
the type of selection 共享库
.
Location
And Kits
slightly modules selected as follows:
Selected by default QtCore
, if the removal of the module, Qt
many types are not available, you can only use C/C++
the data type of the.
If the library contains GUI
, also need to check QtGui
.
Once created, the following documents:
There is a testso_global.h
file stored some macro definitions
#include <QtCore/qglobal.h>
#if defined(TESTSO_LIBRARY)
# define TESTSOSHARED_EXPORT Q_DECL_EXPORT
#else
# define TESTSOSHARED_EXPORT Q_DECL_IMPORT
#endif
If the library only build a class, in order to avoid the use of the back so库
when the trouble, we can be part of the above macro definition header file and added to testso.h
, and then comment out #include "testso_global.h"
.
Then you can put testso_global.h
deleted. In this way, only porting is required when implicit linking is used testso.h
.
If there are multiple classes in the library, it is more convenient to keep them. Is implicit link when the need to testso_global.h
Shaoshang.
Here I have testso
added two function tests
testso.h
#ifndef TESTSO_H
#define TESTSO_H
#include "testso_global.h"
#include <QString>
#include <QDebug>
class TESTSOSHARED_EXPORT Testso
{
public:
Testso();
QString getName();
void testDebug();
};
#endif // TESTSO_H
testso.c
#include "testso.h"
Testso::Testso()
{
}
QString Testso::getName(){
QString re = "testso";
return re;
}
void Testso::testDebug(){
qDebug() << "Debug test success.";
}
If you just build it, the shared library will be generated directly. If you run it, it will look like this:
The pop-up window appeared to indicate that the compilation was successful, and then we got four neatly organized brothers.
Static library
The generation of the static library is the same as the dynamic library in operation, so I won't repeat it.
The resulting file is as follows:
can be found compared to the dynamic library, one less *_global.h
file.
We also add a function for testing to it:
test_staticdll.h
#ifndef TEST_STATICDLL_H
#define TEST_STATICDLL_H
#include <QDebug>
class Test_staticdll
{
public:
Test_staticdll();
void test();
};
#endif // TEST_STATICDLL_H
test_staticdll.c
#include "test_staticdll.h"
Test_staticdll::Test_staticdll()
{
}
void Test_staticdll::test(){
qDebug() << "test Static dll is success.";
}
After compilation, it found that generated a *.a
file
How to call library files
Implicit link
With the help of Qt tools
With the help of Qt tools, 添加库
-> 外部库
-> 选择平台
->选择库文件
After importing the *.pro
automatic will add:
DISTFILES +=
unix:!macx: LIBS += -L$$PWD/../build-testso-Desktop_Qt_5_9_3_GCC_64bit-Debug/ -ltestso
INCLUDEPATH += $$PWD/../build-testso-Desktop_Qt_5_9_3_GCC_64bit-Debug
DEPENDPATH += $$PWD/../build-testso-Desktop_Qt_5_9_3_GCC_64bit-Debug
Then we will be testso.h
copied to the project path. If testso_global.h
there are calls, you need to set one and copy it.
Then import the header file where you need to use it in the project.
Use demo
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Testso *test = new Testso();
ui->label->setText(test->getName());
test->testDebug();
}
MainWindow::~MainWindow()
{
delete ui;
}
effect
add manully
That is, without the aid Qt向导
, directly modify the *.pro
realization of the import library.
You can refer to the previous wizard generated*.pro
Supplementary knowledge :
-L
Indicates that the following is a folder, the project will add this path to the search path of the library file-l
Indicates that what follows is the name of a library file$$PWD
Represents the current path/..
Indicates to return to the previous path
Explicit link
For reference only demo
I.e. using Qlibrary
explicit call, the method does not require migration file header, the following code for reference:
QLibrary mylibrary("/home/hsy/SW/Qt5.9.3/Project/build-testso-Desktop_Qt_5_9_3_GCC_64bit-Debug/testso");
if(!mylibrary.load()){
//加载so失败
qDebug() << "Load Testso.so is failed!";
qDebug() << mylibrary.errorString();
}
//声明函数指针
typedef QString (*Fun_getName)();
typedef void (*Fun_testDebug)();
//resolve得到库中函数地址
Fun_getName getName = (Fun_getName)mylibrary.resolve("_ZN6Testso7getNameEv");
Fun_testDebug testDebug = (Fun_testDebug)mylibrary.resolve("_ZN6Testso9testDebugEv");
if(nullptr == getName){
qDebug() << "Load fun() getName failed!";
}else{
ui->label->setText(getName());
}
if(nullptr == testDebug){
qDebug() << "Load fun() testDebug failed!";
}else{
testDebug();
}
//卸载库
mylibrary.unload();
Code analysis
QLibrary instance
The following methods are commonly used:
The file name is passed in through the constructor. The official recommendation for this file name is to remove the prefix and suffix. For example we Ubuntu
generated on Shi libtestso.so
.
We pass testso
can be, this name has also been called 基名
, as prefixes and suffixes QLibrary
would you try to add accordance systems. So using the base name is written 有利于跨平台移植
in.
If an absolute path is not used , then the QLibrary
rule is to try to add prefixes and suffixes, to go search for a specific location of all system libraries ( in Ubuntu is / usr / lib ).
So if you have so库
moved to a system library, you can write:
QLibrary mylibrary("testso");
When we pass the absolute path when, QLibrary
will go to try to load the directory, if the file is not found then try again depending on the platform-specific file prefix or suffix.
In addition, we can also be used after creating an instance of setFileName( )
the file name explicitly set to load 2 .
In the Ubuntu
next operation I have encountered a pit, see so文件
:
libtestso.so
It is linked to libtestso.so.1.0.0
, and if the libtestso.so
project is copied to the library needs to call, what will happen?
Feelings, you think they are the gourd brothers...
In fact, they are shadow clones!
Mood and Winodw
at copies of the shortcuts, and the original file does not move the same.
Solution :
- Copy
libtestso.so.1.0.0
and change the file name tolibtestso.so
- Compile and generate by yourself
so文件
, then copy theso库
load( )
This function is used to dynamically loaded libraries , loading is completed, by isLoaded( )
determining the success of loading, of course, through load( )
to determine the return values are also possible.
If the loading fails, we can errorString( )
get the wrong information.
After loading, the library will remain in memory until the application terminates. We can try unload( )
to uninstall the library, but if QLibrary
the other instance is using the same library, the call will fail, and only if every instance call unload( )
unload when 3 .
resolve( )
QLibrary库
The typical usage is to parse the exported symbol in a library and call the symbol C函数
. This is called "explicit linking" and it is used resolve( )
.
Therefore, using this function must be derived from a library of symbols C函数
for resolve()
functions. This means that if you use C ++编译器
to compile the library, must be used extern "C"
in a function block in the packing 3 .
Well, if so库
does not use extern "C"
it, for example, I ...
We know that C++
has been able to achieve 多态
, because it is compiled with the rules C
differ, C
the compiler-generated functions only with the type of function , for example int_add
, and C++
the compiler-generated functions also bring parameter type , for example int_add_int_int
. Of course, the specific implementation is related to the compiler.
My idea is to first check so库
the function 4 , Linux
the next instruction can be used are:
- objdump -tT xxx.so
- nm -D xxx.so
I like it personally nm
and can still be used awk过滤
.
So there is the strange function name in the reference code.
Here it is strongly recommended that at the time could not find the function, use this method to see so库
whether contains the desired function, and what its function name, after all, it depends on the compiler to avoid being pit.