调用含std::__1符号的闭源库函数遇链接错误,求解决方法
闭源库含
std::__1::function参数的函数链接失败问题解决 问题背景
尝试调用闭源库libvendor.so中的函数,原工具链及头文件不可用。通过以下命令获取库信息:
$ file libvendor.so libvendor.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=ff, stripped $ nm -CD libvendor.so | grep Start 0001ec3a T nm::vendor::className::Start(int, char const**, std::__1::function<void ()>)
自行编写的头文件header.h:
#include <functional> namespace nm { namespace vendor { class className { public: static className* Get(); void Start(int, char const**, std::function<void ()>); }; } }
main.cpp代码:
#include "header.h" using namespace nm::vendor; using namespace std; std::function<void ()> startFunc; void Start() {} int main(void) { className* c = className::Get(); char const *str = "c style string"; const char** str_ptr = &str; startFunc = Start; c->Start(1, str_ptr, startFunc); }
使用crosstool-ng编译时出现链接错误:
$ ~/x-tools/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-c++ --version arm-linux-gnueabihf-c++ (crosstool-NG 1.25.0) 11.2.0 $ ~/x-tools/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-c++ \ -std=c++11 \ -Wl,-v \ -Wl,-rpath,. \ -ldl \ -mthumb-interwork \ libvendor.so \ -o main \ main.cpp collect2 version 11.2.0 ~/x-tools/arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/11.2.0/../../../../arm-linux-gnueabihf/bin/ld -plugin ~/x-tools/arm-linux-gnueabihf/libexec/gcc/arm-linux-gnueabihf/11.2.0/liblto_plugin.so -plugin-opt=~/x-tools/arm-linux-gnueabihf/libexec/gcc/arm-linux-gnueabihf/11.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/cc35fC2k.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X -m armelf_linux_eabi -o main ~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib/crt1.o ~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib/crti.o ~/x-tools/arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/11.2.0/crtbegin.o -L~/x-tools/arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/11.2.0 -L~/x-tools/arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/11.2.0/../../../../arm-linux-gnueabihf/lib -L~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot/lib -L~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib -v -rpath . -rpath /system/vendor/sony/lib -rpath ~/nw-a50/myfirmware/bootimg/initrd_unpacked/lib/ -ldl libvendor.so /tmp/ccKaDp0K.o -lstdc++ -lm -lc -lgcc_s -lgcc -lc -lgcc_s -lgcc ~/x-tools/arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/11.2.0/crtend.o ~/x-tools/arm-linux-gnueabihf/arm-linux-gnueabihf/sysroot/usr/lib/crtn.o GNU ld (crosstool-NG 1.25.0) 2.26.1 /tmp/ccSbQv2E.o: In function `main': main.cpp:(.text+0x70): undefined reference to `nm::vendor::className::Start(int, char const**, std::function<void ()>)' collect2: error: ld returned 1 exit status
尝试将头文件中声明改为std::__1::function时编译失败:
In file included from main.cpp:2:0: header.h:84:57: error: 'std::__1' has not been declared void Start(int, char const**, std::__1::function<void ()>);
其他函数(如Get())可正常链接调用,需解决该链接问题。
核心原因
闭源库由LLVM/libc编译,其中std::function被放在内联命名空间__1中;而当前使用的GNU libstdc无此内联命名空间,导致代码生成的函数签名与库中符号不匹配,触发链接错误。
解决方法
方法1:切换到libc++编译
如果交叉工具链支持libc++,修改编译命令,指定使用libc替代libstdc,让编译环境与闭源库对齐:
~/x-tools/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-c++ \ -std=c++11 \ -stdlib=libc++ \ -Wl,-v \ -Wl,-rpath,. \ -ldl \ -mthumb-interwork \ libvendor.so \ -o main \ main.cpp
注意:若工具链未预编译libc++,需自行构建带libc++的交叉工具链。
方法2:手动映射内联命名空间
在头文件中手动定义std::__1命名空间,并导入std::function,让编译器生成匹配的符号:
#include <functional> // 手动兼容libc++的内联命名空间__1 namespace std { namespace __1 { using ::std::function; } } namespace nm { namespace vendor { class className { public: static className* Get(); void Start(int, char const**, std::__1::function<void ()>); }; } }
编译时会生成带std::__1::function的函数签名,与闭源库中的符号匹配,即可正常链接。
方法3:用函数指针替代std::function
如果无法修改标准库相关定义,可尝试用C风格函数指针替换std::function参数——多数情况下,std::function可兼容普通函数指针:
修改头文件:
namespace nm { namespace vendor { class className { public: static className* Get(); void Start(int, char const**, void (*)()); }; } }
修改main.cpp:
#include "header.h" using namespace nm::vendor; void Start() {} int main(void) { className* c = className::Get(); char const *str = "c style string"; const char** str_ptr = &str; c->Start(1, str_ptr, &Start); }
此方法避免了标准库命名空间的差异问题,无需依赖std::function。
内容的提问来源于stack exchange,提问作者user1938027
相关产品推荐
相关产品推荐

