boost::asio::ssl::context::context(boost::asic::ssl::context

boost::asio::ssl::context::context(boost::asio::ssl::context_base::method) undefined Symbols

本文关键字:context boost ssl asic asio      更新时间:2023-10-16

我正在运行OSX Yosemite 10.10.5,带有clang-700.0.72和brew安装的boost 1.56。

我将boost::asio用于非ssl和tls套接字。在我的项目中,有问题的行是而不是,但似乎源于boost 1.56本身。

我使用cmake,我使用openssl进行链接,使用find_package(OpenSSL REQUIRED),我确实有openssl 1.0.2g

该项目使用C++11,违规行似乎是:

Undefined symbols for architecture x86_64: "_SSLv2_client_method", referenced from: boost::asio::ssl::context::context(boost::asio::ssl::context_base::method) in asio_tls.cpp.o "_SSLv2_method", referenced from: boost::asio::ssl::context::context(boost::asio::ssl::context_base::method) in asio_tls.cpp.o "_SSLv2_server_method", referenced from: boost::asio::ssl::context::context(boost::asio::ssl::context_base::method) in asio_tls.cpp.o ld: symbol(s) not found for architecture 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)。

我看到了一个SO问题,主题相同,但这里没有答案。

实际链路标志:

/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,使用的头在/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不包括对SSLv2的支持,那么它应该在OpenSSL库头中定义,但显然您的构建没有接受它。

对这种行为的一个常见解释是,您使用一个仍然支持SSLv2的OpenSSL库中的头进行编译,并使用另一个不支持SSLv2OpenSSL库的二进制文件进行链接。在编译器选项中插入-H标志可能会有所帮助,它会在处理标头时记录标头路径,因为您可以验证正在使用哪些标头。