說(shuō)在前面:
筆者環(huán)境:
虛擬機(jī):debian_9_64
gcc: 6.3.0 20170516
uname -a 的結(jié)果:
Linux debian9-64-Desktop 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u6 (2018-10-08) x86_64 GNU/Linux
先從簡(jiǎn)單的問(wèn)題開(kāi)始
需求:和一個(gè)靜態(tài)庫(kù)一起打包成為可執(zhí)行文件
應(yīng)用場(chǎng)景:將所有的ffmpeg的庫(kù)分別打包成為靜態(tài)庫(kù),然后再一起打包為動(dòng)態(tài)庫(kù)給到Android調(diào)用
這里從一個(gè)簡(jiǎn)單的事例開(kāi)始
建立三個(gè)文件 a.h
, a.c
, main.c
內(nèi)容分別為
#ifndef HEADER_A
#define HEADER_A
#include <stdio.h>
void testA();
#endif
#include "a.h"
void testA(){
printf("hello A \n");
}
#include "a.h"
int main(int argc,char* argv[])
{
printf("hello main\n");
testA();
return 0;
}
目錄結(jié)構(gòu)如下
tree .
# 輸出
├── a.c
├── a.h
└── main.c
開(kāi)始創(chuàng)建靜態(tài)庫(kù)
# 生成目標(biāo)文件 a.o
gcc -c a.c -I.
# 創(chuàng)建靜態(tài)庫(kù)【失敗】
ar -cr a.o
> ar: a.o: 不可識(shí)別的文件格式
# 創(chuàng)建靜態(tài)庫(kù)【成功】
ar -cr -o liba.a a.o
開(kāi)始鏈接靜態(tài)庫(kù)
# 開(kāi)始編譯【這里需要注意先后順序哦,否則會(huì)找不到符號(hào)的】
gcc -la main.c -o main.o #【錯(cuò)誤】
gcc -L. main.c -la -o main.o #【正確】
# 對(duì)于上面錯(cuò)誤的寫(xiě)法汹来。輸出
/tmp/cc1oAODM.o:在函數(shù)‘main’中:
main.c:(.text+0x21):對(duì)‘testA’未定義的引用
collect2: error: ld returned 1 exit status
在這里你會(huì)發(fā)現(xiàn)這里出現(xiàn)了未定義的引用,這個(gè)是開(kāi)發(fā)c/c++程序的人經(jīng)常遇到的一個(gè)問(wèn)題之一睬愤,那么如果我們拿著一個(gè)第三方庫(kù)待榔,或者自己因?yàn)橐恍┦д`打出來(lái)的庫(kù)導(dǎo)致的未定義的引用
怎么辦呢屁使?
這里要說(shuō)下: 可以借助工具來(lái)判斷减细,比方說(shuō)上面的liba.a 匆瓜,我們可以判斷是否包含testA
這個(gè)定義
nm ../liba.a
a.o:
U _GLOBAL_OFFSET_TABLE_
U printf
0000000000000000 T testA
如果看不懂 U T 等含義的,這里推薦看一篇文章未蝌,點(diǎn)這里
這里簡(jiǎn)單說(shuō)下含義:
符號(hào) | 含義 |
---|---|
T | text symbol, global 全局符號(hào) |
U | undefined symbol 未定義的符號(hào) |
你會(huì)發(fā)現(xiàn)liba.a 定義了這個(gè)符號(hào)驮吱,卻報(bào)找不到定義∠舴停【如果這里找不到符號(hào)左冬,那么就是庫(kù)本身有問(wèn)題了】
那么只能是順序的問(wèn)題了,改成上面正確的寫(xiě)法就可以了怎憋。
需求:有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù),請(qǐng)一起打包成為可執(zhí)行文件
增加兩個(gè)文件b.h
, b.c
九昧,內(nèi)容為:
#ifndef HEADER_B
#define HEADER_B
#include <stdio.h>
void testB();
#endif
#include "b.h"
void testB(){
printf("hello B \n");
}
生成動(dòng)態(tài)庫(kù)
gcc -shared -fPIC -o libb.so b.c -I
# 這里使用objdump 進(jìn)行查看是否將符號(hào)打到庫(kù)里面了
objdump -Tt libb.so |grep test
# 輸出
0000000000000670 g F .text 0000000000000013 testB
0000000000000670 g DF .text 0000000000000013 Base testB
符號(hào) | 含義 |
---|---|
D | 有定義 |
F | 有符號(hào) |
gcc main.c -L. -la -lb
/tmp/ccTFbai9.o:在函數(shù)‘main’中:
main.c:(.text+0x21):對(duì)‘testA’未定義的引用
collect2: error: ld returned 1 exit status
如果有人說(shuō)將-la绊袋,改成liba.a 也是可以的,但是如果這里就是要用 -la
怎么做呢铸鹰?
gcc main.c -L. -Wl,-Bstatic -la -Wl,-Bdynamic -lb
./a.out
#輸出
./a.out: error while loading shared libraries: libb.so: cannot open shared object file: No such file or directory
上面的錯(cuò)誤癌别,需要將動(dòng)態(tài)庫(kù)的路徑添加到動(dòng)態(tài)庫(kù)的查找路勁下,才可以
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:.
$ ./a.out
hello main
hello A
hello B