当项目中使用asio作为通讯库时,编译打包时总是报如下错误:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl std::bad_cast::bad_cast(char const *)" (__imp_??0bad_cast@std@@QEAA@PEBD@Z) referenced in function "public: __cdecl asio::ip::bad_address_cast::bad_address_cast(void)" (??0bad_address_cast@ip@asio@@QEAA@XZ)
error LNK2001: unresolved external symbol "__declspec(dllimport) public: __cdecl std::bad_cast::bad_cast(char const *)" (__imp_??0bad_cast@std@@QEAA@PEBD@Z)
error LNK2001: unresolved external symbol "protected: virtual void __cdecl std::bad_cast::_Doraise(void)const " (?_Doraise@bad_cast@std@@MEBAXXZ)
error LNK2001: unresolved external symbol "protected: virtual void __cdecl std::bad_cast::_Doraise(void)const " (?_Doraise@bad_cast@std@@MEBAXXZ)
查看asio::ip::bad_address_cast的源代码,发现bad_address_cast继承了<typeinfo>中定义的std::bad_cast,代码如下:
//
// ip/bad_address_cast.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IP_BAD_ADDRESS_CAST_HPP
#define ASIO_IP_BAD_ADDRESS_CAST_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <typeinfo>
#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
/// Thrown to indicate a failed address conversion.
class bad_address_cast : public std::bad_cast
{
public:
/// Default constructor.
bad_address_cast() {}
/// Destructor.
virtual ~bad_address_cast() ASIO_NOEXCEPT_OR_NOTHROW {}
/// Get the message associated with the exception.
virtual const char* what() const ASIO_NOEXCEPT_OR_NOTHROW
{
return "bad address cast";
}
};
} // namespace ip
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IP_ADDRESS_HPP
从代码中看到#include <typeinfo>,应该没有理由找不到std::bad_cast。再查看VC++中提供的typeinfo的源代码:
// typeinfo standard header
/***
*typeinfo - Defines the type_info structure and exceptions used for RTTI
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Modified January 1996 by P.J. Plauger
*
*Purpose:
* Defines the type_info structure and exceptions used for
* Runtime Type Identification.
*
* [Public]
*
****/
#pragma once
#ifndef _TYPEINFO_
#define _TYPEINFO_
#ifndef RC_INVOKED
#include <exception>
#pragma pack(push,_CRT_PACKING)
#pragma warning(push,_STL_WARNING_LEVEL)
#pragma warning(disable: _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
#pragma warning(disable: 4275) // non dll-interface class 'X' used as base for dll-interface class 'Y'
#include <vcruntime_typeinfo.h>
_STD_BEGIN
// size in pointers of std::function and std::any (roughly 3 pointers larger than std::string when building debug)
constexpr int _Small_object_num_ptrs = 6 + 16 / sizeof (void *);
#if !(_HAS_EXCEPTIONS)
// CLASS bad_cast
class _CRTIMP2_IMPORT bad_cast
: public exception
{ // base of all bad cast exceptions
public:
bad_cast(const char *_Message = "bad cast") noexcept
: exception(_Message)
{ // construct from message string
}
virtual ~bad_cast() noexcept
{ // destroy the object
}
protected:
virtual void _Doraise() const
{ // perform class-specific exception handling
_RAISE(*this);
}
};
// CLASS bad_typeid
class _CRTIMP2_IMPORT bad_typeid
: public exception
{ // base of all bad typeid exceptions
public:
bad_typeid(const char *_Message = "bad typeid") noexcept
: exception(_Message)
{ // construct from message string
}
virtual ~bad_typeid() noexcept
{ // destroy the object
}
protected:
virtual void _Doraise() const
{ // perform class-specific exception handling
_RAISE(*this);
}
};
class _CRTIMP2_IMPORT __non_rtti_object
: public bad_typeid
{ // report a non RTTI object
public:
__non_rtti_object(const char *_Message)
: bad_typeid(_Message)
{ // construct from message string
}
};
#endif /* _HAS_EXCEPTIONS */
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma pack(pop)
#pragma warning(pop)
#endif /* RC_INVOKED */
#endif // _TYPEINFO_
/*
* Copyright (c) Microsoft Corporation. ALL RIGHTS RESERVED.
* Modified January 1996 by P.J. Plauger
* Modified November 1998 by P.J. Plauger
* Consult your license regarding permissions and restrictions.
V6.50:0009 */
是class bad_cast定义前有这么一行: #if !(_HAS_EXCEPTIONS)
当在.Build.cs中添加bEnableExceptions = true后,编译时会添加参数:/EHsc,这将导致_HAS_EXCEPTIONS=1,#if !(_HAS_EXCEPTIONS)为false,从而最终class bad_cast不被包含。于是就导致unresolved external symbol。
修改方法也很简单,修改asio::ip::bad_address_cast的源代码,将std::bad_cast替换成std::exception即可:
//
// ip/bad_address_cast.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_IP_BAD_ADDRESS_CAST_HPP
#define ASIO_IP_BAD_ADDRESS_CAST_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <exception>
#include "asio/detail/push_options.hpp"
namespace asio {
namespace ip {
/// Thrown to indicate a failed address conversion.
class bad_address_cast : public std::exception
{
public:
/// Default constructor.
bad_address_cast() {}
/// Destructor.
virtual ~bad_address_cast() ASIO_NOEXCEPT_OR_NOTHROW {}
/// Get the message associated with the exception.
virtual const char* what() const ASIO_NOEXCEPT_OR_NOTHROW
{
return "bad address cast";
}
};
} // namespace ip
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_IP_ADDRESS_HPP