如何在不使用-static选项的情况下用GCC静态链接C++程序的libc
尝试构建动态依赖尽可能少的C++程序,但依赖的libmariadbcpp无法静态链接:使用-static选项编译时会报错:
/usr/bin/ld: attempted static link of dynamic object `/usr/local/lib/../lib/libmariadbcpp.so'
当前编译命令为:
gcc main.cpp -o main -lmariadbcpp
执行ldd main后,显示程序依赖libc.so.6、libm.so.6等系统库。尝试添加-static-libstdc++选项后,libc和libm仍被列为动态依赖。
补充背景:工作环境中服务器OS发行版/版本各不相同,本地编译的带动态依赖的程序在远程服务器无法运行(例如报错/lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.34 not found),不想在每台服务器重新编译或用Docker打包,因此希望仅保留libmariadbcpp的动态依赖,其余库均静态编译。
可以通过gcc传递链接器选项,指定部分库静态链接、部分库动态链接,实现仅保留libmariadbcpp动态依赖的目标:
编译命令
使用g++(推荐用于C程序,避免遗漏C标准库链接),结合链接器的-Bstatic和-Bdynamic选项:
g++ main.cpp -o main -Wl,-Bstatic -lc -lm -lstdc++ -Wl,-Bdynamic -lmariadbcpp
命令解释
-Wl,<option>:将后续选项传递给链接器ld-Wl,-Bstatic:告诉链接器,接下来指定的库使用静态链接-lc -lm -lstdc++:指定要静态链接的系统库(C标准库、数学库、C++标准库)-Wl,-Bdynamic:切换回动态链接模式-lmariadbcpp:最后链接动态版本的libmariadbcpp
前置条件
确保系统已安装对应库的静态版本:
- Debian/Ubuntu系:
sudo apt-get install libc6-dev-static libstdc++-dev-static - CentOS/RHEL系:
sudo yum install glibc-static libstdc++-static
验证
执行ldd main,输出应仅包含libmariadbcpp.so和动态链接器(如ld-linux-x86-64.so.2,这是动态依赖程序必需的组件,无法移除)。
-static-libstdc++这类选项是GCC前端的专属选项,不是链接器ld的选项,因此用ld --help无法查到。
查看方式
- 查看GCC手册:执行
man gcc,在"Options for Linking"章节可找到相关选项说明。 - 查看实际传递的链接器参数:通过
-v选项查看GCC调用链接器时的具体参数,例如:
输出中会显示GCC为了实现静态链接g++ -v main.cpp -o main -static-libstdc++libstdc++,向ld传递了哪些参数。 - GCC源代码定义:这类选项的逻辑在GCC的驱动程序代码中实现,负责将前端选项转换为链接器能识别的参数。
内容的提问来源于stack exchange,提问作者DarkPangloss666

