2016-04-14 66 views
1

我正在运行OSX Yosemite 10.10.5和clang-700.0.72以及brew装机提升1.56。boost :: asio :: ssl :: context :: context(boost :: asio :: ssl :: context_base :: method)undefined符号

我使用boost :: asio for non-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) 
    {} 

后来,intialising插座和上下文的时候,我做的:

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问题,但没有回答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/中的openssl的Cellar版本,所使用的头文件在/usr/local/openssl之下,我不认为它是由brew管理的。

SOLUTION

的问题是在我的CMakeLists.txt我曾以为,find_package(OpenSSL REQUIRED)就足够了,可惜的是这是什么做的是打破库的进口库头连接的版本。

默认库是OSX的openssl,而我明确链接到${OPENSSL_LIBRARIES}

只需添加以下固定的问题(现在它使用从冲泡安装了OpenSSL):

find_package(OpenSSL REQUIRED) 
if (OPENSSL_FOUND) 
    include_directories(${OPENSSL_INCLUDE_DIR}) 
endif() 

然后做一个target_link_libraries(... ${OPENSSL_LIBRARIES})

+0

检查链接参数的顺序(库去_after_自己的对象) – sehe

+1

@sehe谢谢,顺序是正确的,我已经添加了链接标志(cmake详细)的编辑。看来我错过了特定的openssl函数 - 因为openssl的其余部分链接正确。我认为这是本地化的OSX,但我没有访问Linux的ATM。 –

+1

我将验证您正在编译的OpenSSL头文件是否与您要链接的OpenSSL库文件头文件相对应。你可以尝试在你的编译器选项中注入一个'-H'标志来查找。 – rhashimoto

回答

1

升压短耳并在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库头文件中定义,如果它不包含对SSLv2的支持,但显然你的版本没有选择它。

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

+0

感谢您的帮助,您使用'-H'的建议是针对cmake拾取不同库/头的问题。 –