Wednesday 14 August 2019

c++ - Unresolved external symbol for classmethod that isn't even referenced

Answer


Answer




I'm creating a simple debug thread name database (because you can't give thread a name in windows, you can only send that name to debugger). I have this header file:



threadname.h



class ThreadNameMap {

public:
void setThreadName( uint32_t id, const std::string &name );

std::string getThreadName( const uint32_t id ) const;
// If ID given as string
std::string getThreadName( const std::string id ) const;
// If no ID given, current ID is used
std::string getThreadName( ) const;

// A singleton getter

static ThreadNameMap* ThreadNameMap::getInstance();
// Static getters that use the singleton
static std::string getName( const uint32_t id );
static std::string getName( const std::string id );
static std::string getName( );
private:
ThreadNameMap() {maxNameLength = 16;};
int maxNameLength;
// Map of ids and names
std::map names;

};


This is the implementation:



threadname.cpp




ThreadNameMap* ThreadNameMap::getInstance() {
static ThreadNameMap inst = ThreadNameMap();

return &inst;
}

std::string ThreadNameMap::getName( const uint32_t id ) { return getInstance()->getThreadName(id); }
std::string ThreadNameMap::getName( const std::string id ) { return getInstance()->getThreadName(id); }
std::string ThreadNameMap::getName( ) { return getInstance()->getThreadName(); }

void ThreadNameMap::setThreadName( uint32_t id, const std::string &name ) {
setThreadName_private(id, name.c_str());
if(id==-1)

id = boostThreadId();
names[id] = name;
}

std::string ThreadNameMap::getThreadName( const uint32_t id ) const {
if( names.count( id )>0)
return names.at(id);
else
return "";
}

std::string ThreadNameMap::getThreadName( const std::string id ) const {
uint32_t threadNumber = 0;
sscanf(id.c_str(), "%lx", &threadNumber);
return getThreadName(threadNumber);
}
/** THIS ONE IS REPORTED AS UNREFERENCED!!! **/
std::string ThreadNameMap::getThreadName( ) const {
return getThreadName(boostThreadId());
}



I use singleton interface and I access it like this in my logger header file:






#include "... path .../setthreadname.h"
#define LOGMTDBG_tmp(debuglevel, logstream) LOGMT(debugLevel(debuglevel) << datetimeEx << ' ' << ThreadNameMap::getName() << ' ' << __FUNCTION__ << ' ' << logstream)


Logger is included in many and many other cpp and h files - wherever needed. And some of those report unreferenced symbol:





Error 13 error LNK2001: unresolved external symbol "public: class std::basic_string,class std::allocator > __cdecl ThreadNameMap::getThreadName(void)" (?getThreadName@ThreadNameMap@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) D:\techsys\RomeoTT\Source\RunWindow.obj
Error 14 error LNK2019: unresolved external symbol "public: class std::basic_string,class std::allocator > __cdecl ThreadNameMap::getThreadName(void)" (?getThreadName@ThreadNameMap@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function "private: void __cdecl BaseRunPresenter::MessageHandler(class boost::shared_ptr)" (?MessageHandler@BaseRunPresenter@@AEAAXV?$shared_ptr@USMSSBase@@@boost@@@Z) D:\techsys\RomeoTT\Source\BaseRunPresenter.obj
Error 15 error LNK2001: unresolved external symbol "public: class std::basic_string,class std::allocator > __cdecl ThreadNameMap::getThreadName(void)" (?getThreadName@ThreadNameMap@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) D:\techsys\RomeoTT\Source\BaseRunView.obj
Error 16 error LNK2001: unresolved external symbol "public: class std::basic_string,class std::allocator > __cdecl ThreadNameMap::getThreadName(void)" (?getThreadName@ThreadNameMap@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) D:\techsys\RomeoTT\Source\XmlSestavaRunPresenter.obj
Error 17 error LNK2001: unresolved external symbol "public: class std::basic_string,class std::allocator > __cdecl ThreadNameMap::getThreadName(void)" (?getThreadName@ThreadNameMap@@QEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) D:\techsys\RomeoTT\Source\RunSestavaFrame.obj
Error 18 error LNK2019: unresolved external symbol "class std::basic_string,class std::allocator > __cdecl getThreadName(void)" (?getThreadName@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function "public: void __cdecl SestavaHeader::DataSource::Dump2LOG(void)const " (?Dump2LOG@DataSource@SestavaHeader@@QEBAXXZ) D:\techsys\RomeoTT\Source\SestavaDataSource.obj


I searched the project, but there is not a single reference of any of the class non static methods, only the one in logger.h.




I checked many of the Unreferenced external symbol questions, but they all came with two possibilities:




  1. dll is missing - well, I'm not using any dll for this obviously

  2. Function was declared but not implemented - in the code above you can see both declaration and implementation and they are matching



So why would linker complain about method that is not even referenced? I tried to alter const and move static method in .h file, nothing helped. I'm really desperate now.




Edit: Visual studio linker flags:



/OUT:"D:\techsys\RomeoTT\PROJECT\PROJECTd.exe" /INCREMENTAL /NOLOGO /LIBPATH:"..\..\libs\openssl64\lib\VC\static" /LIBPATH:"..\..\libs\boost155\stage\lib64bit" /LIBPATH:"C:\Qt\5.3.0-64\qtbase\lib" "libeay32MTd.lib" "Graph64d.lib" "HelpLib64d.lib" "version.lib" "qtmaind.lib" "Qt5Cored.lib" "Qt5Guid.lib" "Qt5Multimediad.lib" "Qt5Sqld.lib" "Qt5PrintSupportd.lib" "Qt5Svgd.lib" "Qt5Widgetsd.lib" "Qt5Xmld.lib" "Qt5XmlPatternsd.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"D:\techsys\XXXX\obj\x64\XXXX\Debug\XXXXXd.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"D:\techsys\XXXXX\XXXXX64\XXXXXd.pdb" /SUBSYSTEM:WINDOWS /OPT:NOREF /PGD:"D:\techsys\XXXX\XXXX64\XXXXXd.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X64 /ERRORREPORT:NONE 

Answer



You find the likely culprit by examining in detail the error messages (cleaned-up for lisibility):




Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in RunWindow.obj
Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in function "private: void stringBaseRunPresenter::MessageHandler(class boost::shared_ptr)" referenced in BaseRunPresenter.obj

Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in BaseRunView.obj
Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in XmlSestavaRunPresenter.obj
Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in RunSestavaFrame.obj
Unresolved external symbol "string stringThreadNameMap::getThreadName(void)" referenced in function "public: void stringSestavaHeader::DataSource::Dump2LOG(void)const " SestavaDataSource.obj


What these linker errors say is that:




  • Some object files (RunWindow.obj, BaseRunPresenter.obj...) contain a reference to a non-const method getThreadName()


  • It implies that these object files have been generated from source files at a time when the method getThreadName() was declared non-const



However, the declaration of getThreadName() is now const:



std::string getThreadName( ) const;


Thus, each of these object files have been compiled based on an obsolete declaration of getThreadName() and should be recompiled. If possible, as there may be other (undetected) inconsistency errors, you should perform a full rebuild.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...