之前寫TLPI上的代碼一直是手動進行錯誤處理,感覺代碼冗余量很大,最后還是決定使用書上的tlph_hdr.h,順便回顧下動態庫的創建/使用。
參考很久之前的一篇博客 linux上靜態庫和動態庫的編譯和使用
但是感覺這篇博客寫了后我一直沒真正用過動態庫,於是花了些時間復習下,結果倒好,一直出問題。
xyz@ubuntu:~/lib$ ls a.out f.c g.c h.c libutil.so main.c util.h
f.c g.c h.c分別是3個函數f()、g()、h()的定義,util.h是這3個函數的聲明,main.c包含了util.h,並在main()函數中調用了這3個函數。
a.out則是成功生成的程序,生成過程如下
xyz@ubuntu:~/lib$ gcc f.c g.c h.c -fpic -shared -o libutil.so xyz@ubuntu:~/lib$ gcc main.c -L. -lutil
第一步編譯了3份包含函數具體實現的源文件,第二步編譯了主程序。
其中-L.將當前目錄設為動態庫查找位置,-lutil代表查找的動態庫為libutil.so,這只是語法糖,這句命令用libutil.so替換-lutil也可以。
最后運行a.out時報錯
./a.out: symbol lookup error: ./a.out: undefined symbol: f
自己瞎折騰半天不知道原因,起初懷疑動態庫生成錯誤,沒有包含3個函數,但是命令並沒錯。最后還是動用搜索引擎,試着用ldd(1)來查看程序依賴庫(ldd的使用在TLPI的第3章 3.3中查找glibc共享庫的位置時也使用過)
xyz@ubuntu:~/lib$ ldd a.out linux-vdso.so.1 => (0x00007fff509eb000) libutil.so => /usr/lib/x86_64-linux-gnu/libutil.so (0x00007f1a9e581000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1a9e1b7000) /lib64/ld-linux-x86-64.so.2 (0x000055fcfc069000)
原因出來了,系統自帶了一個libutil.so,我自定義的動態庫和它重名了,由於動態庫是優先查找系統路徑(再其次是-L后面的路徑,在這里是當前目錄),系統自帶的libutil.so自然不會有f() g() h()這三個函數,因此f()被認為是未定義的符號,即找不到函數f()的具體定義。
只要改個名字就行了,然后就遇到了下面錯誤
xyz@ubuntu:~/lib$ gcc f.c g.c h.c -fpic -shared -o libfgh.so xyz@ubuntu:~/lib$ gcc main.c -L. -lfgh xyz@ubuntu:~/lib$ ./a.out ./a.out: error while loading shared libraries: libfgh.so: cannot open shared object file: No such file or directory
最好的解決方式還是把動態庫目錄加到環境變量里,而不是把動態庫隨便扔個系統目錄。
xyz@ubuntu:~/lib$ export LD_LIBRARY_PATH=$(pwd) xyz@ubuntu:~/lib$ echo $LD_LIBRARY_PATH /home/xyz/lib xyz@ubuntu:~/lib$ ./a.out f() g() h()
運行成功,然而這個環境變量重啟后就沒了,所以需要把它添加到在~/.bashrc末尾,此時就需要把當前目錄用絕對路徑表示了
export LD_LIBRARY_PATH=/home/xyz/lib
這樣系統重啟之后便仍可運行a.out,如果需要通知系統.bashrc文件已更新,可用命令source ~/.bashrc