我正在运行 OSX Yosemite 10.10.5,带有 clang-700.0.72 和安装了 boost 1.56 的brew。
我正在将 boost::asio 用于非 ssl 和 tls 套接字。 这些有问题的行不在我的项目中,但似乎源自 boost 1.56 本身。
我使用 cmake,并且使用 find_package(需要 OpenSSL)
与 openssl 链接,并且我确实有 openssl 1.0.2g
。
该项目使用 C++11,有问题的行似乎是:
体系结构 x86_64 的 undefined symbol :
“_SSLv2_client_method”,引用自:
asio_tls.cpp.o 中的 boost::asio::ssl::context::context(boost::asio::ssl::context_base::method)
“_SSLv2_method”,引用自:
asio_tls.cpp.o 中的 boost::asio::ssl::context::context(boost::asio::ssl::context_base::method)
“_SSLv2_server_method”,引用自:
asio_tls.cpp.o 中的 boost::asio::ssl::context::context(boost::asio::ssl::context_base::method)
ld:未找到架构 x86_64 的符号
我根本不使用 SSLv2,事实上代码只专注于使用 TLS v2:
class asio_socket_https
{
public:
asio_socket_https(const std::string token)
: ctx_(boost::asio::ssl::context::tlsv12_client), token_(token)
{}
稍后,在初始化套接字和上下文时,我会:
ctx_.set_options(boost::asio::ssl::context::default_workarounds
|boost::asio::ssl::context::no_sslv2
|boost::asio::ssl::context::no_sslv3
|boost::asio::ssl::context::no_tlsv1
|boost::asio::ssl::context::single_dh_use);
我没有编译错误,应用程序链接到 libssl/libcrypto,并且我没有在 Linux 下测试它(仅限 OSX)。
我看到了一个具有相同主题但没有答案的问题 here .
实际链接标志:
/usr/bin/g++ -std=c++11 -Wall -g -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/asio_tls.dir/examples/asio_tls.cpp.o -o asio_tls librapp.0.2.dylib/usr/local/lib/libboost_system-mt.dylib/usr/local/lib/libboost_thread-mt.dylib/usr/local/lib/libboost_random-mt.dylib/usr/local/lib/libboost_unit_test_framework-mt.dylib/usr/local/lib/libboost_program_options-mt.dylib/usr/local/Cellar/openssl/1.0.2g/lib/libssl.dylib/usr/local/Cellar/openssl/1.0.2g/lib/libcrypto.dylib
编辑
我今天在 Ubuntu 14.04 下测试了相同的代码,在检测 openssl 1.0.1f 时它构建得很好(完全没有问题)。 这开始看起来像是 OSX 特有的问题。
@rhashimoto 似乎是正确的,而链接器在 /usr/local/Cellar/openssl/
中使用 Cellar 版本的 openssl,所使用的 header 位于 /usr/local/下openssl
我认为它与brew 管理的不一样。
解决方案
问题出在我的 CMakeLists.txt
中,我以为 find_package(OpenSSL REQUIRED)
就足够了,不幸的是,这破坏了链接库的版本导入的库头文件。
默认库是 OSX 的 openssl,而我使用 ${OPENSSL_LIBRARIES}
显式链接。
只需添加以下内容即可解决问题(现在它使用从 brew 安装的 openssl):
find_package(OpenSSL REQUIRED)
if (OPENSSL_FOUND)
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
然后执行target_link_libraries(... ${OPENSSL_LIBRARIES})
最佳答案
Boost Asio 确实在 boost/asio/ssl/impl/context.ipp
中使用了 SSLv2_client_method()
和 SSLv2_server_method()
,条件是缺少预处理器符号OPENSSL_NO_SSL2
:
#if defined(OPENSSL_NO_SSL2)
case context::sslv2:
case context::sslv2_client:
case context::sslv2_server:
boost::asio::detail::throw_error(
boost::asio::error::invalid_argument, "context");
break;
#else // defined(OPENSSL_NO_SSL2)
case context::sslv2:
handle_ = ::SSL_CTX_new(::SSLv2_method());
break;
case context::sslv2_client:
handle_ = ::SSL_CTX_new(::SSLv2_client_method());
break;
case context::sslv2_server:
handle_ = ::SSL_CTX_new(::SSLv2_server_method());
break;
#endif // defined(OPENSSL_NO_SSL2)
OPENSSL_NO_SSL2
如果您的 OpenSSL 库 header 不包含对 SSLv2 的支持,则应在该 header 中进行定义,但显然您的构建并未采用它。
对这种行为的一种常见解释是,您正在使用仍然支持 SSLv2 的 OpenSSL 库中的 header 进行编译,并链接到另一个不支持 SSLv2 的 OpenSSL 库中的二进制文件。将 -H
标志插入到编译器选项中可能会有所帮助,该选项将在处理时记录 header 路径,以便您可以验证正在使用哪些 header 。
关于c++ - boost::asio::ssl::context::context(boost::asio::ssl::context_base::method) undefined symbol ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36626031/