经过一段时间在Linux和Mac上开发一个项目,最后我得到了一台带有Visual Studio 2015的Windows机器,我有两个通用的小库,一个名为Platform,另一个名为Foundation,当我尝试将Foundation库与Platform(已正确编译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)
Platform库中的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(导出)。
答案 0 :(得分:1)
他们都正确设置了__declspec(导出)
这不合适,他们都没有出口课程。只有DLL可以。
您的Trace :: sm_level变量存储在DLL的数据部分中。对于存在于同一模块中的代码,从同一模块读取和写入全局变量很简单,链接器知道变量的地址。但如果另一个模块中的代码需要访问它,那就不简单了。该地址不再可预测,DLL可能已从其首选基址重新定位。
需要额外的间接级别。一个指针,其目标地址固定为实际的DLL地址。编译器会自动处理这个问题,但 需要知道这不是&#34;正常&#34;全局变量。因此它将使用指针而不是尝试从其自己的数据部分读取它。
链接器抱怨的是什么,你的代码说它与你正在构建的模块相同,#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的项目,使用Project&gt;属性&gt; C / C ++&gt;预处理器&gt;预处理器定义,添加BUILDING_GAMECORE。在使用DLL的任何项目中都不需要进行任何更改,现在它们将看到__declspec(dllimport)。