静态库链接在编译时将.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++免费学习笔记(深入)”;
构建命令看着差不多,但行为完全不同:
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 会静默失败,连错误都不报。










