一個項目碰到代碼移植,由UNIX移植到linux環境,整編譯環境,學到了東西...
第一步移植ACE的包,第三方的東西,整的好,幾分鐘搞定
第二步移植公司自己封裝的一個平台組件,參考ACE的包編譯參數
編譯使用這些參數:
g++ -fvisibility=hidden -fvisibility-inlines-hidden -W -Wall -Wpointer-arith -O3 -g -pipe -fPIC
動態庫的連結:
g++ -shared -o libDicCpt.so.1.0.0 ../../src/public/Reactor.o ../../src/public/Md5.o ../../src/public/DicExceptions.o ../../src/public/Debug.o ../../src/public/DataCDR.o ../../src/public/ObjectRefMgr.o ../../src/configcpt/ConfigCpt.o ../../src/configcpt/ConfigFacade.o
../../src/configcpt/ConfigObjMgr.o ../../src/configcpt/IConfig.o ../../src/configcpt/IniConfig.o ../../src/configcpt/XmlConfig.o ../../src/logcpt/ACELogOutput.o ../../src/logcpt/LogConfig.o ../../src/logcpt/LogFileBackup.o ../../src/logcpt/LogFileStream.o
../../src/logcpt/LogFileStreamMap.o ../../src/logcpt/LogProcessor.o ../../src/logcpt/LogQueueTask.o ../../src/logcpt/LogMsgBlockMgr.o ../../src/logcpt/LogMsgBlock.o ../../src/logcpt/LogTime.o ../../src/logcpt/LogCpt.o ../../src/logcpt/SHMLogOutput.o -Wl,-E
-L. -L/public/abp_icc/release/lib -ldl -lpthread -lrt
第三步就編譯應用程式嘍:
最後連結應用程式的時候報符號找不到
g++ -fPIC -o voiceUrge src/DCVoiceUrgeCheck.o src/DCVoiceUrgeApp.o src/DCVoiceUrgeReDeal.o src/DCVoiceUrgeTask.o src/DCVoiceUrgeParam.o src/soapC.o src/soapClient.o src/stdsoap2.o -L/public/abp_icc/release/lib -L/ora11g/product/11.2.0/lib -Wl,-Bstatic -lICCEngOwe
-lICCApiOwe -Wl,-Bdynamic -lDicCpt -locci11 -lACE -lclntsh -lpthread -lrt -lcrypto
報一堆的undefined reference to錯誤,如:
/public/abp_icc/release/lib/libICCEngOwe.so: undefined reference to `LogCpt::init(char const*, char const*)'
其實在UNIX下這個錯誤也是經常碰到,解決起來也是有一套路子的,但是奇怪的是,這寫個符號在-lDicCpt中全部都是有,包的順序也沒有問題。
解決思路:
通過nm查看發現符號是存在
/public/abp_icc/src/public/DicCpt/mak/make_linux>nm libDicCpt.so |grep LogCpt |grep init
0000000000034fe6 t _ZN6LogCpt4initEPKcS1_
0000000000034f82 t _ZN6LogCpt4initEv
其中發現libACE.so的符號是找得到,奇怪了,都是一樣的編譯參數,怎麼ACE的就可以,但是我們自己的包就不可以呢?尤其是通過參考man ld發現-E參數就是要求export all symbol的,而我們是通過-Wl,-E有帶上的,百思不得其解。
中間有嘗試使用靜態庫,發現靜態庫是可以用的,仔細看了下靜態庫的符號;
0000000000001b36 T _ZN6LogCpt4initEPKcS1_
0000000000001ad2 T _ZN6LogCpt4initEv
發現靜態庫中的類型是T,動態庫中是t.最後經過查看nm的協助,發現小寫字母t標識是local symbol,而大寫字母T就表globle symbol,此時目標算是明確了,就是要把動態庫中的t改成T...
又在網上折騰了下,最終通過參考《 Linux下gcc編譯控制動態庫匯出函數小結》發現編譯選項 -fvisibility=hidden -fvisibility-inlines-hidden 在作怪,因為ACE的代碼都有加ACE_Export宏,類似的有加這樣的代碼 __attribute__ ((visibility("default"))),但是我們代碼沒有這樣寫,最終導致我們的函數符號沒有export,雖然編譯選項中有-Wl,-E。
去掉後,全部符號就能export出來啦,看看已經是大T嘍,連結就不會出錯了。
/public/abp_icc/release/lib>nm libDicCpt.so |grep LogCpt|grep init
0000000000059fd8 T _ZN6LogCpt4initEPKcS1_
0000000000059f70 T _ZN6LogCpt4initEv
感慨:
1)搞了好幾年C的,對這種編譯選項細節的問題,還是小白一個啊;
2)自己封裝的組件跟第三方提供的組件差距還是蠻大的;
3)不要瞎參考別人的編譯參數,除非你很瞭解它們的作用;
4)需要不斷的認真總結分析。