靜態庫依賴關係的一種情況
首先確定的一個概念:lib檔案和obj檔案都是原始碼生成的中間檔案,只不過lib檔案可能是由多個obj檔案集合而來。靜態庫是一個或多個obj檔案的打包。最終都會連結到可執行程式中去。
假設下面一種情況:
應用程式TestCallLib依賴靜態連結庫TestLibB;而TestLibB又依賴靜態連結庫TestLibA。
靜態庫TestLibA的定義
TestLibA是一個靜態連結庫,只有一個匯出類TestLibA,該類只有一個匯出方法print。
#TestLibA.h
#ifndef TESTLIBA_H
#define TESTLIBA_H
class __declspec (dillexport) TestLibA
{
pulic:
TestLibA();
void print();
}
#endif
靜態庫TestLibB的定義
TestLibB是一個靜態連結庫,只有一個匯出類TestLibB,該類只有一個匯出方法Print。
#TestLibB.h
#ifndef TESTLIBB_H
#define TESTLIBB_H
class __declspec(dllexport) TestLibB
{
public:
TestLibB();
void print();
}
#endif
TestLibB::print方法的函式體中呼叫了方法TestLibA::print();
#TestLibB.cpp
#include "TestLibB.h"
#include "TestLibA.h"
#include <QDebug>
TestLibB::TestLibB()
{
}
void TestLibB::print()
{
qDebug()<<"print TestLibB";
TestLibA testLibA;
testLibA.print();
}
TestCallLib是一個應用程式,它會呼叫TestLibB::print方法。
編譯的過程如下
- 我們首先編譯TestLibA庫,生成TestLibA.o檔案,並打包成匯出庫TestLibA.a。
編譯TestLibB庫,由於呼叫了TestLibA::print方法,所以包含了TestLibA.h。
注意:編譯器只需要編譯TestLibB.cpp成TestLibB.o檔案,此時並未連結執行,所以不需要TestLibA::print的方法實現(TestLibA.o或TestLibA.a)。所以我們只包含TestLibA.h而不載入TestLibA.a,也能編譯通過。
TestCallLib編譯時,我們首先連結TestLibB.a,TestLibB.a中並不包含呼叫的TestLibA::print的函式實現,即TestLibA.a,直接編譯將會導致如下錯誤。
error: undefined reference to `TestLibA::TestLibA()'
error: undefined reference to 'TestLibA::print()'
所以我們還需要將TestLibA.a也連結到TestApp中,此時才能編譯通過。
這就是常見的靜態連結庫依賴問題,我們載入一個靜態庫,同時還需要將其依賴的靜態庫,按順序載入進APP的編譯。測試環境QT5.10+QtCreator+MinGW。
根據符號名稱,查詢所在的系統連結庫
靜態庫依賴一般還有下面一種情況,以libuv舉例,編譯靜態庫libuv.lib會使用一些系統方法,在使用libuv.lib時,如果忘記載入系統靜態庫,會報如下的錯誤:
libuv.lib(tty.obj):-1: error: LNK2019: 無法解析的外部符號
__imp__DispatchMessageA@4,該符號在函式
_uv__tty_console_resize_message_loop_thread@4 中被引用。
很多時候,我們並不知道DispatchMessageA到底是屬於哪一個系統靜態庫,那麼我們就需要複製這個函式名,然後到https://msdn.microsoft.com/去搜索該函式的相關介紹,及其所屬庫檔案。如下圖所示: