1

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 はメインで初期化されます
  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

未定義の参照がある場合:

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

}}
4

1 に答える 1

1

しばらくソースを調べた後、原因と解決策を見つけました。

根っ子

Log4cplus は、が定義されているかどうかに応じて、 char/std::stringまたはwchar/を使用します。std::wstringUNICODE

例えば。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コンパイラ フラグに a を追加するだけで、機能していました。Log4cplus は常にwchar- / wstring-versions を使用するようになりました!

これに関係なく、サードパーティのライブラリは将来的に置き換えられ、非 Unicode に戻る可能性がありますが、それは別の話です。

于 2015-09-07T19:48:46.350 に答える