对Logger :: getInstance()的未定义引用 - 但仅在某些情况下

时间:2015-09-03 09:21:33

标签: c++ c++11 gcc undefined-reference log4cplus

我使用的是log4cplus(从当前的git master编译),但我得到链接器未定义的引用错误。但是,这些错误仅在某些类发生

一般来说,每个班级都有以下形式:

标题(.h)

// ...
#include <log4cplus/loggingmacros.h>
// ...    
// namespace(s)

class Example
{
public:
    // ...
private:
    // ...
    static const log4cplus::Logger logger;
};

来源(.cpp)

// includes

// namespace(s)

// implementations

const log4cplus::Logger Example::logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("Example"));

用法

记录器在类中使用,如下所示:

LOG4CPLUS_WARN(logger,  "Ha, ha – whatever you try I wont work!");

编译工作时,链接器会为

引发未定义的引用错误
log4cplus::Logger::getInstance(std::string const&)

log4cplus::detail::macro_forced_log(log4cplus::Logger const&, int, std::string const&, char const*, int, char const*)

对于某些课程。我已经从工作类中复制了记录器部件:结果相同。

由类成员替换静态记录器既不起作用 - getInstance()也找不到。

这个问题的解决方法是使用root-logger;这将编译/链接(即使getRoot()是同一个类的一部分!?):

const log4cplus::Logger Example::logger = log4cplus::Logger::getRoot();

但是那时未定义的引用错误

log4cplus::detail::macro_forced_log(...)

为确保没有拼写错误,我已将这些宏用于声明/定义:

#define LOG_DECL(name)      static const log4cplus::Logger logger
#define LOG_DEF(name)       const log4cplus::Logger name::logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT(#name))

同样的结果,那些曾经工作过的人,以及那些没有......的人。

