对 Logger::getInstance() 的未定义引用 - 但仅在某些情况下
Undefined reference to Logger::getInstance() - but only in some cases
我正在使用 log4cplus(从当前的 git master 编译而来),但是 linker 我得到了未定义的引用错误。但是,这些错误 仅在某些 classes 处发生。
一般来说每个class都有以下形式:
Header (.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"));
用法
记录器在 class 中使用如下:
LOG4CPLUS_WARN(logger, "Ha, ha – whatever you try I wont work!");
在编译工作时,linker 为
引发未定义的引用错误
log4cplus::Logger::getInstance(std::string const&)
和
log4cplus::detail::macro_forced_log(log4cplus::Logger const&, int, std::string const&, char const*, int, char const*)
对于某些 classes。我已经从工作 classes 中复制了 logger-parts:相同的结果。
用 class-member 替换静态记录器也不起作用 – getInstance()
未找到。
解决此问题的方法是使用 root-logger;这将编译 / link(即使 getRoot()
是相同 class 的一部分!?):
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))
相同的结果,之前有效的也有效,而无效的……无效。
更多信息:
- Log4cplus linked 使用 -llog4cplusSU(也用 log4cplusS 测试)并从它的 git master
编译而来
- GCC 4.9 – 使用 C++11
- Eclipse CDT 用于构建项目
- Log4cplus在main中初始化
- 所有 classes 都使用相同的编译器和标志编译
- 完全clean-and-build项目
- 所有文件都以相同的方式编译/linked
- const / not const 无效
nm <NAME>.o | grep -i log4cplus
的结果:
工作object
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
最小class 失败
//////////////////////// 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"));
}}
经过一段时间查看源代码后,我找到了原因和解决方案。
根
Log4cplus 使用 char
/ std::string
或 wchar
/ std::wstring
,取决于是否定义了 UNICODE
。
例如。 LOG4CPLUS_TEXT()
宏处理这些情况,它将字符串转换为正确的字符串类型。
问题
尽管 log4cplus 是使用 Unicode 编译的(并且 IDE 显示了正确的预处理器分支),linker 无法 link 正确的 getInstance()
或其他方法 - 有时, 在某些文件上!
有时他成功了(使用 std::wstring
版本)然后他失败了;未找到 std::string
版本,但实际上不应使用它。
在没有 Unicode 支持的情况下编译 log4cplus 也不起作用(只是相反类型的问题...)
原因
一个第 3 方库 - 在项目中使用 - 在它的深处有这样的代码 header-jungle:
...
#ifdef ...
#define UNICODE
...
(注:UNICODE
不是项目定义的)
所以库在 header 的某处定义了 UNICODE
- 如果发生这种情况,log4cplus 使用 wstring
方法,否则 string
.
这也解释了为什么有些文件可以工作而有些文件失败 - 取决于它包含的 headers(以及那些 headers 自己包含的内容......等等.. .)
如果 UNICODE
使用 wstring
,如果不使用 string
- 由 log4cplus 类型、方法和宏使用(如上面的 LOG4CPLUS_TEXT())。如果此行为被另一个库深处某处的某个标志改变,那就太好了...
解决方案
我只需要在编译器标志中添加一个 -DUNICODE
就可以了! Log4cplus 现在总是使用 wchar
- / wstring
-版本!
不管怎样,以后会替换3rd party库,可能会回到non-unicode,但那是另外一回事了。
我正在使用 log4cplus(从当前的 git master 编译而来),但是 linker 我得到了未定义的引用错误。但是,这些错误 仅在某些 classes 处发生。
一般来说每个class都有以下形式:
Header (.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"));
用法
记录器在 class 中使用如下:
LOG4CPLUS_WARN(logger, "Ha, ha – whatever you try I wont work!");
在编译工作时,linker 为
引发未定义的引用错误log4cplus::Logger::getInstance(std::string const&)
和
log4cplus::detail::macro_forced_log(log4cplus::Logger const&, int, std::string const&, char const*, int, char const*)
对于某些 classes。我已经从工作 classes 中复制了 logger-parts:相同的结果。
用 class-member 替换静态记录器也不起作用 – getInstance()
未找到。
解决此问题的方法是使用 root-logger;这将编译 / link(即使 getRoot()
是相同 class 的一部分!?):
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))
相同的结果,之前有效的也有效,而无效的……无效。
更多信息:
- Log4cplus linked 使用 -llog4cplusSU(也用 log4cplusS 测试)并从它的 git master 编译而来
- GCC 4.9 – 使用 C++11
- Eclipse CDT 用于构建项目
- Log4cplus在main中初始化
- 所有 classes 都使用相同的编译器和标志编译
- 完全clean-and-build项目
- 所有文件都以相同的方式编译/linked
- const / not const 无效
nm <NAME>.o | grep -i log4cplus
的结果:
工作object
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
最小class 失败
//////////////////////// 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"));
}}
经过一段时间查看源代码后,我找到了原因和解决方案。
根
Log4cplus 使用 char
/ std::string
或 wchar
/ std::wstring
,取决于是否定义了 UNICODE
。
例如。 LOG4CPLUS_TEXT()
宏处理这些情况,它将字符串转换为正确的字符串类型。
问题
尽管 log4cplus 是使用 Unicode 编译的(并且 IDE 显示了正确的预处理器分支),linker 无法 link 正确的 getInstance()
或其他方法 - 有时, 在某些文件上!
有时他成功了(使用 std::wstring
版本)然后他失败了;未找到 std::string
版本,但实际上不应使用它。
在没有 Unicode 支持的情况下编译 log4cplus 也不起作用(只是相反类型的问题...)
原因
一个第 3 方库 - 在项目中使用 - 在它的深处有这样的代码 header-jungle:
...
#ifdef ...
#define UNICODE
...
(注:UNICODE
不是项目定义的)
所以库在 header 的某处定义了 UNICODE
- 如果发生这种情况,log4cplus 使用 wstring
方法,否则 string
.
这也解释了为什么有些文件可以工作而有些文件失败 - 取决于它包含的 headers(以及那些 headers 自己包含的内容......等等.. .)
如果 UNICODE
使用 wstring
,如果不使用 string
- 由 log4cplus 类型、方法和宏使用(如上面的 LOG4CPLUS_TEXT())。如果此行为被另一个库深处某处的某个标志改变,那就太好了...
解决方案
我只需要在编译器标志中添加一个 -DUNICODE
就可以了! Log4cplus 现在总是使用 wchar
- / wstring
-版本!
不管怎样,以后会替换3rd party库,可能会回到non-unicode,但那是另外一回事了。