跳转到主内容
极星编程网:以代码为星,赴技术山海!

C++中的动态库与静态库是什么?(如何在构建时进行链接)

静态库链接在编译时将.a文件中用到的代码复制进可执行文件,运行时不依赖外部库但体积大、更新难;动态库链接仅在运行时加载.so,需确保LD_LIBRARY_PATH或rpath正确。 静态库链接:编译时把
.a
文件直接塞进可执行文件 静态库本质是一堆已编译的
.o
目标文件打包成的归档(
libxxx.a
),链接时会把用到的符号代码“复制”进最终的可执行文件。这意味着运行时不依赖外部库文件,但体积大、更新困难。 实操上,用
g++
链接静态库要显式指定路径和库名:
g++ main.cpp -L./libs -lmylib -static-libgcc -static-libstdc++
注意几个关键点:
-L./libs
告诉链接器去哪找库,不是自动搜
/usr/lib
或当前目录
-lmylib
会实际查找
libmylib.a
(不是
mylib.a
),名字必须匹配前缀规则
-static-libgcc
和
-static-libstdc++
是防止混链动态版系统库——否则即使你用了
libmylib.a
,仍可能在运行时报
libstdc++.so.6: version `GLIBCXX_3.4.29' not found
如果
libmylib.a
本身又依赖其他静态库(比如用了
libz.a
),得把依赖库也列在命令行里,且顺序不能错:被依赖的库要放在依赖它的库之后(
-lmylib -lz
,不能反过来) 动态库链接:运行时加载
.so
,构建时只记个符号引用 动态库(
libxxx.so
)不参与编译,链接阶段只检查符号是否存在、签名是否匹配,真正加载发生在程序启动或调用
dlopen()
时。好处是共享内存、便于热更新;坏处是部署时得确保
LD_LIBRARY_PATH
正确,或库在系统默认路径下。 立即学习 “ C++免费学习笔记(深入) ”; 构建命令看着差不多,但行为完全不同: C知道 CSDN推出的一款AI技术问答工具 下载
g++ main.cpp -L./libs -lmylib
这里没加
-static
,链接器默认优先找
.so
。常见陷阱有: 明明放了
libmylib.so
在
./libs
,却报
undefined reference to `xxx'
:大概率是该
.so
编译时没导出对应符号(没加
-fvisibility=default
或没写
__attribute__((visibility("default")))
) 程序编译通过,运行时报
error while loading shared libraries: libmylib.so: cannot open shared object file
:说明运行时找不到它。临时解决可用
export LD_LIBRARY_PATH=./libs
,但生产环境应改用
rpath
:
g++ main.cpp -L./libs -lmylib -Wl,-rpath,'$ORIGIN/../libs'
(
$ORIGIN
指可执行文件所在目录) 动态库版本升级后崩溃?检查
SONAME
是否变了(用
readelf -d libmylib.so | grep SONAME
),
DT_SONAME
不一致会导致链接器拒绝加载
nm
和
objdump
是查符号问题的第一工具 链接失败,别急着重装工具链——先确认符号到底存不存在、可见性对不对。静态库和动态库都适用: 看静态库里有没有某函数:
nm -C libmylib.a | grep 'my_function'
,输出带
T
(text)表示定义了,
U
表示未定义(即只是引用) 看动态库导出的符号(注意是否隐藏):
nm -C -D libmylib.so | grep 'my_function'
,
-D
只显示动态符号表里的内容,没输出就说明没导出 进一步确认符号绑定属性:
objdump -t libmylib.so | grep my_function
,如果显示
*UND*
就是未定义,
FUNC GLOBAL DEFAULT
才算正常导出 这些命令不依赖构建系统,能快速定位是代码没编译进去、声明没导出,还是链接参数漏写了库。 CMake 中控制动静态链接容易混淆的三个配置点 CMake 默认倾向动态链接,但很多项目需要混合或强制静态。关键不在
find_package()
,而在目标属性设置: 让某个 target 强制链接静态版系统库:
set_target_properties(myapp PROPERTIES LINK_FLAGS "-static-libgcc -static-libstdc++")
指定第三方库用静态方式链接(假设
mylib
同时提供
.a
和
.so
):
find_library(MYLIB_STATIC NAMES mylib PATHS ./libs NO_DEFAULT_PATH)target_link_libraries(myapp ${MYLIB_STATIC})
,避免
find_package(mylib)
自动挑
.so
全局禁用动态库搜索(慎用):
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a${CMAKE_FIND_LIBRARY_SUFFIXES}")
,这会让所有
find_library
优先找
.a
,但可能破坏
FindXXX.cmake
模块逻辑 最常被忽略的是:CMake 的
IMPORTED
目标(比如用
add_library(mylib IMPORTED)
)必须手动设置
IMPORTED_LOCATION
指向具体文件,否则
target_link_libraries
会静默失败,连错误都不报。

相关文章