求助:使用arm-linux-gnueabihf-ld链接Cap'n Proto库遇未定义符号错误
ARM交叉编译Cap'n Proto链接未定义符号问题解决
问题现象
在Docker和Snapcraft环境中使用arm-linux-gnueabihf-ld编译链接Cap'n Proto库时,出现大量未定义符号错误:
arm-linux-gnueabihf-ld: error: undefined symbol: capnp::MessageBuilder::getRootInternal() >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildVersion(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildAuth(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildGet(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced 10 more times arm-linux-gnueabihf-ld: error: undefined symbol: capnp::_::PointerBuilder::initStruct(capnp::_::StructSize) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildVersion(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildVersion(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildAuth(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced 23 more times arm-linux-gnueabihf-ld: error: undefined symbol: void capnp::_::PointerBuilder::setBlob<capnp::Text>(capnp::Text::Reader) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildVersion(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildAuth(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegRequestBuilder::buildGet(capnp::MallocMessageBuilder&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)) >>> referenced 12 more times arm-linux-gnueabihf-ld: error: undefined symbol: capnp::_::ListBuilder::asReader() const >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegResponseBuilder::buildEnumerate(capnp::MallocMessageBuilder&, capnp::List<capnp::Text, (capnp::Kind)1>::Builder const&, capnp::schemas::SysregStatus_b56039029f3859aa)) arm-linux-gnueabihf-ld: error: undefined symbol: capnp::_::PointerBuilder::setList(capnp::_::ListReader const&, bool) >>> referenced by main.cpp >>> CMakeFiles/feature-manager.dir/src/main.cpp.o:(SysRegResponseBuilder::buildEnumerate(capnp::MallocMessageBuilder&, capnp::List<capnp::Text, (capnp::Kind)1>::Builder const&, capnp::schemas::SysregStatus_b56039029f3859aa)) clang-11: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [CMakeFiles/feature-manager.dir/build.make:145: feature-manager] Error 1 make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/feature-manager.dir/all] Error 2 make: *** [Makefile:136: all] Error 2
解决方法
确保Cap'n Proto是针对ARM架构交叉编译的
不能直接使用主机系统的x86版本库,必须用arm-linux-gnueabihf工具链重新编译Cap'n Proto:- 下载Cap'n Proto源码,创建交叉编译构建目录
- 运行CMake时指定交叉编译工具链:
cmake .. \ -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \ -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \ -DCMAKE_SYSTEM_NAME=Linux \ -DCMAKE_SYSTEM_PROCESSOR=arm - 编译安装到指定路径,后续链接时使用该路径下的ARM架构库
检查链接配置,确保引入正确的库
在CMakeLists.txt中明确链接Cap'n Proto及其依赖的kj库:# 指定Cap'n Proto库的路径(如果不是系统默认路径) link_directories("/path/to/arm-capnp-install/lib") # 链接目标库 target_link_libraries(feature-manager capnp kj)如果是手动写链接命令,需添加
-lcapnp -lkj参数,并通过-L指定库路径统一C++标准库
错误中的std::__1::basic_string是libc的命名空间,而交叉编译工具链默认可能用libstdc。需保证编译Cap'n Proto和你的代码时使用相同的C++标准库:- 若用clang编译,添加
-stdlib=libstdc++或-stdlib=libc++参数,保持两者一致 - 确认交叉编译工具链支持所选的标准库
- 若用clang编译,添加
匹配Cap'n Proto版本
代码中引用的Cap'n Proto头文件版本必须和链接的库版本完全一致,版本不匹配会导致API符号不一致,引发未定义符号错误完善CMake交叉编译配置
使用CMake交叉编译工具链文件(toolchain file),正确设置以下变量:set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)让CMake优先查找ARM架构的库和头文件,避免误用到主机的x86库
内容的提问来源于stack exchange,提问作者Powdermist
相关产品推荐
相关产品推荐

