You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

dlclose后重新dlopen修改后的CMake共享库仍加载旧版本问题

动态库卸载异常问题分析与解决

更新(已解决)
该问题已解决——简言之,CMake会生成可见的UNIQUE对象,使用-fvisibility=hidden(需手动为必要符号添加visibility=default属性)或--no-gnu-unique编译选项可规避该问题。

问题背景与最小复现代码

在引入大型项目时发现动态库无法被dlclose()真正卸载的问题,以下是最小复现代码:

header.h

struct A {
  typedef void (*func_t)();
  static void empty() {}
  static constexpr func_t funcs[1] = {empty};
  const func_t *func_list;
  A() { func_list = funcs; }
};
struct B {
  B();
};
struct X {
  A a;
  B b;
};

header.cpp

#include "header.h"
B::B() {}

main.cpp

#include "header.h"
extern "C" {

void test() {
  auto x = new X;
  delete x;
  // print(version_nubmer); 
}
}

构建脚本

该库通过CMake构建,配置如下:

add_library(main SHARED main.cpp header.cpp)
target_compile_options(main PRIVATE -fPIC)

测试流程

编写程序依次执行以下操作:

  • dlopen()加载动态库(参数为RTLD_LAZY | RTLD_LOCAL)
  • 通过dlsym()获取test函数并调用
  • 调用dlclose()卸载库
  • 修改库的版本号后重新编译
  • 再次执行dlopen()加载库、dlsym()调用test函数

原本期望第二次加载后打印更新后的版本号,但实际仍输出旧值,说明dlclose()并未真正卸载动态库。

不同构建方式的差异

若开启CMAKE_INTERPROCEDURAL_OPTIMIZATION(即LTO优化),或直接通过命令行编译(如g++ -o libmain.so -fPIC -shared main.cpp header.cpp),上述动态库无法卸载的现象会消失。请问这几种构建方式的核心差异是什么?

更新
在dlclose()和第二次dlopen()之间插入scanf()或getchar()阻塞程序,待重编译库后再继续执行,可确保三种场景(普通CMake构建、CMake+LTO构建、命令行构建)都能复现该问题。


内容的提问来源于stack exchange,提问作者Yuxai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:55:24