動態(tài)庫編譯詳解:
當(dāng)前類介紹:upper.c ( upper) 依賴于 bottom.c(play)
1.生成一個動態(tài)庫
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -c upper.c bottom.c -I ./include/
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ -lplay -Wl,-rpath ./,ypa
gcc: error: ./,ypa: 沒有那個文件或目錄
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ -lplay -Wl,-rpath ./mypath
2.運行程序并且鏈接動態(tài)庫
說明:當(dāng)執(zhí)行可執(zhí)行程序的時候,需要去/lib. /user/lib下和LD_LIBRARY_PATH下尋找so.并不會在當(dāng)前目錄下尋找.
所以執(zhí)行./main.out會報錯.如下:
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
./main.out: error while loading shared libraries: libplay.so: cannot open shared object file: No such file or directory
解決方案:指定.so運行搜尋路徑
1.-Wl,-rpath ./mypath 加入?yún)?shù),并且將libplay.so copy到./mypath目錄下.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ cp libplay.so ./mypath/
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
2.設(shè)置LD_LIBRARY_PATH,指定目錄.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ cd mypath/ && rm libplay.so
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
說明:指定了-Wl,-rpath, 設(shè)置LD_LIBRARY_PATH也是可以生效的.并不是說只會去-Wl,-rpath下尋找.
3.動態(tài)庫鏈接靜態(tài)庫
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -c upper.c bottom.c -I ./include/
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ar rcs -o libbottom.a bottom.o
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared upper.o -o libplay.so -L ./ -lbottom
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ -lplay -I ./include/ -Wl,-rpath ./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
4.動態(tài)庫依賴傳遞的情況
首先生成一個bottom.so,然后用upper.so去依賴bottom.so, 然后main.c 再去依賴upper.so.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -c *.c -I ./include/ &&rm main.o
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libbottom.so bottom.o
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libplay.so upper.o -L ./ -lbottom
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so
/usr/bin/ld: warning: libbottom.so, needed by libplay.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: libplay.so: undefined reference to `play'
collect2: error: ld returned 1 exit status
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
說明:這里編譯的時候直接出錯,是因為沒有指定搜尋路徑,所以無法通過編譯.
解決編譯問題方案.
1.我們依然采用LD_LIBRARY_PATH的方式可以解決編譯和運行的問題.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
2.生成libplay的時候,直接指定-Wl,-rpath 給libbottom.可以解決編譯不通過的問題.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libplay.so upper.o -L ./ -Wl,-rpath ./ -lbottom
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ldd libbottom.so
linux-vdso.so.1 (0x00007fff45ae3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd501ef3000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd502102000)
指定了rpath,在去執(zhí)行./main.out,此時還需要設(shè)置libplay.so 的運行路徑,加入rpath=./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
./main.out: error while loading shared libraries: libplay.so: cannot open shared object file: No such file or directory
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so -Wl,-rpath ./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
3.依賴所有庫
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so libbottom.so
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -c *.c -I ./include/
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libbottom.so bottom.o
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libplay.so upper.o -L ./ -lbottom
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so libbottom.so
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
./main.out: error while loading shared libraries: libplay.so: cannot open shared object file: No such file or directory
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so libbottom.so -Wl,-rpath=./
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
./main.out: error while loading shared libraries: libbottom.so: cannot open shared object file: No such file or directory
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=./
yueqingchan@yueqingChan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
依賴所有庫只能解決編譯問題,無法處理運行的路徑.
另一種思路:我們在執(zhí)行main.out的時候 執(zhí)行-Wl,-rpath.并不在生成libplay的時候指定,看下是否正常.
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc -fPIC -shared -o libplay.so upper.o -L ./ libbottom.so
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so
/usr/bin/ld: warning: libbottom.so, needed by libplay.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: libplay.so: undefined reference to `play'
collect2: error: ld returned 1 exit status
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -L ./ libplay.so -Wl,-rpath ./
yueqingchan@yueqingchan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
./main.out: error while loading shared libraries: libbottom.so: cannot open shared object file: No such file or directory
由此可見,-Wl,-rpath 只能針對直接依賴的libplay.so指定了路徑,但是libbottom還是無法查找到 .但是LD_LIBRARY是可以的.
rpath只能對直接依賴的so設(shè)置搜尋目錄,并且可以設(shè)置所有依賴的編譯路徑.
總結(jié): 解決編譯問題,在生成libplay的時候指定-Wl,-rpath運行路徑,或者設(shè)置LD_LIBRARAY_PATH,都可以解決這個問題.
或者直接依賴所有的.so,但是這樣是不合理的,我們不需要去依賴間接的依賴.
5.動態(tài)庫依賴
當(dāng)我們現(xiàn)在擁有的so包含一個直接依賴的so和很多間接依賴的so,但是沒有設(shè)置rpath.所以是不能直接依賴主so進(jìn)行編譯和運行的.
為了通過編譯:
1.在只鏈接主so的情況下可以去設(shè)置rpath或者LD_LIBRARY_PATH.
2.或者鏈接所有so.
為了通過運行:
為了正常運行可以設(shè)置LD_LIBRARY_PATH.
6.如果我們想只去依賴一個直接so,并且不讓使用方主動去設(shè)置LD_LIBRARY_PATH就可以直接運行程序,還有一種方式:
--disable-new-dtags,--copy-dt-needed-entries
yueqingchan@yueqing-Chan:~/Desktop/TestGcc-Files/TestDynamic1$ export LD_LIBRARY_PATH=
yueqingchan@yueqing-Chan:~/Desktop/TestGcc-Files/TestDynamic1$ gcc main.c -o main.out -Wl,-rpath=./,--disable-new-dtags,--copy-dt-needed-entries -L ./ -lplay
yueqingchan@yueqing-Chan:~/Desktop/TestGcc-Files/TestDynamic1$ ./main.out
Hello, World!
Bottom--->底層的播放功能
Upper---->上層的封裝能力
yueqingchan@yueqing-Chan:~/Desktop/TestGcc-Files/TestDynamic1$
結(jié)論概述:
1.我們在生成間接依賴的庫的時候,為了保證其他庫可以直接依賴,需要加入-Wl,-rpath.保證編譯通過.
2.LD_LIBRARY_PATH可以解決一切編譯運行問題.