最近在作一個項目須要http接口,由此將框架中依賴libcurl的http單獨拿來用linux
libcurl提供兩種庫:靜態庫跟動態庫,首先curl目下只提供了libcurl.a,並無生成libcurl.so,由此開始編譯依賴靜態的http.so
g++ -shared -fPIC -o lib/libhttp.so http_handle.cpp -I./ -I./curl-7.34.0/include -L./ -lcurl 框架
./lib/libhttp.so: undefined reference to `SSL_connect'
./lib/libhttp.so: undefined reference to `X509_check_issued'
./lib/libhttp.so: undefined reference to `SSL_CTX_set_srp_password'
./lib/libhttp.so: undefined reference to `BIO_free'
./lib/libhttp.so: undefined reference to `BIO_s_mem'
./lib/libhttp.so: undefined reference to `UI_method_get_reader'
./lib/libhttp.so: undefined reference to `UI_get_string_type'
./lib/libhttp.so: undefined reference to `sk_pop_free'
./lib/libhttp.so: undefined reference to `BIO_ctrl'
./lib/libhttp.so: undefined reference to `DES_set_odd_parity'curl
爆出一堆未定義符號,而後用nm libhttp.so查看符號
000000000000ca80 T curl_multi_info_read
000000000000cff0 T curl_multi_init
000000000000e5f0 T curl_multi_perform
000000000000ead0 T curl_multi_remove_handle
000000000000c800 T curl_multi_setopt
000000000000ea80 T curl_multi_socket
000000000000ea30 T curl_multi_socket_action
000000000000e9e0 T curl_multi_socket_allsocket
發現靜態庫的libcurl.a的符號已經在http.so中定義了,那這些符號經過google能夠發現是openssl crypto libdl libz librt
接着將上面的靜態庫加入連接中
g++ -shared -fPIC -o lib/libhttp.so http_handle.cpp -I./ -I./curl-7.34.0/include -L./ -lcurl -lssl -lcrypto -ldl -lz -lrt
g++ -o main main.cpp -L./lib -lhttp -Wl,--rpath=./lib
能夠正常編譯經過google
後來下載了libcurl庫而後make編譯出了libcurl.so
則只須要g++ -shared -fPIC -o lib/libhttp.so http_handle.cpp -I./ -I./curl-7.34.0/include -lcurl就能夠了,不須要加-lssl -lcrypto等
使用readelf -d libcurl.so查看其.dynamic段能夠看出,此段已經將所依賴的共享庫包含了,其ldd命令原理也是經過連接器查看.dynamic段中
的d_tag類型爲DT_NEED(表示依賴的共享對象文件)將其打印
Dynamic section at offset 0x5c1c0 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libssl.so.1.0.0]
0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.1.0.0]
0x0000000000000001 (NEEDED) Shared library: [libz.so.1]
0x0000000000000001 (NEEDED) Shared library: [librt.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]url
而gcc在編譯連接的默認搜索路徑能夠經過ld --verbose顯示
SEARCH_DIR("/usr/x86_64-redhat-linux/lib64");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/x86_64-redhat-linux/lib");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/local/lib");
SEARCH_DIR("/lib");
SEARCH_DIR("/usr/lib");
因爲本身的開發環境已經將openssl.so libdl.so libz.so libcrypto.so librt.so放入/usr/lib64中,剛好gcc在連接可執行文件時搜尋可執行文件所須要的符號定義都在
搜索路徑中,由此gcc編譯生成http.so時,只須要跟curl.so造成依賴關係便可,curl所依賴的庫不須要再編譯http.so時再次添加。
再將libcurl.so添加到/usr/lib64(後來發現有人已經添加到了)
編譯可執行文件時只須要g++ -o main main.cpp -L./lib -lhttp -Wl,--rpath=./liborm
執行./main能夠正常運行,緣由加了-rpath,經過readelf -d main
......
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x000000000000000f (RPATH) Library rpath: [./lib]
RPATH是可執行文件執行時所依賴的動態庫搜索路徑(不是編譯生成的路徑),經過rpath來指定了。
也能夠將http.so添加到LD_LIBRARY_PATH,這樣main也能夠正常啓動對象
Linux gcc編譯連接時的動態庫搜索路徑
GCC編譯、連接生成可執行文件時,動態庫的搜索路徑就包含LIBRARY_PATH,具體的搜索路徑順序以下(注意不會遞歸性地在其子目錄下搜索):遞歸
一、gcc編譯、連接命令中的-L選項;
二、gcc的環境變量的LIBRARY_PATH(多個路徑用冒號分割);
三、gcc默認動態庫目錄:/lib:/usr/lib:usr/lib64:/usr/local/lib。接口
總結:執行可執行文件時,動態庫的加載器將按照如下路徑搜索一、編譯目標代碼時指定的動態庫搜索路徑:用選項-Wl,rpath和include指定的動態庫的搜索路徑,好比gcc -Wl,-rpath,include -L. -ldltest hello.c,在執行文件時會搜索路徑`./include`;二、環境變量LD_LIBRARY_PATH(多個路徑用冒號分割);三、在 /etc/ld.so.conf.d/ 目錄下的配置文件指定的動態庫絕對路徑(經過ldconfig生效,通常是非root用戶時使用);四、gcc默認動態庫目錄:/lib:/usr/lib:usr/lib64:/usr/local/lib等。