2016-04-14 211 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拾取不同庫/頭的問題。 –