linux下動態庫編譯的依賴問題

這裏主要是想試驗一下,對一個具有多層嵌套的動態庫進行編譯時,是否要把最底層的庫也包含進來的問題,結論是:只要直接依賴的庫名稱,不需要最底層庫名稱。

一,目錄結構
ZZZ
├── add
│   ├── add.cpp
│   └── add.h
├── calc
│   ├── calc.cpp
│   └── calc.h
├── main
├── main.cpp
├── pkg
│   ├── pkg.cpp
│   └── pkg.h
└── sub
    ├── sub.cpp
    └── sub.h

二,文件內容:
1, add模塊內容:
[add.cpp ]
int add(int a, int b)
{
    return a+b;
}
[add.h]
extern  int add(int a, int b);

2, sub模塊內容:
[sub.cpp]
int sub(int a, int b)
{
    return a-b;
}
[sub.h]
extern int sub(int a, int b);

3, calc模塊內容:
[calc.cpp]
#include "calc.h"
#include "add.h"
#include "sub.h"
#include <stdio.h>

void func(int a, int b)
{
    int result = add(a,b);
    printf("%d+%d=%d\n",a, b, result);

    result = sub(a,b);
    printf("%d-%d=%d\n",a, b, result);
}
[calc.h]
extern void func(int a, int b);

4, pkg模塊: 對calc模塊進行了簡單封裝
[pkg.cpp]
#include "pkg.h"
#include "calc.h"

void pkg_func()
{
    func(100, 80);
}
[pkg.h]
extern void pkg_func();
5, main程序:調用pkg模塊
[main.cpp]
#include "pkg.h"

int main()
{
    pkg_func();

    return 0;
}


三,編譯:
ZZZ目錄下:(單功能模塊)
1,[add模塊]
    g++ -g -shared -fPIC add/add.* -o libadd.so
2, [sub模塊]:(單功能模塊)
    g++ -g -shared -fPIC sub/sub.* -o libsub.so
3, [calc模塊]: clac模塊依賴於add和sub模塊,用到了兩者的頭文件,並調用了接口
    錯誤:g++ -g -shared -fPIC -Iadd -Isub calc/calc.*  -o libcalc.so
    (編譯雖然可以過,但是參數不足,這種遺漏依賴庫的問題現在不解決,在編譯嵌套它的上層庫時就會暴露出來)
    正確:g++ -g -shared -fPIC -Iadd -Isub -ladd -lsub -L. calc/calc.*  -o libcalc.so
4, [pkg模塊]:封裝calc模塊
    錯誤:g++ -g -shared -fPIC -Icalc  pkg/pkg.* -o libpkg.so
    正確:g++ -g -shared -fPIC -Icalc -lcalc -L. pkg/pkg.* -o libpkg.so
5, [main程序]
    g++ -g -Ipkg -lpkg -L. main.cpp -o main

四,試驗

我們知道各模塊的依賴關係:pkg->calc->add+sub,讓我們慢慢分析,通過3,4步的編譯參數我們可以看出:
編譯鏈接某個so的時候,系統並不檢查接口是否可以導出,而只是檢查編譯是否通過。所以編譯參數只包含依賴庫的文件名是可以通過,但並不保證是正確的。(製作動態庫的時候,到底有沒有鏈接這個過程?,否則爲什麼在第一層調用庫的時候就不報錯呢)
1)g++ -g -Ipkg main.cpp -o main
/tmp/ccjKIuei.o: In function `main':
/home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
A: main.cpp裏面沒有找到pkg_func接口,沒包含庫名稱怎麼可能找得到接口呢?

2) g++ -g -Ipkg -lpkg main.cpp -o main
/usr/bin/ld: cannot find -lpkg
collect2: ld 返回 1
A: 沒有找到庫名,需要指定庫目錄

3)g++ -g -Ipkg -lpkg -L. main.cpp -o main
/tmp/cc4JknbM.o: In function `main':
/home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
./libpkg.so: undefined reference to `func(int, int)'
collect2: ld 返回 1
A: libpkg.so裏沒有找到func接口,說明libpkg.so庫在編譯時沒有包含依賴庫名稱,執行第4步的正確編譯命令。

4)g++ -g -Ipkg -lpkg -L. main.cpp -o main
/tmp/ccGpm3HQ.o: In function `main':
/home/TEST/ZZZ/main.cpp:5: undefined reference to `pkg_func()'
libcalc.so: undefined reference to `sub(int, int)'
libcalc.so: undefined reference to `add(int, int)'
collect2: ld 返回 1
A: libcalc.so裏沒找到add,sub接口,說明libcalc.so時在編譯時沒有包含依賴庫名稱,執行第3步正確編譯命令。

5) g++ -g -Ipkg -lpkg -L. main.cpp -o main
100+80=180
100-80=20

五,引申:
現在要在main.cpp是需跨層調用add模塊的add接口,需要做的操作是:
1)添加代碼:main.cpp包含add.h頭文件,增加add()函數代碼,
2)添加編譯選項:只需要添加-I選項即可,不需要再加-l選項的。

六,結論:
因爲庫具有疊加性,最上層庫的接口中已經包含了中間層和最低層的導出接口了,這個可以使用ldd命令來查看。
所以在編譯具有多層依賴的動態庫時,你只需要包含當前庫直接依賴的庫名稱即可,不需要再把它所依賴庫的依賴庫名稱包含進來。以上面的例子來說,編譯pkg模塊庫的時候,只需要把calc的庫包含進來就行了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章