기사 디렉토리
앞에 쓰기
주위
- Ubuntu 18.04
- Qt 5.9.3
Qt 라이브러리 분류
QtCreator 에서 새 프로젝트 를 만들고 Library - C ++ 라이브러리를 선택 합니다.
세 가지 유형, 즉 다음을 제공한다는 것을 알 수 있습니다.
-
공유 라이브러리 (DLL)
타입의 선택은, 동적 링크 라이브러리를 생성한다linux
(가)이다*.so
에서Windows
시*.dll
. -
정적 링크 라이브러리 정적 링크 라이브러리
를 생성하려면이 유형을 선택하십시오*.a
. 최종 생성 된 라이브러리는 입니다. -
이 유형의 Qt 플러그인은 플러그인 과 관련이PASS
있습니다.
ps : 프로그램이 컴파일 될 때 정적 라이브러리가 대상 코드에 링크되고 프로그램이 실행 중일 때 정적 라이브러리가 더 이상 필요하지 않습니다. 컴파일 후 프로그램 파일은 크지 만 로딩이 빠르고 격리가 좋습니다. 동적 라이브러리는 프로그램이 컴파일 될 때 대상 코드에 링크되지 않지만 프로그램이 실행될 때로드되므로 동적 라이브러리가 실행될 때 프로그램에 있어야합니다. 여러 응용 프로그램을 한 번만 메모리에 동적 라이브러리를로드, 동일한 동적 라이브러리, 시간 발사 여러 응용 프로그램을 사용할 수 있습니다 1 .
라이브러리 파일을 생성하는 방법
공유 라이브러리
새 프로젝트, 템플릿 선택 Liabary
- C++库
선택 유형 共享库
.
Location
그리고 Kits
다음과 같이 약간 모듈을 선택했습니다.
기본적으로 선택되어 QtCore
있으며, 모듈을 제거하면 Qt
많은 유형을 사용할 수 없으며 C/C++
의 데이터 유형 만 사용할 수 있습니다 .
라이브러리에 포함 된 GUI
경우 또한 확인해야합니다 QtGui
.
생성되면 다음 문서 : 일부 매크로 정의가 저장된 파일
이 있습니다 .testso_global.h
#include <QtCore/qglobal.h>
#if defined(TESTSO_LIBRARY)
# define TESTSOSHARED_EXPORT Q_DECL_EXPORT
#else
# define TESTSOSHARED_EXPORT Q_DECL_IMPORT
#endif
라이브러리가 클래스 만 빌드하는 so库
경우 문제가 발생할 때 백 사용을 피하기 위해 위의 매크로 정의 헤더 파일의 일부가되어에 추가 testso.h
한 다음 주석 처리 할 수 #include "testso_global.h"
있습니다.
그런 다음 testso_global.h
삭제할 수 있습니다 . 이런 식으로 암시 적 링크가 사용되는 경우에만 이식이 필요합니다 testso.h
.
라이브러리에 여러 클래스가있는 경우 보관하는 것이 더 편리합니다. testso_global.h
Shaoshang 이 필요할 때 암시 적 링크 입니다.
여기 testso
에 두 가지 기능 테스트를 추가했습니다.
testo.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
testo.c
#include "testso.h"
Testso::Testso()
{
}
QString Testso::getName(){
QString re = "testso";
return re;
}
void Testso::testDebug(){
qDebug() << "Debug test success.";
}
빌드 만하면 공유 라이브러리가 직접 생성되며 실행하면 다음과 같습니다.
컴파일이 성공했음을 알리는 팝업 창이 나타나고 깔끔하게 정리 된 4 명의 형제가 생겼습니다.
정적 라이브러리
정적 라이브러리의 생성은 작동중인 동적 라이브러리와 동일하므로 반복하지 않습니다.
결과 파일은 다음과 같습니다.
동적 라이브러리와 비교하여 하나 더 적은 *_global.h
파일 을 찾을 수 있습니다 .
테스트를위한 함수도 추가합니다.
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.";
}
컴파일 후 *.a
파일 이 생성되었음을 발견했습니다.
라이브러리 파일을 호출하는 방법
암시 적 링크
Qt 도구의 도움으로
Qt 도구의 도움으로 添加库
-> 外部库
-> 选择平台
->选择库文件
가져온 후 *.pro
자동은 다음을 추가합니다.
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
그런 다음 testso.h
프로젝트 경로에 복사됩니다. testso_global.h
통화가있는 경우 하나를 설정하고 복사해야합니다.
그런 다음 프로젝트에서 사용해야하는 헤더 파일을 가져옵니다.
데모 사용
#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;
}
효과
manully 추가
즉, 도움없이 가져 오기 라이브러리 Qt向导
의 *.pro
실현을 직접 수정합니다 .
생성 된 이전 마법사를 참조 할 수 있습니다.*.pro
보충 지식 :
-L
다음이 폴더임을 나타냅니다. 프로젝트는이 경로를 라이브러리 파일의 검색 경로에 추가합니다.-l
다음은 라이브러리 파일의 이름임을 나타냅니다.$$PWD
현재 경로를 나타냅니다./..
이전 경로로 돌아가도록 나타냅니다.
명시 적 링크
참조 전용 데모
즉 Qlibrary
, 명시 적 호출을 사용하는 경우이 메서드에는 마이그레이션 파일 헤더가 필요하지 않으며 다음 코드를 참조하십시오.
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();
코드 분석
QLibrary 인스턴스
다음 방법이 일반적으로 사용됩니다.
파일 이름은 생성자를 통해 전달됩니다.이 파일 이름에 대한 공식 권장 사항은 접두사와 접미사를 제거하는 것입니다. 예를 들어 우리 Ubuntu
는 Shi에서 생성했습니다 libtestso.so
.
우리는 합격 testso
이 이름은 호출 된이 될 수 基名
접두사와 접미사로, QLibrary
당신이에 따라 시스템을 추가하려고합니다. 따라서 기본 이름을 사용하여 작성 有利于跨平台移植
됩니다.
경우 절대 경로를 사용하지 않는 , 그 QLibrary
규칙은 (모든 시스템 라이브러리의 특정 위치를 검색 가고, 접두사와 접미사를 추가하는 것입니다 우분투는 / usr / lib 디렉토리에서 ).
따라서 so库
시스템 라이브러리로 이동 한 경우 다음 과 같이 작성할 수 있습니다.
QLibrary mylibrary("testso");
절대 경로를 전달할 때 QLibrary
디렉토리로드를 시도하고 파일을 찾을 수없는 경우 플랫폼 별 파일 접두사 또는 접미사에 따라 다시 시도합니다.
또한 setFileName( )
명시 적으로 load 2로 설정된 파일 이름 의 인스턴스를 생성 한 후에도 사용할 수 있습니다 .
에서 Ubuntu
내가 구덩이를 발견 한 다음 작업을 참조하십시오 so文件
:
libtestso.so
에 링크되어 libtestso.so.1.0.0
있으며 libtestso.so
프로젝트를 라이브러리에 복사해야하는 경우 어떻게됩니까?
감정, 당신은 그들이 박 형제라고 생각합니다 ...
사실 그들은 섀도우 클론입니다!
기분과 Winodw
바로 가기의 복사본은 원본 파일과 동일하게 이동하지 않습니다.
해결책 :
libtestso.so.1.0.0
파일 이름을 다음으로 복사 하고 변경하십시오.libtestso.so
- 직접 컴파일하고 생성 한
so文件
다음so库
로드 ()
이 함수는 동적으로로드 된 라이브러리에 사용되며 ,로드가 완료되면로드 isLoaded( )
의 성공 여부 load( )
를 판단하여 물론 반환 값을 결정하는 것도 가능합니다.
로드에 실패 errorString( )
하면 잘못된 정보를 얻을 수 있습니다 .
로드 후 라이브러리는 응용 프로그램이 종료 될 때까지 메모리에 남아 있습니다. unload( )
라이브러리 제거 를 시도 할 수 있지만 QLibrary
다른 인스턴스가 동일한 라이브러리를 사용하는 경우 호출이 실패하고 모든 인스턴스 unload( )
가 3 일 때 unload 를 호출하는 경우에만 호출이 실패 합니다.
해결 ()
QLibrary库
일반적인 사용법은 라이브러리에서 내 보낸 심볼을 구문 분석하고 심볼을 호출하는 것입니다 C函数
. 이를 "명시 적 링크"라고하며 사용됩니다 resolve( )
.
따라서이 함수를 사용하는 것은 함수에 C函数
대한 기호 라이브러리에서 파생되어야합니다 resolve()
. 즉 C ++编译器
, 라이브러리를 컴파일하는 데 사용 extern "C"
하는 경우 패킹 3 의 함수 블록에서 사용해야합니다 .
음, 경우는 so库
사용하지 않는 extern "C"
내가, 예를 들어,을 ...
우리는 아는 C++
달성 할 수있다 多态
규칙으로 컴파일되어 있기 때문에, C
다른, C
단지와 컴파일러가 생성 기능을 기능 유형 예를 들어 int_add
, 및 C++
도 가져 컴파일러 생성 기능 매개 변수 유형을 예를 들어 int_add_int_int
. 물론 특정 구현은 컴파일러와 관련이 있습니다.
내 생각은 먼저 so库
기능을 확인 하는 것입니다 4 , Linux
다음 명령을 사용할 수 있습니다.
- objdump -tT xxx.so
- nm -D xxx.so
개인적으로 좋아하고 nm
여전히 사용할 수 있습니다 awk过滤
.
따라서 참조 코드에 이상한 함수 이름이 있습니다.
이때 함수를 찾을 수없는 경우이 메서드를 사용 so库
하여 원하는 함수가 포함되어 있는지 확인하고 함수 이름이 무엇인지 확인하는 것이 좋습니다 . 결국 컴파일러에 따라 문제가 발생하지 않습니다.