1. 程式人生 > >靜態庫依賴關係的一種情況

靜態庫依賴關係的一種情況

首先確定的一個概念: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方法。

編譯的過程如下

  1. 我們首先編譯TestLibA庫,生成TestLibA.o檔案,並打包成匯出庫TestLibA.a。
  2. 編譯TestLibB庫,由於呼叫了TestLibA::print方法,所以包含了TestLibA.h。

    注意:編譯器只需要編譯TestLibB.cpp成TestLibB.o檔案,此時並未連結執行,所以不需要TestLibA::print的方法實現(TestLibA.o或TestLibA.a)。所以我們只包含TestLibA.h而不載入TestLibA.a,也能編譯通過。

  3. 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/去搜索該函式的相關介紹,及其所屬庫檔案。如下圖所示:
這裡寫圖片描述