iOS编译Thrift 0.21.0 C++库时出现arm64未定义符号错误
问题背景
尝试为iOS编译Thrift 0.21.0版本的共享库(.dylib)时遇到链接错误,静态库编译正常(设置-DBUILD_SHARED_LIBS=OFF),但无法生成所需的动态库。
使用的编译配置(CMake ExternalProject)
ExternalProject_Add(thrift SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${THRIFT_DIR} INSTALL_DIR ${THIRDPARTY_INSTALL_DIR} CMAKE_ARGS ${EXTERNAL_PROJECT_CMAKE_ARGS} -DOPENSSL_ROOT_DIR=${OPENSSL_INSTALL_DIR} -DOPENSSL_CRYPTO_LIBRARY=${OPENSSL_INSTALL_DIR}/lib/libcrypto.a -DOPENSSL_SSL_LIBRARY=${OPENSSL_INSTALL_DIR}/lib/libssl.a -DBoost_INCLUDE_DIR=${BOOST_INCLUDE_DIR} -DWITH_ZLIB=${ZLIB_INSTALL_DIR} -DCMAKE_FIND_LIBRARY_SUFFIXES=".a" -DBUILD_SHARED_LIBS=ON -DBUILD_JAVA=OFF -DBUILD_JAVASCRIPT=OFF -DBUILD_NODEJS=OFF -DBUILD_PYTHON=OFF -DBUILD_PY3=OFF -DBUILD_QT=OFF -DBUILD_QT4=OFF -DBUILD_RUBY=OFF -DBUILD_PHP=OFF -DBUILD_SWIFT=OFF -DBUILD_TESTING=OFF BUILD_COMMAND make clean && make CFLAGS+=-DOPENSSL_NO_SSL3 CFLAGS+=-fPIC CXXFLAGS+=-DOPENSSL_NO_SSL3 CXXFLAGS+=-fPIC INSTALL_COMMAND make install )
错误信息
[ 93%] Linking CXX shared library ../libthriftz.dylib
cd /Users/Technaharia/Downloads/Demo/build-ios/SDKThirdParty-prefix/src/SDKThirdParty-build/thrift-prefix/src/thrift-build/lib/cpp && /Applications/CMake.app/Contents/bin/cmake -E cmake_link_script CMakeFiles/thriftz.dir/link.txt --verbose=1
Undefined symbols for architecture arm64:
"apache::thrift::GlobalOutput", referenced from:
apache::thrift::transport::TZlibTransport::checkZlibRvNothrow(int, char const*) in TZlibTransport.cpp.o
"apache::thrift::protocol::TProtocol::skip_virt(apache::thrift::protocol::TType)", referenced from:
vtable for apache::thrift::protocol::TProtocolDefaults in THeaderProtocol.cpp.o
"apache::thrift::protocol::TProtocol::~TProtocol()", referenced from:
std::__1::__shared_ptr_emplace<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::THeaderTransport, apache::thrift::protocol::TNetworkBigEndian>, std::__1::allocator<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::THeaderTransport, apache::thrift::protocol::TNetworkBigEndian>>>::~__shared_ptr_emplace() in THeaderProtocol.cpp.o
std::__1::__shared_ptr_emplace<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::THeaderTransport, apache::thrift::protocol::TNetworkBigEndian>, std::__1::allocator<apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::THeaderTransport, apache::thrift::protocol::TNetworkBigEndian>>>::~__shared_ptr_emplace() in THeaderProtocol.cpp.o
apache::thrift::protocol::TBinaryProtocolT<apache::thrift::transport::THeaderTransport, apache::thrift::protocol::TNetworkBigEndian>::~TBinaryProtocolT() in THeaderProtocol.cpp.o
额外尝试的编译步骤
单独编译Thrift的流程:
- 下载Thrift 0.21.0源码包并解压
- 创建编译目录:
mkdir build-ios && cd build-ios - 执行CMake配置:
cmake \ -DCMAKE_TOOLCHAIN_FILE=/Users/varun/Downloads/ios-cmake-master/ios.toolchain.cmake \ -DPLATFORM=OS64 \ -DCMAKE_INSTALL_PREFIX=../install-ios \ -DOPENSSL_INCLUDE_DIR={OpenSSL头文件路径} \ -DOPENSSL_ROOT_DIR={iOS版OpenSSL根目录} \ -DOPENSSL_CRYPTO_LIBRARY={iOS版OpenSSL库路径}/libcrypto.1.1.dylib \ -DOPENSSL_SSL_LIBRARY={iOS版OpenSSL库路径}/libssl.1.1.dylib \ -DBoost_INCLUDE_DIR={iOS版Boost头文件路径}/include \ -DBUILD_SHARED_LIBS=ON \ -DWITH_ZLIB=ON \ -DWITH_C_GLIB=OFF \ -DWITH_CPP=ON \ -DWITH_STATIC_LIB=OFF \ ..
- 执行编译:
cmake --build . --target install --config Release,在此步骤失败 - 验证架构命令:
otool -L install-ios/lib/libthrift.dylib
注意:使用脚本为Mac编译时成功,但为iOS编译时失败。推测问题为zlib未与Thrift正确链接。
解决思路
修正zlib链接参数:
将-DWITH_ZLIB=${ZLIB_INSTALL_DIR}拆分为-DZLIB_INCLUDE_DIR=${ZLIB_INSTALL_DIR}/include和-DZLIB_LIBRARY=${ZLIB_INSTALL_DIR}/lib/libz.dylib,确保指定iOS版的动态zlib库,避免CMake仅找到静态库导致链接问题。调整CMake库查找策略:
移除-DCMAKE_FIND_LIBRARY_SUFFIXES=".a",编译动态库时需要优先查找.dylib后缀的库文件,强制只找静态库会导致依赖库无法以动态方式链接,进而引发符号缺失。检查Thrift子库依赖关系:
libthriftz.dylib依赖libthrift.dylib,确保编译libthriftz时正确链接了libthrift动态库。可在CMake配置中添加-DWITH_THRIFTZ=ON,并确认链接脚本中包含libthrift.dylib的引用。统一依赖库类型:
OpenSSL、Boost、zlib都必须是针对iOS arm64架构编译的动态库,不能混合使用静态库和动态库。比如将OpenSSL的库路径改为.dylib文件而非.a静态库。添加显式链接参数:
在BUILD_COMMAND中添加链接参数,比如LDFLAGS+=-L${ZLIB_INSTALL_DIR}/lib -lz,强制链接zlib动态库,避免CMake自动链接时出错。检查符号导出设置:
对于iOS动态库,需确保Thrift的全局符号(如GlobalOutput、TProtocol相关虚函数)被正确导出。可检查Thrift源码中的EXPORT宏定义,确保在iOS编译环境下生成正确的符号导出表。
内容的提问来源于stack exchange,提问作者Varun Naharia

