隨着程序寫的逐漸變多,或多或少的我們都會使用別人寫好的庫;或者我們不想讓別人看到我們的一些核心程序,可以將核心程序封裝成庫。本次和大家分享的是在Ubuntu下使用Qt生成共享庫以及在Qt中鏈接共享庫的方法。
共享庫是在Linux下的稱呼,在Windows下被稱為動態庫。這塊大家需要了解的是程序在編譯時使用的庫和程序在運行時使用的庫需要一致,不然程序可能會閃退。而且運行時庫的路徑如果沒有設置,那么系統就會在默認的路徑下進行搜索,如果沒找到程序直接就掛了。之后的文章會進行總結說明的。
程序平台: Ubuntu14.04、 Qt5.5.1
一、Qt 創建共享庫
- 創建類型為庫的Qt工程
① 新建工程-> Library -> C++ 庫:
②類型選擇默認的共享庫,填寫名稱並選擇工程路徑。簡單說下庫的類型分別是動態庫、靜態庫和Qt的插件
③選擇默認的套件即可
④選擇所需模塊,這里我沒有勾選任何模塊
⑤設置類的基本信息
⑥完成向導
2.工程文件
①工程創建完成后,刪掉了Qt生成的一些文件,文件目錄如下
② .pro 文件的修改,添加版本號的設置
QT -= core gui
TARGET = TestLib
TEMPLATE = lib
VERSION += 1.1.0
CONFIG += debug_and_release
CONFIG(debug, debug|release) {
unix: TARGET = $$join(TARGET,,,_debug)
else: TARGET = $$join(TARGET,,,d)
}
DEFINES += TESTLIB_LIBRARY
SOURCES += addlib.cpp
HEADERS += addlib.h
unix {
target.path = /usr/lib
INSTALLS += target
}
TARGET : 庫的名稱
TEMPLATE :模板類型,類型為lib ,即生成的是一個庫文件
VERSION(新增部分) :庫的版本號設置
CONFIG (新增部分) :控制編譯的Debug與Release庫的版本名稱
3.生成共享庫
該共享庫實現了計算兩個整型數和的功能,過於簡單,莫要介意~
①.h文件內容
#ifndef ADDLIB_H
#define ADDLIB_H
class AddLib
{
public:
AddLib();
int myAdd(int x, int y);
};
#endif // ADDLIB_H
②.cpp內容
#include "addlib.h"
AddLib::AddLib()
{
}
int AddLib::myAdd(int x, int y)
{
return x + y;
}
③構建與運行
只構建的話就會直接生成共享庫,如果運行的話就是下面這個樣子。
④生成動態庫效果
到這里我們就已經生成好了動態庫,可以看下我們添加的動態庫的版本號。
注意,我這里沒有區分Debug與Release版本。
二、鏈接動態庫
- 創建工程添加文件
創建一個繼承QWidget的應用程序后,在與.pro文件同級目錄下添加一個如下目錄組織的文件:
main.cpp
***.pro
Lib/
test/
linux_x32/
Include/
addlib.h
lib/
libTestLib.so**
2.借助Qt添加庫
①右鍵項目->添加庫
②選擇鏈接庫的類型,選擇【外部庫】
③選擇鏈接庫的路徑與平台等信息
①.pro中新增文件
unix:!macx: LIBS += -L$$PWD/Lib/test/linux_x32/lib/ -lTestLib
INCLUDEPATH += $$PWD/Lib/test/linux_x32/include
DEPENDPATH += $$PWD/Lib/test/linux_x32/include
$$PWD :用於指定包含.pro文件目錄的完整路徑
INCLUDEPATH :指定了編譯項目時被搜索到的 #include 目錄
LIBS :指定了鏈接到項目中庫的列表
④修改后的.pro文件
實際項目中我們的庫可能會用到多個平台,所以一般創建如下
unix{
contains(QT_ARCH, i386){
INCLUDEPATH += $$PWD/Lib/test/linux_x32/include
LIBS += -L$$PWD/Lib/test/linux_x32/lib -lTestLib
}
contains(QT_ARCH, x86_64){
}
}else{
contains(QT_ARCH, i386){
}
contains(QT_ARCH, x86_64){
#64bit
}
}
3.測試程序的編寫
①.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "addlib.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pbn_testAddLib_clicked();
private:
Ui::Widget *ui;
AddLib m_addLib;
};
#endif // WIDGET_H
② .cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pbn_testAddLib_clicked()
{
int x = ui->le_x->text().toInt();
int y = ui->le_y->text().toInt();
int ret = m_addLib.myAdd(x,y);
ui->le_ret->setText(QString::number(ret));
qDebug() << "add ret is :" << ret;
}
③ UI輸入兩個數字,點擊按鈕后通過共享庫計算,如下:
三、后記總結
- 使用共享庫問題與解決方法
以前在使用共享時,報了一個這樣的錯誤:
error while loading shared libraries: libTestLib.so.1: cannot open shared object file: No such file or directory
加載共享庫時失敗,沒找到。那會兒的解決辦法是把共享庫拷貝到 usr/local/lib下,這樣問題就沒有了,拷貝后要使用ldconfig命令。
上面的錯誤是在運行時沒有找到共享庫,在Linux下,可以使用 ldd命令查看一個可執行程序所需的庫,效果如下:
2.為什么在Qt中運行沒有報上面的錯誤?
由於以前使用共享庫遇到過上面的問題,但是在剛剛測試共享庫的時候,為什么沒有報錯呢?是Qt將生成的共享庫放到Linux默認的搜索路徑下了么?
於是我使用了locate +庫名 命令進行搜索,但是並沒有在其他路徑下發現剛剛生成的共享庫;於是我又去找配置Linux環境變量的文件,發現也沒有。root下,在/etc/ld.so.conf.d文件下查看。
然鵝我並沒有放棄,於是借助谷歌,搜索了下相關問題【Qt 編譯工程的過程】,雖然沒有找到答案,但是發現了一些線索:
在Projects中的Run Environment 下的LD_LIBRARY_PATH對應的Value里面,我看到了在程序中鏈接庫的目錄。至此,我覺得我找到了原因。
3.小結中的小結
通過對一個問題的求解,我們順藤摸瓜的會學習到很多其他知識。像本次就知道幾個Linux命令的使用場景。
歡迎大家關注公眾號 : Pou光明
如需工程源碼可在后台留下郵箱或其他聯系方式