QT-Guide for creating and using dynamic library & static library under Linux

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

Insert picture description here
It can be found that it provides three types, namely:

  • Shared library (DLL)
    selection of the type, will generate dynamic link library, linuxthe is *.so, in Windowscase 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 being PASS.

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 共享库.

LocationAnd Kitsslightly modules selected as follows:

Insert picture description here
Selected by default QtCore, if the removal of the module, Qtmany 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:
Insert picture description here
There is a testso_global.hfile 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.hdeleted. 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.hShaoshang.

Here I have testsoadded 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:

Insert picture description here
The pop-up window appeared to indicate that the compilation was successful, and then we got four neatly organized brothers.

Insert picture description here

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:
Insert picture description here
can be found compared to the dynamic library, one less *_global.hfile.

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 *.afile

Insert picture description here

How to call library files

Implicit link

With the help of Qt tools

With the help of Qt tools, 添加库-> 外部库-> 选择平台->选择库文件

Insert picture description here
Insert picture description here
Insert picture description here

After importing the *.proautomatic 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.hcopied to the project path. If testso_global.hthere are calls, you need to set one and copy it.

Insert picture description here
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
Insert picture description here

add manully

That is, without the aid Qt向导, directly modify the *.prorealization 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 Qlibraryexplicit 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 Ubuntugenerated on Shi libtestso.so.

We pass testsocan be, this name has also been called 基名, as prefixes and suffixes QLibrarywould you try to add accordance systems. So using the base name is written 有利于跨平台移植in.

Insert picture description here
If an absolute path is not used , then the QLibraryrule is to try to add prefixes and suffixes, to go search for a specific location of all system libraries ( in Ubuntu is / usr / lib ).
Insert picture description here
So if you have so库moved to a system library, you can write:

QLibrary mylibrary("testso");

When we pass the absolute path when, QLibrarywill 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 Ubuntunext operation I have encountered a pit, see so文件:

Insert picture description here
Insert picture description here
libtestso.soIt is linked to libtestso.so.1.0.0, and if the libtestso.soproject is copied to the library needs to call, what will happen?
Insert picture description here
Feelings, you think they are the gourd brothers...

Insert picture description here
In fact, they are shadow clones!
Insert picture description here
Mood and Winodwat copies of the shortcuts, and the original file does not move the same.

Solution :

  • Copy libtestso.so.1.0.0and change the file name tolibtestso.so
  • Compile and generate by yourself so文件, then copy theso库

Insert picture description here

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 QLibrarythe 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 Cdiffer, Cthe 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 , Linuxthe next instruction can be used are:

  • objdump -tT xxx.so
  • nm -D xxx.so

I like it personally nmand can still be used awk过滤.

Insert picture description here
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.

Reference thanks


  1. The difference between dynamic library (.so) and static library (.a) under Linux↩︎

  2. Use QLibrary dynamic loading ↩︎

  3. QLibrary Class ↩︎ ↩︎

  4. Linux view dynamic library .so export function list↩︎

Guess you like

Origin blog.csdn.net/weixin_40774605/article/details/105724118