=Start=
缘由:
之前有记录过「静态库和动态库」、「GCC的常用编译选项」两篇文章,但说来惭愧,还一直没有真正实践过特定场景的静态编译,趁着周末有时间,再加上之前刚好有一个场景需要用到静态编译的功能,实际验证了一下Linux下gcc的静态编译的相关选项及其功能和注意事项。在此记录一下,方便以后参考。
正文:
参考解答:
之前有篇文章记录了如何使用OpenSSL库来实现字符串的base64编解码功能「Linux下C语言实现的base64加解密」,这里使用该文章中的代码进行演示说明:
$ gcc openssl_base64.c -lcrypto #默认情况下,gcc会优先找动态库,找不到了再找静态库。所以上面的编译选项会去/usr/lib和/lib下(64位系统对应的是/usr/lib64和/lib64)查找 libcrypto.so ,如果你是自己手动编译安装的OpenSSL,动态库不在上述目录中,可以使用-L选项来显示指定库搜索路径。
&
# gcc openssl_base64.c -static -lcrypto -lssl -o oabc /usr/bin/ld: cannot find -lc collect2: ld returned 1 exit status # # gcc openssl_base64.c -Wl,-Bstatic -lcrypto -lssl -Wl,-Bdynamic -o oabc -Wl,--no-as-needed -ldl -lzlib /usr/bin/ld: cannot find -lzlib collect2: ld returned 1 exit status # # gcc openssl_base64.c -Wl,-Bstatic -lcrypto -lssl -Wl,-Bdynamic -o oabc -Wl,--no-as-needed -ldl -lz # # ldd oabc linux-vdso.so.1 => (0x00007fff42dff000) libdl.so.2 => /lib64/libdl.so.2 (0x00007ffbe717b000) libz.so.1 => /lib64/libz.so.1 (0x00007ffbe6f65000) libc.so.6 => /lib64/libc.so.6 (0x00007ffbe6bd0000) /lib64/ld-linux-x86-64.so.2 (0x00007ffbe738c000) # # rpm -qf /lib64/libz.so.1 zlib-1.2.3-29.el6.x86_64 # yum search zlib | grep --color "static" mingw32-zlib-static.noarch : Static libraries for mingw32-zlib development. mingw64-zlib-static.noarch : Static libraries for mingw64-zlib development zlib-static.x86_64 : Static libraries for Zlib development # # yum install zlib-static -y # # rpm -qf /lib64/libdl.so.2 glibc-2.12-1.149.el6_6.7.x86_64 # rpm -qf /lib64/libz.so.1 zlib-1.2.3-29.el6.x86_64 # rpm -qf /lib64/libc.so.6 glibc-2.12-1.149.el6_6.7.x86_64 # # gcc openssl_base64.c -Wl,-Bstatic -lcrypto -lssl -lz -Wl,-Bdynamic -o oabc -Wl,--no-as-needed -ldl # ldd oabc linux-vdso.so.1 => (0x00007fffe27ff000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f765c3fc000) libc.so.6 => /lib64/libc.so.6 (0x00007f765c068000) /lib64/ld-linux-x86-64.so.2 (0x00007f765c60d000) # # gcc openssl_base64.c -static -lcrypto -lssl -lz -ldl -o oabc /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libcrypto.a(fips.o): In function `verify_checksums': (.text+0x62b): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking # # echo $? 0 # gcc openssl_base64.c -static -lcrypto -lssl -lz -ldl -lc -o oabc /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/libcrypto.a(fips.o): In function `verify_checksums': (.text+0x62b): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking # ldd oabc not a dynamic executable # # readelf -d oabc There is no dynamic section in this file. #
0、静态编译之前,需要知道可执行程序依赖哪些库;
一、先用常规的gcc选项将源代码动态编译成一个可执行文件(假设可执行文件名为 a.out); 二、然后用ldd/readelf命令查看该可执行文件依赖哪些共享库;
1、要想进行静态编译,还需要系统安装有对应的静态库(.a结尾);
#这里以zlib库为例说明该如何用yum安装对应的静态库 # yum search zlib | grep --color "static" mingw32-zlib-static.noarch : Static libraries for mingw32-zlib development. mingw64-zlib-static.noarch : Static libraries for mingw64-zlib development zlib-static.x86_64 : Static libraries for Zlib development # # yum install zlib-static -y # find / -type f -iname "libz.*" /lib64/libz.so.1.2.3 /usr/lib64/libz.a #刚刚安装的静态库文件
2、静态编译需要为gcc指定一些特定选项;
如果直接使用 -static 或者 -dynamic 会使所有库都使用这种形式链接,显示不是我们想要的。 当我们想要为某些库链接静态库,某些链接静态库,其余的按默认链接,则需要下面的样子: -L/path/to/lib/ -Wl,-Bstatic -l<static_lib> #指定静态库 -L/path/to/lib/ -Wl,-Bdynamic -l<dynamic_lib> #指定动态库 -Wl,-Bdynamic #恢复默认设置 == gcc使用-Wl传递连接器参数,ld使用-Bdynamic强制连接动态库,-Bstatic强制连接静态库。所以部分静态,部分动态连接这么写: # gcc ... -Wl,-Bstatic -l<your-static-lib> -Wl,-Bdynamic -l<your-dynamic-lib> ... 举个例子,你想动态连接libA.so同时静态连接libB.a,(先保证你的连接路径-L里面能找到对应的静态或者动态库),这么写: # gcc ... -Wl,-Bstatic -lA -Wl,-Bdynamic -lB ...
3、如何定位手动编译的静态库文件;
Linux下链接库时使用-L来指定路径,使用-l来指定库名。
4、验证编译后的可执行程序是否满足要求;
# ldd oabc not a dynamic executable # # readelf -d oabc There is no dynamic section in this file. # # readelf -d oabc | grep --color "NEEDED" #
参考链接:
- 在Linux下,如何强制让GCC静态链接?
https://www.zhihu.com/question/22940048 - 技巧:Linux 动态库与静态库制作及使用详解
https://www.ibm.com/developerworks/cn/linux/l-cn-linklib/ - Linux下C调用静态库和动态库 #不错
http://answerywj.com/2016/10/10/Linux%E4%B8%8BC%E8%B0%83%E7%94%A8%E9%9D%99%E6%80%81%E5%BA%93%E5%92%8C%E5%8A%A8%E6%80%81%E5%BA%93/ - Linux下的静态库、动态库和动态加载库 #不错
http://www.techug.com/linux-static-lib-dynamic-lib - Linux gcc编译生成静态库和共享动态库的过程
https://typecodes.com/cseries/gccgensharedlib.html
=END=
《 “Linux下用gcc进行静态编译” 》 有 3 条评论
C静态库连接的顺序问题
http://www.pchou.info/linux/2016/09/15/c-static-link.html
随想录(libc.so和ld.so调试)
https://blog.csdn.net/feixiaoxing/article/details/79888886
随想录(常用的c库)
https://blog.csdn.net/feixiaoxing/article/details/79773530
宋宝华: 关于Linux编译优化几个必须掌握的姿势
https://mp.weixin.qq.com/s/CIYzI6SAWcHWTD6z3PvOuQ
`
下面给几条实践指南:
1、尽量不要尝试用O0去编译内核,这不符合真实的工程实践,也不太被主流Linux社区所支持;内核依赖O2/Os去做较多的优化;
2、追求你的代码在O2的情况下,仍然是正确的,代码要经得起编译优化;比如O0工作正常,而O2不正常,应该尽可能从自身找原因,分析汇编;
3、如果在全局优化的情况下,想针对某个局部避免优化,可以尝试用noinline,__attribute__((optimize(“O0”)))等进行外科手术式地调整。
`