繁体   English   中英

类中受保护的静态枚举的链接器错误,甚至已经定义

[英]Linker error of an protected static enum from a class, even being defined already

在Linux和Mac上开发项目一段时间后,终于有了一台装有Visual Studio 2015的Windows机器,我有两个通用的小库,一个叫Platform,另一个叫Foundation,当我尝试链接Foundation时出现问题具有Platform的库(平台库已正确编译,没有特殊警告)输出以下链接器错误:

(我省略了其中一些)

1>TUID.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Units.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Wildcard.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>RPC.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>SmartPtr.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Stream.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>String.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Natural.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Numeric.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@1W4Type@TraceLevels@2@A)
1>Profile.obj : error LNK2001: unresolved external symbol "protected: static enum GameCore::TraceLevels::Type GameCore::Trace::sm_level" (?sm_level@Trace@GameCore@@@@1W4Type@TraceLevels@2@A)

平台库中Trace.h的以下头文件如下:

namespace TraceLevels
{
  enum Type
  {
    Debug,    ///< Debug logging messages.
    Info,     ///< General info messages.
    Warning,  ///< Warning messages.
    Error,    ///< Critical error messages.
  };
}
typedef GameCore::TraceLevels::Type TraceLevel;

/// Trace interface.
class GAMECORE_PLATFORM_API Trace
{
public:
  /// Default size for formatted trace message buffers without requiring dynamic memory allocation.
  static const size_t DEFAULT_MESSAGE_BUFFER_SIZE = 1024;

  /// @name Logging Interface
  //@{
  static void SetLevel( TraceLevel level );
  static inline TraceLevel GetLevel();

  static void Output( TraceLevel level, const char* pFormat, ... );
  static void OutputVa( TraceLevel level, const char* pFormat, va_list argList );
  //@}

protected:
  /// Current logging level.
  static TraceLevel sm_level; // This is the missing symbol which the linker complain

  /// Logging level of the last message.
  static TraceLevel sm_lastMessageLevel;

  /// True if logging just started a fresh line.
  static bool sm_bNewLine;

  /// @name Logging Implementation
  //@{
  static void OutputImplementation( const char* pMessage );
  //@}

  /// @name Static Utility Functions
  //@{
  static const char* GetLevelString( TraceLevel level );
  //@}
};

并将其定义正确添加到其源文件(Trace.cpp)中

using namespace GameCore;

GameCore::TraceLevel Trace::sm_level = GameCore::TraceLevels::Info;
GameCore::TraceLevel Trace::sm_lastMessageLevel = GameCore::TraceLevels::Debug;
bool GameCore::Trace::sm_bNewLine = true;

我正在使用CMake生成我的解决方案文件,输出.lib和.dll位于lib \\和bin \\目录中,位于根构建目录(源代码之外)内,并将lib \\设置为链接目录(使用cmake link_directories)

他们两个都在两个库中正确设置了__declspec(export)。

他们两个都正确设置了__declspec(export)

那是不适当的,因为它们都不都导出类。 只有DLL可以。

您的Trace :: sm_level变量存储在DLL的数据部分中。 对于驻留在同一模块中的代码,从同一模块读取和写入全局变量很简单,链接器知道该变量的地址。 但是,如果另一个模块中的代码需要访问它,这并不简单。 该地址不再可预测,该DLL可能已从其首选的基地址重定位。

需要额外的间接级别。 一个指针,其目标地址固定为实际的DLL地址。 编译器会自动进行处理,但是确实需要知道它不再是“正常”的全局变量。 因此,它将使用指针,而不是尝试从其自己的数据部分读取指针。

链接器在抱怨什么,您的代码说它在您正在构建的同一模块中,#include这样做了。 但是链接器在您正在构建的模块的数据部分中找不到Trace :: sm_level变量。 当然,这是准确的,它存在于DLL中。

您可以通过声明类__declspec(dllimport)来告知编译器。 现在知道了。

我们看不到GAMECORE_PLATFORM_API的外观,但这是存在问题的通心粉。 它看起来应该像这样:

#if BUILDING_GAMECORE
#  define GAMECORE_PLATFORM_API __declspec(dllexport)
#else
#  define GAMECORE_PLATFORM_API __declspec(dllimport)
#endif

并更改构建DLL的项目,使用“项目”>“属性”>“ C / C ++”>“预处理器”>“预处理器定义”,添加BUILDING_GAMECORE。 在使用DLL的任何项目中都不需要进行任何更改,它们现在将看到__declspec(dllimport)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM