使用 `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)
首先,这是我的最小可重现程序:
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)