更多信息:

  1. 使用-llog4cplusSU(也使用log4cplusS测试)链接Log4cplus,并从它的git master
  2. 编译
  3. GCC 4.9 - 使用C ++ 11
  4. 用于构建项目的Eclipse CDT
  5. Log4cplus在主
  6. 中初始化
  7. 使用相同的编译器和标志
  8. 编译所有类
  9. 完全清理并构建项目
  10. 所有文件都以相同的方式编译/链接
  11. const / not const无效
  12. nm <NAME>.o | grep -i log4cplus的结果:

    工作对象

                     U _ZN9log4cplus6detail16macro_forced_logERKNS_6LoggerEiRKSbIwSt11char_traitsIwESaIwEEPKciSB_
    0000000000000000 W _ZN9log4cplus6detail17macros_get_loggerERKNS_6LoggerE
                     U _ZN9log4cplus6detail18get_macro_body_ossEv
                     U _ZN9log4cplus6Logger11getInstanceERKSbIwSt11char_traitsIwESaIwEE
                     U _ZN9log4cplus6LoggerC1ERKS0_
                     U _ZN9log4cplus6LoggerD1Ev
    00000000000002c8 r _ZN9log4cplusL13ALL_LOG_LEVELE
    00000000000002ac r _ZN9log4cplusL13OFF_LOG_LEVELE
    00000000000002bc r _ZN9log4cplusL14INFO_LOG_LEVELE
    00000000000002b8 r _ZN9log4cplusL14WARN_LOG_LEVELE
    00000000000002c0 r _ZN9log4cplusL15DEBUG_LOG_LEVELE
    00000000000002b4 r _ZN9log4cplusL15ERROR_LOG_LEVELE
    00000000000002b0 r _ZN9log4cplusL15FATAL_LOG_LEVELE
    00000000000002c4 r _ZN9log4cplusL15TRACE_LOG_LEVELE
    00000000000002cc r _ZN9log4cplusL17NOT_SET_LOG_LEVELE
                     U _ZNK9log4cplus6Logger12isEnabledForEi
    

    未定义的引用:

                     U _ZN9log4cplus6detail16macro_forced_logERKNS_6LoggerEiRKSsPKciS7_
    0000000000000000 W _ZN9log4cplus6detail17macros_get_loggerERKNS_6LoggerE
                     U _ZN9log4cplus6detail18get_macro_body_ossEv
                     U _ZN9log4cplus6Logger11getInstanceERKSs
                     U _ZN9log4cplus6LoggerC1ERKS0_
                     U _ZN9log4cplus6LoggerD1Ev
    00000000000001ec r _ZN9log4cplusL13ALL_LOG_LEVELE
    00000000000001d0 r _ZN9log4cplusL13OFF_LOG_LEVELE
    00000000000001e0 r _ZN9log4cplusL14INFO_LOG_LEVELE
    00000000000001dc r _ZN9log4cplusL14WARN_LOG_LEVELE
    00000000000001e4 r _ZN9log4cplusL15DEBUG_LOG_LEVELE
    00000000000001d8 r _ZN9log4cplusL15ERROR_LOG_LEVELE
    00000000000001d4 r _ZN9log4cplusL15FATAL_LOG_LEVELE
    00000000000001e8 r _ZN9log4cplusL15TRACE_LOG_LEVELE
    00000000000001f0 r _ZN9log4cplusL17NOT_SET_LOG_LEVELE
                     U _ZNK9log4cplus6Logger12isEnabledForEi
    

    失败的最小类

    //////////////////////// Header ////////////////////////
    namespace so {
    namespace example {
    
    class FailingExample
    {
    public:
        FailingExample(other_ns::Config* config, other_ns::Command* cmd);
        bool updateData(uint8_t* dataPtr, uint32_t dataSize);
        virtual ~FailingExample();
    
    private:
        static const log4cplus::Logger logger;
    };
    }}
    
    
    //////////////////////// Source ////////////////////////
    namespace so {
    namespace example {
    
    FailingExample::FailingExample(other_ns::Config* config, other_ns::Command* cmd)
    {
    }
    
    bool FailingExample::updateData(uint8_t* dataPtr, uint32_t dataSize)
    {
        return true;
    }
    
    FailingExample::~FailingExample()
    {
    }
    
    // Undefined reference to getInstance() here
    const log4cplus::Logger FailingExample::logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("FailingExample"));
    
    }}
    

1 个答案:

答案 0 :(得分:1)

经过一段时间的浏览,我找到了原因 - 以及解决方案。

Log4cplus使用char / std::stringwchar / std::wstring,具体取决于UNICODE是否已定义。

例如。 LOG4CPLUS_TEXT()宏处理这些情况,它将字符串转换为正确的字符串类型。

问题

虽然log4cplus是使用Unicode编译的(并且IDE显示了正确的预处理器分支),但是链接器无法链接正确的getInstance()或其他方法 - 有时候,在某些文件上!

有时他成功(使用std::wstring版本)然后他失败了; std::string版本尚未找到,但实际上并未使用。

编译没有Unicode支持的log4cplus也没有工作(只是相反的类型问题...)

原因

第三方图书馆 - 在项目中使用 - 在其中有如此深入的代码 - 丛林丛林:

...
#ifdef ...
#define UNICODE
...

(注意:UNICODE未由项目定义)

因此,库在标题中的某处定义了UNICODE - 如果发生这种情况,log4cplus使用wstring方法,否则使用string

这也解释了为什么有些文件正在运行而有些失败 - 取决于它包含哪些标题(以及这些标题包括哪些标题......等等......)

如果UNICODE使用wstring,则使用string - 由log4cplus类型,方法和宏使用(如上面的LOG4CPLUS_TEXT())。如果这个行为在另一个库深处的某个标志处发生变化,那就太棒了......

解决方案

我只需要在编译器标志中添加一个-DUNICODE就可以了! Log4cplus始终使用wchar - / wstring - 现在版本!

无论如何,第三方图书馆将来会被替换,可能会回到非unicode,但这是另一个故事。