How is it possible to declare and define object in a header file and use that in several statically built libs? Consider the following Headerfile in which I have implemented a class called Logger
which I intend on using like this in several libraries that I'm developing :
Utils::Logging::Logger.Display(true) << SOURCEINFO << "An exception occured: " << exp.what() << Utils::Logging::Save;
In other words, I'm trying to implement and use it kind of like how std::cout is used. As you can see below, I tried the following approaches and failed each time :
- Trying
static Log Logger;
results in :
Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1
- Doing
extern inline Log Logger;
results :
Severity Code Description Project File Line Suppression State
Error C7526 'Logger': inline variable is undefined FV D:\Codes\fac_ver\cpp\port\LibtorchPort\Dependencies\include\Utility.h 513
- And simply doing
extern Log Logger;
results in :
Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1
At this point I'm not sure if I'm trying something impossible or I simply doing it wrong.
Here is the Utility.h
:
#ifndef UTILITY_H
#define UTILITY_H
/* If we are we on Windows, we want a single define for it.*/
#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
#define _WIN32 //for both 32 and 64 bit. use _WIN64 for 64 bit only
#endif // _WIN32
#if defined(__GNUC__) || defined(unix) || defined(__unix__) || defined(__unix)
# define _UNIX
#endif // _UNIX
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <chrono>
#include <iomanip>
#include <type_traits>
#include <typeinfo>
namespace Utils
{
namespace Logging
{
#ifdef _WIN32
#define FUNC_SIG __FUNCSIG__
#endif
#ifdef _UNIX
#define FUNC_SIG __PRETTY_FUNCTION__
#endif
#define SOURCEINFO __FILE__<<":"<<__LINE__<<":"<<FUNC_SIG<<": "
template<typename... Args>
void LogMsg(std::string logFilename = "FVLog.txt", bool display = true, Args... args)
{
std::ofstream logFile;
logFilename = (logFilename == "") ? "FVLog.txt" : logFilename;
logFile.open(logFilename, std::ios::out | std::ios::app);
logFile << DateTime::Now(false);
if (display)
((std::cout << args), ...);
//cpp17 fold-expression:, recursively send each value to be saved in our stream
((logFile << args), ...);
}
enum class Mode
{
Save = 0,
Load = 1
};
static constexpr Mode Save = Mode::Save;
class Log
{
private:
std::stringstream stream;
bool isNew = true;
bool displayResults=false;
bool benchMode = false;
public:
template <typename T>
Log& operator<<(const T& value)
{
if (isNew)
{
stream << DateTime::Now(false) << " ";
isNew = false;
}
if constexpr (std::is_same<T, Logging::Mode>::value)
{
if (value == Mode::Save)
Save();
if (displayResults)
std::cout << std::endl;;
}
else
{
stream << value;
}
if (displayResults)
std::cout << stream.str();
return *this;
}
void Save(std::string logFilename= "FVLog.txt")
{
isNew = true;
if (benchMode)
return;
std::ofstream logFile;
logFilename = (logFilename == "") ? "FVLog.txt" : logFilename;
logFile.open(logFilename, std::ios::out | std::ios::app);
logFile << this->Get() << std::endl;
this->stream.clear();
this->stream.str("");
logFile.close();
}
Log& Display(bool showOutput, bool benchMode=false)
{
displayResults = showOutput;
this->benchMode = benchMode;
return *this;
}
std::string Get() const
{
return this->stream.str();
}
friend std::ostream& operator<<(std::ostream& os, const Log& log);
};
std::ostream& operator<<(std::ostream& os, const Log& log)
{
os << log.Get();
return os;
}
extern Log Logger;
}
}
#endif // !UTILITY_H
What am I missing here?
Update
Following @Peter's answer. I did the first option, that is in the header file we have Log Logger;
and then in one of the libs e.g. FV.cpp
I did :
#include <Utility.h>
...
Utils::Logging::Log Logger;
this fails with the following error :
Severity Code Description Project File Line Suppression State
Error LNK2005 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl Utils::Logging::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Utils::Logging::Log const &)" (??6Logging@Utils@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV23@AEBVLog@01@@Z) already defined in FV.lib(FV.obj) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\AntiSpoofer.lib(AntiSpoofer.obj) 1
Error LNK2001 unresolved external symbol "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\FV_Test_Lib\FV.lib(FV.obj) 1
Error LNK1120 1 unresolved externals FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1
Update 2
Here is a Minimal Repreducible Example : https://gofile.io/d/eJeADp