服務器部署問題:
本質上,目標程序開發完成后,要在機器上部署,要求開發機器必須於服務器環境一致,這樣風險相對較小,部署相對容易。可是現實中常常因為各種原因,很難保證開發機器與部署機器的一致性。下面是一些問題總結。
動態庫依賴動態庫
最常問題:
庫版本兼容問題(如:`GLIBCXX_3.4.20' not found 問題)
問題原理如下:
該問題源於程序本身直接依賴的庫沒有問題,但是在遷移到其他機器時,間接依賴的庫版本不兼容(某些接口已經刪除了)。實際上就是找不到某些接口的問題,外在的表現就是某些符號找不到。此類問題一般不會在編譯的時候表現出來,編譯通過后,啟動程序時才會提示。
解決的方法就是升級到對應版本的庫。比如上面libstdc++.so.6,我們可以看看其鏈接的具體版本:
我沒有急着去安裝,因為之前可能有人已經安裝過了,只是沒有創建對應的軟鏈接,可以先查找看看:
找到了其他版本的庫,但是我們並不確定其是否符合我們的要求,也就是內部是是否包含我們所有要求的”符號“,可以使用如下命令驗證:
以上輸出證明該版本庫確實符合我們的要求,刪掉舊的鏈接重新建立新版本的庫的鏈接就好了:
動態庫”依賴“靜態庫
1)常規用法與變異
靜態庫的的初衷是編譯進可執行文件,並且不再依賴。一般用於直接”依賴“,目標文件--->libxx.a:
以上是常規形式,但是也不排除下面這種模式: 目標文件—>動態庫---->靜態庫。libxx3.so在編譯時把libyy.a編譯進去了。
這種形式一般用於:
(1)不想將libyy.a暴露給甲方,(提供動態庫,甲方能直接看到)
(2)為了編譯的程序的依賴樹更加簡潔
(3)鎖死間接依賴,避免出現上面提到的"GLIBCXX_3.4.20' not found 問題"。(這一條很重要)
(4)歡迎補充。。。
2)動態庫包含“依賴”靜態庫的問題:
靜態庫參編譯進可執行文件后,其存在價值就不存在了,因為,靜態庫的源碼已經連接到了可執行文件,本質上來講靜態庫編譯進可執行文件,和二進制文件(*.o)鏈接成一個可執行文件沒有本質的區別。libyy.a的本質就是一個包含了眾多二進制文件的包。同理,如果靜態庫被編譯到動態庫中也是一樣的。動態庫編譯成功后,靜態庫刪掉也不影響動態庫的使用。所謂靜態依賴就是編譯時依賴,運行時已經不再需要。但是這里有一個問題:將一個靜態庫編譯進可執行文件和動態庫,對這個靜態庫的要求是不一樣的。從編譯步驟說起:
靜態庫/動態庫 | 步驟 | 中間文件 |
libxyz.a | gcc -c xx.c yy.c zz.c ar r libxyz.a xx.o yy.o zz.o |
xx.o yy.o zz.o |
libxyz,so | gcc -c -fPIC xx.c yy.c zz.c ar r libxyz.a xx.o yy.o zz.o |
xx.o yy.o zz.o |
動態庫在生成時需要使用-fPIC選項告訴編譯器生成與位置無關的代碼,講的明白點就是一個進程在運行時可以加載動態庫到一個區域中的任何虛擬地址(下圖中紅色箭頭指向),而不是絕對的位置。而靜態庫是依賴絕對位置的,哪里調用,它就被安排在那里 ,被靜態的嵌入進去(下圖綠色箭頭部分),其代碼塊地址是絕對的。
如果我們直接在使用上面這種方法生成的靜態庫編譯動態庫(將靜態庫編入動態庫),會怎么樣呢?錯誤提示大概如下!
/usr/bin/ld: /usr/lib64/libxyz.a(gen_uuid.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC /usr/lib64/libxyz.a: could not read symbols: Bad value collect2: error: ld returned 1 exit status make[1]: *** [libapr-1.la] 錯誤 1
make[1]:正在離開目錄 `/home/fernando/OneMS/OneMS-TR-Install/depends/apr-1.4.5' make: *** [all-recursive] 錯誤 1
其提示我們需要重新使用-fPIC選項來編譯靜態庫,才能使用改靜態庫構建其他的動態庫。
所以我們需要的是這樣:
gcc -c -fPIC xx.c yy.c zz.c
ar r libxyz.a xx.o yy.o zz.o
這樣生成的靜態庫可以帶有-fPIC的標記,與動態庫生成的第一步統一了,兼容了動態庫的生成要求。
此時再使用:
gcc -shared -o libxx.so xx.c libbxyz.a
libxx.so就可以正常生成了
二進制兼容問題:
(續)
關於“undefined reference to”問題,這種問題最為常見,也容易處理,總結幾種無非就是,找不到庫,C版本接口命名傾軋,舊庫依賴問題,庫依賴順序等問題。下面的的文章總結的不錯。可以看看。
https://blog.csdn.net/KgdYsg/article/details/90705766
參考資料:
《Linux/Unix系統編程》
《Linux編程手冊》
參考博客
https://blog.csdn.net/KgdYsg/article/details/90705766