g++ 未定义对成员函数的引用,但仅在编译发布时

g++ undefined reference to member function, but only when compiling for release

我的 cli 应用程序中使用了一个日志 class。它基于此 post:http://www.drdobbs.com/cpp/logging-in-c/201804215?pgno=1

基本部分是

  1. 一个基本日志 class 处理日志级别,抓取当前时间等。它还包含一个 ostringstream,但无处输出。我将日志 class 拆分为没有模板部分的 "Log" 和 "Log2" ,后者在其析构函数中声明并定义了 ostringstream 的转储。
  2. 一个输出class,其中日志class的转储ostringstream实际上被发送到输出设备。目前 Output2STDOUT 是这个 class.
  3. 一个方便的单行宏,可以轻松地在我的代码中放置日志记录。

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&)'

你能帮我找出这里出了什么问题吗? 我的意思是:

所以我有点迷茫,不知道如何继续解决这个问题。

谢谢!

您可能需要从两个定义中删除 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文件中,只有在编译该文件时才可见,并且在该文件中没有使用,编译器将它们删除。