Reputation: 53119
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<uint32_t, std::string> 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:
logger.h
#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:
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
Upvotes: 1
Views: 2260
Reputation: 1528
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:
getThreadName()
getThreadName()
was declared non-constHowever, 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.
Upvotes: 2