0

I have several libraries that I want to statically link together. Let's call them Lib1, Lib2, Lib3 and Lib4. Lib4 uses Lib1 and Lib3 (Lib1 internally uses Lib2).

I can easily create the DLLs and all work just fine. the issue however is, when I try to build them as static libs I get the already defined objects error which are given bellow.

I get these errors when I include Utility.h header file which contains some utility functions that can be used in several libs. For now I am forced to not use it in except like Lib4 in order to not face any issues in static builds. This is not good and just nullifies the whole point of creating Utility.h. I did include the header guards, but it seems its irrelevant here and does not help.

What are my options here? How should I go about this to get this solved? Errors I get:

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   LNK2005 "class Utils::Logging::Log Utils::Logging::Logger" (?Logger@Logging@Utils@@3VLog@12@A) 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   LNK2005 "class std::vector<class std::filesystem::path,class std::allocator<class std::filesystem::path> > __cdecl Utils::GetFileNames(class std::vector<class std::filesystem::path,class std::allocator<class std::filesystem::path> >)" (?GetFileNames@Utils@@YA?AV?$vector@Vpath@filesystem@std@@V?$allocator@Vpath@filesystem@std@@@3@@std@@V23@@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   LNK2005 "class std::vector<class std::filesystem::path,class std::allocator<class std::filesystem::path> > __cdecl Utils::GetFiles(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,bool)" (?GetFiles@Utils@@YA?AV?$vector@Vpath@filesystem@std@@V?$allocator@Vpath@filesystem@std@@@3@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@3@_N@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   LNK2005 "class std::vector<class std::filesystem::path,class std::allocator<class std::filesystem::path> > __cdecl Utils::GetFiles(class std::filesystem::path,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,bool)" (?GetFiles@Utils@@YA?AV?$vector@Vpath@filesystem@std@@V?$allocator@Vpath@filesystem@std@@@3@@std@@Vpath@filesystem@3@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@3@_N@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   LNK2005 "class std::vector<class std::filesystem::path,class std::allocator<class std::filesystem::path> > __cdecl Utils::GetDirectories(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool)" (?GetDirectories@Utils@@YA?AV?$vector@Vpath@filesystem@std@@V?$allocator@Vpath@filesystem@std@@@3@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@_N@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   LNK2005 "bool __cdecl Utils::NotIn(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?NotIn@Utils@@YA_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@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   LNK2005 "double __cdecl Utils::Timer::GetSeconds(class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >,class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >)" (?GetSeconds@Timer@Utils@@YANV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@0@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   LNK2005 "double __cdecl Utils::Timer::GetElapsedTime(class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,enum Utils::Timer::Duration,bool)" (?GetElapsedTime@Timer@Utils@@YANV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@W4Duration@12@_N@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   LNK2005 "double __cdecl Utils::Timer::GetElapsedNanoSeconds(class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >)" (?GetElapsedNanoSeconds@Timer@Utils@@YANV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@@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   LNK2005 "double __cdecl Utils::Timer::GetElapsedMicroSeconds(class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >)" (?GetElapsedMicroSeconds@Timer@Utils@@YANV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@@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   LNK2005 "double __cdecl Utils::Timer::GetElapsedMilliSeconds(class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > >)" (?GetElapsedMilliSeconds@Timer@Utils@@YANV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@@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   LNK2005 "class std::chrono::time_point<struct std::chrono::steady_clock,class std::chrono::duration<__int64,struct std::ratio<1,1000000000> > > __cdecl Utils::Timer::Now(void)" (?Now@Timer@Utils@@YA?AV?$time_point@Usteady_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@XZ) 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   LNK2005 "void __cdecl Utils::DateTime::Sleep(unsigned long)" (?Sleep@DateTime@Utils@@YAXK@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   LNK2005 "double __cdecl Utils::DateTime::GetSeconds(class std::chrono::time_point<struct std::chrono::system_clock,class std::chrono::duration<__int64,struct std::ratio<1,10000000> > >,class std::chrono::time_point<struct std::chrono::system_clock,class std::chrono::duration<__int64,struct std::ratio<1,10000000> > >)" (?GetSeconds@DateTime@Utils@@YANV?$time_point@Usystem_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0JIJGIA@@std@@@23@@chrono@std@@0@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   LNK2005 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Utils::DateTime::Now(bool)" (?Now@DateTime@Utils@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_N@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   LNK2005 "class std::chrono::time_point<struct std::chrono::system_clock,class std::chrono::duration<__int64,struct std::ratio<1,10000000> > > __cdecl Utils::DateTime::Now(void)" (?Now@DateTime@Utils@@YA?AV?$time_point@Usystem_clock@chrono@std@@V?$duration@_JU?$ratio@$00$0JIJGIA@@std@@@23@@chrono@std@@XZ) 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   LNK2005 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Utils::operator*(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int)" (??DUtils@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V12@I@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   LNK1169 one or more multiply defined symbols found  FV_Test_Lib D:\Codes\rika\cpp\port\LibtorchPort\x64\Release\FV_Test_Lib.exe 1   

And this is how my Utility.h looks like :

#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 <algorithm> 
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <chrono>
#include <thread>
#include <cmath>
#include <iomanip>
#include <type_traits>
#include <bitset>
#include <typeinfo>

using namespace std::chrono;
using namespace std::chrono_literals;
typedef std::chrono::system_clock Time;
typedef std::chrono::milliseconds ms;
typedef std::chrono::duration<float> fsec;

#include <filesystem>
namespace fs = std::filesystem;

namespace Utils
{
    const double PI = 3.141592653589793;
    const double e = 2.7182818284590452353602874713527;
    typedef unsigned char byte;

    // to compare floats
    template<class T>
    typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
    {
        // the machine epsilon has to be scaled to the magnitude of the values used
        // and multiplied by the desired precision in ULPs (units in the last place)
        return std::fabs(x - y) <= std::numeric_limits<T>::epsilon() * std::fabs(x + y) * ulp
            // unless the result is subnormal
            || std::fabs(x - y) < std::numeric_limits<T>::min();
    }

    //overloading the * operator for string, so that we can do "*"*5 
    // like the way we can in python
    std::string operator * (std::string a, unsigned int b)
    {
        std::string output = "";
        while (b--) {
            output += a;
        }
        return output;
    }

    //ref https://github.com/Coderx7/C-Python-like-Decorators
    template<typename F>
    auto BenchmarkFunc(const F& func)
    {
        return [func](auto&&... args)
        {
            std::cout << "*******" << std::endl;
            auto start = std::chrono::high_resolution_clock::now();
            auto var = func(std::forward<decltype(args)>(args)...);
            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> elapsed_ms = end - start;
            std::cout << "elapsed time : " << elapsed_ms.count() << " ms" << std::endl;
            std::cout << std::flush << "\n*******" << std::endl;
            return var;
        };
    }

    template<typename F>
    auto BenchmarkMethod(const F& func)
    {
        return [func](auto& obj, std::string msg, auto&&... args)
        {
            std::cout << "*******" << msg << "*******" << std::endl;
            auto start = std::chrono::high_resolution_clock::now();
            auto var = (obj.*func)(std::forward<decltype(args)>(args)...);
            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> elapsed_ms = end - start;
            std::cout << "elapsed time : " << elapsed_ms.count() << " ms" << std::endl;
            std::cout << std::flush << "**************" << std::string("*") * msg.size() << std::endl;
            return var;
        };
    }

    namespace DateTime
    {
        std::chrono::system_clock::time_point Now()
        {
            return std::chrono::system_clock::now();
        }

        std::string Now(bool time_only)
        {
            auto current_time = Now();
            std::time_t t = std::chrono::system_clock::to_time_t(current_time);
            std::tm* tm = localtime(&t);
            std::stringstream ss;
            //%T is  HH:mm:ss  and %F is YYYY-MM-DD 
            std::string mode = time_only ? "%T" : "%F %T";
            ss << std::put_time(tm, mode.c_str()); // a %b %d %H:%M:%S %Y

            return ss.str();
        }

        /// <summary>
        /// Returns the difference between two time points in seconds
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        double GetSeconds(std::chrono::system_clock::time_point start, std::chrono::system_clock::time_point end)
        {
            std::chrono::duration<double, std::milli> elapsed_ms = end - start;
            return elapsed_ms.count() * 1000;
        }

        /// <summary>
        /// Sleeps for the given duration in milliseconds
        /// </summary>
        /// <param name="duration"></param>
        void Sleep(unsigned long duration)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(duration));
        }
    }

    
    /// @brief deals with machine level times used for benchmarking mostly
    namespace Timer
    {
        enum class Duration
        {
            Milli = 0,
            Micro = 1,
            Nano = 2
        };

        std::chrono::steady_clock::time_point Now()
        {
            //high_resolution_clock can be an alias to an 
            //arbitary number of classes such as steady_clock , system_clock 
            //or something else. on windows and MSVCP its steady_clock but in G++
            //linux its an alias for system_clock. 
            return std::chrono::steady_clock::now();
        }

        double GetElapsedMilliSeconds(std::chrono::steady_clock::time_point start)
        {
            auto end = std::chrono::steady_clock::now();
            std::chrono::duration<double, std::milli> milliseconds = end - start;
            return milliseconds.count();
        }

        double GetElapsedMicroSeconds(std::chrono::steady_clock::time_point start)
        {
            auto end = std::chrono::steady_clock::now();
            std::chrono::duration<double, std::micro> microseconds = end - start;
            return microseconds.count();
        }

        double GetElapsedNanoSeconds(std::chrono::steady_clock::time_point start)
        {
            auto end = std::chrono::steady_clock::now();
            std::chrono::duration<double, std::nano> nanoseconds = end - start;
            return nanoseconds.count();
        }

        /// <summary>
        /// Retruns the elapsed time in milliseconds from the given starting point
        /// to the current moment.
        /// </summary>
        /// <param name="start">starting time_point</param>
        /// <param name="message">message to display before showing the actual elapsed time</param>
        /// <param name="displayResult">whethr to display the result</param>
        /// <returns>elapsed milliseconds</returns>
        double GetElapsedTime(std::chrono::steady_clock::time_point start, std::string message = "elapsed time : ", Duration duration = Duration::Milli, bool displayResult = true)
        {
            auto end = std::chrono::steady_clock::now();
            double elapsedTime = 0;
            std::string symbol = " ms";

            switch (duration)
            {
                case Utils::Timer::Duration::Milli:
                    elapsedTime = Utils::Timer::GetElapsedMilliSeconds(start);
                    break;
                case Utils::Timer::Duration::Micro:
                    elapsedTime = Utils::Timer::GetElapsedMicroSeconds(start);
                    //micro second symbol is c2b5 which would be \xc2\xb5 but I used the textual
                    //symbol to be more readable. the console needs to support unicode (utf8) though!
                    symbol = " µs";
                    break;
                case Utils::Timer::Duration::Nano:
                    elapsedTime = Utils::Timer::GetElapsedNanoSeconds(start);
                    symbol = " ns";
                    break;
                default:
                    throw std::runtime_error("Duration not supported");
            }

            if (displayResult)
            {    //std::cout takes : 0.3425 - 0.9 ms
                std::cout << message << elapsedTime << symbol << std::endl;
            }

            return elapsedTime;
        }
        
        double GetSeconds(std::chrono::steady_clock::time_point start, std::chrono::steady_clock::time_point end)
        {
            std::chrono::duration<double, std::milli> elapsed_ms = end - start;
            return elapsed_ms.count() * 1000;
        }
    }

    /// <summary>
    /// Checks whether the input value exists in  the given list
    /// </summary>
    /// <typeparam name="F"></typeparam>
    /// <param name="value">value to be searched for</param>
    /// <param name="list">the list to be searched in</param>
    /// <returns>true if the value IS found, false otherwise</returns>
    template<typename F>
    bool In(F value, std::vector<F>& list)
    {
        auto it = std::find(list.begin(), list.end(), value);
        return (it != list.end());
    }

    template<typename F>
    int In(std::vector<F> smallList, std::vector<F>& largeList, bool returnDiff = false)
    {
        int status = returnDiff ? 0 : 1;
        for (auto v : smallList)
        {
            auto it = std::find(largeList.begin(), largeList.end(), v);
            if (returnDiff)
            {
                status += (it != largeList.end());
            }
            else
            {
                status *= (it != largeList.end());
            }
        }
        if (returnDiff)
        {
            return largeList.size() - status;
        }
        else
        {
            return status;
        }
    }

    /// <summary>
    /// Checks whether the input value does "Not" exists in the given list
    /// </summary>
    /// <typeparam name="F"></typeparam>
    /// <param name="value">value to be searched for</param>
    /// <param name="list">the list to be searched in</param>
    /// <returns>true if the value is Not found, false otherwise</returns>
    template<typename F>
    bool NotIn(F value, std::vector<F>& list)
    {
        return !In(value, list);
    }

    bool NotIn(std::string value_to_search, std::string string_to_search_in)
    {
        return string_to_search_in.find(value_to_search) != std::string::npos;
    }

    std::vector<fs::path> GetDirectories(std::string dirPath, bool nameOnly=true)
    {
        std::vector<fs::path> dirs;
        for (auto p : fs::directory_iterator(dirPath))
        {
            if (fs::is_directory(p))
            {
                if (nameOnly)
                    dirs.emplace_back(p);
                else
                    dirs.emplace_back(fs::path(dirPath) / p);
            }
        }
        return dirs;
    }

    std::vector<fs::path> GetFiles(fs::path directoryPath, std::vector<std::string> extensions = { ".jpg" }, bool excludeExtensions = false)
    {
        std::vector<fs::path> files;
        fs::path file;
        for (auto& p : fs::directory_iterator(directoryPath))
        {
            file = p.path();
            if (fs::is_regular_file(file))
            {
                if (excludeExtensions)
                {
                    if (NotIn(file.extension().string(), extensions))
                    {
                        files.emplace_back(file);
                    }
                }
                else if (In(file.extension().string(), extensions))
                {
                    files.emplace_back(file);
                }
            }
        }
        return files;
    }

    std::vector<fs::path> GetFiles(std::string directoryPath, std::vector<std::string> extensions = { ".jpg" }, bool exclude_extensions = false)
    {
        return GetFiles(fs::path(directoryPath), extensions, exclude_extensions);
    }

    std::vector<fs::path> GetFileNames(std::vector<fs::path> files)
    {
        std::vector<fs::path> res;
        for (auto& f : files)
        {
            res.emplace_back(f.filename());
        }
        return res;
    }


    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;
       }
       
       Log Logger;
    }
}
#endif // !UTILITY_H

Update

Thanks @Scheff and inlining all the functions in the header file, their respective linker error is gone now however, the linker error concerning Logger object in Logging namespace still exists. even making it static doesn't do any good and still I get 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

Using extern inline Log Logger; now results in the following error:

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 

halfer
  • 19,824
  • 17
  • 99
  • 186
Hossein
  • 24,202
  • 35
  • 119
  • 224
  • 1
    Are you sure all the static libraries have been built with the exact same compiler version and compiler flags? That linker error is expected and inevitable if the duplicated symbols ended up with differing definitions. It should fold perfectly fine if compiled identically. – Ext3h Sep 30 '20 at 05:28
  • They are build every time in succession. I rebuild the FV_Test which is a test t hat uses `FV.lib` (Lib4 in my example) and then it goes and builds AntiSpoofer, Blinker, Detector, etc. to my knowledge they all use C++17. – Hossein Sep 30 '20 at 05:30
  • and by the way, this is how headers look like : https://paste.ee/p/NE7KP in case its of any use. (all libs has the same format ) – Hossein Sep 30 '20 at 05:38
  • Plain functions, inline implemented in the header... Shouldn't they be remarked as `inline`? AFAIK, this is how you request the compiler to sort out duplicates. The same is true for global (`const`) variables (not only declared but) defined in the header. – Scheff's Cat Sep 30 '20 at 06:05
  • 1
    FYI: [SO: When should I write the keyword 'inline' for a function/method?](https://stackoverflow.com/a/1759575/7478597) – Scheff's Cat Sep 30 '20 at 06:08
  • @Scheff thanks a lot. I think I actually did that to no avail. but I'll give it a try again maybe I missed something there. I'll update how it goes – Hossein Sep 30 '20 at 06:17
  • @Scheff You were right. adding inline did remove lots of linker errors(concerning functions). and the only linker error I get now pertains to the Logger object thats defined in `Logging` namespace. I set it as static, but that doesnt seem to work! what should I be doing about this one? – Hossein Sep 30 '20 at 07:10
  • About `Log Logger;`, I'm a bit uncertain. It could be a declaration or a definition (with default construction). How about `extern inline Log Logger;`? (And, there shouldn't be any definition in any C++ file in this case, of course.) – Scheff's Cat Sep 30 '20 at 07:15
  • 1
    Concerning _even making it static doesnt do any good_: `static` is a bad idea for global variables. It causes a separate instance in each Translation Unit which includes this header. (It's not like `static` member variables.) – Scheff's Cat Sep 30 '20 at 07:20
  • @Scheff I did as you said, and now I get `Severity Code Description Project File Line Suppression State Error C7526 'Logger': inline variable is undefined FV D:\Codes\rika\cpp\port\LibtorchPort\Dependencies\include\Utility.h 513 ` error ! – Hossein Sep 30 '20 at 07:21
  • Damn, this drives me to the borders of my (foggy) knowledge... Ehm... `extern Log Logger; inline Log Logger{};` Maybe, google for `c++ extern inline variables`. I'm quite sure you're not the first one with this issue. (I believe I already saw some hits when I googled myself this morning.) – Scheff's Cat Sep 30 '20 at 07:23
  • @Scheff Thanks a lot greatly appreciate your kind help on this. I had a look at how cout was defined and it was sth like :`__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2_IMPORT ostream cout;` basically it was :`extern __declspec(dllimport) ostream cout;` I wonder why mine cant be worked out like this. I'll dig deeper and hopefully find something about this. Thanks again – Hossein Sep 30 '20 at 07:34
  • 1
    The `__declspec(dllimport)` concerns DLLs only but shouldn't affect static linking. The usual way as I know it (before I became aware of `inline` variables): declare a global var. `extern` in the header. (If it's a DLL then `__declspec(dllexport)` when the DLL itself is built, otherwise `__declspec(dllimport)`, or `/* no __declspec */` for static libraries - achieved with the "usual" macro trickery.) The definition goes into the Translation Unit (aka. C++ file). So, it is ensured that there will be only one definition. But what if the transl. unit appears in two static libraries? (Does it?) – Scheff's Cat Sep 30 '20 at 07:44
  • No mind. A translation unit shouldn't appear in two static libraries. ;-) – Scheff's Cat Sep 30 '20 at 07:46

0 Answers0