我的cli
应用程序中使用了一个日志类。它基于这篇文章:http://www.drdobbs.com/cpp/logging-in-c/201804215?pgno=1
基本部分是
Output2STDOUT
是此类。log.hpp 看起来像
#define STDOUT_LOG(level,text) \
{ \
if (level > STDOUTLog::ReportingLevel() || !Output2STDOUT::Stream()) ; \
else STDOUTLog().Get(level) << text ; \
}
class Output2STDOUT
{
public:
static FILE*& Stream();
static void Output(const std::string& msg);
};
class Log
{
public:
Log();
virtual ~Log(){}
std::ostringstream& Get(TLogLevel level = logINFO);
public:
static TLogLevel& ReportingLevel();
static std::string ToString(TLogLevel level);
static TLogLevel FromString(const std::string& level);
protected:
std::ostringstream os;
private:
Log(const Log&);
Log& operator =(const Log&);
};
template <typename T>
class Log2 : public Log
{
public:
~Log2()
{
os << std::endl;
T::Output(os.str());
}
};
class STDOUTLog : public Log2<Output2STDOUT> {};
template class Log2<Output2STDOUT>;
和 log.cpp 看起来像
#include <sys/time.h>
#include "log.hpp"
inline std::string NowTime()
{
char buffer[11];
time_t t;
time(&t);
//tm r = {0};
tm r = {0,0,0,0,0,0,0,0,0,0,0};
strftime(buffer, sizeof(buffer), "%X", localtime_r(&t, &r));
struct timeval tv;
gettimeofday(&tv, 0);
char result[100] = {0};
sprintf(result, "%s.%03ld", buffer, (long)tv.tv_usec / 1000);
return result;
}
Log::Log()
{
os.setf(std::ios::fixed);
os.precision(8);
}
std::ostringstream& Log::Get(TLogLevel level)
{
os << "- " << NowTime();
os << " " << ToString(level) << ": ";
return os;
}
TLogLevel& Log::ReportingLevel()
{
static TLogLevel reportingLevel = logDEBUG4;
return reportingLevel;
}
std::string Log::ToString(TLogLevel level)
{
static const char * const buffer[] = {"ERROR", "WARNING", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4"};
return buffer[level];
}
TLogLevel Log::FromString(const std::string& level)
{
if (level == "DEBUG4")
return logDEBUG4;
if (level == "DEBUG3")
return logDEBUG3;
if (level == "DEBUG2")
return logDEBUG2;
if (level == "DEBUG1")
return logDEBUG1;
if (level == "DEBUG")
return logDEBUG;
if (level == "INFO")
return logINFO;
if (level == "WARNING")
return logWARNING;
if (level == "ERROR")
return logERROR;
//Log<T>().Get(logWARNING) << "Unknown logging level '" << level << "'. Using INFO level as default.";
return logINFO;
}
//----------------------------------------------------------------------
inline FILE*& Output2STDOUT::Stream()
{
static FILE* pStream = stdout;
return pStream;
}
inline void Output2STDOUT::Output(const std::string& msg)
{
FILE* pStream = Stream();
if (!pStream)
return;
fprintf(pStream, "%s", msg.c_str());
fflush(pStream);
}
以及任何其他文件#include "log.hpp"
并将其用作
STDOUT_LOG(logWARNING, "this is a log message of level WARNING.");
上面的代码在调试模式下编译良好,但在发布时不编译。我使用自定义makefile,唯一的区别是我删除了-g
并在选项中添加了-O2
。
链接命令如下所示:
g++ -O2 -Wall -Wextra -pedantic -std=c++11 -DOSC_COM -DENOSE_ON_SOCKET -I../oscpack obj_rel/indicators.opp obj_rel/threadedinput.opp obj_rel/signals.opp obj_rel/threadedserialport.opp obj_rel/core_enose.opp obj_rel/main_enose.opp obj_rel/serialport.opp obj_rel/cppthread.opp obj_rel/sensor.opp obj_rel/timer.opp obj_rel/log.opp obj_rel/threadedrrdupd.opp obj_rel/threaded_tcp_client.opp obj_rel/bufferedwriter.opp obj_rel/alarm.opp obj_rel/messenger.opp -o "enalu_rel" -L../oscpack -pthread -lgsl -lgslcblas -lm -lrrd_th -lconfig++ -loscpack
所以log.opp确实存在。但我仍然可以从使用宏
的所有文件中获取indicators.cpp:(.text+0x3709): undefined reference to `Output2STDOUT::Stream()'
indicators.cpp:(.text+0x384c): undefined reference to `Output2STDOUT::Output(std::string const&)'
你能帮我辨别一下这里有什么问题吗? 我的意思是:
Output2STDOUT不是模板类,因此符号位于log.opp
中$ nm obj_rel/log.opp |grep Stream
0000000000000000 u _ZGVZN13Output2STDOUT6StreamEvE7pStream
0000000000000000 u _ZZN13Output2STDOUT6StreamEvE7pStream
$ nm obj_rel/log.opp |grep Output
0000000000000000 u _ZGVZN13Output2STDOUT6StreamEvE7pStream
0000000000000500 T _ZN10Output2OSC6OutputERKSs
0000000000000000 W _ZN4Log2I13Output2STDOUTED0Ev
0000000000000000 W _ZN4Log2I13Output2STDOUTED1Ev
0000000000000000 W _ZN4Log2I13Output2STDOUTED2Ev
0000000000000000 n _ZN4Log2I13Output2STDOUTED5Ev
0000000000000000 V _ZTI4Log2I13Output2STDOUTE
0000000000000000 V _ZTS4Log2I13Output2STDOUTE
0000000000000000 V _ZTV4Log2I13Output2STDOUTE
0000000000000000 u _ZZN13Output2STDOUT6StreamEvE7pStream
所以我很失落,不知道如何解决这个问题。
谢谢!
答案 0 :(得分:3)
您可能需要从两个定义中删除inline
:
FILE*& Output2STDOUT::Stream()
{
static FILE* pStream = stdout;
return pStream;
}
void Output2STDOUT::Output(const std::string& msg)
{
FILE* pStream = Stream();
if (!pStream)
return;
fprintf(pStream, "%s", msg.c_str());
fflush(pStream);
}
可能发生的事情是,当您编译DEBUG版本时,编译器不会内联函数,也不会删除生成的代码的未使用函数。
但是在编译RELEASE版本时,由于这些内联函数位于CPP文件中,因此只有在编译该文件时才可见,并且由于它们未从该文件中使用,编译器会将其删除。