动态库静态库差异对比

最近在做一个项目需要http接口,由此将框架中依赖libcurl的http单独拿来用

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'


爆出一堆未定义符号,然后用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_all

发现静态库的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
可以正常编译通过


后来下载了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]

而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=./lib

执行./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,具体的搜索路径顺序如下(注意不会递归性地在其子目录下搜索):

1、gcc编译、链接命令中的-L选项;
2、gcc的环境变量的LIBRARY_PATH(多个路径用冒号分割);
3、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib。


总结:执行可执行文件时,动态库的加载器将按照以下路径搜索
1、编译目标代码时指定的动态库搜索路径:用选项-Wl,rpath和include指定的动态库的搜索路径,比如gcc -Wl,-rpath,include -L. -ldltest hello.c,在执行文件时会搜索路径`./include`;
2、环境变量LD_LIBRARY_PATH(多个路径用冒号分割);
3、在 /etc/ld.so.conf.d/ 目录下的配置文件指定的动态库绝对路径(通过ldconfig生效,一般是非root用户时使用);
4、gcc默认动态库目录:/lib:/usr/lib:usr/lib64:/usr/local/lib等。

 

posted on 2019-02-13 10:17  笨拙的菜鸟  阅读(787)  评论(0编辑  收藏  举报

导航