C++ boost::asio::ssl::context::context(boost::asio::ssl::context\u base::method)未定义的符号

C++ boost::asio::ssl::context::context(boost::asio::ssl::context\u base::method)未定义的符号,c++,macos,ssl,boost,C++,Macos,Ssl,Boost,我正在运行OSX Yosemite 10.10.5和clang-700.0.72,并安装了brew boost 1.56 我正在为非ssl和tls套接字使用boost::asio。 在我的项目中,有问题的行不是,而是源自boost 1.56本身 我使用cmake,我使用find_包(需要openssl)与openssl链接,我有openssl 1.0.2g 该项目使用C++11,出现问题的行如下: 架构x86_64的未定义符号: “\u SSLv2\u客户端\u方法”,引用自: asio_tl

我正在运行OSX Yosemite 10.10.5和clang-700.0.72,并安装了brew boost 1.56

我正在为非ssl和tls套接字使用boost::asio。 在我的项目中,有问题的行不是,而是源自boost 1.56本身

我使用cmake,我使用
find_包(需要openssl)
与openssl链接,我有
openssl 1.0.2g

该项目使用C++11,出现问题的行如下:


架构x86_64的未定义符号:
“\u SSLv2\u客户端\u方法”,引用自:
asio_tls.cpp.o中的boost::asio::ssl::context::context(boost::asio::ssl::context_base::method)
“_SSLv2_方法”,引用自:
asio_tls.cpp.o中的boost::asio::ssl::context::context(boost::asio::ssl::context_base::method)
“\u SSLv2\u服务器\u方法”,引用自:
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)

我见过一个主题相同但没有答案的问题

实际链接标志:


/usr/bin/g++-std=c++11-Wall-g-Wl,-search\u path\u first-Wl,-headerpad_max_install_name cmakfiles/asio_tls.dir/examples/asio_tls.cpp.o-o asio_tls librapp.0.2.dylib/usr/local/libboost_system-mt.dylib/usr/local/lib/libboost_thread-mt.dylib/usr/local/libboost_random-mt.dylib/usr/local/libboost/libboost_单元测试框架-mt.dylib/usr/local/ceral/openssl/1.0.2g/lib/libssl.dylib/usr/local/ceral/openssl/1.0.2g/lib/libcrypto.dylib

编辑 我今天在Ubuntu 14.04下测试了相同的代码,当检测到openssl 1.0.1f时,它构建得很好(没有任何问题)。 这似乎开始成为OSX特有的问题

@rhashimoto似乎是对的,而链接器在
/usr/local/ceral/openssl/
中使用的是Cell版本的openssl。使用的标题位于
/usr/local/openssl
下,我认为这与brew管理的标题不同

解决方案 问题是在我的
CMakeLists.txt
中,我假设
find_包(需要OpenSSL)
就足够了,不幸的是,这破坏了与导入的库头链接的库版本

默认库是OSX的openssl,而我是用
${openssl\u LIBRARIES}
显式链接的

只需添加以下内容即可解决此问题(现在它使用从brew安装的openssl):


然后做一个
目标链接库(…${OPENSSL\u libraries})
Boost Asio确实使用了
SSLv2\u客户端方法()
SSLv2\u服务器方法()
,前提是没有预处理器符号
OPENSSL\u NO\u 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\u NO\u SSL2
如果不包括对SSLv2的支持,那么应该在您的OPENSSL库头中定义,但显然您的构建没有接受它


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

检查链接参数的顺序(库跟随您自己的对象)@sehe谢谢,顺序正确,我添加了链接标志的编辑(cmake冗长)。我似乎只缺少了特定的openssl函数-其他openssl链接都是正确的。我认为这是OSX的本地化,但我没有访问Linux ATM。我将验证您编译的openssl头是否是您链接的openssl库的头。您可以尝试注入
-H
标记到您的编译器选项中以查找。@rhashimoto我认为boost 1.56可能是指不推荐使用的函数。起初我以为我是链接到apple libcrypto,但上面的输出使用brew安装的openssl。我没有在cmake中包含头,因此这可能意味着它使用了其他头?但是cmake find_包确实指向openssl 1.0.2g。不过,我会尝试你的建议,看看结果如何,非常感谢!@rhashimoto你是对的,不同的头和库!如果你想,请添加一个答案:-)谢谢你的帮助,您建议使用
-H
,这正是pin指出的问题所在,因为cmake使用了不同的库/头。
#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)