在嵌入式设备(ARM、uClibc)上工作,我有一个静态可执行文件,它与不同的库静态链接,并具有使用 dlopen 的动态加载功能。
set(EXTERNAL_LIBS "-lpthread -lpcap -lcurl -ldl")
target_link_libraries(myApp -static ${EXTERNAL_LIBS})
加载简单插件时,一切工作正常。
void plugin::execute() {
std::cout << "hello world" << std::endl;
}
添加字符串变量时:
void plugin::execute() {
//THIS IS NOT WORKING
std::string test = "hello world from thing";
std::cout << test << std::endl;
}
我得到:
“无法解析符号 '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_'”
我尝试按照此处的建议添加-rdynamic: dlopen a dynamic library from a static library, when the dynamic library uses symbols of the static one 通过添加:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wl,-export-dynamic")
但是还是不行。
静态二进制文件中确实存在缺失的符号(使用 nm 验证)
我在这里缺少什么?
添加了构建过程的简化输出:
编译目标文件
arm-linux-uclibcgnueabi-g++ -fPIC -std=gnu++98 -o CMakeFiles/libstaticlib.dir/test1.cpp.o -c /work/src/test1.cpp
arm-linux-uclibcgnueabi-gcc -fPIC -std=gnu++98 -o CMakeFiles/libstaticlib.dir/test2.cpp.o -c /work/src/test2.cpp
链接CXX静态库
arm-linux-uclibcgnueabi-ar qc libstaticlib.a CMakeFiles/libstaticlib.dir/test1.cpp.o CMakeFiles/libstaticlib.dir/test2.cpp.o
arm-linux-uclibcgnueabi-ranlib libstaticlib.a
编译myApp
arm-linux-uclibcgnueabi-g++ -fPIE -std=gnu++98 -o CMakeFiles/myapp.dir/main.cpp.o -c /work/src/main.cpp
链接 CXX 可执行文件
arm-linux-uclibcgnueabi-g++ -rdynamic CMakeFiles/myapp.dir/main.cpp.o -o myapp -L/work/lib -Wl,-rpath,/work/lib -rdynamic -static libstaticlib.a -lpthread -lpcap -lcurl -ldl
编译插件
arm-linux-uclibcgnueabi-g++ -fPIC -std=gnu++98 -o CMakeFiles/plugin.dir/plugin/plugin.cpp.o -c /work/src/plugins/plugin/plugin.cpp
链接CXX共享库../libplugin.so
arm-linux-uclibcgnueabi-g++ -fPIC -shared -Wl,-soname,libplugin.so -o ../libplugin.so CMakeFiles/plugin.dir/plugin/plugin.cpp.o -L/work/lib
readelf -s myapp 的输出 | grep ...:
0021ce74 68 FUNC WEAK DEFAULT 2 _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_
最佳答案
-rdynamic
是 GCC 链接选项。所以你可以直接将其传递给
GCC 在调用链接器 (ld
) 时。 -rdynamic
的作用是
让 GCC 在调用 ld
时传递 --export-dynamic
,如您所见
在 GCC manual: 3.14 Options for Linking
--export-dynamic
不是 GCC 选项,而是 ld
option 。你
可以通过传递 -Wl,--export-dynamic
来告诉 GCC 在调用 ld
时传递此选项
到海湾合作委员会。
所以你的 GCC 选项:
-rdynamic -Wl,-export-dynamic
做同样的事情两次:-rdynamic
就足够了。
但是设置:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
不会导致 GCC 在调用链接器时传递 -rdynamic
。
那是因为CMAKE_CXX_FLAGS
设置将传递给的选项
每个 C++ 编译。由于编译时没有发生链接,因此链接
选项将被忽略且无效。链接选项应设置在
CMAKE_EXE_LINKER_FLAGS
,
像:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
但即便如此...
你的问题的标题仍然是正确的,因为-rdynamic
不能在静态二进制文件中工作,句号。
--export-dynamic
When creating a dynamically linked executable, using the -E option or the --export-dynamic option causes the linker to add all symbols to the dynamic symbol table.
我的重点。并且您没有创建动态链接的可执行文件,因为您
正在链接-static
。不会有一个动态符号表来容纳所有符号
可以添加。
这是一个基本演示。
main.c
int foo() {
return 0;
}
int main()
{
return foo();
}
正常编译链接:
$ gcc main.c
动态符号表:
$ nm -D a.out
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main
编译并链接-rdynamic
;参见动态符号表:
$ gcc -rdynamic main.c
$ nm -D a.out
0000000000201010 B __bss_start
w __cxa_finalize
0000000000201000 D __data_start
0000000000201000 W data_start
0000000000201010 D _edata
0000000000201018 B _end
0000000000000884 T _fini
00000000000007ea T foo
w __gmon_start__
00000000000006a0 T _init
0000000000000890 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000880 T __libc_csu_fini
0000000000000810 T __libc_csu_init
U __libc_start_main
00000000000007f5 T main
00000000000006e0 T _start
现在有更多符号,包括 main
和 foo
。
编译并链接-static
;参见动态符号表:
$ gcc -static main.c
$ nm -D a.out
nm: a.out: no symbols
最后:
$ gcc -rdynamic -static main.c
$ nm -D a.out
nm: a.out: no symbols
如果您希望插件引用它定义的符号,则不能静态链接程序。
关于c++ - -rdynamic 在静态二进制文件中使用 dlopen 时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53430990/