使用 `dlopen` 时关于 "undefined symbol" 的共享库错误

shared library error about "undefined symbol" when using `dlopen`

首先,这是我的最小可重现程序:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.17)
project(untitled4)

set(CMAKE_CXX_STANDARD 17)

add_library(lib1 SHARED lib1.cpp)

add_executable(untitled4 main.cpp)
target_link_libraries(untitled4 PRIVATE dl)

main.cpp:

#include "iostream"
#include <dlfcn.h>
int Test() {
  return 123456;
}
int main() {
  auto* handler = dlopen("/home/liu/source/untitled4/cmake-build-debug/liblib1.so", RTLD_LAZY|RTLD_GLOBAL);
  if (!handler) {
    std::cerr << dlerror();
    exit(1);
  }
}

和lib1.cpp:

#include "iostream"
extern int Test();
class Foo {
 public:
  Foo() {
    std::cout << Test() << std::endl;
  }
};
Foo foo;

现在让我解释一下:

如您所见,我在 main.cpp 中定义了一个名为 Test 的函数,我希望共享库 liblib1.so 在加载时调用它。

但是当我运行 main() 函数时,有一个错误日志说:

/home/liu/source/untitled4/cmake-build-debug/liblib1.so: undefined symbol: _Z4Testv

我使用 nm untitled4 |grep Test 检查符号,该符号似乎存在:

0000000000000b87 t _GLOBAL__sub_I__Z4Testv
0000000000000aea T _Z4Testv

那我做错了什么?如何解决这个问题?

需要注意的重要一点是,在实际情况下,lib1 的构建和main.cpp 的构建是完全分开的,两个构建互不认识。但是如果能解决这个问题(如果没有其他办法),我可以把它们合二为一(非常困难)。

P.S。我尝试使用 extern "C" 来环绕两个文件中的 Test(),但没有用,似乎不是 C/C++ 函数命名问题。

添加链接器选项 -rdynamic 您的代码不会因“未定义符号”而失败。

您可以使用 set_target_properties(untitled4 PROPERTIES ENABLE_EXPORTS 1)target_link_options(untitled4 BEFORE PRIVATE "-rdynamic") 进行设置。

示例:

cmake_minimum_required(VERSION 3.17)
project(untitled4)

set(CMAKE_CXX_STANDARD 17)

add_library(lib1 SHARED lib1.cpp)

add_executable(untitled4 main.cpp)
set_target_properties(untitled4 PROPERTIES ENABLE_EXPORTS 1)

target_link_libraries(untitled4 PRIVATE dl)