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

Undefined reference to Logger::getInstance() - but only in some cases

提问人:ollo 提问时间:9/3/2015 最后编辑:ollo 更新时间:9/8/2015 访问量:3672

问:

我正在使用 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()

解决此问题的方法是改用根记录器;这将编译/链接(即使是同一类的一部分!?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. Log4cplus 使用 -llog4cplusSU 链接(也使用 log4cplusS 进行测试),并从它的 git master 编译而来
  2. GCC 4.9 – 使用 C++11
  3. 用于构建项目的 Eclipse CDT
  4. Log4cplus 在 main 中初始化
  5. 所有类都使用相同的编译器和标志进行编译
  6. 全面清洁和建造项目
  7. 所有文件都以相同的方式编译/链接
  8. const / not const 没有效果

结果: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

Whith 未定义的引用:

                 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"));

}}
C++ C++11 GCC 未定义引用 log4cplus

评论

0赞 Vladimir Kunschikov 9/3/2015
从 nm 输出中可以看出,您有可用的 get_instance(“wide char string”),而您没有 get_instance(“c char string”)。
0赞 ollo 9/3/2015
负责字符串类型,不幸的是,即使使用 ,也没有任何区别。LOG4CPLUS_TEXT()std::stringstd::wstringlog4cplus::tstring
0赞 ollo 9/3/2015
令人费解的是,将记录器添加到一个类可能会使另一个类失败,而该类以前是有效的。因此,将记录器添加到 A 类会导致 B 类不再查找 - 即使它在 A 类更改之前可用!?getInstance()
0赞 Vladimir Kunschikov 9/3/2015
没有代码就无法判断。看看你的要求清单 - 成功的和错误的。它们在使用的 get_instance() 上有所不同。成功的链接到 get_instance(std::string<whar_t>)。错误的链接到 get_instance(std::string<char>)。这意味着日志记录包中缺少get_instance(common char std::string)。到目前为止,所有这些都可以在没有源代码的情况下说。
1赞 Vladimir Kunschikov 9/4/2015
有趣的是,如果从 log4cpp 标头中删除 get_instance(std::string),在编译阶段会发生什么 - 为什么 gcc 选择这个版本。

答:

1赞 ollo 9/8/2015 #1

经过一段时间的搜索,我找到了原因和解决方案。

根源

Log4cplus 使用 / 或 / ,具体取决于是否定义。charstd::stringwcharstd::wstringUNICODE

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

问题

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

有时他成功了(使用版本),然后他失败了;找不到该版本,尽管实际上不应该使用它。std::wstringstd::string

在没有Unicode支持的情况下编译log4cplus也不起作用(只是相反的类型问题......

原因

项目中使用的第三方库在其 header-jungle 深处有这样的代码:

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

(注意:UNICODE不是由项目定义的)

因此,在标头中的某处定义的库 - 如果发生这种情况,log4cplus 将使用这些方法,否则 .UNICODEwstringstring

这也解释了为什么有些文件可以正常工作,而有些文件失败了 - 取决于它包含哪些标头(以及这些标头包含哪些内容......等等......

If use , if not use - 由 log4cplus 类型、方法和宏使用(如上面的 LOG4CPLUS_TEXT() 所示)。如果这种行为在另一个库深处的某个地方改变了某个标志,那就太好了......UNICODEwstringstring

解决方案

我只需要在编译器标志中添加一个,它就可以工作了!Log4cplus 现在总是使用 - / -versions !-DUNICODEwcharwstring

无论如何,第三方库将在未来被替换,也许会回到非 unicode,但那是另一回事了。